模板解析器
在web项目中,我们使用 ITemplateResolver 的实现 ServletContextTemplateResolver,用以从Servlet上下文中获取模板作为资源。
除了通过实现ITemplateResolver来创建模板解析器之外,还包括一下四种实现:
-
org.thymeleaf.templateresolver.ClassLoaderTemplateResolver,它将模板解析为类加载器资源,例如:
return Thread.currentThread().getContextClassLoader().getResourceAsStream(template);
-
org.thymeleaf.templateresolver.FileTemplateResolver,它将模板解析为来自文件系统的文件,例如:
return new FileInputStream(new File(template));
-
org.thymeleaf.templateresolver.UrlTemplateResolver,它将模板解析为URL(甚至是非本地的URL),例如:
return (new URL(template)).openStream();
-
org.thymeleaf.templateresolver.StringTemplateResolver,它直接将模板解析 String 为指定为的名称template(或模板名称,在这种情况下,显然不仅仅是一个简单的名称):
return new StringReader(templateName);
所有预先捆绑的 ITemplateResolver 实现都允许使用相同的配置参数集,其中包括:
-
前缀和后缀:
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
-
模板别名允许使用与文件名不直接对应的模板名。如果后缀/前缀和别名都存在,则别名将在前缀/后缀之前应用:
templateResolver.addTemplateAlias("adminHome","profiles/admin/home");
templateResolver.setTemplateAliases(aliasesMap);
-
读取模板时要应用的编码:
templateResolver.setCharacterEncoding("UTF-8");
-
使用的模板模式:
// Default is HTML
templateResolver.setTemplateMode("XML");
-
模板缓存的默认模式,以及用于定义特定模板是否可缓存的模式:
// Default is true
templateResolver.setCacheable(false);
templateResolver.getCacheablePatternSpec().addPattern("/users/*");
源自此模板解析器的已解析模板缓存条目的TTL(以毫秒为单位)。如果未设置,则从缓存中删除条目的唯一方法是超过缓存的最大大小(最旧的条目将被删除)。
// Default is no TTL (only cache size exceeded would remove entries)
templateResolver.setCacheTTLMs(60000L);
Thymeleaf + Spring集成软件包提供了一种 SpringResourceTemplateResolver 实现,该实现使用所有Spring基础结构来访问和读取应用程序中的资源,这是在支持Spring的应用程序中推荐的实现。
模板解析器链
此外,模板引擎可以指定多个模板解析器,在这种情况下,可以在它们之间建立顺序以进行模板解析,这样,如果第一个解析器无法解析模板,则要求第二个解析器,依此类推:
ClassLoaderTemplateResolver classLoaderTemplateResolver = new ClassLoaderTemplateResolver();
classLoaderTemplateResolver.setOrder(Integer.valueOf(1));
ServletContextTemplateResolver servletContextTemplateResolver =
new ServletContextTemplateResolver(servletContext);
servletContextTemplateResolver.setOrder(Integer.valueOf(2));
templateEngine.addTemplateResolver(classLoaderTemplateResolver);
templateEngine.addTemplateResolver(servletContextTemplateResolver);
当应用多个模板解析器时,建议为每个模板解析器指定模式,以便Thymeleaf可以快速丢弃那些不打算解析模板的模板解析器,从而提高性能。并不是必须这样做,而是建议:
ClassLoaderTemplateResolver classLoaderTemplateResolver = new ClassLoaderTemplateResolver();
classLoaderTemplateResolver.setOrder(Integer.valueOf(1));
// This classloader will not be even asked for any templates not matching these patterns
classLoaderTemplateResolver.getResolvablePatternSpec().addPattern("/layout/*.html");
classLoaderTemplateResolver.getResolvablePatternSpec().addPattern("/menu/*.html");
ServletContextTemplateResolver servletContextTemplateResolver =
new ServletContextTemplateResolver(servletContext);
servletContextTemplateResolver.setOrder(Integer.valueOf(2));
如果未指定这些可解析的模式,我们将依赖于 ITemplateResolver 我们所使用的每个实现的特定功能。请注意,并非所有的实现都能够在解析之前确定模板的存在,因此始终可以将模板视为可解析的,并打破了解析链(不允许其他解析器检查同一模板),但是却无法阅读实际资源。
所有 ITemplateResolver 附带核心Thymeleaf实现包括一种机制,将使我们能够使解析器真正检查如果资源考虑之前存在解析。它是 checkExistence 标志,其工作方式如下:
ClassLoaderTemplateResolver classLoaderTemplateResolver = new ClassLoaderTemplateResolver();
classLoaderTemplateResolver.setOrder(Integer.valueOf(1));
classLoaderTempalteResolver.setCheckExistence(true);
该 checkExistence 标志强制解析器在解析阶段对资源是否存在进行真正的检查(如果存在检查返回false,则调用链中的以下解析器)。尽管这在每种情况下听起来都不错,但在大多数情况下,这将意味着对资源本身的双重访问(一次检查是否存在,另一次读取它),并且在某些情况下可能会成为性能问题,例如,基于远程URL的模板资源–潜在的性能问题可能会通过使用模板缓存而在很大程度上得到缓解(在这种情况下,仅在首次访问模板时才能解决模板问题)。
邮件解析器
StandardMessageResolver 是 IMessageResolver 接口的标准实现,但是如果需要,我们可以创建自己的接口,以适应应用程序的特定需求。
Thymeleaf + Spring集成软件包默认提供一种 IMessageResolver 实现,该实现使用标准Spring方法来检索外部化消息,方法是使用 MessageSource 在Spring Application Context声明的bean。
标准消息解析器
那么,如何 StandardMessageResolver 查找在特定模板上请求的消息?
如果模板名称为 home,并且位于中 /WEB-INF/templates/home.html,并且请求的语言环境为 gl_ES 则此解析器将按以下顺序在以下文件中查找消息:
-
/WEB-INF/templates/home_gl_ES.properties
-
/WEB-INF/templates/home_gl.properties
-
/WEB-INF/templates/home.properties
StandardMessageResolver 有关完整的消息解析机制如何工作的更多详细信息,请参阅该类的JavaDoc文档。
配置消息解析器
如果我们想向模板引擎添加消息解析器(或更多)怎么办?简单:
// For setting only one
templateEngine.setMessageResolver(messageResolver);
// For setting more than one
templateEngine.addMessageResolver(messageResolver);
为什么我们要拥有多个消息解析器?出于与模板解析器相同的原因:如果第一个无法解析特定的消息,则将询问第二个,然后询问第三个,依此类推。
转换服务
转换服务,使我们用的手段来进行数据转换和格式化操作双括号语法(${{...}})实际上是标准方言的特点,而不是Thymeleaf模板引擎本身。
因此,配置 IStandardConversionService 接口的方法是将接口的自定义实现直接设置 StandardDialect 为要配置到模板引擎中的接口的实例。例如:
IStandardConversionService customConversionService = ...
StandardDialect dialect = new StandardDialect();
dialect.setConversionService(customConversionService);
templateEngine.setDialect(dialect);
请注意,thymeleaf-spring3和thymeleaf-spring4软件包包含 SpringStandardDialect,并且该方言已经预先配置了 IStandardConversionService 将Spring自己的Conversion Service基础结构集成到Thymeleaf中的实现。
日志
Thymeleaf非常重视日志记录,并始终尝试通过其日志记录界面提供尽可能多的有用信息。
slf4j,实际上,所使用的日志记录库实际上充当了我们想要在应用程序中使用的任何日志记录实现的桥梁(例如log4j)。
Thymeleaf班会记录TRACE,DEBUG,INFO级别信息,这取决于我们希望的详细程度,并且除了一般的记录它会使用与TemplateEngine类,我们可以为不同的目的而单独配置相关的三个特殊记录器:
-
org.thymeleaf.TemplateEngine.CONFIG 在初始化期间将输出库的详细配置。
-
org.thymeleaf.TemplateEngine.TIMER 将输出有关处理每个模板所需时间的信息(可用于基准测试!)
-
org.thymeleaf.TemplateEngine.cache 是一组记录器的前缀,该记录器输出有关缓存的特定信息。尽管缓存记录器的名称可由用户配置,因此可以更改,但是默认情况下它们是:
-
-
org.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE
-
org.thymeleaf.TemplateEngine.cache.EXPRESSION_CACHE
-
使用的Thymeleaf日志记录基础结构的示例配置log4j可能是:
log4j.logger.org.thymeleaf=DEBUG
log4j.logger.org.thymeleaf.TemplateEngine.CONFIG=TRACE
log4j.logger.org.thymeleaf.TemplateEngine.TIMER=TRACE
log4j.logger.org.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE=TRACE
回复以下关键字,获取更多资源
SpringCloud进阶之路 | Java 基础 | 微服务 | JAVA WEB | JAVA 进阶 | JAVA 面试 | MK 精讲
笔者开通了个人微信公众号【银河架构师】,分享工作、生活过程中的心得体会,填坑指南,技术感悟等内容,会比博客提前更新,欢迎订阅。