Thymeleaf教程 (二) 虚拟购物商店
在Good Thymes Virtual Grocery GitHub repository中都可以找到示例中的源代码以及本指南未来章节。
一个购物网站
本教程将阐述Thymeleaf在处理模板中的角色,并介绍一个演示应用供您下载。
这个系统是一个虚构的虚拟商店平台,并为用户提供丰富的实例演示不同Thymeleaf功能。
为此, 我们计划构建一个极为简洁的实体模型来代表我们的应用程序: 将Products(商品)与Orders(订单)关联起来, 并将此关系用于将Orders卖给Customers(客户). 此外, 我们还需维护Products的Comments以记录相关信息. 同时, 在此架构中, 我们也将维护Products的Comments以记录相关信息. 应用程序模型如下:

我们的小型应用程序将配备一个极为简单的功能模块组合,其服务功能由以下功能模块构成:
public class ProductService {
...
public List<Product> findAll() {
return ProductRepository.getInstance().findAll();
}
public Product findById(Integer id) {
return ProductRepository.getInstance().findById(id);
}
}
最后,在Web层设置了一个过滤器,并根据请求URL进行Thymeleaf-enabled命令的委托执行:
private boolean process(HttpServletRequest request, HttpServletResponse response)
throws ServletException {
try {
/* * 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.
*/
IGTVGController controller = GTVGApplication.resolveControllerForRequest(request);
if (controller == null) {
return false;
}
/* * Obtain the TemplateEngine instance.
*/
TemplateEngine templateEngine = GTVGApplication.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.
*/
controller.process(request, response, this.servletContext, templateEngine);
return true;
} catch (Exception e) {
throw new ServletException(e);
}
}
这是我们的 IGTVGController 接口:
public interface IGTVGController {
public void process(HttpServletRequest request, HttpServletResponse response,ServletContext servletContext, TemplateEngine templateEngine);
}
为了实现IGTVGController接口的功能需求, 我们将按照以下步骤开展工作: 首先, 使用TemplateEngine对象对模板文件进行解析; 然后, 根据解析结果生成相应的业务逻辑代码; 最后, 从服务层获取相关的配置参数并将其整合到生成的代码中。
或者:
为了完成IGTVGController接口的开发任务, 我们计划采取以下措施: 首先, 使用TemplateEngine对象对模板文件进行编译; 接着, 根据编译结果自动生成相应的控制逻辑代码; 最终, 从服务层获取必要的配置信息以支持控制逻辑的功能实现。
为了完成IGTVGController接口的开发任务, 我们计划采取以下步骤: 首先使用TemplateEngine对象对模板文件进行处理; 然后根据处理结果自动生成相应的业务逻辑代码; 最终将从服务层获取的数据整合到生成的代码中。
为了完成IGTVGController接口的开发任务, 我们计划采取以下步骤: 首先使用TemplateEngine对象对模板文件进行处理; 然后根据处理结果自动生成相应的业务逻辑代码; 最终将从服务层获取的数据整合到生成的代码中。

但首先让我们看看模板引擎是如何初始化的。
建立和配置模板引擎
在我们的过滤器的process(…)方法包含这个句子:
TemplateEngine templateEngine = GTVGApplication.getTemplateEngine();
该应用类GTVGApplication负责创建并配置程序中的核心对象TemplateEngine实例。我们的org.thymeleaf.TemplateEngine对象的初始化流程如下:
public class GTVGApplication {
...
private TemplateEngine templateEngine;
...
public GTVGApplication(final ServletContext servletContext) {
super();
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
// HTML is the default mode, but we will set it anyway for better understanding of code
templateResolver.setTemplateMode(TemplateMode.HTML);
// This will convert "home" to "/WEB-INF/templates/home.html"
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
// Set template cache TTL to 1 hour. If not set, entries would live in cache until expelled by LRU
templateResolver.setCacheTTLMs(Long.valueOf(3600000L));
// Cache is set to true by default. Set to false if you want templates to
// be automatically updated when modified.
templateResolver.setCacheable(true);
this.templateEngine = new TemplateEngine();
this.templateEngine.setTemplateResolver(templateResolver);
this.controllersByURL = new HashMap<String, IGTVGController>();
this.controllersByURL.put("/", new HomeController());
this.controllersByURL.put("/product/list", new ProductListController());
this.controllersByURL.put("/product/comments", new ProductCommentsController());
this.controllersByURL.put("/order/list", new OrderListController());
this.controllersByURL.put("/order/details", new OrderDetailsController());
this.controllersByURL.put("/subscribe", new SubscribeController());
this.controllersByURL.put("/userprofile", new UserProfileController());
}
...
}
显然有多种方法用于配置TemplateEngine对象。然而目前这几行代码足以满足我们的需求。
模板解析器
让我们先从模板解析器开始:
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
模板解析组件遵循了Thymeleaf API中的org.thymeleaf.templateresolver.ITemplateResolver接口。
public interface ITemplateResolver {
...
/* * Templates are resolved by String name (templateProcessingParameters.getTemplateName())
* Will return null if template cannot be handled by this template resolver.
*/
public TemplateResolution resolveTemplate(
TemplateProcessingParameters templateProcessingParameters);
}
该工具负责识别如何访问我们的模板。此外我们能够从servlet容器中提取和解析所需的模版文件。
但上述仅是模板解析器功能的一部分,由于我们可以配置一些参数设置.例如,设置模板模式,一个标准的例子如下:
templateResolver.setTemplateMode("XHTML");
XHTML是ServletContextTemplateResolver默认的模板模式。
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
这些前缀与后缀用于修饰在模板引擎中使用的模板路径,在具体应用中可举例如下:在MikroTik设备配置中使用配置文件时会遇到类似情况
servletContext.getResourceAsStream("/WEB-INF/templates/product/list.html")
可选地设置,在缓存中有效时间进行解析配置,并通过cacheTTLMs属性进行设置。
templateResolver.setCacheTTLMs(3600000L);
自然情况下,一个模板在达到最大缓存时之前是可以被删除的;当达到该阈值时,则会删除最久未使用的条目.
缓存行为模式及其规模可由用户通过实现ICacheManager接口或简单修改StandardCacheManager来进行调整。
模板引擎
模板引擎是一个实例oforg.thymeleaf.TemplateEngine类的对象。
以下案例初始化了一个模板引擎实例:
$templateEngine = new org.thymeleaf.TemplateEngine();
templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
极其简单真的吗?为了达到目标的目的, 我们只需要做两件事: 首先, 瞬时化一个实例; 其次, 配置该实例上的模板解析器。
它是TemplateEngine所必需的单一参数。然而,在此之后还有其他一些参数需要设置(如消息解析器与缓存容量)。从当前情况来看,这正是我们的需求所在。
我们的模板引擎现在已经准备好并就绪,我们即将投入使用的Thymeleaf将被用来创建我们的页面。
