在Web层,我们的应用程序将有一个过滤器,它将根据请求URL将执行委托给启用Thymeleaf的命令:
private boolean process(HttpServletRequest request, HttpServletResponse response)
throws ServletException {
try {
// This prevents triggering engine executions for resource URLs
// 这将阻止触发资源URL的引擎执行(判断资源的请求是否为css、images、favicon)
if (request.getRequestURI().startsWith("/css") ||
request.getRequestURI().startsWith("/images") ||
request.getRequestURI().startsWith("/favicon")) {
return false;
}
/*
* Query controller/URL mapping and obtain the controller
* that will process the request. If no controller is available,
* return false and let other filters/servlets process the request.
*/
/**
* 根据url映射并获取可处理请求的控制器,如果没有可用的控制器则返回false
* 让其他过滤器/servlet处理请求。
*/
IGTVGController controller = this.application.resolveControllerForRequest(request);
if (controller == null) {
return false;
}
/*
* Obtain the TemplateEngine instance.
* 获取模板引擎的实例
*/
ITemplateEngine templateEngine = this.application.getTemplateEngine();
/*
* Write the response headers
* 书写响应头的一些属性
*/
response.setContentType("text/html;charset=UTF-8");
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
/*
* Execute the controller and process view template,
* writing the results to the response writer.
* 控制器执行并处理视图模板,将结果写入响应的writer
*/
controller.process(
request, response, this.servletContext, templateEngine);
return true;
} catch (Exception e) {
try {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
} catch (final IOException ignored) {
// Just ignore this
}
throw new ServletException(e);
}
}
让我们从模板解析器开始
ServletContextTemplateResolver templateResolver =
new ServletContextTemplateResolver(servletContext);
模板解析器是实现Thymeleaf API的接口的对象,称为org.thymeleaf.templateresolver.ITemplateResolver:
public interface ITemplateResolver {
...
/*
* Templates are resolved by their name (or content) and also (optionally) their
* owner template in case we are trying to resolve a fragment for another template.
* Will return null if template cannot be handled by this template resolver.
* 模板通过其名称(或内容)和(可选)其所有者模板,以防我们试图解析另一个模板的片段。
* 如果模板解析程序无法处理模板,则返回空值。
*/
public TemplateResolution resolveTemplate(
final IEngineConfiguration configuration,
final String ownerTemplate, final String template,
final Map<String, Object> templateResolutionAttributes);
}
These objects are in charge of determining how our templates will be accessed, and in this GTVG application, the org.thymeleaf.templateresolver.ServletContextTemplateResolver means that we are going to retrieve our template files as resources from the Servlet Context: an application-wide javax.servlet.ServletContext object that exists in every Java web application, and that resolves resources from the web application root.
这些ITemplateResolver的实现类负责确定如何访问模板,在这个GTVG应用程序中,org.thymeleaf.templateresolver.ServletContextTemplateResolver这个模板解析器意味着我们将从Servlet上下文中去检索对应的模板文件资源;javax.servlet.ServletContext是每个Java Web应用程序中都存在的应用程序范围的对象,从Web应用程序的根目录解析资源。
对于Good Thymes Virtual Grocery来说,他选择了ServletContextTemplateResolver作为ITemplateResolver的实现类,它允许我们从Servlet Context获取模板资源。
我们除了能够通过实现ITemplateResolver创建其模板解析器,Thymeleaf提供了四个开箱即用的模板解析器:
(一)org.thymeleaf.templateresolver.ClassLoaderTemplateResolver
解析模板为类加载器资源,如:
(二)org.thymeleaf.templateresolver.FileTemplateResolver
解析模板为文件系统中的文件
(三)org.thymeleaf.templateresolver.UrlTemplateResolver
解析模板为URL类型(甚至是非本地的)
(四)org.thymeleaf.templateresolver.StringTemplateResolver
解析指定为模板的字符串,
进一步的配置
//配置模板模式,默认为html
templateResolver.setTemplateMode(TemplateMode.HTML);
//配置资源文件或模板的前后缀
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
//(非必选)配置模板缓存的时间
templateResolver.setCacheTTLMs(3600000L);
//设置编码
templateResolver.setEncoding("UTF-8");
// 设置开启缓存,默认为true
templateResolver.setCacheable(false);
//设置特殊路径下的缓存策略
templateResolver.getCacheablePatternSpec().addPattern("/users/*");
关于templateResolver模板解析器还有很多东西需要学习,但是现在让我们来看看Template Engine模板引擎对象的创建
//模板引擎对象是org.thymeleaf.ITemplateEngine接口的实现。其中,
//org.thymeleaf.TemplateEngine这个实现是由Thymeleaf核心提供的
//我们在这里创建一个实例:
templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
//我们要做的仅仅是为这个templateEngine模板引擎实例设置一个templateResolver模板解析器。
模板解析链(Chaining Template Resolvers)
//同时,一个模板引擎可以指定多个模板解析器,在这个情况下,可以为不同的模板解析器设置order顺序来进行执行。这样,如果第一个无法解析模板,则会询问第二个,依此类推:
//创建类加载模板解析器
ClassLoaderTemplateResolver classLoaderTemplateResolver = new ClassLoaderTemplateResolver();
//设置改模板解析器的执行次序
classLoaderTemplateResolver.setOrder(Integer.valueOf(1));
//创建servlet上下文模板解析器
ServletContextTemplateResolver servletContextTemplateResolver = new ServletContextTemplateResolver(servletContext);
//设置改模板解析器的执行次序
servletContextTemplateResolver.setOrder(Integer.valueOf(2));
//为模板引擎设置模板解析器
templateEngine.addTemplateResolver(classLoaderTemplateResolver);
templateEngine.addTemplateResolver(servletContextTemplateResolver);
建议:当存在多个模板解析器时,建议为每个模板解析器指定模式,以便Thymeleaf可以快速丢弃那些不打算解析模板的模板解析器,从而提高性能。
如果没有为模板解析器设置解析的模式,我们将以当前使用的ITemplateResolver实现类指定的特定正则表达为标准。请注意,注意:并非所有实现类都可以在解析之前确定模板的存在,因此可以始终将模板视为可解析并打破解析链,不会继续往下使用另外一个解析器(不允许其他解析器检查相同的模板),但随后无法阅读真实资源。