项目场景:
公司有个需求,用到了freemaker,maven依赖直接上的低版本,所以初始化配置需要自己去写。
问题描述:
配置模板文件路径时,本地windows开发环境,idea中写的代码可以正常执行,但是到了测试服务器,就报空指针异常。错误原因 ***************does not exist.
创建freemaker相关配置类出错:/opt/wkhtmltox/src/main/resources/template/ftl does not exist.;建议检查模板路径。 2021-11-23 10:26:23.707 INFO [cpms-project-meng-provider,,,,] 1 --- [io-33003-exec-7] .c.m.s.d.i.DesignDispatchFlowServiceImpl : freemaker生成临时html文件工具类,io异常!:Template /designdispatch.ftl not found. 2021-11-23 10:26:23.819 DEBUG [cpms-project-meng-provider,,,,] 1 --- [io-33003-exec-7] .m.m.a.ExceptionHandlerExceptionResolver : Using @ExceptionHandler public com.chinamobile.cmss.cpms.meng.dto.response.ResponseDto com.chinamobile.cmss.cpms.meng.config.exception.MengGlobalExceptionHandler.exceptionNullPointer(java.lang.NullPointerException) 2021-11-23 10:26:23.820 TRACE [cpms-project-meng-provider,,,,] 1 --- [io-33003-exec-7] .w.s.m.m.a.ServletInvocableHandlerMethod : Arguments: [java.lang.NullPointerException] 2021-11-23 10:26:23.820 ERROR [cpms-project-meng-provider,,,,] 1 --- [io-33003-exec-7] c.c.c.c.m.c.e.MengGlobalExceptionHandler : 空指针处理异常
原因分析:
本地代码直接访问windows相关路径,文件系统固定不变,代码可以访问的到,但是,代码一旦上传到服务器,springboot项目将会变成jar包,jar包无法访问外部路径,因此,写死的路径将无法访问。
问题代码行:configuration.setDirectoryForTemplateLoading(new File(templatePath));
import freemarker.template.Configuration;
import freemarker.template.TemplateExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
@Slf4j
public class FreeMakerUtil {
private static Configuration configuration = null;
public static Configuration getConfiguration(final String templatePath) {
if( configuration == null){
synchronized (FreeMakerUtil.class){
if(configuration == null){
/* ------------------------------------------------------------------------ */
/* You should do this ONLY ONCE in the whole application life-cycle: */
/* Create and adjust the configuration singleton */
configuration = new Configuration();
try {
configuration.setDirectoryForTemplateLoading(new File(templatePath));
} catch (IOException e) {
log.info("创建freemaker相关配置类出错:{};建议检查模板路径。",e.getMessage());
}
configuration.setDefaultEncoding("UTF-8");
configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
/* ------------------------------------------------------------------------ */
/* You usually do these for MULTIPLE TIMES in the application life-cycle: */
}
}
}
return configuration;
}
}
解决方案:
Freemarker提供了3种加载模板目录的方法。 它使用Configuration类加载模板
public void setClassForTemplateLoading(Class clazz, String pathPrefix);
public void setDirectoryForTemplateLoading(File dir) throws IOException;
public void setServletContextForTemplateLoading(Object servletContext, String path);
我用的:
-
public void setClassForTemplateLoading(Class clazz, String pathPrefix)
;
方法,基于类路径去找模板文件
public class FreeMakerUtil {
private static Configuration configuration = null;
public static Configuration getConfiguration(final String templatePath) {
if( configuration == null){
synchronized (FreeMakerUtil.class){
if(configuration == null){
/* ------------------------------------------------------------------------ */
/* You should do this ONLY ONCE in the whole application life-cycle: */
/* Create and adjust the configuration singleton */
configuration = new Configuration();
configuration.setClassForTemplateLoading(FreeMakerUtil.class,templatePath);
configuration.setDefaultEncoding("UTF-8");
configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
/* ------------------------------------------------------------------------ */
/* You usually do these for MULTIPLE TIMES in the application life-cycle: */
}
}
}
return configuration;
}
}
备注:
.ftl模板文件存放的位置; 创建freemaker的configuration时传入的路径字符串为:
"/template/ftl"
参考文章:Freemarker中Configuration的setClassForTemplateLoading方法参数问题_CourageHe的博客-CSDN博客