我正在开发一个简单的Web应用程序,该应用程序提供用于管理多种资源的RestFul API。
我正在使用Java标准版-openjdk version "1.8.0_191
和以下javalite依赖项:
javalite-common-2.3-SNAPSHOT.jar
activejdbc-2.3-SNAPSHOT.jar
activeweb-2.3-SNAPSHOT.jar
activeweb-testing-2.3-SNAPSHOT.jar
freemarker-2.3.28.jar
我将嵌入式jetty v9.4.1
用于Web服务器,整个项目打包为具有依赖项的jar,并使用以下命令运行:
java -Dconfig=/etc/project/config.properties -jar jarname.jar
该Web应用程序设计为仅提供JSON,并且所有FreeMarker模板均构造JSON消息。这是我的FreeMarker配置类:
public class FreeMarkerConfig extends AbstractFreeMarkerConfig {
@Override
public void init() {
// this is to override a strange FreeMarker default processing of numbers
Configuration config = this.getConfiguration();
config.setNumberFormat("0.##");
config.setClassicCompatible(true);
config.setClassForTemplateLoading(this.getClass(), "webapp/WEB-INF/views");
}
}
包装后,罐子内的结构如下(这是只有一种资源的简化版本):
├── META-INF
│ ├── MANIFEST.MF
│ └── maven
│ └── project.control
│ └── panel
│ ├── pom.properties
│ └── pom.xml
├── activejdbc_models.properties
├── app
│ ├── config
│ │ ├── AppBootstrap.class
│ │ ├── AppControllerConfig.class
│ │ ├── DbConfig.class
│ │ ├── FreeMarkerConfig.class
│ │ └── RouteConfig.class
│ ├── controllers
│ │ ├── APIController.class
│ │ ├── CatchAllFilter.class
│ │ ├── OfficesController.class
│ └── models
│ ├── Office.class
├── config.properties
├── project
│ └── control
│ └── panel
│ ├── Launcher.class
│ ├── dao
│ │ ├── query
│ │ │ ├── Query.class
│ │ │ ├── QueryBuilder.class
│ │ │ ├── QueryStringBuilder.class
│ │ │ ├── StatsParamsHandler.class
│ │ └── validators
│ │ ├── OfficeValidator.class
│ ├── exceptions
│ │ └── ResourceNotFoundException.class
│ └── util
│ ├── Config.class
│ ├── JsonHelper.class
└── webapp
└── WEB-INF
├── views
│ ├── offices
│ │ ├── _comma.ftl
│ │ ├── _office.ftl
│ │ ├── _office_agency.ftl
│ │ ├── _office_agent.ftl
│ │ └── index.ftl
│ ├── layouts
│ │ └── default_layout.ftl
│ ├── shared
│ │ ├── _paging.ftl
│ │ └── message.ftl
│ ├── system
│ │ ├── 404.ftl
│ │ └── error.ftl
└── web.xml
大多数时候,一切似乎都可以正常运行,没有任何问题。但是在某些时候发生了某些情况,FreeMarker无法找到以前多次提供的模板。
我无法在localhost上重现该行为,因此无法对其进行调试。
在服务器上运行时发生了几次。我唯一的观察是它在几个空闲时间后发生-即几个小时没有任何请求,下一个请求失败,因为FreeMarker无法找到所需的模板。这是在请求/offices
时引发的确切异常:
2019-06-24 15:22:50 - INFO LazyList:164 - {"sql":"SELECT * FROM offices ORDER BY id LIMIT 20 OFFSET 0 ","params":[],"duration_millis":2,"cache":"miss"}
2019-06-24 15:22:50 - INFO DB:164 - {"sql":"SELECT COUNT(*) FROM offices","params":[],"duration_millis":0}
2019-06-24 15:22:50 - INFO FreeMarkerTemplateManager:81 - Rendering template: '/offices/index.ftl' without layout.
2019-06-24 15:22:50 - INFO FreeMarkerTemplateManager:81 - Rendering template: '/shared/message.ftl' without layout.
2019-06-24 15:22:50 - INFO RequestDispatcher:360 - {"controller":"app.controllers.OfficesController","duration_millis":15,"remote_ip":"127.0.0.1","method":"GET","action":"index","error":"Failed to render template: '/shared/message.ftl' without layout. Template not found for name \\\"/shared/message.ftl\\\".\\nThe name was interpreted by this TemplateLoader: WebappTemplateLoader(subdirPath=\\\"/WEB-INF/views/\\\", servletContext={contextPath=\\\"\\\", displayName=\\\"activeweb\\\"}).","url":"http://127.0.0.1:5050/offices","status":404}
2019-06-24 15:22:50 - INFO FreeMarkerTemplateManager:81 - Rendering template: '/system/404.ftl' with layout: '/layouts/default_layout.ftl'.
2019-06-24 15:22:50 - ERROR RequestDispatcher:290 - ActiveWeb internal error:
org.javalite.activeweb.ViewMissingException: Failed to render template: '/system/404.ftl' with layout: '/layouts/default_layout.ftl'. Template not found for name "/system/404.ftl".
The name was interpreted by this TemplateLoader: WebappTemplateLoader(subdirPath="/WEB-INF/views/", servletContext={contextPath="", displayName="activeweb"}).
at org.javalite.activeweb.freemarker.FreeMarkerTemplateManager.merge(FreeMarkerTemplateManager.java:109)
at org.javalite.activeweb.RenderTemplateResponse.doProcess(RenderTemplateResponse.java:88)
at org.javalite.activeweb.ControllerResponse.process(ControllerResponse.java:67)
at org.javalite.activeweb.RequestDispatcher.renderSystemError(RequestDispatcher.java:283)
at org.javalite.activeweb.RequestDispatcher.doFilter(RequestDispatcher.java:219)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1613)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:541)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1584)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1228)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:481)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1553)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1130)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.Server.handle(Server.java:564)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:320)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:112)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:672)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:590)
at java.lang.Thread.run(Thread.java:748)
如有需要,可以提供其他详细信息。
可能导致此类问题的原因-尽管一切似乎正常,但是FreeMaker突然无法找到以前没有问题的模板。
任何有助于调试该问题的建议都会受到赞赏。
谢谢!
答案 0 :(得分:2)
经过更详细的调查,看来Jetty从罐子中提取了FreeMarker模板并将其放置在/tmp
文件夹中。文件夹具有以下模式
/tmp/jetty-<host>-<port>-<resourceBase>-<context>-<virtualhost>-<randomdigits>.dir
示例:
jetty-0.0.0.0-5050-webapp-_-any-35239075401795634.dir
基于Unix的操作系统具有清除/tmp
文件夹的策略,并且在删除文件夹后-显然找不到模板。
解决方案是将jetty的WebAppContext配置为使用另一个目录来存储此类数据。这可以通过setTempDirectory
方法完成:
String webViewsPath = Launcher.class.getResource("/webapp").toString();
WebAppContext webapp = new WebAppContext(webViewsPath, "/");
webapp.setTempDirectory(new File("/data/templates"));
server.setHandler(webapp);
有关码头临时目录的更多信息,请参见: https://www.eclipse.org/jetty/documentation/9.4.x/ref-temporary-directories.html