Skip to content

2.1 示例:一家杂货店的网站

为了更好地解释使用 Thymeleaf 处理模板时涉及的概念,本教程将使用一个示例应用程序,你可以从项目网站下载它。 这个应用是一个虚构的虚拟杂货店网站,它将为我们提供许多场景,用来展示 Thymeleaf 的众多特性。 首先,我们需要为应用准备一组简单的模型实体: 通过创建订单(Orders)向顾客(Customers)销售产品(Products),并且管理这些产品的评论(Comments): 示例应用模型示例应用模型

我们的应用还会包含一个非常简单的服务层,由若干 Service 类构成,这些类中包含如下方法:

java
public class ProductService {

    ...

    public List<Product> findAll() {
        return ProductRepository.getInstance().findAll();
    }

    public Product findById(Integer id) {
        return ProductRepository.getInstance().findById(id);
    }
    
}

Web 层,我们的应用会有一个过滤器,它会根据请求 URL,将执行逻辑委托给支持 Thymeleaf 的处理逻辑:

java
/*
 * 需先声明应用对象(实现 IWebApplication 接口)
 * 本例中将使用基于 Jakarta 的版本。
 */
public void init(final FilterConfig filterConfig) throws ServletException {
    this.application =
            JakartaServletWebApplication.buildApplication(
                filterConfig.getServletContext());
    // 后续会介绍 TemplateEngine 对象的创建和配置方式
    this.templateEngine = buildTemplateEngine(this.application);
}

/*
 * 每个请求的处理流程:
 * 1. 创建交换对象(封装请求、响应及处理所需的所有数据)
 * 2. 调用对应的控制器处理请求
 */
private boolean process(HttpServletRequest request, HttpServletResponse response)
        throws ServletException {
    
    try {

        final IWebExchange webExchange = 
            this.application.buildExchange(request, response);
        final IWebRequest webRequest = webExchange.getRequest();

        // 过滤资源 URL,避免触发模板引擎执行(如 CSS/图片/网站图标)
        if (request.getRequestURI().startsWith("/css") ||
                request.getRequestURI().startsWith("/images") ||
                request.getRequestURI().startsWith("/favicon")) {
            return false;
        }
        
        /*
         * 1. 查询控制器/URL 映射关系,获取处理当前请求的控制器
         * 2. 若未找到对应控制器,返回 false,交由其他过滤器/Servlet 处理
         */
        final IGTVGController controller = 
            ControllerMappings.resolveControllerForRequest(webRequest);
        if (controller == null) {
            return false;
        }

        /*
         * 设置响应头信息
         */
        response.setContentType("text/html;charset=UTF-8");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);

        /*
         * 获取响应输出流的 Writer 对象
         */
        final Writer writer = response.getWriter();

        /*
         * 执行控制器逻辑,处理视图模板,
         * 并将结果写入响应的 Writer 中。
         */
        controller.process(webExchange, this.templateEngine, writer);
        
        return true;
        
    } catch (Exception e) {
        try {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        } catch (final IOException ignored) {
            // 忽略该异常
        }
        throw new ServletException(e);
    }
    
}

这是我们的 IGTVGController 接口定义:

java
public interface IGTVGController {

    public void process(
            final IWebExchange webExchange, 
            final ITemplateEngine templateEngine,
            final Writer writer)
            throws Exception;
    
}

现在,我们只需实现 IGTVGController 接口即可——在实现类中从服务层获取数据,并通过 ITemplateEngine 对象处理模板。

最终的整体架构会是这样: 示例应用程序首页示例应用程序首页

但首先,我们先来看看这个模板引擎是如何初始化的。