> For the complete documentation index, see [llms.txt](https://jack80342.gitbook.io/thymeleaf/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://jack80342.gitbook.io/thymeleaf/i.-using-thymeleaf/2-the-good-thymes-virtual-grocery/2.1-a-website-for-a-grocery.md).

# 2.1 杂货店网站

为了更好地解释在使用Thymeleaf处理模版时涉及的概念，本教程将会使用一个演示应用。你可以从项目的网站上下载⏬。

这个应用是一个虚构的杂货店的网站。它将会提供我们许多场景，来展示Thymeleaf的诸多特性。

首先，我们需要为应用准备一套简单的模型实体：通过创建`订单`卖给`顾客`的`产品`。我们也会管理与那些`产品`有关的`评论`。

![Example application model](http://www.thymeleaf.org/doc/tutorials/3.0/images/usingthymeleaf/gtvg-model.png)

我们的应用也会🈶️一个非常简单的服务层，由包含如下方法的`服务`对象组成：

```java
public class ProductService {

    ...

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

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

}
```

在网络层，我们的应用将会🈶️一个过滤器。它会依据请求的URL，分配执行启用Thymeleaf的命令：

```java
private boolean process(HttpServletRequest request, HttpServletResponse response)
        throws ServletException {

    try {

        // This prevents triggering engine executions for resource URLs
        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.
         */
        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. 
         */
        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);
    }

}
```

这是我们的`IGTVGController`接口：

```java
public interface IGTVGController {

    public void process(
            HttpServletRequest request, HttpServletResponse response,
            ServletContext servletContext, ITemplateEngine templateEngine);    

}
```

现在我们要做的就是创建`IGTVGController`接口的实现，从服务中取回数据，并使用`ITemplateEngine`对象处理模版。

最后，它看起来就像这样：

![Example application home page](http://www.thymeleaf.org/doc/tutorials/3.0/images/usingthymeleaf/gtvg-view.png)

但是，先让我们看看那个模版引擎是怎么被初始化的。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jack80342.gitbook.io/thymeleaf/i.-using-thymeleaf/2-the-good-thymes-virtual-grocery/2.1-a-website-for-a-grocery.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
