jfinal-undertow环境下Freemarker模板路径的配置问题

从项目刚开始就一直关注着,因为项目一直在用Freemarker模板,新出的jfinal-undertow在第一时间就部署了。可是Freemarker模板总是找不到了。在最初版出来时就反馈给波总了。现在1.1出来后,试用了下,好像还是没有找到。不知道是不是我配置有问题

在我的配置类中配置了模板的默认路径为templates

public void configRoute(Routes routes) {
    routes.setBaseViewPath("/templates");

    routes.add("/", MainController.class, "");

}

在测试的MainController中添加action

public class MainController extends Controller {
    public void index(){
       setAttr("name", "Jfinal");
       renderFreeMarker("demo.ftl");
    }
}


一直报模板找不到

[ERROR]-[Thread: XNIO-1 task-1]-[com.jfinal.core.ActionHandler.handle()]: /
com.jfinal.render.RenderException: freemarker.template.TemplateNotFoundException: Template not found for name "/templates/demo.ftl".
The name was interpreted by this TemplateLoader: WebappTemplateLoader(subdirPath="/", servletContext={contextPath="", displayName=null}).
	at com.jfinal.render.FreeMarkerRender.render(FreeMarkerRender.java:161)
	at com.jfinal.core.ActionHandler.handle(ActionHandler.java:106)
	at com.jfinal.ext.handler.ContextPathHandler.handle(ContextPathHandler.java:48)
	at com.jfinal.core.JFinalFilter.doFilter(JFinalFilter.java:86)
	at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
	at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
	at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
	at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
	at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
	at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
	at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
	at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
	at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
	at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
	at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
	at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
	at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
	at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
	at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
	at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
	at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
	at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
	at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
	at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
	at io.undertow.server.Connectors.executeRootHandler(Connectors.java:360)
	at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
Caused by: freemarker.template.TemplateNotFoundException: Template not found for name "/templates/demo.ftl".
The name was interpreted by this TemplateLoader: WebappTemplateLoader(subdirPath="/", servletContext={contextPath="", displayName=null}).
	at freemarker.template.Configuration.getTemplate(Configuration.java:2797)
	at freemarker.template.Configuration.getTemplate(Configuration.java:2599)
	at com.jfinal.render.FreeMarkerRender.render(FreeMarkerRender.java:156)

我试着把/templates目录放到/webapp/WEB-INF下也是一样 。

@JFinal 这个问题怎么处理 , 是需要额外添加路径配置吗?我试着用

FreeMarkerRender.getConfiguration()去配也没有成功。


评论区

没牙的小朋友

2018-12-02 10:06

routes.setBaseViewPath("/templates");去掉,直接把demo.ftl放到webapp下也不行

没牙的小朋友

2018-12-02 10:37

使用Undertow在Config类里的afterJFinalStart()方法中,获取的ServletContext servletContext = JFinal.me().getServletContext();
servletContext.getResource("demo.ftl")得到的是null,而在Jetty环境下,可以得到实际的路径/src/main/webapp/demo.ftl

没牙的小朋友

2018-12-02 11:21

我找到原因了
ResourceManagerKit中的 public static ResourceManager buildResourceManager(String resourcePath, ClassLoader classLoader) 方法

public static ResourceManager buildResourceManager(String resourcePath, ClassLoader classLoader) {
CompositeResourceManager ret = new CompositeResourceManager();
String resourcePathArray[] = resourcePath.split(",");

for (String path : resourcePathArray) {
path = path.trim(); //注意,这里拿到的是src/main/webapp, webapp, src/main/resource/webapp
if (new File(path).isDirectory()) { //new File()不是实际的路径
ret.add(new FileResourceManager(new File(path)));
}
}

if (UndertowKit.isDeployMode()) {
forDeployMode(classLoader, ret);
}

return ret;
}
其中new File(path).isDirectory()这里有问题,应该永远都是false,导致CompositeResourceManager类里的resourceManagers一直是空。为path只是相对路径,没有加上项目的实际路径,可以在前面添加PathKit.getWebRootPath()
我把path = path.trim(); 修改为
path = PathKit.getWebRootPath() + "/" + path.trim();
现在没有问题了。

JFinal

2018-12-02 11:39

异常提示的是:Template not found for name "/templates/demo.ftl".

那么将模板文件放在 webapp/templates 下面即可

JFinal

2018-12-02 11:39

根据异常提示去找原因,我们用着都没问题,你手动修改的那个地方对于部署可能会造成问题,你测试一下

没牙的小朋友

2018-12-02 12:23

@JFinal 我已经把模板路径配成默认的webapp根目录了,模板也在。还是一样的问题。应该我是有一个子模块,获取webapp去找父模块的/src/main/webapp了。这应该怎么解决。项目的目录结构是这样的
├─jfinal-starter-web
│ ├─src
│ │ └─main
│ │ ├─java
│ │ │ └─cn
│ │ │ └─edu
│ │ │ └─nxu
│ │ │ └─mjl
│ │ │ ├─config
│ │ │ ├─controller
│ │ ├─resources
│ │ └─webapp
│ │ ├─templates
│ │ ├─demo.ftl
│ │ │ └─main
│ │ └─WEB-INF

└─src
└─main
└─webapp**(去找这个目录了)

JFinal

2018-12-02 12:39

在 FreeMakerRender 中的 render() 方法中调试一下,看具体是什么行为

默认是去 src/main/webapp 下面去找模板,你删掉项目根目录下面的 webapp , 只保留 src/main/webapp 试试

JFinal

2018-12-03 16:56

由于有了 jfinal enjoy 模板引擎,所以两年没用过 freemarker,所以今天针对这个问题专门在 jfinal undertow 上做了测试

测试结果是没有任何问题,以前的 freemarker 项目在 jfinal undertow 不做任何改动就可运行

JFinal

2018-12-03 17:35

@没牙的小朋友 最后给你一个方案:
1:将 webapp 目录整体挪到 src/main/resources 目录之下

2: configEngine 中配置
engine.setBaseTemplatePath("webapp");
engine.setToClassPathSourceFactory());

3:打包描述文件 package.xml 中的复制 src/main/webapp 目录资源到 jar 包中的配置由 "${basedir}/src/main/webapp" 改成 "${basedir}/src/main/resources/webapp"

由于 src/main/resources 属于 class path 的范畴,而这个路径是很稳固的,所以将所有 web 资源放在这里很方便使用,部署环境也很方便

邶风

2019-01-08 14:21

@没牙的小朋友
undertow.txt文件使用配置
undertow.resourcePath=xxxxx/src/main/webapp
xxxxx是你子模块的文件夹name

热门反馈

扫码入社