Thymeleaf 教程:使用Thymeleaf[官方]

Thymeleaf 教程:使用Thymeleaf[官方]

 

目录

 

1介绍Thymeleaf

2 The Good Thymes虚拟杂货店

3使用文本

4标准表达式语法

5设置属性值

6迭代

7条件评估

8模板布局

9局部变量

10属性优先级

11评论和块

12内联

13文本模板模式

14我们杂货店的更多页面

15有关配置的更多信息

16模板缓存

17解耦模板逻辑

18附录A:表达式基本对象

19附录B:表达式实用程序对象

20附录C:标记选择器语法

多值类匹配


1介绍Thymeleaf

1.1什么是Thymeleaf?

Thymeleaf是一个适用于Web和独立环境的现代服务器端Java模板引擎,能够处理HTML,XML,JavaScript,CSS甚至纯文本。

Thymeleaf的主要目标是提供一种优雅且高度可维护的模板创建方式。为实现这一目标,它以自然模板的概念为基础,将其逻辑注入模板文件,其方式不会影响模板被用作设计原型。这改善了设计沟通,缩小了设计和开发团队之间的差距。

Thymeleaf也从一开始就设计了Web标准 - 特别是HTML5 - 允许您创建完全验证的模板,如果这是您的需要。

1.2 Thymeleaf过程可以使用哪种模板?

开箱即用,Thymeleaf允许您处理六种模板,每种模板称为模板模式

  • HTML
  • XML
  • 文本
  • JAVASCRIPT
  • CSS
  • 生的

有两种标记模板模式(HTMLXML),三种文本模板模式(TEXTJAVASCRIPTCSS)和一种无操作模板模式(RAW)。

HTML模板模式将允许任何类型的HTML的输入,包括HTML5,HTML4和XHTML。不会执行验证或格式良好检查,并且将在输出中尽可能地尊重模板代码/结构。

XML模板模式将允许XML输入。在这种情况下,代码应该是格式良好的 - 没有未封闭的标签,没有不带引号的属性等 - 如果发现格式错误,解析器将抛出异常。请注意,不会执行任何验证(针对DTD或XML架构)。

TEXT模板模式将允许非标记性质的模板使用特殊的语法。此类模板的示例可能是文本电子邮件或模板文档。请注意,HTML或XML模板也可以被处理TEXT,在这种情况下,它们不会被解析为标记,并且每个标记,DOCTYPE,注释等都将被视为纯文本。

JAVASCRIPT模板模式将允许在Thymeleaf应用程序的JavaScript文件的处理。这意味着能够以与HTML文件相同的方式在JavaScript文件中使用模型数据,但是使用特定于JavaScript的集成,例如专门的转义或自然脚本。该JAVASCRIPT模板模式被认为是一种文本模式,因此使用相同的特殊语法的TEXT模板模式。

CSS模板模式将允许参与Thymeleaf应用CSS文件的处理。与JAVASCRIPT模式类似,CSS模板模式也是文本模式,并使用TEXT模板模式中的特殊处理语法。

RAW模板模式将根本不处理模板。它用于将未经处理的资源(文件,URL响应等)插入到正在处理的模板中。例如,HTML格式的外部非受控资源可以包含在应用程序模板中,安全地知道这些资源可能包含的任何Thymeleaf代码都不会被执行。

1.3方言:标准方言

Thymeleaf是一个极易扩展的模板引擎(实际上它可以称为模板引擎框架),允许您定义和自定义模板处理的细节级别。

将一些逻辑应用于标记工件(标签,某些文本,注释或仅仅是占位符,如果模板不是标记)的对象称为处理器,这些处理器的集合 - 加上可能还有一些额外的工件 - 是什么一个方言通常是由。开箱即用,Thymeleaf的核心库提供了一种称为标准方言的方言,对大多数用户来说应该足够了。

请注意,方言实际上可以没有处理器,并且完全由其他类型的工件组成,但处理器绝对是最常见的用例。

本教程涵盖标准方言。您将在以下页面中了解的每个属性和语法功能都由此方言定义,即使没有明确提及。

当然,如果用户希望在利用库的高级功能的同时定义自己的处理逻辑,则可以创建自己的方言(甚至扩展标准方言)。Thymeleaf也可以配置为一次使用多种方言。

官方的thymeleaf-spring3和thymeleaf-spring4集成包都定义了一种称为“SpringStandard Dialect”的方言,它与标准方言大致相同,但是为了更好地利用Spring Framework中的某些功能(例如) ,使用Spring Expression Language或SpringEL代替OGNL)。因此,如果您是Spring MVC用户,那么您不会浪费时间,因为您在此处学习的几乎所有内容都将在Spring应用程序中使用。

标准方言的大多数处理器都是属性处理器。这使得浏览器甚至可以在处理之前正确显示HTML模板文件,因为它们只会忽略其他属性。例如,虽然使用标记库的JSP可能包含不能由浏览器直接显示的代码片段,例如:


<form:inputText name="userName" value="${user.name}" />

...... Thymeleaf标准方言将允许我们实现相同的功能:


<input type="text" name="userName" value="James Carrot" th:value="${user.name}" />

这不仅可以被浏览器正确显示,而且还允许我们(可选地)在其中指定一个值属性(在这种情况下为“James Carrot”),当在浏览器中静态打开原型时将显示该属性,并且这将由${user.name}在处理模板期间评估得到的值代替。

这有助于您的设计人员和开发人员处理相同的模板文件,并减少将静态原型转换为工作模板文件所需的工作量。执行此操作的能力是称为自然模板的功能。

2 The Good Thymes虚拟杂货店

可以在Good Thymes Virtual Grocery GitHub存储库中找到本指南的本章和后续章节中显示的示例的源代码。

2.1杂货店的网站

为了更好地解释使用Thymeleaf处理模板所涉及的概念,本教程将使用可从项目网站下载的演示应用程序。

这个应用程序是一个假想的虚拟杂货的网站,并将为我们提供许多场景来展示Thymeleaf的许多功能。

首先,我们需要一套简单的模型实体用于我们的应用程序:通过创建Products销售。我们还将管理这些:CustomersOrdersCommentsProducts

Thymeleaf 教程:使用Thymeleaf[官方]_第1张图片uploading.4e448015.gif转存失败重新上传取消Thymeleaf 教程:使用Thymeleaf[官方]_第2张图片

示例应用程序模型

我们的应用程序还有一个非常简单的服务层,由Service包含以下方法的对象组成:


public class ProductService {

    ...

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

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

在Web层,我们的应用程序将有一个过滤器,它将根据请求URL将执行委托给启用Thymeleaf的命令:


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界面:


public interface IGTVGController {

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

我们现在要做的就是创建IGTVGController接口的实现,从服务中检索数据并使用ITemplateEngine对象处理模板。

最后,它看起来像这样:

Thymeleaf 教程:使用Thymeleaf[官方]_第3张图片uploading.4e448015.gif转存失败重新上传取消Thymeleaf 教程:使用Thymeleaf[官方]_第4张图片

示例应用程序主页

但首先让我们看看该模板引擎是如何初始化的。

2.2创建和配置模板引擎

我们的过滤器中的process(...)方法包含以下行:


ITemplateEngine templateEngine = this.application.getTemplateEngine();

这意味着GTVGApplication类负责创建和配置Thymeleaf应用程序中最重要的对象之一:TemplateEngine实例(ITemplateEngine接口的实现)。

我们的org.thymeleaf.TemplateEngine对象初始化如下:


public class GTVGApplication {
  
    
    ...
    private final TemplateEngine templateEngine;
    ...
    
    
    public GTVGApplication(final ServletContext servletContext) {

        super();

        ServletContextTemplateResolver templateResolver = 
                new ServletContextTemplateResolver(servletContext);
        
        // HTML is the default mode, but we 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");
        // Template cache TTL=1h. If not set, entries would be cached until expelled
        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);
        
        ...

    }

}

配置TemplateEngine对象有很多种方法,但是现在这几行代码将足以告诉我们所需的步骤。

模板解析器

让我们从模板解析器开始:


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, Object> templateResolutionAttributes);
}

这些对象负责确定我们的模板的访问方式,在这个GTVG应用程序中,org.thymeleaf.templateresolver.ServletContextTemplateResolver我们将从Servlet上下文中检索模板文件作为资源的方式:javax.servlet.ServletContext每个Java Web应用程序中都存在的应用程序范围的对象,并从Web应用程序根解析资源。

但这并不是我们可以说的关于模板解析器的全部内容,因为我们可以在其上设置一些配置参数。一,模板模式:


templateResolver.setTemplateMode(TemplateMode.HTML);

HTML是默认的模板模式ServletContextTemplateResolver,但最好还是建立它,以便我们的代码清楚地记录正在发生的事情。


templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");

前缀后缀修改,我们将传递到发动机获得要使用的真实资源名称的模板名称。

使用此配置,模板名称“product / list”将对应于:


servletContext.getResourceAsStream("/WEB-INF/templates/product/list.html")

(可选)通过cacheTTLMs属性在模板解析器中配置解析模板可以在缓存中存在的时间量:


templateResolver.setCacheTTLMs(3600000L);

如果达到最大高速缓存大小并且它是当前高速缓存的最旧条目,则在达到该TTL之前,模板仍然可以从高速缓存中排出。

用户可以通过实现ICacheManager接口或修改StandardCacheManager对象来管理默认缓存来定义缓存行为和大小。

关于模板解析器还有很多东西需要学习,但是现在我们来看看Template Engine对象的创建。

模板引擎

Template Engine对象是org.thymeleaf.ITemplateEngine接口的实现。其中一个实现是由Thymeleaf核心提供的:org.thymeleaf.TemplateEngine我们在这里创建一个实例:


templateEngine = new TemplateEngine();
templateEngine.setTemplateResolver(templateResolver);

相当简单,不是吗?我们所需要的只是创建一个实例并将模板解析器设置为它。

模板解析器是唯一需要的参数TemplateEngine,尽管稍后将介绍许多其他参数(消息解析器,缓存大小等)。现在,这就是我们所需要的。

我们的模板引擎现已准备就绪,我们可以使用Thymeleaf开始创建我们的页面。

3使用文本

3.1多语言欢迎

我们的第一个任务是为我们的杂货网站创建一个主页。

这个页面的第一个版本非常简单:只是标题和欢迎信息。这是我们的/WEB-INF/templates/home.html文件:




<html xmlns:th="http://www.thymeleaf.org">

  <head>
    <title>Good Thymes Virtual Grocerytitle>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link rel="stylesheet" type="text/css" media="all" 
          href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
  head>

  <body>
  
    <p th:text="#{home.welcome}">Welcome to our grocery store!p>
  
  body>

html>

您将注意到的第一件事是该文件是HTML5,任何浏览器都可以正确显示它,因为它不包含任何非HTML标记(浏览器会忽略它们不理解的所有属性,例如th:text)。

但是您可能还注意到此模板实际上不是有效的 HTML5文档,因为th:*HTML5规范不允许我们在表单中使用这些非标准属性。事实上,我们甚至xmlns:th在我们的标签中添加了一个属性,绝对不是HTML5-ish:


<html xmlns:th="http://www.thymeleaf.org">

...它在模板处理中根本没有任何影响,但是作为一个咒语,阻止我们的IDE抱怨缺少所有这些th:*属性的命名空间定义。

那么如果我们想让这个模板HTML5有效呢?简单:切换到Thymeleaf的数据属性语法,使用data-属性名称和hyphen(-)分隔符的前缀而不是分号(:):




<html>

  <head>
    <title>Good Thymes Virtual Grocerytitle>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link rel="stylesheet" type="text/css" media="all" 
          href="../../css/gtvg.css" data-th-href="@{/css/gtvg.css}" />
  head>

  <body>
  
    <p data-th-text="#{home.welcome}">Welcome to our grocery store!p>
  
  body>

html>

data-HTML5规范允许使用自定义前缀属性,因此,使用上面的代码,我们的模板将是有效的HTML5文档

两种表示法都是完全等效且可互换的,但为了代码示例的简单性和紧凑性,本教程将使用名称空间表示法th:*)。此外,th:*符号更通用,并且在每个Thymeleaf模板模式(XMLTEXT...)中data-都允许使用,而符号仅允许在HTML模式中使用。

使用th:文本和外化文本

外化文本是从模板文件中提取模板代码的片段,以便它们可以保存在单独的文件(通常是.properties文件)中,并且可以使用其他语言编写的等效文本(称为国际化或简称i18n)轻松替换它们。外化的文本片段通常称为“消息”

消息始终具有标识它们的键,而Thymeleaf允许您指定文本应与具有以下#{...}语法的特定消息对应:


<p th:text="#{home.welcome}">Welcome to our grocery store!p>

我们在这里看到的实际上是Thymeleaf标准方言的两个不同特征:

  • th:text属性评估其值表达式并将结果设置为主机标签的主体,有效地替换了我们在代码中看到的“欢迎使用我们的杂货店!”文本。
  • #{home.welcome}表达,在指定的标准表达式语法,指示要由所使用的文本th:text属性应与该消息home.welcome对应于哪个语言环境,我们正在处理与模板键。

现在,这个外化文本在哪里?

Thymeleaf中外化文本的位置是完全可配置的,它取决于org.thymeleaf.messageresolver.IMessageResolver所使用的具体实现。通常,.properties将使用基于文件的实现,但是如果我们想要,例如,从数据库获取消息,我们可以创建自己的实现。

但是,我们在初始化期间没有为模板引擎指定消息解析器,这意味着我们的应用程序正在使用标准消息解析器,由org.thymeleaf.messageresolver.StandardMessageResolver。实现。

标准消息解析程序期望/WEB-INF/templates/home.html在同一文件夹中找到属性文件中的消息,并使用与模板相同的名称,例如:

  • /WEB-INF/templates/home_en.properties 用于英文文本。
  • /WEB-INF/templates/home_es.properties 西班牙语文本。
  • /WEB-INF/templates/home_pt_BR.properties 用于葡萄牙语(巴西)语言文本。
  • /WEB-INF/templates/home.properties 对于默认文本(如果区域设置不匹配)。

我们来看看我们的home_es.properties文件:

home.welcome=¡Bienvenido a nuestra tienda de comestibles!

这就是我们将Thymeleaf流程作为模板所需的全部内容。让我们创建我们的Home控制器。

上下文

为了处理我们的模板,我们将创建一个HomeController实现IGTVGController我们之前看到的接口的类:


public class HomeController implements IGTVGController {

    public void process(
            final HttpServletRequest request, final HttpServletResponse response,
            final ServletContext servletContext, final ITemplateEngine templateEngine)
            throws Exception {
        
        WebContext ctx = 
                new WebContext(request, response, servletContext, request.getLocale());
        
        templateEngine.process("home", ctx, response.getWriter());
        
    }

}

我们看到的第一件事是创建一个上下文。Thymeleaf上下文是实现org.thymeleaf.context.IContext接口的对象。上下文应包含在变量映射中执行模板引擎所需的所有数据,并且还引用必须用于外部化消息的语言环境。


public interface IContext {

    public Locale getLocale();
    public boolean containsVariable(final String name);
    public Set getVariableNames();
    public Object getVariable(final String name);
    
}

这个接口有一个专门的扩展,org.thymeleaf.context.IWebContext用于基于ServletAPI的Web应用程序(如SpringMVC)。


public interface IWebContext extends IContext {
    
    public HttpServletRequest getRequest();
    public HttpServletResponse getResponse();
    public HttpSession getSession();
    public ServletContext getServletContext();
    
}

Thymeleaf核心库提供了以下每个接口的实现:

  • org.thymeleaf.context.Context 器物 IContext
  • org.thymeleaf.context.WebContext 器物 IWebContext

正如您在控制器代码中看到的那样,WebContext是我们使用的那个。实际上我们必须这样做,因为使用a ServletContextTemplateResolver要求我们使用上下文实现IWebContext


WebContext ctx = new WebContext(request, response, servletContext, request.getLocale());

这四个构造函数参数中只有三个是必需的,因为如果没有指定系统,将使用系统的默认语言环境(尽管在实际应用程序中不应该发生这种情况)。

我们可以使用一些专门的表达式来从WebContext模板中获取请求参数以及请求,会话和应用程序属性。例如:

  • ${x}将返回x存储在Thymeleaf上下文中的变量或作为请求属性
  • ${param.x}将返回一个被调用的请求参数x(可能是多值的)。
  • ${session.x}将返回一个名为的会话属性x
  • ${application.x}将返回一个名为的servlet上下文属性x

执行模板引擎

准备好上下文对象后,现在我们可以告诉模板引擎使用上下文处理模板(通过其名称),并将响应编写器传递给它,以便可以将响应写入它:


templateEngine.process("home", ctx, response.getWriter());

让我们使用西班牙语语言环境查看结果:




<html>

  <head>
    <title>Good Thymes Virtual Grocerytitle>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
    <link rel="stylesheet" type="text/css" media="all" href="/gtvg/css/gtvg.css" />
  head>

  <body>
  
    <p>¡Bienvenido a nuestra tienda de comestibles!p>

  body>

html>

3.2有

3.2有关文本和变量的更多信息

未转义的文字

我们主页的最简单版本现在似乎已经准备就绪,但有一些我们没有想过的......如果我们有这样的消息怎么办?


home.welcome=Welcome to our fantastic grocery store!

如果我们像以前一样执行此模板,我们将获得:


<p>Welcome to our <b>fantastic</b> grocery store!p>

这不完全符合我们的预期,因为我们的标签已被转义,因此它将在浏览器中显示。

这是th:text属性的默认行为。如果我们希望Thymeleaf尊重我们的HTML标签而不是逃避它们,我们将不得不使用不同的属性:( th:utext对于“非转义文本”):


<p th:utext="#{home.welcome}">Welcome to our grocery store!p>

这将输出我们的消息,就像我们想要的那样:


<p>Welcome to our <b>fantasticb> grocery store!p>

使用和显示变量

现在让我们在主页上添加更多内容。例如,我们可能希望在欢迎消息下方显示日期,如下所示:

Welcome to our fantastic grocery store!

Today is: 12 july 2010

首先,我们必须修改控制器,以便将该日期添加为上下文变量:


public void process(
            final HttpServletRequest request, final HttpServletResponse response,
            final ServletContext servletContext, final ITemplateEngine templateEngine)
            throws Exception {
        
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
    Calendar cal = Calendar.getInstance();
        
    WebContext ctx = 
            new WebContext(request, response, servletContext, request.getLocale());
    ctx.setVariable("today", dateFormat.format(cal.getTime()));
        
    templateEngine.process("home", ctx, response.getWriter());
        
}

我们添加了一个String调用today我们上下文的变量,现在我们可以在模板中显示它:


<body>

  <p th:utext="#{home.welcome}">Welcome to our grocery store!p>

  <p>Today is: <span th:text="${today}">13 February 2011span>p>
  
body>

正如您所看到的,我们仍在使用th:text作业的属性(这是正确的,因为我们想要替换标签的主体),但这次语法有点不同而不是#{...}表达式值,我们使用的是${...}一。这是一个变量表达式,它包含一个名为OGNL(对象图导航语言)的语言表达式,该表达式将在我们之前讨论过的上下文变量映射上执行。

${today}表达式只是表示“今天拿到称为变量”,但这些表述可能更加复杂(如${user.name}“获取被叫用户的变量,并调用它的getName()方法”)。

属性值有很多可能性:消息,变量表达式......还有很多。下一章将向我们展示所有这些可能性。

4标准表达式语法

我们将在杂货虚拟商店的开发中稍作休息,以了解Thymeleaf标准方言中最重要的部分之一:Thymeleaf标准表达式语法。

我们已经看到在这种语法中表达的两种类型的有效属性值:消息和变量表达式:


<p th:utext="#{home.welcome}">Welcome to our grocery store!p>

<p>Today is: <span th:text="${today}">13 february 2011span>p>

但是有更多类型的表达式,以及更多有趣的细节来了解我们已经知道的。首先,让我们看一下标准表达式功能的快速摘要:

  • 简单表达:
    • 变量表达式: ${...}
    • 选择变量表达式: *{...}
    • 消息表达式: #{...}
    • 链接网址表达式: @{...}
    • 片段表达式: ~{...}
  • 字面
    • 文本文字:'one text''Another one!',...
    • 号码文字:0343.012.3,...
    • 布尔文字:truefalse
    • 空字面: null
    • 文字标记:onesometextmain,...
  • 文字操作:
    • 字符串连接: +
    • 文字替换: |The name is ${name}|
  • 算术运算:
    • 二元运算符:+-*/%
    • 减号(一元运算符): -
  • 布尔运算:
    • 二元运算符:andor
    • 布尔否定(一元运算符): !not
  • 比较和平等:
    • 比较:><>=<=gtltgele
    • 平等运营商:==!=eqne
  • 有条件的运营商:
    • IF-THEN: (if) ? (then)
    • IF-THEN-ELSE: (if) ? (then) : (else)
    • 默认: (value) ?: (defaultvalue)
  • 特殊代币:
    • 无操作: _

所有这些功能都可以组合和嵌套:


'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))

4.1消息

我们已经知道,#{...}消息表达式允许我们链接:


<p th:utext="#{home.welcome}">Welcome to our grocery store!p>

......对此:

home.welcome=¡Bienvenido a nuestra tienda de comestibles!

但是有一个方面我们还没有想到:如果消息文本不是完全静态会发生什么?例如,如果我们的应用程序知道谁是随时访问该网站的用户并且我们想通过名字问候他们怎么办?


<p>¡Bienvenido a nuestra tienda de comestibles, John Apricot!p>

这意味着我们需要在消息中添加一个参数。像这样:

home.welcome=¡Bienvenido a nuestra tienda de comestibles, {0}!

参数根据java.text.MessageFormat标准语法指定,这意味着您可以格式化为java.text.*包的类API文档中指定的数字和日期。

为了为我们的参数指定一个值,并给定一个被调用的HTTP会话属性user,我们可以:


<p th:utext="#{home.welcome(${session.user.name})}">
  Welcome to our grocery store, Sebastian Pepper!
p>

请注意,使用th:utext此处意味着格式化的消息不会被转义。此示例假定user.name已经转义。

可以指定几个参数,以逗号分隔。

消息密钥本身可以来自变量:


<p th:utext="#{${welcomeMsgKey}(${session.user.name})}">
  Welcome to our grocery store, Sebastian Pepper!
p>

4.2变量

我们已经提到${...}表达式实际上是在上下文中包含的变量映射上执行的OGNL(对象 - 图形导航语言)表达式。

有关OGNL语法和功能的详细信息,请阅读OGNL语言指南

在Spring支持MVC的应用程序中,OGNL将被SpringEL取代,但其语法与OGNL的语法非常相似(实际上,对于大多数常见情况来说,完全相同)。

从OGNL的语法,我们知道表达式:


<p>Today is: <span th:text="${today}">13 february 2011span>.p>

......实际上相当于:


ctx.getVariable("today");

但是OGNL允许我们创建更强大的表达式,这就是:


<p th:utext="#{home.welcome(${session.user.name})}">
  Welcome to our grocery store, Sebastian Pepper!
p>

...通过执行以下命令获取用户名:


((User) ctx.getVariable("session").get("user")).getName();

但是getter方法导航只是OGNL的功能之一。让我们看看更多:


/*
 * Access to properties using the point (.). Equivalent to calling property getters.
 */
${person.father.name}

/*
 * Access to properties can also be made by using brackets ([]) and writing 
 * the name of the property as a variable or between single quotes.
 */
${person['father']['name']}

/*
 * If the object is a map, both dot and bracket syntax will be equivalent to 
 * executing a call on its get(...) method.
 */
${countriesByCode.ES}
${personsByName['Stephen Zucchini'].age}

/*
 * Indexed access to arrays or collections is also performed with brackets, 
 * writing the index without quotes.
 */
${personsArray[0].name}

/*
 * Methods can be called, even with arguments.
 */
${person.createCompleteName()}
${person.createCompleteNameWithSeparator('-')}

表达式基本对象

在上下文变量上评估OGNL表达式时,某些对象可用于表达式以获得更高的灵活性。将从#符号开始引用这些对象(根据OGNL标准):

  • #ctx:上下文对象。
  • #vars: 上下文变量。
  • #locale:上下文区域设置。
  • #request:(仅限Web Contexts)HttpServletRequest对象。
  • #response:(仅限Web Contexts)HttpServletResponse对象。
  • #session:(仅限Web Contexts)HttpSession对象。
  • #servletContext:(仅限Web Contexts)ServletContext对象。

所以我们可以这样做:


Established locale country: <span th:text="${#locale.country}">USspan>.

您可以在附录A中阅读这些对象的完整参考。

Expression Utility对象

除了这些基本对象,Thymeleaf还将为我们提供一组实用程序对象,帮助我们在表达式中执行常见任务。

  • #execInfo:有关正在处理的模板的信息。
  • #messages:在变量表达式中获取外化消息的方法,与使用#{...}语法获取的方法相同。
  • #uris:转义部分URL / URI的方法
  • #conversions:用于执行已配置的转换服务的方法(如果有)。
  • #datesjava.util.Date对象的方法:格式化,组件提取等。
  • #calendars:类似于#dates,但java.util.Calendar对象。
  • #numbers:格式化数字对象的方法。
  • #stringsString对象的方法:contains,startsWith,prepending / appending等。
  • #objects:一般的对象的方法。
  • #bools:布尔评估的方法。
  • #arrays:数组的方法。
  • #lists:列表方法。
  • #sets:集合的方法。
  • #maps:地图的方法。
  • #aggregates:在数组或集合上创建聚合的方法。
  • #ids:处理可能重复的id属性的方法(例如,作为迭代的结果)。

您可以在附录B中查看每个实用程序对象提供的功能。

在我们的主页中重新格式化日期

现在我们了解这些实用程序对象,我们可以使用它们来改变我们在主页中显示日期的方式。而不是在我们这样做HomeController


SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
Calendar cal = Calendar.getInstance();

WebContext ctx = new WebContext(request, servletContext, request.getLocale());
ctx.setVariable("today", dateFormat.format(cal.getTime()));

templateEngine.process("home", ctx, response.getWriter());

......我们可以做到这一点:


WebContext ctx = 
    new WebContext(request, response, servletContext, request.getLocale());
ctx.setVariable("today", Calendar.getInstance());

templateEngine.process("home", ctx, response.getWriter());

...然后在视图层本身中执行日期格式设置:


<p>
  Today is: <span th:text="${#calendars.format(today,'dd MMMM yyyy')}">13 May 2011span>
p>

关文本

4.3选择表达式(星号语法)

变量表达式不仅可以写成${...},也可以作为*{...}

但是有一个重要的区别:星号语法评估所选对象上的表达式而不是整个上下文。也就是说,只要没有选定的对象,美元和星号语法就会完全相同。

什么是选定的对象?使用th:object属性的表达式的结果。我们在用户个人资料(userprofile.html)页面中使用一个:


  <div th:object="${session.user}">
    <p>Name: <span th:text="*{firstName}">Sebastianspan>.p>
    <p>Surname: <span th:text="*{lastName}">Pepperspan>.p>
    <p>Nationality: <span th:text="*{nationality}">Saturnspan>.p>
  div>

这完全等同于:


<div>
  <p>Name: <span th:text="${session.user.firstName}">Sebastianspan>.p>
  <p>Surname: <span th:text="${session.user.lastName}">Pepperspan>.p>
  <p>Nationality: <span th:text="${session.user.nationality}">Saturnspan>.p>
div>

当然,美元和星号语法可以混合使用:


<div th:object="${session.user}">
  <p>Name: <span th:text="*{firstName}">Sebastianspan>.p>
  <p>Surname: <span th:text="${session.user.lastName}">Pepperspan>.p>
  <p>Nationality: <span th:text="*{nationality}">Saturnspan>.p>
div>

当对象选择到位时,所选对象也可用作美元表达式作为#object表达式变量:


<div th:object="${session.user}">
  <p>Name: <span th:text="${#object.firstName}">Sebastianspan>.p>
  <p>Surname: <span th:text="${session.user.lastName}">Pepperspan>.p>
  <p>Nationality: <span th:text="*{nationality}">Saturnspan>.p>
div>

如上所述,如果没有执行任何对象选择,则美元和星号语法是等效的。


<div>
  <p>Name: <span th:text="*{session.user.name}">Sebastianspan>.p>
  <p>Surname: <span th:text="*{session.user.surname}">Pepperspan>.p>
  <p>Nationality: <span th:text="*{session.user.nationality}">Saturnspan>.p>
div>

4.4链接URL

由于它们的重要性,URL是Web应用程序模板中的一等公民,而Thymeleaf Standard Dialect具有特殊的语法,@语法:@{...}

有不同类型的网址:

  • 绝对网址: http://www.thymeleaf.org
  • 相对URL,可以是:
    • 页面相对: user/login.html
    • 上下文相关:( /itemdetails?id=3服务器中的上下文名称将自动添加)
    • 服务器相对:( ~/billing/processInvoice允许在同一服务器中的另一个上下文(=应用程序)中调用URL。
    • 协议相对URL: //code.jquery.com/jquery-2.0.3.min.js

这些表达式的实际处理及其转换为将要输出的URL是通过org.thymeleaf.linkbuilder.ILinkBuilder注册到ITemplateEngine正在使用的对象中的接口的实现来完成的。

默认情况下,此接口的单个​​实现是在类中注册的org.thymeleaf.linkbuilder.StandardLinkBuilder,这对于基于Servlet API的脱机(非Web)和Web方案都是足够的。其他方案(例如与非ServletAPI Web框架的集成)可能需要链接构建器接口的特定实现。

让我们使用这种新语法。符合th:href属性:



<a href="details.html" 
   th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">viewa>


<a href="details.html" th:href="@{/order/details(orderId=${o.id})}">viewa>


<a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">viewa>

这里要注意的一些事情:

与消息语法(#{...})的情况一样,URL基数也可以是评估另一个表达式的结果:


<a th:href="@{${url}(orderId=${o.id})}">viewa>
<a th:href="@{'/details/'+${user.login}(orderId=${o.id})}">viewa>

我们主页的菜单

既然我们知道如何创建链接URL,那么在我们的主页中为网站中的其他一些页面添加一个小菜单呢?


<p>Please select an optionp>
<ol>
  <li><a href="product/list.html" th:href="@{/product/list}">Product Lista>li>
  <li><a href="order/list.html" th:href="@{/order/list}">Order Lista>li>
  <li><a href="subscribe.html" th:href="@{/subscribe}">Subscribe to our Newslettera>li>
  <li><a href="userprofile.html" th:href="@{/userprofile}">See User Profilea>li>
ol>

服务器根目录相对URL

可以使用其他语法来创建服务器根相对(而不是上下文根相对)URL,以便链接到同一服务器中的不同上下文。这些URL将被指定为@{~/path/to/something}

4.5片段

片段表达式是表示标记片段并将其移动到模板周围的简单方法。这允许我们复制它们,将它们作为参数传递给其他模板,等等。

最常见的用途是使用th:insert或进行片段插入th:replace(在后面的部分中将详细介绍):


<div th:insert="~{commons :: main}">...div>

但它们可以在任何地方使用,就像任何其他变量一样:


<div th:with="frag=~{footer :: #main/text()}">
  <p th:insert="${frag}">
div>

本教程后面有一整节专门介绍模板布局,包括对片段表达式的更深入解释。

4.6文字

文字文字

文本文字只是在单引号之间指定的字符串。它们可以包含任何字符,但您应该使用它们中的任何单引号\'


<p>
  Now you are looking at a <span th:text="'working web application'">template filespan>.
p>

数字文字

数字文字只是:数字。


<p>The year is <span th:text="2013">1492span>.p>
<p>In two years, it will be <span th:text="2013 + 2">1494span>.p>

布尔文字

布尔文字是truefalse。例如:


<div th:if="${user.isAdmin()} == false"> ...

在这个例子中,它== false被写在大括号外面,因此是Thymeleaf来处理它。如果它是在大括号内写的,那么它将由OGNL / SpringEL引擎负责:


<div th:if="${user.isAdmin() == false}"> ...

null文字

null文本也可用于:


<div th:if="${variable.something} == null"> ...

文字代币

实际上,数字,布尔和空文字是文字标记的特例。

这些令牌允许在标准表达式中进行一些简化。它们的工作方式与文本文字('...')完全相同,但它们只允许使用字母(A-Za-z),数字(0-9),括号([]),点(.),连字符(-)和下划线(_)。所以没有空格,没有逗号等。

好的部分?令牌不需要任何围绕它们的引号。所以我们可以这样做:


<div th:class="content">...div>

代替:


<div th:class="'content'">...div>

和变量的

4.7附加文本

文本,无论是文字还是评估变量或消息表达式的结果,都可以使用+运算符轻松附加:


<span th:text="'The name of the user is ' + ${user.name}">

4.8字面替换

文字替换允许轻松格式化包含变量值的字符串,而无需附加文字'...' + '...'

这些替换必须用竖线(|)包围,如:


<span th:text="|Welcome to our application, ${user.name}!|">

这相当于:


<span th:text="'Welcome to our application, ' + ${user.name} + '!'">

文字替换可以与其他类型的表达相结合:


<span th:text="${onevar} + ' ' + |${twovar}, ${threevar}|">

唯一的变量/消息表达式(${...}*{...}#{...})被允许内部|...|字面取代。没有其他文字('...'),布尔/数字标记,条件表达式等。

4.9算术运算

一些算术运算也可用:+-*/%


<div th:with="isEven=(${prodStat.count} % 2 == 0)">

请注意,这些运算符也可以应用于OGNL变量表达式本身(在这种情况下,将由OGNL而不是Thymeleaf标准表达式引擎执行):


<div th:with="isEven=${prodStat.count % 2 == 0}">

请注意,其中一些运算符存在文本别名:div/),mod%)。

4.10比较器和平等

在表达式中的值可以与进行比较><>=<=符号,以及==!=运营商可以被用来检查是否相等(或缺乏)。请注意,XML确定不应在属性值中使用<>符号,因此应将它们替换为<>


<div th:if="${prodStat.count} > 1">
<span th:text="'Execution mode is ' + ( (${execMode} == 'dev')? 'Development' : 'Production')">

更简单的替代方法可能是使用某些运算符存在的文本别名:gt>),lt<),ge>=),le<=),not!)。还eq==),neqne!=)。

4.11条件表达式

条件表达式仅用于评估两个表达式中的一个,具体取决于评估条件的结果(它本身就是另一个表达式)。

让我们来看一个例子片段(引入另一个属性修改器th:class):


<tr th:class="${row.even}? 'even' : 'odd'">
  ...
tr>

条件表达式(conditionthenelse)的所有三个部分本身都是表达式,这意味着它们可以是变量(${...}*{...}),消息(#{...}),URL(@{...})或文字('...')。

条件表达式也可以使用括号嵌套:


<tr th:class="${row.even}? (${row.first}? 'first' : 'even') : 'odd'">
  ...
tr>

其他表达式也可以省略,在这种情况下,如果条件为false,则返回null值:


<tr th:class="${row.even}? 'alt'">
  ...
tr>

4.12默认表达式(Elvis运算符)

一个默认的表情是一种特殊的条件值的没有那么一部分。它等同于某些语言(如Groovy)中存在的Elvis运算符,允许您指定两个表达式:如果它不计算为null,则使用第一个表达式,但如果确实如此,则使用第二个表达式。

让我们在用户个人资料页面中看到它:


<div th:object="${session.user}">
  ...
  <p>Age: <span th:text="*{age}?: '(no age specified)'">27span>.p>
div>

正如您所看到的,运算符是?:,并且我们在此处使用它来指定名称的默认值(在这种情况下为文字值),仅当评估结果*{age}为null时。因此,这相当于:


<p>Age: <span th:text="*{age != null}? *{age} : '(no age specified)'">27span>.p>

与条件值一样,它们可以包含括号之间的嵌套表达式:


<p>
  Name: 
  <span th:text="*{firstName}?: (*{admin}? 'Admin' : #{default.username})">Sebastianspan>
p>

4.13无操作令牌

No-Operation标记由下划线符号(_)表示。

这个标记背后的想法是指定表达式的期望结果是什么都不做,即完全就像可处理属性(例如th:text)根本不存在一样。

除了其他可能性之外,这允许开发人员将原型文本用作默认值。例如,而不是:


<span th:text="${user.name} ?: 'no user authenticated'">...span>

...我们可以直接使用“无用户身份验证”作为原型文本,从设计的角度来看,这会使代码更简洁,更通用:


<span th:text="${user.name} ?: _">no user authenticatedspan>

4.14数据转换/格式化

Thymeleaf 为variable()和selection()表达式定义了一个双括号语法,允许我们通过配置的转换服务应用数据转换${...}*{...}

它基本上是这样的:


<td th:text="${{user.lastAccessDate}}">...td>

注意到那里的双支撑?:${{...}}。这指示Thymeleaf将user.lastAccessDate表达式的结果传递给转换服务,并要求它在写入结果之前执行格式化操作(转换为String)。

假设它user.lastAccessDate是类型java.util.Calendar,如果已经注册了转换服务(实现IStandardConversionService)并且包含有效的转换Calendar -> String,则将应用它。

IStandardConversionServiceStandardConversionService类)的默认实现只是.toString()在转换为的任何对象上执行String。有关如何注册自定义转换服务实现的更多信息,请查看“ 更多配置”部分。

官方thymeleaf-spring3和thymeleaf-spring4集成软件包的透明集成了Spring自己Thymeleaf的转换服务机制转换服务的基础设施,所以在Spring配置宣称,转换服务和格式化将进行自动获得${{...}}*{{...}}表达。

4.15预处理

除了用于表达式处理的所有这些功能外,Thymeleaf还具有预处理表达式的功能。

预处理是在正常表达式之前完成的表达式的执行,它允许修改最终将被执行的表达式。

预处理表达式与普通表达式完全相同,但显示为双下划线符号(如__${expression}__)。

让我们假设我们有一个Messages_fr.properties包含OGNL表达式的i18n 条目,该表达式调用特定于语言的静态方法,如:


article.text=@myapp.translator.Translator@translateToFrench({0})

......和a Messages_es.properties equivalent


article.text=@myapp.translator.Translator@translateToSpanish({0})

我们可以创建一个标记片段,根据语言环境评估一个表达式或另一个表达式。为此,我们将首先选择表达式(通过预处理),然后让Thymeleaf执行它:


<p th:text="${__#{article.text('textVar')}__}">Some text here...p>

请注意,法语区域设置的预处理步骤将创建以下等效项:


<p th:text="${@myapp.translator.Translator@translateToFrench(textVar)}">Some text here...p>

__可以使用在属性中对预处理字符串进行转义\_\_

5设置属性值

本章将解释我们在标记中设置(或修改)属性值的方式。

5.1设置任何属性的值

假设我们的网站发布了一个时事通讯,我们希望我们的用户能够订阅它,所以我们创建一个/WEB-INF/templates/subscribe.html带有以下形式的模板:


<form action="subscribe.html">
  <fieldset>
    <input type="text" name="email" />
    <input type="submit" value="Subscribe!" />
  fieldset>
form>

与Thymeleaf一样,此模板更像是静态原型,而不是Web应用程序的模板。首先,action我们表单中的属性静态链接到模板文件本身,因此没有地方可以进行有用的URL重写。其次,value提交按钮中的属性使其显示英文文本,但我们希望它能够国际化。

然后输入th:attr属性,以及更改其设置的标记属性值的能力:


<form action="subscribe.html" th:attr="action=@{/subscribe}">
  <fieldset>
    <input type="text" name="email" />
    <input type="submit" value="Subscribe!" th:attr="value=#{subscribe.submit}"/>
  fieldset>
form>

这个概念非常简单:th:attr只需要一个为属性赋值的表达式。创建了相应的控制器和消息文件后,处理该文件的结果将是:


<form action="/gtvg/subscribe">
  <fieldset>
    <input type="text" name="email" />
    <input type="submit" value="¡Suscríbe!"/>
  fieldset>
form>

除了新的属性值之外,您还可以看到applicacion上下文名称已自动添加到URL基础中/gtvg/subscribe,如前一章所述。

但是,如果我们想一次设置多个属性呢?XML规则不允许您在标记中设置两次属性,因此th:attr将采用以逗号分隔的分配列表,例如:


<img src="../../images/gtvglogo.png" 
     th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />

给定所需的消息文件,这将输出:


<img src="/gtgv/images/gtvglogo.png" title="Logo de Good Thymes" alt="Logo de Good Thymes" />

5.2为特定属性设置值

到现在为止,您可能会想到以下内容:


<input type="submit" value="Subscribe!" th:attr="value=#{subscribe.submit}"/>

......是一个非常丑陋的标记。在属性值中指定赋值可能非常实用,但如果您必须始终执行此操作,则它不是创建模板的最佳方式。

Thymeleaf同意你的意见,这就是th:attr模板中几乎没有使用的原因。通常,您将使用th:*其任务设置特定标记属性的其他属性(而不仅仅是任何属性th:attr)。

例如,要设置value属性,请使用th:value


<input type="submit" value="Subscribe!" th:value="#{subscribe.submit}"/>

这看起来好多了!让我们尝试actionform标记中的属性执行相同操作:


<form action="subscribe.html" th:action="@{/subscribe}">

你还记得th:href我们home.html之前放过的东西吗?它们正是同样的属性:


<li><a href="product/list.html" th:href="@{/product/list}">Product Lista>li>

有很多这样的属性,每个属性都针对特定的HTML5属性:

th:abbr th:accept th:accept-charset
th:accesskey th:action th:align
th:alt th:archive th:audio
th:autocomplete th:axis th:background
th:bgcolor th:border th:cellpadding
th:cellspacing th:challenge th:charset
th:cite th:class th:classid
th:codebase th:codetype th:cols
th:colspan th:compact th:content
th:contenteditable th:contextmenu th:data
th:datetime th:dir th:draggable
th:dropzone th:enctype th:for
th:form th:formaction th:formenctype
th:formmethod th:formtarget th:fragment
th:frame th:frameborder th:headers
th:height th:high th:href
th:hreflang th:hspace th:http-equiv
th:icon th:id th:inline
th:keytype th:kind th:label
th:lang th:list th:longdesc
th:low th:manifest th:marginheight
th:marginwidth th:max th:maxlength
th:media th:method th:min
th:name th:onabort th:onafterprint
th:onbeforeprint th:onbeforeunload th:onblur
th:oncanplay th:oncanplaythrough th:onchange
th:onclick th:oncontextmenu th:ondblclick
th:ondrag th:ondragend th:ondragenter
th:ondragleave th:ondragover th:ondragstart
th:ondrop th:ondurationchange th:onemptied
th:onended th:onerror th:onfocus
th:onformchange th:onforminput th:onhashchange
th:oninput th:oninvalid th:onkeydown
th:onkeypress th:onkeyup th:onload
th:onloadeddata th:onloadedmetadata th:onloadstart
th:onmessage th:onmousedown th:onmousemove
th:onmouseout th:onmouseover th:onmouseup
th:onmousewheel th:onoffline th:ononline
th:onpause th:onplay th:onplaying
th:onpopstate th:onprogress th:onratechange
th:onreadystatechange th:onredo th:onreset
th:onresize th:onscroll th:onseeked
th:onseeking th:onselect th:onshow
th:onstalled th:onstorage th:onsubmit
th:onsuspend th:ontimeupdate th:onundo
th:onunload th:onvolumechange th:onwaiting
th:optimum th:pattern th:placeholder
th:poster th:preload th:radiogroup
th:rel th:rev th:rows
th:rowspan th:rules th:sandbox
th:scheme th:scope th:scrolling
th:size th:sizes th:span
th:spellcheck th:src th:srclang
th:standby th:start th:step
th:style th:summary th:tabindex
th:target th:title th:type
th:usemap th:value th:valuetype
th:vspace th:width th:wrap
th:xmlbase th:xmllang th:xmlspace

5.3一次设置多个值

有两个叫比较特殊的属性th:alt-titleth:lang-xmllang可用于同时设置两个属性相同的值。特别:

  • th:alt-title将设置alttitle
  • th:lang-xmllang将设置langxml:lang

对于我们的GTVG主页,这将允许我们替换:


<img src="../../images/gtvglogo.png" 
     th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />

......或者这个,相当于:


<img src="../../images/gtvglogo.png" 
     th:src="@{/images/gtvglogo.png}" th:title="#{logo}" th:alt="#{logo}" />

…有了这个:


<img src="../../images/gtvglogo.png" 
     th:src="@{/images/gtvglogo.png}" th:alt-title="#{logo}" />

5.4附加和预先

Thymeleaf还提供了th:attrappendth:attrprepend属性,它们将评估结果附加(后缀)或前置(前缀)到现有属性值。

例如,您可能希望将要添加的CSS类的名称(未设置,仅添加)存储到上下文变量中的某个按钮,因为要使用的特定CSS类将取决于用户执行的操作。之前:


<input type="button" value="Do it!" class="btn" th:attrappend="class=${' ' + cssStyle}" />

如果您在cssStyle变量设置为的情况下处理此模板"warning",您将获得:


<input type="button" value="Do it!" class="btn warning" />

标准方言中还有两个特定的附加属性th:classappendth:styleappend属性,用于向元素添加CSS类或样式片段而不覆盖现有元素:


<tr th:each="prod : ${prods}" class="row" th:classappend="${prodStat.odd}? 'odd'">

(不要担心该th:each属性。它是一个迭代属性,我们稍后会讨论它。)

5.5固定值布尔属性

HTML具有布尔属性的概念,没有值的属性和一个值的前提意味着值为“true”。在XHTML中,这些属性只占用1个值,这本身就是一个值。

例如,checked


<input type="checkbox" name="option2" checked /> 
<input type="checkbox" name="option1" checked="checked" /> 

标准方言包含允许您通过评估条件来设置这些属性的属性,因此如果计算为true,则属性将设置为其固定值,如果计算为false,则不会设置该属性:


<input type="checkbox" name="active" th:checked="${user.active}" />

标准方言中存在以下固定值布尔属性:

th:async th:autofocus th:autoplay
th:checked th:controls th:declare
th:default th:defer th:disabled
th:formnovalidate th:hidden th:ismap
th:loop th:multiple th:novalidate
th:nowrap th:open th:pubdate
th:readonly th:required th:reversed
th:scoped th:seamless th:selected

更多信息

5.6设置任何属性的值(默认属性处理器)

Thymeleaf提供了一个默认属性处理器,允许我们设置任何属性的值,即使th:*在标准方言中没有为它定义特定的处理器。

所以类似于:


<span th:whatever="${user.name}">...span>

将导致:


<span whatever="John Apricot">...span>

5.7支持HTML5友好的属性和元素名称

也可以使用完全不同的语法以更加HTML5友好的方式将处理器应用于模板。


<table>
    <tr data-th-each="user : ${users}">
        <td data-th-text="${user.login}">...td>
        <td data-th-text="${user.name}">...td>
    tr>
table>

data-{prefix}-{name}语法编写自定义属性在HTML5中,而无需开发人员使用任何命名空间的名称,如标准的方式th:*。Thymeleaf使所有方言(不仅是标准方言)自动使用此语法。

还有一种语法来指定自定义标签:{prefix}-{name},它遵循W3C自定义元素规范(较大的W3C Web组件规范的一部分)。例如,这可以用于th:block元素(或者也可以th-block),这将在后面的部分中解释。

重要提示:此语法是对命名空间语法的补充th:*,它不会替换它。完全没有意图在将来弃用命名空间语法。

6迭代

到目前为止,我们已经创建了一个主页,一个用户个人资料页面以及一个允许用户订阅我们的新闻通讯的页面......但是我们的产品呢?为此,我们需要一种方法来迭代集合中的项目以构建我们的产品页面。

6.1迭代基础知识

要在我们的/WEB-INF/templates/product/list.html页面中显示产品,我们将使用表格。我们的每个产品都会连续显示(一个元素),因此对于我们的模板,我们需要创建一个模板行 - 一个可以说明我们希望如何显示每个产品的模板行 - 然后指示Thymeleaf重复它,每个产品一次。

标准方言为我们提供了一个属性:th:each

使用th:each

对于我们的产品列表页面,我们需要一个控制器方法,从服务层检索产品列表并将其添加到模板上下文中:


public void process(
        final HttpServletRequest request, final HttpServletResponse response,
        final ServletContext servletContext, final ITemplateEngine templateEngine)
        throws Exception {
    
    ProductService productService = new ProductService();
    List allProducts = productService.findAll(); 
    
    WebContext ctx = new WebContext(request, response, servletContext, request.getLocale());
    ctx.setVariable("prods", allProducts);
    
    templateEngine.process("product/list", ctx, response.getWriter());
    
}

然后我们将th:each在我们的模板中使用迭代产品列表:




<html xmlns:th="http://www.thymeleaf.org">

  <head>
    <title>Good Thymes Virtual Grocerytitle>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <link rel="stylesheet" type="text/css" media="all" 
          href="../../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
  head>

  <body>

    <h1>Product listh1>
  
    <table>
      <tr>
        <th>NAMEth>
        <th>PRICEth>
        <th>IN STOCKth>
      tr>
      <tr th:each="prod : ${prods}">
        <td th:text="${prod.name}">Onionstd>
        <td th:text="${prod.price}">2.41td>
        <td th:text="${prod.inStock}? #{true} : #{false}">yestd>
      tr>
    table>
  
    <p>
      <a href="../home.html" th:href="@{/}">Return to homea>
    p>

  body>

html>

也就是说prod : ${prods}您在上面看到的属性值是指“用于评估的结果的每个元素${prods},重复模板的该片段,用在变量称为刺当前元素”。让我们给出一个我们看到的每个事物的名称:

  • 我们将调用${prods}迭代式迭代变量
  • 我们将调用prod迭代变量或者干脆ITER变量

请注意,proditer变量的作用域是元素,这意味着它可用于内部标记

可重复的值

java.util.List班是不是可以用于Thymeleaf迭代onlyvalue。有一组非常完整的对象被属性认为是可迭代th:each

  • 任何对象实现 java.util.Iterable
  • 任何对象实现java.util.Enumeration
  • 任何实现的对象java.util.Iterator,其值将在迭代器返回时使用,而不需要将所有值缓存在内存中。
  • 任何对象实现java.util.Map。迭代地图时,iter变量将属于类java.util.Map.Entry
  • 任何数组。
  • 任何其他对象都将被视为包含对象本身的单值列表。

6.2保持迭代状态

使用时th:each,Thymeleaf提供了一种机制,可用于跟踪迭代的状态状态变量

状态变量在th:each属性中定义,包含以下数据:

  • 当前迭代索引,从0开始。这是index属性。
  • 当前迭代索引,从1开始。这是count属性。
  • 迭代变量中元素的总量。这是size酒店。
  • 每次迭代的iter变量。这是current酒店。
  • 当前迭代是偶数还是奇数。这些是even/odd布尔属性。
  • 当前迭代是否是第一个迭代。这是first布尔属性。
  • 当前迭代是否是最后一次迭代。这是last布尔属性。

让我们看看我们如何在前面的例子中使用它:


<table>
  <tr>
    <th>NAMEth>
    <th>PRICEth>
    <th>IN STOCKth>
  tr>
  <tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.odd}? 'odd'">
    <td th:text="${prod.name}">Onionstd>
    <td th:text="${prod.price}">2.41td>
    <td th:text="${prod.inStock}? #{true} : #{false}">yestd>
  tr>
table>

状态变量(iterStat在此示例中)在th:each属性中通过在iter变量本身之后写入其名称来定义,用逗号分隔。就像iter变量一样,状态变量的范围也限定为由包含该th:each属性的标记定义的代码片段。

我们来看看处理模板的结果:




<html>

  <head>
    <title>Good Thymes Virtual Grocerytitle>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
    <link rel="stylesheet" type="text/css" media="all" href="/gtvg/css/gtvg.css" />
  head>

  <body>

    <h1>Product listh1>
  
    <table>
      <tr>
        <th>NAMEth>
        <th>PRICEth>
        <th>IN STOCKth>
      tr>
      <tr class="odd">
        <td>Fresh Sweet Basiltd>
        <td>4.99td>
        <td>yestd>
      tr>
      <tr>
        <td>Italian Tomatotd>
        <td>1.25td>
        <td>notd>
      tr>
      <tr class="odd">
        <td>Yellow Bell Peppertd>
        <td>2.50td>
        <td>yestd>
      tr>
      <tr>
        <td>Old Cheddartd>
        <td>18.75td>
        <td>yestd>
      tr>
    table>
  
    <p>
      <a href="/gtvg/" shape="rect">Return to homea>
    p>

  body>
  
html>

请注意,我们的迭代状态变量已经完美地工作,odd仅将CSS类建立到奇数行。

如果您没有显式设置状态变量,Thymeleaf将始终通过后缀Stat为迭代变量的名称为您创建一个:


<table>
  <tr>
    <th>NAMEth>
    <th>PRICEth>
    <th>IN STOCKth>
  tr>
  <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
    <td th:text="${prod.name}">Onionstd>
    <td th:text="${prod.price}">2.41td>
    <td th:text="${prod.inStock}? #{true} : #{false}">yestd>
  tr>
table>

6.3通过延迟检索数据进行优化

有时我们可能希望优化数据集合的检索(例如,从数据库中),以便只有在真正使用它们时才会检索这些集合。

实际上,这可以应用于任何数据片段,但考虑到内存中集合可能具有的大小,检索要迭代的集合是此方案的最常见情况。

为了支持这一点,Thymeleaf提供了一种懒惰加载上下文变量的机制。实现ILazyContextVariable接口的上下文变量- 最有可能通过扩展其LazyContextVariable默认实现 - 将在执行时解决。例如:


context.setVariable(
     "users",
     new LazyContextVariable>() {
         @Override
         protected List loadValue() {
             return databaseRepository.findAllUsers();
         }
     });

可以在不知道其惰性的情况下使用此变量,例如:


<ul>
  <li th:each="u : ${users}" th:text="${u.name}">user nameli>
ul>

但与此同时,loadValue()如果在代码中condition进行求值,则永远不会被初始化(它的方法永远不会被调用)false


<ul th:if="${condition}">
  <li th:each="u : ${users}" th:text="${u.name}">user nameli>
ul>

7条件评估

7.1简单条件:“if”和“除非”

有时,如果满足某个条件,您将需要模板的片段才会出现在结果中。

例如,假设我们希望在产品表中显示一列,其中包含每个产品的评论数量,如果有任何评论,则指向该产品的评论详细信息页面的链接。

为此,我们将使用以下th:if属性:


<table>
  <tr>
    <th>NAMEth>
    <th>PRICEth>
    <th>IN STOCKth>
    <th>COMMENTSth>
  tr>
  <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
    <td th:text="${prod.name}">Onionstd>
    <td th:text="${prod.price}">2.41td>
    <td th:text="${prod.inStock}? #{true} : #{false}">yestd>
    <td>
      <span th:text="${#lists.size(prod.comments)}">2span> comment/s
      <a href="comments.html" 
         th:href="@{/product/comments(prodId=${prod.id})}" 
         th:if="${not #lists.isEmpty(prod.comments)}">viewa>
    td>
  tr>
table>

这里有很多东西要看,所以让我们关注重要的一点:


<a href="comments.html"
   th:href="@{/product/comments(prodId=${prod.id})}" 
   th:if="${not #lists.isEmpty(prod.comments)}">viewa>

这将创建指向评论页面(带有URL /product/comments)的链接,其prodId参数设置为id产品的参数,但仅限于产品有任何评论。

我们来看看生成的标记:


<table>
  <tr>
    <th>NAMEth>
    <th>PRICEth>
    <th>IN STOCKth>
    <th>COMMENTSth>
  tr>
  <tr>
    <td>Fresh Sweet Basiltd>
    <td>4.99td>
    <td>yestd>
    <td>
      <span>0span> comment/s
    td>
  tr>
  <tr class="odd">
    <td>Italian Tomatotd>
    <td>1.25td>
    <td>notd>
    <td>
      <span>2span> comment/s
      <a href="/gtvg/product/comments?prodId=2">viewa>
    td>
  tr>
  <tr>
    <td>Yellow Bell Peppertd>
    <td>2.50td>
    <td>yestd>
    <td>
      <span>0span> comment/s
    td>
  tr>
  <tr class="odd">
    <td>Old Cheddartd>
    <td>18.75td>
    <td>yestd>
    <td>
      <span>1span> comment/s
      <a href="/gtvg/product/comments?prodId=4">viewa>
    td>
  tr>
table>

完善!这正是我们想要的。

请注意,该th:if属性不仅会评估布尔条件。它的功能稍微超出了它,它将按照true以下规则评估指定的表达式:

  • 如果value不为null:
    • 如果value是布尔值,则为true
    • 如果value是数字且不为零
    • 如果value是一个字符且不为零
    • 如果value是String并且不是“false”,“off”或“no”
    • 如果value不是布尔值,数字,字符或字符串。
  • (如果value为null,则th:if将计算为false)。

此外,th:if还有一个inverse属性,th:unless我们可以在前面的示例中使用它,而不是not在OGNL表达式中使用:


<a href="comments.html"
   th:href="@{/comments(prodId=${prod.id})}" 
   th:unless="${#lists.isEmpty(prod.comments)}">viewa>

7.2切换语句

还有一种方法可以使用Java中的等效开关结构有条件地显示内容:th:switchth:case属性集。


<div th:switch="${user.role}">
  <p th:case="'admin'">User is an administratorp>
  <p th:case="#{roles.manager}">User is a managerp>
div>

请注意,只要th:case评估true一个th:case属性,就会将同一切换上下文中的每个其他属性评估为false

默认选项指定为th:case="*"


<div th:switch="${user.role}">
  <p th:case="'admin'">User is an administratorp>
  <p th:case="#{roles.manager}">User is a managerp>
  <p th:case="*">User is some other thingp>
div>

8模板布局

8.1包括模板片段

定义和引用片段

在我们的模板中,我们经常需要包含其他模板中的部分,页脚,标题,菜单等部分......

为了做到这一点,Thymeleaf需要我们定义这些部分,“片段”,以便包含,这可以使用th:fragment属性来完成。

假设我们要在所有杂货页面上添加标准版权页脚,因此我们创建一个/WEB-INF/templates/footer.html包含以下代码的文件:




<html xmlns:th="http://www.thymeleaf.org">

  <body>
  
    <div th:fragment="copy">
      © 2011 The Good Thymes Virtual Grocery
    div>
  
  body>
  
html>

上面的代码定义了一个名为的片段copy,我们可以使用其中一个th:insertth:replace属性轻松地在我们的主页中包含这些片段(并且th:include,尽管自Thymeleaf 3.0以来不再推荐使用它):


<body>

  ...

  <div th:insert="~{footer :: copy}">div>
  
body>

请注意,th:insert需要一个片段表达式~{...}),它是一个导致片段的表达式。在上面的例子中,这是一个非复杂的片段表达式,(~{})封闭是完全可选的,所以上面的代码相当于:


<body>

  ...

  <div th:insert="footer :: copy">div>
  
body>

片段规范语法

片段表达式的语法非常简单。有三种不同的格式:

  • "~{templatename::selector}"包括在名为的模板上应用指定标记选择器而产生的片段templatename。请注意,selector可以仅仅是一个片段的名字,所以你可以指定为简单的东西~{templatename::fragmentname}就像在~{footer :: copy}上面。

    标记选择器语法由底层的AttoParser解析库定义,类似于XPath表达式或CSS选择器。有关详细信息,请参阅附录C.

  • "~{templatename}"包含名为的完整模板templatename

    请注意,您在th:insertth:replacetags中使用的模板名称必须由模板引擎当前使用的模板解析器解析。

  • ~{::selector}""~{this::selector}"插入来自同一模板的片段,进行匹配selector。如果在表达式出现的模板上找不到,则模板调用(插入)的堆栈将遍历最初处理的模板(),直到selector在某个级别匹配。

双方templatenameselector在上面的例子可以是全功能的表达式(甚至条件语句!),如:


<div th:insert="footer :: (${user.isAdmin}? #{footer.admin} : #{footer.normaluser})">div>

再次注意周围的~{...}包络在th:insert/中是如何可选的th:replace

片段可以包含任何th:*属性。一旦将片段包含在目标模板(具有th:insertth:replaceattribute的模板)中,就会评估这些属性,并且它们将能够引用此目标模板中定义的任何上下文变量。

这种片段方法的一大优点是,您可以在浏览器完全可显示的页面中编写片段,具有完整且有效的标记结构,同时仍保留使Thymeleaf将其包含在其他模板中的能力。

没有引用片段 th:fragment

由于标记选择器的强大功能,我们可以包含不使用任何th:fragment属性的片段。它甚至可以是来自不同应用程序的标记代码,完全不了解Thymeleaf:


...
<div id="copy-section">
  © 2011 The Good Thymes Virtual Grocery
div>
...

我们可以使用上面的片段,通过其id属性简单地引用它,与CSS选择器类似:


<body>

  ...

  <div th:insert="~{footer :: #copy-section}">div>
  
body>

th:insertth:replace(和th:include)之间的区别

和之间有什么区别th:insertth:replace(和th:include,因为3.0不推荐)?

  • th:insert 是最简单的:它只是插入指定的片段作为其主机标签的主体。

  • th:replace实际上指定的片段替换它的主机标签。

  • th:include类似于th:insert,但不是插入片段,它只插入此片段的内容

所以像这样的HTML片段:


<footer th:fragment="copy">
  © 2011 The Good Thymes Virtual Grocery
footer>

...在主机

标签中包含三次,如下所示:


<body>

  ...

  <div th:insert="footer :: copy">div>

  <div th:replace="footer :: copy">div>

  <div th:include="footer :: copy">div>
  
body>

......将导致:


<body>

  ...

  <div>
    <footer>
      © 2011 The Good Thymes Virtual Grocery
    footer>
  div>

  <footer>
    © 2011 The Good Thymes Virtual Grocery
  footer>

  <div>
    © 2011 The Good Thymes Virtual Grocery
  div>
  
body>

8.2可参数化的片段签名

为了为模板片段创建更像函数的机制,使用定义的片段th:fragment可以指定一组参数:


<div th:fragment="frag (onevar,twovar)">
    <p th:text="${onevar} + ' - ' + ${twovar}">...p>
div>

这需要使用这两种语法之一来从th:insert或调用片段th:replace


<div th:replace="::frag (${value1},${value2})">...div>
<div th:replace="::frag (onevar=${value1},twovar=${value2})">...div>

请注意,在最后一个选项中,顺序并不重要:


<div th:replace="::frag (twovar=${value2},onevar=${value1})">...div>

片段局部变量没有片段参数

即使片段定义没有这样的参数:


<div th:fragment="frag">
    ...
div>

我们可以使用上面指定的第二种语法来调用它们(只有第二种语法):


<div th:replace="::frag (onevar=${value1},twovar=${value2})">

这将相当于组合th:replaceth:with


<div th:replace="::frag" th:with="onevar=${value1},twovar=${value2}">

请注意,片段的局部变量的这种规范 - 无论它是否具有参数签名 - 都不会导致在执行之前清空上下文。片段仍然可以访问调用模板中使用的每个上下文变量,就像它们当前一样。

th:断言in-template断言

th:assert属性可以指定一个以逗号分隔的表达式列表,这些表达式应该被评估并为每次评估生成true,否则会引发异常。


<div th:assert="${onevar},(${twovar} != 43)">...div>

这对于验证片段签名的参数非常方便:


<header th:fragment="contentheader(title)" th:assert="${!#strings.isEmpty(title)}">...header>

8.3灵活的布局:仅仅是片段插入

由于片段表达式,我们可以为不是文本,数字,bean对象的片段指定参数......而是指定标记片段。

这允许我们以一种方式创建我们的片段,使得它们可以通过来自调用模板的标记来丰富,从而产生非常灵活的模板布局机制

注意在下面的片段中使用titlelinks变量:


<head th:fragment="common_header(title,links)">

  <title th:replace="${title}">The awesome applicationtitle>

  
  <link rel="stylesheet" type="text/css" media="all" th:href="@{/css/awesomeapp.css}">
  <link rel="shortcut icon" th:href="@{/images/favicon.ico}">
  <script type="text/javascript" th:src="@{/sh/scripts/codebase.js}">script>

  
  <th:block th:replace="${links}" />

head>

我们现在可以将这个片段称为:


...
<head th:replace="base :: common_header(~{::title},~{::link})">

  <title>Awesome - Maintitle>

  <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
  <link rel="stylesheet" th:href="@{/themes/smoothness/jquery-ui.css}">

head>
...

...结果将使用我们的调用模板中的实际</code>和<code><link></code>标签作为<code>title</code>和<code>links</code>变量的值,从而导致我们的片段在插入过程中自定义:</p> <pre><code class="language-html"> <code class="language-html">... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>head</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>title</span><span style="color:#b9bdb6;">></span></span>Awesome - Main<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>title</span><span style="color:#b9bdb6;">></span></span> <span style="color:#cf9a49;"><!-- Common styles and scripts --></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>stylesheet<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">type</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>text/css<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">media</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>all<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/awe/css/awesomeapp.css<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>shortcut icon<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/awe/images/favicon.ico<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>script</span> <span style="color:#e0e8ff;">type</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>text/javascript<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">src</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/awe/sh/scripts/codebase.js<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>script</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>stylesheet<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/awe/css/bootstrap.min.css<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>stylesheet<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/awe/themes/smoothness/jquery-ui.css<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>head</span><span style="color:#b9bdb6;">></span></span> ...</code></code></pre> <h3 id="%E4%BD%BF%E7%94%A8%E7%A9%BA%E7%89%87%E6%AE%B5" style="margin-left:0px;"><em><strong>使用空片段</strong></em></h3> <p style="margin-left:0px;">一个特殊的片段表达式,即<em>空片段</em>(<code>~{}</code>),可用于指定<em>无标记</em>。使用前面的示例:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>head</span> <span style="color:#e0e8ff;">th:replace</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>base :: common_header(~{::title},~{})<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>title</span><span style="color:#b9bdb6;">></span></span>Awesome - Main<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>title</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>head</span><span style="color:#b9bdb6;">></span></span> ...</code></code></pre> <p style="margin-left:0px;">注意fragment(<code>links</code>)的第二个参数是如何设置为<em>空片段的</em>,因此没有为<code><th:block th:replace="${links}" /></code>块写入任何内容:</p> <pre><code class="language-html"> <code class="language-html">... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>head</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>title</span><span style="color:#b9bdb6;">></span></span>Awesome - Main<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>title</span><span style="color:#b9bdb6;">></span></span> <span style="color:#cf9a49;"><!-- Common styles and scripts --></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>stylesheet<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">type</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>text/css<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">media</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>all<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/awe/css/awesomeapp.css<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>shortcut icon<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/awe/images/favicon.ico<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>script</span> <span style="color:#e0e8ff;">type</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>text/javascript<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">src</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/awe/sh/scripts/codebase.js<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>script</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>head</span><span style="color:#b9bdb6;">></span></span> ...</code></code></pre> <h3 id="%E4%BD%BF%E7%94%A8%E6%97%A0%E6%93%8D%E4%BD%9C%E4%BB%A4%E7%89%8C" style="margin-left:0px;"><em><strong>使用无操作令牌</strong></em></h3> <p style="margin-left:0px;">如果我们只想让我们的片段使用其当前标记作为默认值,则no-op也可以用作片段的参数。再次,使用<code>common_header</code>示例:</p> <pre><code class="language-html"> <code class="language-html">... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>head</span> <span style="color:#e0e8ff;">th:replace</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>base :: common_header(_,~{::link})<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>title</span><span style="color:#b9bdb6;">></span></span>Awesome - Main<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>title</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>stylesheet<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>@{/css/bootstrap.min.css}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>stylesheet<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>@{/themes/smoothness/jquery-ui.css}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>head</span><span style="color:#b9bdb6;">></span></span> ...</code></code></pre> <p style="margin-left:0px;">看看如何将<code>title</code>参数(<code>common_header</code>片段的第一个参数)设置为<em>no-op</em>(<code>_</code>),这导致片段的这一部分根本不被执行(<code>title</code>= <em>无操作</em>):</p> <pre><code class="language-html"> <code class="language-html"> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>title</span> <span style="color:#e0e8ff;">th:replace</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${title}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>The awesome application<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>title</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">结果是:</p> <pre><code class="language-html"> <code class="language-html">... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>head</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>title</span><span style="color:#b9bdb6;">></span></span>The awesome application<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>title</span><span style="color:#b9bdb6;">></span></span> <span style="color:#cf9a49;"><!-- Common styles and scripts --></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>stylesheet<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">type</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>text/css<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">media</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>all<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/awe/css/awesomeapp.css<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>shortcut icon<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/awe/images/favicon.ico<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>script</span> <span style="color:#e0e8ff;">type</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>text/javascript<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">src</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/awe/sh/scripts/codebase.js<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>script</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>stylesheet<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/awe/css/bootstrap.min.css<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>stylesheet<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/awe/themes/smoothness/jquery-ui.css<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>head</span><span style="color:#b9bdb6;">></span></span> ...</code></code></pre> <h3 id="%E9%AB%98%E7%BA%A7%E6%9D%A1%E4%BB%B6%E6%8F%92%E5%85%A5%E7%89%87%E6%AE%B5" style="margin-left:0px;"><em><strong>高级条件插入片段</strong></em></h3> <p style="margin-left:0px;"><em>emtpy片段</em>和<em>无操作令牌</em>的可用性允许我们以非常简单和优雅的方式执行片段的条件插入。</p> <p style="margin-left:0px;">例如,我们可以这样做,以便<em>仅</em>在用户是管理员时插入我们的<code>common :: adminhead</code>片段,并且如果不是,则不插入任何内容(emtpy片段):</p> <pre><code class="language-html"> <code class="language-html">... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:insert</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${user.isAdmin()} ? ~{common :: adminhead} : ~{}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span> ...</code></code></pre> <p style="margin-left:0px;">此外,我们可以使用<em>无操作令牌</em>,以便仅在满足指定条件时插入片段,但如果不满足条件则保留标记而不进行修改:</p> <pre><code class="language-html"> <code class="language-html">... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:insert</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${user.isAdmin()} ? ~{common :: adminhead} : _<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> Welcome [[${user.name}]], click <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">th:href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>@{/support}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>here<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> for help-desk support. <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span> ...</code></code></pre> <p style="margin-left:0px;">另外,如果我们已经配置了模板解析器来<em>检查</em>模板资源<em>是否存在</em> - 通过它们的<code>checkExistence</code>标志 - 我们可以使用片段本身的存在作为<em>默认</em>操作中的条件:</p> <pre><code class="language-html"> <code class="language-html">... <span style="color:#cf9a49;"><!-- The body of the <div> will be used if the "common :: salutation" fragment --></span> <span style="color:#cf9a49;"><!-- does not exist (or is empty). --></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:insert</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>~{common :: salutation} ?: _<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> Welcome [[${user.name}]], click <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">th:href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>@{/support}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>here<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> for help-desk support. <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span> ...</code></code></pre> <h2 id="8.4%E5%88%A0%E9%99%A4%E6%A8%A1%E6%9D%BF%E7%89%87%E6%AE%B5" style="margin-left:-2em;"><em><span style="color:#ffffff;">8.4删除模板片段</span></em></h2> <p style="margin-left:0px;">回到示例应用程序,让我们重新访问我们的产品列表模板的最新版本:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>NAME<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>PRICE<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>IN STOCK<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>COMMENTS<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">th:each</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>prod : ${prods}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prodStat.odd}? <span style="color:#b9bdb6;">'</span>odd<span style="color:#b9bdb6;">'</span><span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prod.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Onions<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prod.price}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>2.41<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prod.inStock}? #{true} : #{false}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#lists.size(prod.comments)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>2<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>comments.html<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>@{/product/comments(prodId<span style="color:#b9bdb6;">=</span>${prod.id})}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:unless</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#lists.isEmpty(prod.comments)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>view<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>table</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">这段代码作为一个模板很好,但作为一个静态页面(当浏览器直接打开而没有Thymeleaf处理它时)它就不会成为一个好的原型。</p> <p style="margin-left:0px;">为什么?因为虽然浏览器可以完全显示,但该表只有一行,而且这行包含模拟数据。作为原型,它看起来不够逼真......我们应该有多个产品,<em>我们需要更多行</em>。</p> <p style="margin-left:0px;">所以让我们添加一些:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>NAME<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>PRICE<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>IN STOCK<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>COMMENTS<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">th:each</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>prod : ${prods}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prodStat.odd}? <span style="color:#b9bdb6;">'</span>odd<span style="color:#b9bdb6;">'</span><span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prod.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Onions<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prod.price}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>2.41<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prod.inStock}? #{true} : #{false}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#lists.size(prod.comments)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>2<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>comments.html<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>@{/product/comments(prodId<span style="color:#b9bdb6;">=</span>${prod.id})}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:unless</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#lists.isEmpty(prod.comments)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>view<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>odd<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Blue Lettuce<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>9.55<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>no<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>0<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Mild Cinnamon<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>1.99<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>3<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>comments.html<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>view<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>table</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">好的,现在我们有三个,对原型来说肯定更好。但是......当我们用Thymeleaf处理它时会发生什么?:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>NAME<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>PRICE<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>IN STOCK<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>COMMENTS<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Fresh Sweet Basil<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>4.99<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>0<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>odd<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Italian Tomato<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>1.25<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>no<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>2<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/gtvg/product/comments?prodId<span style="color:#b9bdb6;">=</span>2<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>view<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Yellow Bell Pepper<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>2.50<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>0<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>odd<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Old Cheddar<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>18.75<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>1<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/gtvg/product/comments?prodId<span style="color:#b9bdb6;">=</span>4<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>view<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>odd<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Blue Lettuce<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>9.55<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>no<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>0<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Mild Cinnamon<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>1.99<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>3<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>comments.html<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>view<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>table</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">最后两行是模拟行!嗯,当然它们是:迭代仅适用于第一行,所以没有理由为什么Thymeleaf应该删除其他两个。</p> <p style="margin-left:0px;">我们需要一种在模板处理过程中删除这两行的方法。让我们<code>th:remove</code>在第二个和第三个<code><tr></code>标签上使用该属性:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>NAME<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>PRICE<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>IN STOCK<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>COMMENTS<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">th:each</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>prod : ${prods}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prodStat.odd}? <span style="color:#b9bdb6;">'</span>odd<span style="color:#b9bdb6;">'</span><span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prod.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Onions<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prod.price}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>2.41<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prod.inStock}? #{true} : #{false}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#lists.size(prod.comments)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>2<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>comments.html<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>@{/product/comments(prodId<span style="color:#b9bdb6;">=</span>${prod.id})}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:unless</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#lists.isEmpty(prod.comments)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>view<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>odd<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:remove</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>all<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Blue Lettuce<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>9.55<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>no<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>0<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">th:remove</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>all<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Mild Cinnamon<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>1.99<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>3<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>comments.html<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>view<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>table</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">处理完毕后,所有内容都将按原样重复:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>NAME<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>PRICE<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>IN STOCK<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>COMMENTS<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Fresh Sweet Basil<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>4.99<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>0<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>odd<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Italian Tomato<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>1.25<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>no<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>2<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/gtvg/product/comments?prodId<span style="color:#b9bdb6;">=</span>2<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>view<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Yellow Bell Pepper<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>2.50<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>0<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>odd<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Old Cheddar<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>18.75<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>1<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/gtvg/product/comments?prodId<span style="color:#b9bdb6;">=</span>4<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>view<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>table</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;"><code>all</code>属性中的这个值是什么意思?<code>th:remove</code>可以根据其价值以五种不同的方式表现:</p> <ul style="margin-left:2em;"> <li><code>all</code>:删除包含标记及其所有子标记。</li> <li><code>body</code>:不要删除包含标记,但删除其所有子标记。</li> <li><code>tag</code>:删除包含标记,但不删除其子项。</li> <li><code>all-but-first</code>:除第一个子项外,删除包含标记的所有子项。</li> <li><code>none</code>: 没做什么。此值对于动态评估很有用。</li> </ul> <p style="margin-left:0px;">这个<code>all-but-first</code>价值有什么用呢?它将让我们<code>th:remove="all"</code>在原型设计时节省一些:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>thead</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>NAME<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>PRICE<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>IN STOCK<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>COMMENTS<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>thead</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tbody</span> <span style="color:#e0e8ff;">th:remove</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>all-but-first<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">th:each</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>prod : ${prods}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prodStat.odd}? <span style="color:#b9bdb6;">'</span>odd<span style="color:#b9bdb6;">'</span><span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prod.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Onions<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prod.price}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>2.41<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${prod.inStock}? #{true} : #{false}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#lists.size(prod.comments)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>2<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>comments.html<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>@{/product/comments(prodId<span style="color:#b9bdb6;">=</span>${prod.id})}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:unless</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#lists.isEmpty(prod.comments)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>view<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>odd<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Blue Lettuce<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>9.55<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>no<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>0<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>Mild Cinnamon<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>1.99<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span>yes<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>3<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> comment/s <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>comments.html<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>view<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tbody</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>table</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">该<code>th:remove</code>属性可采取任何<em>Thymeleaf标准表示</em>,因为它返回允许字符串值中的一个,只要(<code>all</code>,<code>tag</code>,<code>body</code>,<code>all-but-first</code>或<code>none</code>)。</p> <p style="margin-left:0px;">这意味着删除可能是有条件的,例如:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/something<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:remove</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${condition}? tag : none<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Link text not to be removed<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">另请注意,<code>th:remove</code>考虑<code>null</code>到同义词<code>none</code>,因此以下工作方式与上面的示例相同:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/something<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:remove</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${condition}? tag<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Link text not to be removed<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">在这种情况下,如果<code>${condition}</code>为false,<code>null</code>将返回,因此不会执行删除。</p> <h2 id="8.5%E5%B8%83%E5%B1%80%E7%BB%A7%E6%89%BF" style="margin-left:-2em;"><em><span style="color:#ffffff;">8.5布局继承</span></em></h2> <p style="margin-left:0px;">为了能够将单个文件作为布局,可以使用片段。具有<code>title</code>和<code>content</code>使用<code>th:fragment</code>和的简单布局示例<code>th:replace</code>:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#cf9a49;"><!DOCTYPE html></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>html</span> <span style="color:#e0e8ff;">th:fragment</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>layout (title, content)<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">xmlns:th</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>http://www.thymeleaf.org<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>head</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>title</span> <span style="color:#e0e8ff;">th:replace</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${title}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Layout Title<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>title</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>head</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>body</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>h1</span><span style="color:#b9bdb6;">></span></span>Layout H1<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>h1</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:replace</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${content}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span>Layout content<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>footer</span><span style="color:#b9bdb6;">></span></span> Layout footer <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>footer</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>body</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>html</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">此示例声明了一个名为<strong>layout</strong>的片段,其中<em>title</em>和<em>content</em>作为参数。在下面的示例中,两者都将在页面上替换,并通过提供的片段表达式继承它。</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#cf9a49;"><!DOCTYPE html></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>html</span> <span style="color:#e0e8ff;">th:replace</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>~{layoutFile :: layout(~{::title}, ~{::section})}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>head</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>title</span><span style="color:#b9bdb6;">></span></span>Page Title<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>title</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>head</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>body</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>section</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span>Page content<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span><span style="color:#b9bdb6;">></span></span>Included on page<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>section</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>body</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>html</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">在这个文件中,该<code>html</code>标签将被替换<em>的布局</em>,但在布局<code>title</code>和<code>content</code>将已被替换<code>title</code>,并<code>section</code>分别块。</p> <p style="margin-left:0px;">如果需要,布局可以由多个片段组成<em>页眉</em>和<em>页脚</em>。</p> <h1 id="9%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F" style="margin-left:0px;"><em><strong>9局部变量</strong></em></h1> <p style="margin-left:0px;">Thymeleaf将<em>局部变量</em>称为为模板的特定片段定义的变量,并且仅可用于在该片段内进行评估。</p> <p style="margin-left:0px;">我们已经看到的一个例子是<code>prod</code>我们的产品列表页面中的iter变量:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">th:each</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>prod : ${prods}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">该<code>prod</code>变量仅在<code><tr></code>标记的范围内可用。特别:</p> <ul style="margin-left:2em;"> <li>它将可用于<code>th:*</code>在该标记中执行的任何其他属性,其<em>优先级</em>低于<code>th:each</code>(这意味着它们将在之后执行<code>th:each</code>)。</li> <li>它将可用于<code><tr></code>标记的任何子<code><td></code>元素,例如任何元素。</li> </ul> <p style="margin-left:0px;">Thymeleaf为您提供了一种使用<code>th:with</code>属性声明局部变量而无需迭代的方法,其语法类似于属性值赋值:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:with</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>firstPer<span style="color:#b9bdb6;">=</span>${persons[0]}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span> The name of the first person is <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${firstPer.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Julius Caesar<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span>. <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">当<code>th:with</code>被处理时,该<code>firstPer</code>变量被创建为一个局部变量,并加入到变量映射从上下文来,使得它可用于评估与在上下文中声明的任何其它变量一起,但仅在含有的边界<code><div></code>标记。</p> <p style="margin-left:0px;">您可以使用通常的多重赋值语法同时定义多个变量:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:with</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>firstPer<span style="color:#b9bdb6;">=</span>${persons[0]},secondPer<span style="color:#b9bdb6;">=</span>${persons[1]}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span> The name of the first person is <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${firstPer.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Julius Caesar<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span>. <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span> But the name of the second person is <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${secondPer.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Marcus Antonius<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span>. <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">该<code>th:with</code>属性允许重用在同一属性中定义的变量:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:with</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>company<span style="color:#b9bdb6;">=</span>${user.company + <span style="color:#b9bdb6;">'</span> Co.<span style="color:#b9bdb6;">'</span>},account<span style="color:#b9bdb6;">=</span>${accounts[company]}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">我们在Grocery的主页上使用它!还记得我们为输出格式化日期而编写的代码吗?</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span> Today is: <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#calendars.format(today,<span style="color:#b9bdb6;">'</span>dd MMMM yyyy<span style="color:#b9bdb6;">'</span>)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>13 february 2011<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">那么,如果我们想要<code>"dd MMMM yyyy"</code>实际依赖于语言环境怎么办?例如,我们可能希望将以下消息添加到我们的<code>home_en.properties</code>:</p> <pre class="has"><code>date.format=MMMM dd'','' yyyy</code></pre> <p style="margin-left:0px;">......和我们相同的一个<code>home_es.properties</code>:</p> <pre class="has"><code>date.format=dd ''de'' MMMM'','' yyyy</code></pre> <p style="margin-left:0px;">现在,让我们使用<code>th:with</code>将本地化的日期格式转换为变量,然后在<code>th:text</code>表达式中使用它:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span> <span style="color:#e0e8ff;">th:with</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>df<span style="color:#b9bdb6;">=</span>#{date.format}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> Today is: <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#calendars.format(today,df)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>13 February 2011<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">那简洁干净。事实上,鉴于这一事实<code>th:with</code>具有较高的<code>precedence</code>比<code>th:text</code>,我们可以解决这一切的<code>span</code>标签:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span> Today is: <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:with</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>df<span style="color:#b9bdb6;">=</span>#{date.format}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#calendars.format(today,df)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>13 February 2011<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">你可能在想:优先权?我们还没有谈过这个!好吧,不要担心,因为这正是下一章的内容。</p> <h1 id="10%E5%B1%9E%E6%80%A7%E4%BC%98%E5%85%88%E7%BA%A7" style="margin-left:0px;"><em><strong>10属性优先级</strong></em></h1> <p style="margin-left:0px;"><code>th:*</code>在同一个标​​签中写入多个属性会发生什么?例如:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>ul</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>li</span> <span style="color:#e0e8ff;">th:each</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>item : ${items}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${item.description}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Item description here...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>li</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>ul</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">我们希望该<code>th:each</code>属性在之前执行,<code>th:text</code>以便我们得到我们想要的结果,但是考虑到HTML / XML标准没有给标签中的属性写入的顺序赋予任何意义,<em>优先级</em>必须在属性本身中建立机制,以确保这将按预期工作。</p> <p style="margin-left:0px;">因此,所有Thymeleaf属性都定义了一个数字优先级,它确定了它们在标记中执行的顺序。这个顺序是:</p> <table> <thead> <tr> <th style="text-align:left;vertical-align:top;">订购</th> <th style="text-align:left;vertical-align:top;">特征</th> <th style="text-align:left;vertical-align:top;">属性</th> </tr> </thead> <tbody> <tr> <td style="text-align:left;vertical-align:top;">1</td> <td style="text-align:left;vertical-align:top;">片段包含</td> <td style="text-align:left;vertical-align:top;"><code>th:insert</code><br><code>th:replace</code></td> </tr> <tr> <td style="text-align:left;vertical-align:top;">2</td> <td style="text-align:left;vertical-align:top;">片段迭代</td> <td style="text-align:left;vertical-align:top;"><code>th:each</code></td> </tr> <tr> <td style="text-align:left;vertical-align:top;">3</td> <td style="text-align:left;vertical-align:top;">有条件的评估</td> <td style="text-align:left;vertical-align:top;"><code>th:if</code><br><code>th:unless</code><br><code>th:switch</code><br><code>th:case</code></td> </tr> <tr> <td style="text-align:left;vertical-align:top;">4</td> <td style="text-align:left;vertical-align:top;">局部变量定义</td> <td style="text-align:left;vertical-align:top;"><code>th:object</code><br><code>th:with</code></td> </tr> <tr> <td style="text-align:left;vertical-align:top;">五</td> <td style="text-align:left;vertical-align:top;">一般属性修改</td> <td style="text-align:left;vertical-align:top;"><code>th:attr</code><br><code>th:attrprepend</code><br><code>th:attrappend</code></td> </tr> <tr> <td style="text-align:left;vertical-align:top;">6</td> <td style="text-align:left;vertical-align:top;">具体属性修改</td> <td style="text-align:left;vertical-align:top;"><code>th:value</code><br><code>th:href</code><br><code>th:src</code><br><code>...</code></td> </tr> <tr> <td style="text-align:left;vertical-align:top;">7</td> <td style="text-align:left;vertical-align:top;">文字(标签正文修改)</td> <td style="text-align:left;vertical-align:top;"><code>th:text</code><br><code>th:utext</code></td> </tr> <tr> <td style="text-align:left;vertical-align:top;">8</td> <td style="text-align:left;vertical-align:top;">片段规范</td> <td style="text-align:left;vertical-align:top;"><code>th:fragment</code></td> </tr> <tr> <td style="text-align:left;vertical-align:top;">9</td> <td style="text-align:left;vertical-align:top;">片段删除</td> <td style="text-align:left;vertical-align:top;"><code>th:remove</code></td> </tr> </tbody> </table> <p style="margin-left:0px;">这个优先级机制意味着如果属性位置被反转,上面的迭代片段将给出完全相同的结果(尽管它的可读性稍差):</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>ul</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>li</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${item.description}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:each</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>item : ${items}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Item description here...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>li</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>ul</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <h1 id="11%E8%AF%84%E8%AE%BA%E5%92%8C%E5%9D%97" style="margin-left:0px;"><em><strong>11评论和块</strong></em></h1> <h2 id="11.1%E3%80%82%E6%A0%87%E5%87%86HTML%20%2F%20XML%E6%B3%A8%E9%87%8A" style="margin-left:-2em;"><em><span style="color:#ffffff;">11.1。标准HTML / XML注释</span></em></h2> <p style="margin-left:0px;">标准HTML / XML注释<code><!-- ... --></code>可以在Thymeleaf模板中的任何位置使用。Thymeleaf将不会处理这些评论中的任何内容,并将逐字复制到结果中:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#cf9a49;"><!-- User info follows --></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${...}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <h2 id="11.2%E3%80%82Thymeleaf%E8%A7%A3%E6%9E%90%E5%99%A8%E7%BA%A7%E6%B3%A8%E9%87%8A%E5%9D%97" style="margin-left:-2em;"><em><span style="color:#ffffff;">11.2。Thymeleaf解析器级注释块</span></em></h2> <p style="margin-left:0px;">解析器级注释块是在Thymeleaf解析它时将简单地从模板中删除的代码。它们看起来像这样:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#cf9a49;"><!--/* This code will be removed at Thymeleaf parsing time! */--></span></code></code></pre> <p style="margin-left:0px;">Thymeleaf将删除一切与<code><!--/*</code>和<code>*/--></code>,所以这些注释块也可以用于显示当模板是静态开放代码,知道当Thymeleaf处理它,它都将被删除:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#cf9a49;"><!--/*--></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span><span style="color:#b9bdb6;">></span></span> you can see me only before Thymeleaf processes me! <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span> <span style="color:#cf9a49;"><!--*/--></span></code></code></pre> <p style="margin-left:0px;">对于具有大量原型的表进行原型设计,这可能非常方便<code><tr></code>,例如:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">th:each</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>x : ${xs}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#cf9a49;"><!--/*--></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#cf9a49;"><!--*/--></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>table</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <h2 id="11.3%E3%80%82Thymeleaf%E5%8E%9F%E5%9E%8B%E8%AF%84%E8%AE%BA%E5%9D%97" style="margin-left:-2em;"><em><span style="color:#ffffff;">11.3。Thymeleaf原型评论块</span></em></h2> <p style="margin-left:0px;">当模板静态打开时(即作为原型),Thymeleaf允许定义标记为注释的特殊注释块,但在执行模板时Thymeleaf认为是正常标记。</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>hello!<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> <span style="color:#cf9a49;"><!--/*/ <div th:text="${...}"> ... </div> /*/--></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>goodbye!<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">Thymeleaf的解析系统将简单地删除<code><!--/*/</code>和<code>/*/--></code>标记,但不删除其内容,因此将保留未注释。因此,在执行模板时,Thymeleaf实际上会看到:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>hello!<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${...}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span><span style="color:#b9bdb6;">></span></span>goodbye!<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">与解析器级注释块一样,此功能与方言无关。</p> <h2 id="11.4%E3%80%82%E5%90%88%E6%88%90th%3Ablock%E6%A0%87%E7%AD%BE" style="margin-left:-2em;"><em><span style="color:#ffffff;">11.4。合成<code>th:block</code>标签</span></em></h2> <p style="margin-left:0px;">标准方言中包含的Thymeleaf唯一的元素处理器(不是属性)是<code>th:block</code>。</p> <p style="margin-left:0px;"><code>th:block</code>是一个纯粹的属性容器,允许模板开发人员指定他们想要的任何属性。Thymeleaf将执行这些属性,然后简单地使块,但不是它的内容,消失。</p> <p style="margin-left:0px;">因此,在创建<code><tr></code>每个元素需要多个迭代表时,它可能很有用:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th:block</span> <span style="color:#e0e8ff;">th:each</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>user : ${users}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${user.login}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${user.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">colspan</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>2<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${user.address}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th:block</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>table</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">当与仅原型注释块结合使用时尤其有用:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#cf9a49;"><!--/*/ <th:block th:each="user : ${users}"> /*/--></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${user.login}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${user.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">colspan</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>2<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${user.address}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#cf9a49;"><!--/*/ </th:block> /*/--></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>table</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">注意这个解决方案如何让模板成为有效的HTML(不需要在<code><div></code>里面添加禁止的块<code><table></code>),并且在浏览器中作为原型静态打开时仍然可以正常工作!</p> <h1 id="12%E5%86%85%E8%81%94" style="margin-left:0px;"><em><strong>12内联</strong></em></h1> <h2 id="12.1%E8%A1%A8%E8%BE%BE%E5%86%85%E8%81%94" style="margin-left:-2em;"><em><span style="color:#ffffff;">12.1表达内联</span></em></h2> <p style="margin-left:0px;">虽然标准方言允许我们使用标签属性几乎完成所有操作,但在某些情况下我们可能更喜欢将表达式直接写入HTML文本。例如,我们更喜欢这样写:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span>Hello, [[${session.user.name}]]!<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">......而不是这个:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span>Hello, <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${session.user.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Sebastian<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span>!<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">在Thymeleaf 之间表达<code>[[...]]</code>或被<code>[(...)]</code>认为是<strong>内联表达式</strong>,在其中我们可以使用任何类型的表达式,这些表达式在一个<code>th:text</code>或<code>th:utext</code>属性中也是有效的。</p> <p style="margin-left:0px;">请注意,虽然<code>[[...]]</code>对应于<code>th:text</code>(即结果将被<em>HTML转义</em>),但是<code>[(...)]</code>对应于<code>th:utext</code>并且不会执行任何HTML转义。所以对于一个变量,如<code>msg = 'This is <b>great!</b>'</code>给定这个片段:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span>The message is "[(${msg})]"<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">结果将使这些<code><b></code>标签不转义,因此:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span>The message is "This is <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>b</span><span style="color:#b9bdb6;">></span></span>great!<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>b</span><span style="color:#b9bdb6;">></span></span>"<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">而如果像以下一样逃脱:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span>The message is "[[${msg}]]"<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">结果将被HTML转义:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span>The message is "This is <b>great!</b>"<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">请注意,<strong>默认情况下</strong>,<strong>文本内联</strong>在标记中的每个标记的主体中<strong>都是活动的</strong> - 而不是标记本身 - 因此我们无需执行任何操作即可启用它。</p> <h3 id="%E5%86%85%E8%81%94vs%E8%87%AA%E7%84%B6%E6%A8%A1%E6%9D%BF" style="margin-left:0px;"><em><strong>内联vs自然模板</strong></em></h3> <p style="margin-left:0px;">如果你来自其他模板引擎,其中这种输出文本的方式是常态,你可能会问:<em>为什么我们从一开始就不这样做?它的代码少于所有这些</em> <code>th:text</code> <em>属性!</em></p> <p style="margin-left:0px;">好吧,小心那里,因为虽然你可能会发现内联非常有趣,但你应该永远记住,当你静态打开它们时,内联表达式将逐字显示在你的HTML文件中,所以你可能无法将它们用作设计原型了!</p> <p style="margin-left:0px;">浏览器静态显示我们的代码片段而不使用内联的区别...</p> <pre class="has"><code>Hello, Sebastian!</code></pre> <p style="margin-left:0px;">......并使用它......</p> <pre class="has"><code>Hello, [[${session.user.name}]]!</code></pre> <p style="margin-left:0px;">......在设计实用性方面非常清楚。</p> <h3 id="%E7%A6%81%E7%94%A8%E5%86%85%E8%81%94" style="margin-left:0px;"><em><strong>禁用内联</strong></em></h3> <p style="margin-left:0px;">但是,可以禁用此机制,因为实际上可能存在我们确实希望输出<code>[[...]]</code>或<code>[(...)]</code>序列而不将其内容作为表达式处理的情况。为此,我们将使用<code>th:inline="none"</code>:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>none<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>A double array looks like this: [[1, 2, 3], [4, 5]]!<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">这将导致:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span>A double array looks like this: [[1, 2, 3], [4, 5]]!<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <h2 id="12.2%E6%96%87%E5%AD%97%E5%86%85%E8%81%94" style="margin-left:-2em;"><em><span style="color:#ffffff;">12.2文字内联</span></em></h2> <p style="margin-left:0px;"><em>文本内联</em>与我们刚刚看到的<em>表达内联</em>功能非常相似,但它实际上增加了更多功能。它必须明确启用<code>th:inline="text"</code>。</p> <p style="margin-left:0px;">文本内联不仅允许我们使用我们刚才看到的相同<em>内联表达式</em>,而且实际上处理<em>标签主体</em>就好像它们是在<code>TEXT</code>模板模式下处理的模板一样,这允许我们执行基于文本的模板逻辑(不仅仅是输出表达式)。</p> <p style="margin-left:0px;">我们将在下一章中看到有关<em>文本模板模式的更多信息</em>。</p> <h2 id="12.3%20JavaScript%E5%86%85%E8%81%94" style="margin-left:-2em;"><em><span style="color:#ffffff;">12.3 JavaScript内联</span></em></h2> <p style="margin-left:0px;">JavaScript内联允许<code><script></code>在<code>HTML</code>模板模式下处理的模板中更好地集成JavaScript 块。</p> <p style="margin-left:0px;">与<em>文本内联一样</em>,这实际上相当于处理脚本内容,就好像它们是<code>JAVASCRIPT</code>模板模式中的模板一样,因此<em>文本模板模式的</em>所有<em>功能</em>(见下一章)都将在眼前。但是,在本节中,我们将重点介绍如何使用它将Thymeleaf表达式的输出添加到JavaScript块中。</p> <p style="margin-left:0px;">必须使用<code>th:inline="javascript"</code>以下方式明确启用此模式:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>script</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>javascript<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... var username = [[${session.user.name}]]; ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>script</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">这将导致:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>script</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>javascript<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... var username = "Sebastian \"Fruity\" Applejuice"; ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>script</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">上面代码中需要注意的两件重要事项:</p> <p style="margin-left:0px;"><em>首先</em>,JavaScript内联不仅会输出所需的文本,而且还会用引号和JavaScript来包含它 - 转义其内容,以便将表达式结果输出为<strong>格式良好的JavaScript文字</strong>。</p> <p style="margin-left:0px;"><em>其次</em>,发生这种情况是因为我们将<code>${session.user.name}</code>表达式输出为<strong>转义</strong>,即使用双括号表达式:<code>[[${session.user.name}]]</code>。如果相反,我们使用非<em>转义,</em>如:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>script</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>javascript<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... var username = [(${session.user.name})]; ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>script</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">结果如下:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>script</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>javascript<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... var username = Sebastian "Fruity" Applejuice; ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>script</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">...这是一个格式错误的JavaScript代码。但是,如果我们通过附加内联表达式来构建脚本的一部分,那么输出未转义的内容可能就是我们所需要的,因此最好有这个工具。</p> <h3 id="JavaScript%E8%87%AA%E7%84%B6%E6%A8%A1%E6%9D%BF" style="margin-left:0px;"><em><strong>JavaScript自然模板</strong></em></h3> <p style="margin-left:0px;">所提到的JavaScript内联机制的<em>智能</em>远不止仅仅应用特定于JavaScript的转义并将表达式结果输出为有效文字。</p> <p style="margin-left:0px;">例如,我们可以在JavaScript注释中包装我们的(转义的)内联表达式,例如:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>script</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>javascript<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... var username = /*[[${session.user.name}]]*/ "Gertrud Kiwifruit"; ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>script</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">并且Thymeleaf将忽略我们<em>在注释之后和分号之前</em>(在这种情况下<code>'Gertrud Kiwifruit'</code>)编写的所有内容,因此执行此操作的结果看起来与我们不使用包装注释时的结果完全相同:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>script</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>javascript<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... var username = "Sebastian \"Fruity\" Applejuice"; ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>script</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">但请仔细查看原始模板代码:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>script</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>javascript<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... var username = /*[[${session.user.name}]]*/ "Gertrud Kiwifruit"; ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>script</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">请注意这是<strong>有效的JavaScript</strong>代码。当您以静态方式打开模板文件时(无需在服务器上执行),它将完美执行。</p> <p style="margin-left:0px;">所以我们这里有一个做<strong>自然模板的方法</strong>!</p> <h3 id="%E9%AB%98%E7%BA%A7%E5%86%85%E8%81%94%E8%AF%84%E4%BC%B0%E5%92%8CJavaScript%E5%BA%8F%E5%88%97%E5%8C%96" style="margin-left:0px;"><em><strong>高级内联评估和JavaScript序列化</strong></em></h3> <p style="margin-left:0px;">关于JavaScript内联的一个重要注意事项是,这种表达式评估是智能的,不仅限于字符串。Thymeleaf将在JavaScript语法中正确编写以下类型的对象:</p> <ul style="margin-left:2em;"> <li>字符串</li> <li>数字</li> <li>布尔</li> <li>数组</li> <li>集合</li> <li>地图</li> <li>Bean(具有<em>getter</em>和<em>setter</em>方法的对象)</li> </ul> <p style="margin-left:0px;">例如,如果我们有以下代码:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>script</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>javascript<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... var user = /*[[${session.user}]]*/ null; ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>script</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">该<code>${session.user}</code>表达式将评估为一个<code>User</code>对象,Thymeleaf将正确地将其转换为Javascript语法:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>script</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>javascript<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... var user = {"age":null,"firstName":"John","lastName":"Apricot", "name":"John Apricot","nationality":"Antarctica"}; ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>script</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">这种JavaScript序列化的方式是通过<code>org.thymeleaf.standard.serializer.IStandardJavaScriptSerializer</code>接口的实现,可以<code>StandardDialect</code>在模板引擎使用的实例上配置。</p> <p style="margin-left:0px;">此JS序列化机制的默认实现将在类路径中查找Jackson库,如果存在,将使用它。如果没有,它将应用内置的序列化机制,涵盖大多数场景的需求并产生类似的结果(但不太灵活)。</p> <h2 id="12.4%20CSS%E5%86%85%E8%81%94" style="margin-left:-2em;"><em><span style="color:#ffffff;">12.4 CSS内联</span></em></h2> <p style="margin-left:0px;">Thymeleaf还允许在CSS <code><style></code>标签中使用内联,例如:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>style</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>css<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>style</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">例如,假设我们将两个变量设置为两个不同的<code>String</code>值:</p> <pre class="has"><code>classname = 'main elems' align = 'center'</code></pre> <p style="margin-left:0px;">我们可以像以下一样使用它们:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>style</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>css<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> .[[${classname}]] { text-align: [[${align}]]; } <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>style</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">结果将是:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>style</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>css<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> .main\ elems { text-align: center; } <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>style</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">请注意CSS内联如何具有一些<em>智能</em>,就像JavaScript一样。具体来说,通过<em>转义</em>表达式输出的表达式<code>[[${classname}]]</code>将作为<strong>CSS标识符</strong>进行转义。这就是为什么我们<code>classname = 'main elems'</code>已经<code>main\ elems</code>在上面的代码片段中变成了原因。</p> <h3 id="%E9%AB%98%E7%BA%A7%E5%8A%9F%E8%83%BD%EF%BC%9ACSS%E8%87%AA%E7%84%B6%E6%A8%A1%E6%9D%BF%E7%AD%89" style="margin-left:0px;"><em><strong>高级功能:CSS自然模板等</strong></em></h3> <p style="margin-left:0px;">与之前针对JavaScript解释的内容相同,CSS内联还允许我们的<code><style></code>标记静态和动态地工作,即通过在注释中包装内联表达式作为<strong>CSS自然模板</strong>。看到:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>style</span> <span style="color:#e0e8ff;">th:inline</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>css<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> .main\ elems { text-align: /*[[${align}]]*/ left; } <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>style</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <h1 id="13%E6%96%87%E6%9C%AC%E6%A8%A1%E6%9D%BF%E6%A8%A1%E5%BC%8F" style="margin-left:0px;"><em><strong>13文本模板模式</strong></em></h1> <h2 id="13.1%E6%96%87%E6%9C%AC%E8%AF%AD%E6%B3%95" style="margin-left:-2em;"><em><span style="color:#ffffff;">13.1文本语法</span></em></h2> <p style="margin-left:0px;">在Thymeleaf的三种<em>模板模式</em>被认为是<strong>文字</strong>:<code>TEXT</code>,<code>JAVASCRIPT</code>和<code>CSS</code>。这使它们与标记模板模式区别开来:<code>HTML</code>和<code>XML</code>。</p> <p style="margin-left:0px;"><em>文本</em>模板模式与标记模式之间的关键区别在于,在文本模板中没有标签可以以属性的形式插入逻辑,因此我们必须依赖其他机制。</p> <p style="margin-left:0px;">这些机制中的第一个也是最基本的是<strong>内联</strong>,我们已在前一章中详细介绍过。内联语法是在文本模板模式下输出表达式结果的最简单方法,因此这是一个完全有效的文本电子邮件模板。</p> <pre class="has"><code> Dear [(${name})], Please find attached the results of the report you requested with name "[(${report.name})]". Sincerely, The Reporter.</code></pre> <p style="margin-left:0px;">即使没有标签,上面的例子也是一个完整有效的Thymeleaf模板,可以在<code>TEXT</code>模板模式下执行。</p> <p style="margin-left:0px;">但是为了包含比仅仅<em>输出表达式</em>更复杂的逻辑,我们需要一种新的基于非标记的语法:</p> <pre class="has"><code>[# th:each="item : ${items}"] - [(${item})] [/]</code></pre> <p style="margin-left:0px;">这实际上是更详细的<em>浓缩</em>版本:</p> <pre class="has"><code>[#th:block th:each="item : ${items}"] - [#th:block th:utext="${item}" /] [/th:block]</code></pre> <p style="margin-left:0px;">请注意这个新语法是如何基于声明为<code>[#element ...]</code>而不是的元素(即可处理标记)<code><element ...></code>。元素是开放的像<code>[#element ...]</code>封闭一样<code>[/element]</code>,并且可以通过最小化open元素来声明独立标签<code>/</code>,其方式几乎等同于XML标签:<code>[#element ... /]</code>。</p> <p style="margin-left:0px;">标准方言只包含其中一个元素的处理器:已知的<code>th:block</code>,虽然我们可以在我们的方言中扩展它并以通常的方式创建新元素。此外,允许将<code>th:block</code>element(<code>[#th:block ...] ... [/th:block]</code>)缩写为空字符串(<code>[# ...] ... [/]</code>),因此上面的块实际上等效于:</p> <pre class="has"><code>[# th:each="item : ${items}"] - [# th:utext="${item}" /] [/]</code></pre> <p style="margin-left:0px;">并且给定<code>[# th:utext="${item}" /]</code>等效于<em>内联非转义表达式</em>,我们可以使用它来获得更少的代码。因此,我们最终得到了上面看到的第一个代码片段:</p> <pre class="has"><code>[# th:each="item : ${items}"] - [(${item})] [/]</code></pre> <p style="margin-left:0px;">请注意,<em>文本语法需要完整的元素平衡(没有未关闭的标记)和引用的属性</em> - 它比HTML风格更加XML风格。</p> <p style="margin-left:0px;">让我们看一个更完整的<code>TEXT</code>模板示例,一个<em>纯文本</em>电子邮件模板:</p> <pre class="has"><code>Dear [(${customer.name})], This is the list of our products: [# th:each="prod : ${products}"] - [(${prod.name})]. Price: [(${prod.price})] EUR/kg [/] Thanks, The Thymeleaf Shop</code></pre> <p style="margin-left:0px;">执行后,结果可能是这样的:</p> <pre class="has"><code>Dear Mary Ann Blueberry, This is the list of our products: - Apricots. Price: 1.12 EUR/kg - Bananas. Price: 1.78 EUR/kg - Apples. Price: 0.85 EUR/kg - Watermelon. Price: 1.91 EUR/kg Thanks, The Thymeleaf Shop</code></pre> <p style="margin-left:0px;">另一个例子是<code>JAVASCRIPT</code>模板模式,一个<code>greeter.js</code>文件,我们作为文本模板处理,我们从HTML页面调用结果。请注意,这<em>不是</em><code><script></code> HTML模板中的块,而是<code>.js</code>自己作为模板处理的文件:</p> <pre><code class="language-javascript"> <code class="language-javascript">var greeter = function() { var username = [[${session.user.name}]]; [# th:each="salut : ${salutations}"] alert([[${salut}]] + " " + username); [/] };</code></code></pre> <p style="margin-left:0px;">执行后,结果可能是这样的:</p> <pre><code class="language-javascript"> <code class="language-javascript">var greeter = function() { var username = "Bertrand \"Crunchy\" Pear"; alert("Hello" + " " + username); alert("Ol\u00E1" + " " + username); alert("Hola" + " " + username); };</code></code></pre> <h3 id="%E8%BD%AC%E4%B9%89%E5%85%83%E7%B4%A0%E5%B1%9E%E6%80%A7" style="margin-left:0px;"><em><strong>转义元素属性</strong></em></h3> <p style="margin-left:0px;">为了避免与可能在其他模式中处理的模板部分的交互(例如<code>text</code>,<code>HTML</code>模板内部的模式内联),Thymeleaf 3.0允许转义其<em>文本语法</em>中元素的属性。所以:</p> <ul style="margin-left:2em;"> <li><code>TEXT</code>模板模式中的属性将是<em>HTML-unescaped</em>。</li> <li><code>JAVASCRIPT</code>模板模式中的属性将是<em>JavaScript-unescaped</em>。</li> <li><code>CSS</code>模板模式中的属性将是<em>CSS-unescaped</em>。</li> </ul> <p style="margin-left:0px;">所以这在<code>TEXT</code>模式模板中完全可以(注意<code>></code>):</p> <pre class="has"><code> [# th:if="${120<user.age}"] Congratulations! [/]</code></pre> <p style="margin-left:0px;">当然,<code><</code>在<em>真实的文本</em>模板中没有任何意义,但如果我们使用<code>th:inline="text"</code>包含上述代码的块处理HTML模板并且我们希望确保我们的浏览器不会将其<code><user.age</code>作为名称,那么这是一个好主意。静态打开文件作为原型时打开标记。</p> <h2 id="13.2%E5%8F%AF%E6%89%A9%E5%B1%95%E6%80%A7" style="margin-left:-2em;"><em><span style="color:#ffffff;">13.2可扩展性</span></em></h2> <p style="margin-left:0px;">这种语法的一个优点是它和<em>标记</em>一样可扩展。开发人员仍然可以使用自定义元素和属性定义自己的方言,为它们应用前缀(可选),然后在文本模板模式中使用它们:</p> <pre class="has"><code> [#myorg:dosomething myorg:importantattr="211"]some text[/myorg:dosomething]</code></pre> <h2 id="13.3%E4%BB%85%E6%96%87%E6%9C%AC%E5%8E%9F%E5%9E%8B%E6%B3%A8%E9%87%8A%E5%9D%97%EF%BC%9A%E6%B7%BB%E5%8A%A0%E4%BB%A3%E7%A0%81" style="margin-left:-2em;"><em><span style="color:#ffffff;">13.3仅文本原型注释块:添加代码</span></em></h2> <p style="margin-left:0px;">在<code>JAVASCRIPT</code>和<code>CSS</code>模板模式(不适用于<code>TEXT</code>),允许包括一个特殊的注释语法之间的代码<code>/*[+...+]*/</code>,这样Thymeleaf会处理模板时自动取消注释这样的代码:</p> <pre><code class="language-javascript"> <code class="language-javascript">var x = 23; /*[+ var msg = "This is a working application"; +]*/ var f = function() { ...</code></code></pre> <p style="margin-left:0px;">将被执行为:</p> <pre><code class="language-javascript"> <code class="language-javascript">var x = 23; var msg = "This is a working application"; var f = function() { ...</code></code></pre> <p style="margin-left:0px;">您可以在这些注释中包含表达式,并将对它们进行评估:</p> <pre><code class="language-javascript"> <code class="language-javascript">var x = 23; /*[+ var msg = "Hello, " + [[${session.user.name}]]; +]*/ var f = function() { ...</code></code></pre> <h2 id="13.4%E6%96%87%E6%9C%AC%E8%A7%A3%E6%9E%90%E5%99%A8%E7%BA%A7%E6%B3%A8%E9%87%8A%E5%9D%97%EF%BC%9A%E5%88%A0%E9%99%A4%E4%BB%A3%E7%A0%81" style="margin-left:-2em;"><em><span style="color:#ffffff;">13.4文本解析器级注释块:删除代码</span></em></h2> <p style="margin-left:0px;">在类似于仅原型的注释块的方式,所有三个文本模板模式(<code>TEXT</code>,<code>JAVASCRIPT</code>和<code>CSS</code>)使其能够指示Thymeleaf特殊之间移除代码<code>/*[- */</code>和<code>/* -]*/</code>标志,就像这样:</p> <pre><code class="language-javascript"> <code class="language-javascript">var x = 23; /*[- */ var msg = "This is shown only when executed statically!"; /* -]*/ var f = function() { ...</code></code></pre> <p style="margin-left:0px;">或者这个,在<code>TEXT</code>模式中:</p> <pre class="has"><code>... /*[- Note the user is obtained from the session, which must exist -]*/ Welcome [(${session.user.name})]! ...</code></pre> <h2 id="13.5%E8%87%AA%E7%84%B6JavaScript%E5%92%8CCSS%E6%A8%A1%E6%9D%BF" style="margin-left:-2em;"><em><span style="color:#ffffff;">13.5自然JavaScript和CSS模板</span></em></h2> <p style="margin-left:0px;">如上一章所示,JavaScript和CSS内联提供了在JavaScript / CSS注释中包含内联表达式的可能性,例如:</p> <pre><code class="language-javascript"> <code class="language-javascript">... var username = /*[[${session.user.name}]]*/ "Sebastian Lychee"; ...</code></code></pre> <p style="margin-left:0px;">...这是有效的JavaScript,一旦执行可能看起来像:</p> <pre><code class="language-html"> <code class="language-html">... var username = "John Apricot"; ...</code></code></pre> <p style="margin-left:0px;">在注释中包含内联表达式的相同<em>技巧</em>实际上可以用于整个文本模式语法:</p> <pre class="has"><code> /*[# th:if="${user.admin}"]*/ alert('Welcome admin'); /*[/]*/</code></pre> <p style="margin-left:0px;">当模板静态打开时,将显示上面代码中的警报 - 因为它是100%有效的JavaScript - 以及当用户是管理员时模板运行时。它相当于:</p> <pre class="has"><code> [# th:if="${user.admin}"] alert('Welcome admin'); [/]</code></pre> <p style="margin-left:0px;">...实际上是在模板解析期间转换初始版本的代码。</p> <p style="margin-left:0px;">但请注意,注释中的包装元素不会<code>;</code>像内联输出表达式那样清除它们所在的行(在找到之前的右侧)。该行为仅为内联输出表达式保留。</p> <p style="margin-left:0px;">因此,Thymeleaf 3.0允许<strong>以自然模板的形式</strong>开发<strong>复杂的JavaScript脚本和CSS样式表</strong>,既可用作<em>原型</em>,也可用作<em>工作模板</em>。</p> <h1 id="14%E6%88%91%E4%BB%AC%E6%9D%82%E8%B4%A7%E5%BA%97%E7%9A%84%E6%9B%B4%E5%A4%9A%E9%A1%B5%E9%9D%A2" style="margin-left:0px;"><em><strong>14我们杂货店的更多页面</strong></em></h1> <p style="margin-left:0px;">现在我们对使用Thymeleaf了解很多,我们可以在我们的网站上添加一些新页面来进行订单管理。</p> <p style="margin-left:0px;">请注意,我们将重点关注HTML代码,但如果要查看相应的控制器,可以查看捆绑的源代码。</p> <h2 id="14.1%E8%AE%A2%E5%8D%95%E6%B8%85%E5%8D%95" style="margin-left:-2em;"><em><span style="color:#ffffff;">14.1订单清单</span></em></h2> <p style="margin-left:0px;">让我们从创建订单列表页面开始<code>/WEB-INF/templates/order/list.html</code>:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#cf9a49;"><!DOCTYPE html></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>html</span> <span style="color:#e0e8ff;">xmlns:th</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>http://www.thymeleaf.org<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>head</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>title</span><span style="color:#b9bdb6;">></span></span>Good Thymes Virtual Grocery<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>title</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>meta</span> <span style="color:#e0e8ff;">http-equiv</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>Content-Type<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">content</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>text/html; charset<span style="color:#b9bdb6;">=</span>UTF-8<span style="color:#b9bdb6;">"</span></span> <span style="color:#b9bdb6;">/></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>stylesheet<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">type</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>text/css<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">media</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>all<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>../../../css/gtvg.css<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>@{/css/gtvg.css}<span style="color:#b9bdb6;">"</span></span> <span style="color:#b9bdb6;">/></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>head</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>body</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>h1</span><span style="color:#b9bdb6;">></span></span>Order list<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>h1</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>DATE<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>CUSTOMER<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>TOTAL<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">th:each</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>o : ${orders}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${oStat.odd}? <span style="color:#b9bdb6;">'</span>odd<span style="color:#b9bdb6;">'</span><span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#calendars.format(o.date,<span style="color:#b9bdb6;">'</span>dd/MMM/yyyy<span style="color:#b9bdb6;">'</span>)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>13 jan 2011<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${o.customer.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Frederic Tomato<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#aggregates.sum(o.orderLines.{purchasePrice * amount})}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>23.32<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>details.html<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>@{/order/details(orderId<span style="color:#b9bdb6;">=</span>${o.id})}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>view<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>../home.html<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>@{/}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Return to home<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>body</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>html</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">这里没有什么可以让我们感到惊讶,除了这一点OGNL魔法:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${#aggregates.sum(o.orderLines.{purchasePrice * amount})}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>23.32<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">这样做,对于顺序中的每个订单行(<code>OrderLine</code>对象),将其<code>purchasePrice</code>和<code>amount</code>属性相乘(通过调用相应的<code>getPurchasePrice()</code>和<code>getAmount()</code>方法)并将结果返回到数字列表中,稍后由<code>#aggregates.sum(...)</code>函数聚合以获得订单总数价钱。</p> <p style="margin-left:0px;">你必须喜欢OGNL的力量。</p> <h2 id="14.2%E8%AE%A2%E5%8D%95%E8%AF%A6%E6%83%85" style="margin-left:-2em;"><em><span style="color:#ffffff;">14.2订单详情</span></em></h2> <p style="margin-left:0px;">现在,对于订单详细信息页面,我们将在其中大量使用星号语法:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#cf9a49;"><!DOCTYPE html></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>html</span> <span style="color:#e0e8ff;">xmlns:th</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>http://www.thymeleaf.org<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>head</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>title</span><span style="color:#b9bdb6;">></span></span>Good Thymes Virtual Grocery<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>title</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>meta</span> <span style="color:#e0e8ff;">http-equiv</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>Content-Type<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">content</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>text/html; charset<span style="color:#b9bdb6;">=</span>UTF-8<span style="color:#b9bdb6;">"</span></span> <span style="color:#b9bdb6;">/></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>link</span> <span style="color:#e0e8ff;">rel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>stylesheet<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">type</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>text/css<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">media</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>all<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>../../../css/gtvg.css<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>@{/css/gtvg.css}<span style="color:#b9bdb6;">"</span></span> <span style="color:#b9bdb6;">/></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>head</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>body</span> <span style="color:#e0e8ff;">th:object</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${order}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>h1</span><span style="color:#b9bdb6;">></span></span>Order details<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>h1</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>b</span><span style="color:#b9bdb6;">></span></span>Code:<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>b</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>*{id}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>99<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>b</span><span style="color:#b9bdb6;">></span></span>Date:<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>b</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>*{#calendars.format(date,<span style="color:#b9bdb6;">'</span>dd MMM yyyy<span style="color:#b9bdb6;">'</span>)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>13 jan 2011<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>h2</span><span style="color:#b9bdb6;">></span></span>Customer<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>h2</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:object</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>*{customer}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>b</span><span style="color:#b9bdb6;">></span></span>Name:<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>b</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>*{name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Frederic Tomato<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>b</span><span style="color:#b9bdb6;">></span></span>Since:<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>b</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>*{#calendars.format(customerSince,<span style="color:#b9bdb6;">'</span>dd MMM yyyy<span style="color:#b9bdb6;">'</span>)}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>1 jan 2011<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>h2</span><span style="color:#b9bdb6;">></span></span>Products<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>h2</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>PRODUCT<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>AMOUNT<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>th</span><span style="color:#b9bdb6;">></span></span>PURCHASE PRICE<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>th</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">th:each</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>ol,row : *{orderLines}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${row.odd}? <span style="color:#b9bdb6;">'</span>odd<span style="color:#b9bdb6;">'</span><span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${ol.product.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Strawberries<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${ol.amount}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>number<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>3<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${ol.purchasePrice}<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>number<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>23.32<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>b</span><span style="color:#b9bdb6;">></span></span>TOTAL:<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>b</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>*{#aggregates.sum(orderLines.{purchasePrice * amount})}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>35.23<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>a</span> <span style="color:#e0e8ff;">href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>list.html<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:href</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>@{/order/list}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Return to order list<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>a</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>body</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>html</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">除了这个嵌套对象选择之外,这里没什么新东西:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>body</span> <span style="color:#e0e8ff;">th:object</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${order}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:object</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>*{customer}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>b</span><span style="color:#b9bdb6;">></span></span>Name:<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>b</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>*{name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Frederic Tomato<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span> ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span> ... <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>body</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">......这<code>*{name}</code>相当于:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>p</span><span style="color:#b9bdb6;">></span></span><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>b</span><span style="color:#b9bdb6;">></span></span>Name:<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>b</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>span</span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${order.customer.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Frederic Tomato<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>span</span><span style="color:#b9bdb6;">></span></span><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>p</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <h1 id="15%E6%9C%89%E5%85%B3%E9%85%8D%E7%BD%AE%E7%9A%84%E6%9B%B4%E5%A4%9A%E4%BF%A1%E6%81%AF" style="margin-left:0px;"><em><strong>15有关配置的更多信息</strong></em></h1> <h2 id="15.1%E6%A8%A1%E6%9D%BF%E8%A7%A3%E6%9E%90%E5%99%A8" style="margin-left:-2em;"><em><span style="color:#ffffff;">15.1模板解析器</span></em></h2> <p style="margin-left:0px;">对于Good Thymes Virtual Grocery,我们选择了一个<code>ITemplateResolver</code>名为的实现<code>ServletContextTemplateResolver</code>,它允许我们从Servlet Context获取模板作为资源。</p> <p style="margin-left:0px;">除了让我们能够通过实现<code>ITemplateResolver,</code>Thymeleaf 创建我们自己的模板解析器包括四个开箱即用的实现:</p> <ul style="margin-left:2em;"> <li> <p style="margin-left:0px;"><code>org.thymeleaf.templateresolver.ClassLoaderTemplateResolver</code>,将模板解析为类加载器资源,如:</p> <pre><code class="language-java"> <code class="language-java"><span style="color:#99cc33;">return</span> Thread<span style="color:#b9bdb6;">.</span>currentThread<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">.</span>getContextClassLoader<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">.</span>getResourceAsStream<span style="color:#b9bdb6;">(</span>template<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> </li> <li> <p style="margin-left:0px;"><code>org.thymeleaf.templateresolver.FileTemplateResolver</code>,将模板解析为文件系统中的文件,如:</p> <pre><code class="language-java"> <code class="language-java"><span style="color:#99cc33;">return</span> <span style="color:#99cc33;">new</span> FileInputStream<span style="color:#b9bdb6;">(</span><span style="color:#99cc33;">new</span> File<span style="color:#b9bdb6;">(</span>template<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> </li> <li> <p style="margin-left:0px;"><code>org.thymeleaf.templateresolver.UrlTemplateResolver</code>,将模板解析为URL(甚至是非本地的),如:</p> <pre><code class="language-java"> <code class="language-java"><span style="color:#99cc33;">return</span> <span style="color:#b9bdb6;">(</span><span style="color:#99cc33;">new</span> URL<span style="color:#b9bdb6;">(</span>template<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">.</span>openStream<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> </li> <li> <p style="margin-left:0px;"><code>org.thymeleaf.templateresolver.StringTemplateResolver</code>,它可以直接解析模板,因为它<code>String</code>被指定为<code>template</code>(或<em>模板名称</em>,在这种情况下显然不仅仅是一个名称):</p> <pre><code class="language-java"> <code class="language-java"><span style="color:#99cc33;">return</span> <span style="color:#99cc33;">new</span> StringReader<span style="color:#b9bdb6;">(</span>templateName<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> </li> </ul> <p style="margin-left:0px;">所有预绑定的实现都<code>ITemplateResolver</code>允许相同的配置参数集,包括:</p> <ul style="margin-left:2em;"> <li> <p style="margin-left:0px;">前缀和后缀(已经看到):</p> <pre><code class="language-java"> <code class="language-java">templateResolver<span style="color:#b9bdb6;">.</span>setPrefix<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">"/WEB-INF/templates/"</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> templateResolver<span style="color:#b9bdb6;">.</span>setSuffix<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">".html"</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> </li> <li> <p style="margin-left:0px;">允许使用与文件名不直接对应的模板名称的模板别名。如果同时存在后缀/前缀和别名,则将在前缀/后缀之前应用别名:</p> <pre><code class="language-java"> <code class="language-java">templateResolver<span style="color:#b9bdb6;">.</span>addTemplateAlias<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">"adminHome"</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">"profiles/admin/home"</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> templateResolver<span style="color:#b9bdb6;">.</span>setTemplateAliases<span style="color:#b9bdb6;">(</span>aliasesMap<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> </li> <li> <p style="margin-left:0px;">读取模板时要应用的编码:</p> <pre><code class="language-java"> <code class="language-java">templateResolver<span style="color:#b9bdb6;">.</span>setEncoding<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">"UTF-8"</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> </li> <li> <p style="margin-left:0px;">要使用的模板模式:</p> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">// Default is HTML</span> templateResolver<span style="color:#b9bdb6;">.</span>setTemplateMode<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">"XML"</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> </li> <li> <p style="margin-left:0px;">模板缓存的默认模式,以及用于定义特定模板是否可缓存的模式:</p> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">// Default is true</span> templateResolver<span style="color:#b9bdb6;">.</span>setCacheable<span style="color:#b9bdb6;">(</span><span style="color:#8bd1ff;">false</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> templateResolver<span style="color:#b9bdb6;">.</span>getCacheablePatternSpec<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">.</span>addPattern<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">"/users/*"</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> </li> <li> <p style="margin-left:0px;">解析模板缓存条目的TTL(以毫秒为单位)源自此模板解析程序。如果未设置,从缓存中删除条目的唯一方法是超过缓存最大大小(将删除最旧的条目)。</p> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">// Default is no TTL (only cache size exceeded would remove entries)</span> templateResolver<span style="color:#b9bdb6;">.</span>setCacheTTLMs<span style="color:#b9bdb6;">(</span>60000L<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> </li> </ul> <blockquote> <p style="margin-left:0px;">Thymeleaf + Spring集成包提供了一个<code>SpringResourceTemplateResolver</code>实现,它使用所有Spring基础结构来访问和读取应用程序中的资源,这是在启用Spring的应用程序中推荐的实现。</p> </blockquote> <h3 id="%E9%93%BE%E6%8E%A5%E6%A8%A1%E6%9D%BF%E8%A7%A3%E6%9E%90%E5%99%A8" style="margin-left:0px;"><em><strong>链接模板解析器</strong></em></h3> <p style="margin-left:0px;">此外,模板引擎可以指定多个模板解析器,在这种情况下,可以在它们之间建立用于模板解析的顺序,这样,如果第一个无法解析模板,则会询问第二个,依此类推:</p> <pre><code class="language-java"> <code class="language-java">ClassLoaderTemplateResolver classLoaderTemplateResolver = <span style="color:#99cc33;">new</span> ClassLoaderTemplateResolver<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> classLoaderTemplateResolver<span style="color:#b9bdb6;">.</span>setOrder<span style="color:#b9bdb6;">(</span>Integer<span style="color:#b9bdb6;">.</span>valueOf<span style="color:#b9bdb6;">(</span><span style="color:#8bd1ff;">1</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> ServletContextTemplateResolver servletContextTemplateResolver = <span style="color:#99cc33;">new</span> ServletContextTemplateResolver<span style="color:#b9bdb6;">(</span>servletContext<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> servletContextTemplateResolver<span style="color:#b9bdb6;">.</span>setOrder<span style="color:#b9bdb6;">(</span>Integer<span style="color:#b9bdb6;">.</span>valueOf<span style="color:#b9bdb6;">(</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> templateEngine<span style="color:#b9bdb6;">.</span>addTemplateResolver<span style="color:#b9bdb6;">(</span>classLoaderTemplateResolver<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> templateEngine<span style="color:#b9bdb6;">.</span>addTemplateResolver<span style="color:#b9bdb6;">(</span>servletContextTemplateResolver<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> <p style="margin-left:0px;">当应用多个模板解析器时,建议为每个模板解析器指定模式,以便Thymeleaf可以快速丢弃那些不打算解析模板的模板解析器,从而提高性能。这样做不是必要条件,而是建议:</p> <pre><code class="language-java"> <code class="language-java">ClassLoaderTemplateResolver classLoaderTemplateResolver = <span style="color:#99cc33;">new</span> ClassLoaderTemplateResolver<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> classLoaderTemplateResolver<span style="color:#b9bdb6;">.</span>setOrder<span style="color:#b9bdb6;">(</span>Integer<span style="color:#b9bdb6;">.</span>valueOf<span style="color:#b9bdb6;">(</span><span style="color:#8bd1ff;">1</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> <span style="color:#cf9a49;">// This classloader will not be even asked for any templates not matching these patterns </span> classLoaderTemplateResolver<span style="color:#b9bdb6;">.</span>getResolvablePatternSpec<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">.</span>addPattern<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">"/layout/*.html"</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> classLoaderTemplateResolver<span style="color:#b9bdb6;">.</span>getResolvablePatternSpec<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">.</span>addPattern<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">"/menu/*.html"</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> ServletContextTemplateResolver servletContextTemplateResolver = <span style="color:#99cc33;">new</span> ServletContextTemplateResolver<span style="color:#b9bdb6;">(</span>servletContext<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> servletContextTemplateResolver<span style="color:#b9bdb6;">.</span>setOrder<span style="color:#b9bdb6;">(</span>Integer<span style="color:#b9bdb6;">.</span>valueOf<span style="color:#b9bdb6;">(</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> <p style="margin-left:0px;">如果未指定这些<em>可解析的模式</em>,我们将依赖于<code>ITemplateResolver</code>我们正在使用的每个实现的特定功能。请注意,并非所有实现都可以在解析之前确定模板的存在,因此可以始终将模板视为<em>可解析</em>并破坏解析链(不允许其他解析器检查相同的模板),但随后无法阅读真实的资源。</p> <p style="margin-left:0px;"><code>ITemplateResolver</code>核心Thymeleaf中包含的所有实现都包含一种机制,允许我们在解析<em>可解析</em>之前让解析器<em>真正检查</em>资源是否存在。这是旗帜,其作用如下:<code>checkExistence</code></p> <pre><code class="language-java"> <code class="language-java">ClassLoaderTemplateResolver classLoaderTemplateResolver = <span style="color:#99cc33;">new</span> ClassLoaderTemplateResolver<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> classLoaderTemplateResolver<span style="color:#b9bdb6;">.</span>setOrder<span style="color:#b9bdb6;">(</span>Integer<span style="color:#b9bdb6;">.</span>valueOf<span style="color:#b9bdb6;">(</span><span style="color:#8bd1ff;">1</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> classLoaderTempalteResolver<span style="color:#b9bdb6;">.</span>setCheckExistence<span style="color:#b9bdb6;">(</span><span style="color:#8bd1ff;">true</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> <p style="margin-left:0px;">此<code>checkExistence</code>标志强制解析器在解析阶段执行资源存在的<em>实际检查</em>(如果存在检查返回false,则调用链中的后续解析器)。虽然这在每种情况下听起来都不错,但在大多数情况下,这意味着对资源本身的双重访问(一次用于检查存在,另一次用于读取它),并且在某些情况下可能是性能问题,例如基于远程URL模板资源 - 一个潜在的性能问题,无论如何都可以通过使用模板缓存来大大减轻(在这种情况下,模板只会在第一次访问时<em>解析</em>)。</p> <h2 id="15.2%E6%B6%88%E6%81%AF%E8%A7%A3%E6%9E%90%E5%99%A8" style="margin-left:-2em;"><em><span style="color:#ffffff;">15.2消息解析器</span></em></h2> <p style="margin-left:0px;">我们没有为Grocery应用程序明确指定Message Resolver实现,正如之前所解释的那样,这意味着所使用的实现是一个<code>org.thymeleaf.messageresolver.StandardMessageResolver</code>对象。</p> <p style="margin-left:0px;"><code>StandardMessageResolver</code>是<code>IMessageResolver</code>接口的标准实现,但我们可以根据需要创建自己的,以适应我们的应用程序的特定需求。</p> <blockquote> <p style="margin-left:0px;">Thymeleaf + Spring集成包默认提供了一个<code>IMessageResolver</code>实现,它使用标准的Spring方法检索外部化消息,使用<code>MessageSource</code>在Spring Application Context中声明的bean。</p> </blockquote> <h3 id="%E6%A0%87%E5%87%86%E6%B6%88%E6%81%AF%E8%A7%A3%E6%9E%90%E5%99%A8" style="margin-left:0px;"><em><strong>标准消息解析器</strong></em></h3> <p style="margin-left:0px;">那么如何<code>StandardMessageResolver</code>查找特定模板中请求的消息?</p> <p style="margin-left:0px;">如果模板名称是,<code>home</code>并且它位于<code>/WEB-INF/templates/home.html</code>,并且请求的区域设置是,<code>gl_ES</code>则此解析程序将按以下顺序查找以下文件中的消息:</p> <ul style="margin-left:2em;"> <li><code>/WEB-INF/templates/home_gl_ES.properties</code></li> <li><code>/WEB-INF/templates/home_gl.properties</code></li> <li><code>/WEB-INF/templates/home.properties</code></li> </ul> <p style="margin-left:0px;"><code>StandardMessageResolver</code>有关完整消息解析机制如何工作的更多详细信息,请参阅该类的JavaDoc文档。</p> <h3 id="%E9%85%8D%E7%BD%AE%E9%82%AE%E4%BB%B6%E8%A7%A3%E6%9E%90%E5%99%A8" style="margin-left:0px;"><em><strong>配置邮件解析器</strong></em></h3> <p style="margin-left:0px;">如果我们想要向模板引擎添加消息解析器(或更多),该怎么办?简单:</p> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">// For setting only one</span> templateEngine<span style="color:#b9bdb6;">.</span>setMessageResolver<span style="color:#b9bdb6;">(</span>messageResolver<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> <span style="color:#cf9a49;">// For setting more than one</span> templateEngine<span style="color:#b9bdb6;">.</span>addMessageResolver<span style="color:#b9bdb6;">(</span>messageResolver<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> <p style="margin-left:0px;">为什么我们想拥有多个消息解析器?出于与模板解析器相同的原因:订购消息解析器,如果第一个消息解析器无法解析特定消息,则会询问第二个,然后是第三个,等等。</p> <h2 id="15.3%E8%BD%AC%E6%8D%A2%E6%9C%8D%E5%8A%A1" style="margin-left:-2em;"><em><span style="color:#ffffff;">15.3转换服务</span></em></h2> <p style="margin-left:0px;">使我们能够通过<em>双括号</em>语法()执行数据转换和格式化操作的<em>转换服务</em>实际上是标准方言的一个特征,而不是Thymeleaf模板引擎本身。<code>${{...}}</code></p> <p style="margin-left:0px;">因此,配置它的方法是将<code>IStandardConversionService</code>接口的自定义实现直接设置到<code>StandardDialect</code>正在配置到模板引擎中的实例中。喜欢:</p> <pre><code class="language-java"> <code class="language-java">IStandardConversionService customConversionService = <span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span> StandardDialect dialect = <span style="color:#99cc33;">new</span> StandardDialect<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> dialect<span style="color:#b9bdb6;">.</span>setConversionService<span style="color:#b9bdb6;">(</span>customConversionService<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> templateEngine<span style="color:#b9bdb6;">.</span>setDialect<span style="color:#b9bdb6;">(</span>dialect<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> <blockquote> <p style="margin-left:0px;">请注意,thymeleaf-spring3和thymeleaf-spring4软件包包含<code>SpringStandardDialect</code>,并且此方言已预先配置了一个实现<code>IStandardConversionService</code>,将Spring自己的<em>转换服务</em>基础结构集成到Thymeleaf中。</p> </blockquote> <h2 id="15.4%E8%AE%B0%E5%BD%95" style="margin-left:-2em;"><em><span style="color:#ffffff;">15.4记录</span></em></h2> <p style="margin-left:0px;">Thymeleaf非常关注日志记录,并始终尝试通过其日志记录界面提供最大量的有用信息。</p> <p style="margin-left:0px;">使用的日志库<code>slf4j,</code>实际上充当了我们可能希望在我们的应用程序中使用的任何日志记录实现的桥梁(例如,<code>log4j</code>)。</p> <p style="margin-left:0px;">Thymeleaf班会记录<code>TRACE</code>,<code>DEBUG</code>并<code>INFO</code>-level信息,这取决于我们希望的详细程度,并且除了一般的记录它会使用与TemplateEngine类,我们可以为不同的目的而单独配置相关的三个特殊记录器:</p> <ul style="margin-left:2em;"> <li><code>org.thymeleaf.TemplateEngine.CONFIG</code> 将在初始化期间输出库的详细配置。</li> <li><code>org.thymeleaf.TemplateEngine.TIMER</code> 将输出有关处理每个模板所用时间的信息(对基准测试很有用!)</li> <li><code>org.thymeleaf.TemplateEngine.cache</code>是一组记录器的前缀,用于输出有关高速缓存的特定信息。虽然缓存记录器的名称可由用户配置,因此可能会更改,但默认情况下它们是: <ul style="margin-left:2em;"> <li><code>org.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE</code></li> <li><code>org.thymeleaf.TemplateEngine.cache.EXPRESSION_CACHE</code></li> </ul></li> </ul> <p style="margin-left:0px;">使用Thymeleaf的日志记录基础结构的示例配置<code>log4j</code>可以是:</p> <pre class="has"><code>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</code></pre> <h1 id="16%E6%A8%A1%E6%9D%BF%E7%BC%93%E5%AD%98" style="margin-left:0px;"><em><strong>16模板缓存</strong></em></h1> <p style="margin-left:0px;">Thymeleaf的工作得益于一组解析器 - 用于标记和文本 - 将模板解析为事件序列(开放标记,文本,关闭标记,注释等)和一系列处理器 - 每种类型的行为都需要一个应用 - 修改模板解析的事件序列,以便通过将原始模板与我们的数据相结合来创建我们期望的结果。</p> <p style="margin-left:0px;">它还包括 - 默认情况下 - 一个存储已解析模板的缓存; 在处理模板文件之前读取和解析模板文件所产生的事件序列。这在Web应用程序中工作时特别有用,并基于以下概念构建:</p> <ul style="margin-left:2em;"> <li>输入/输出几乎总是任何应用程序中最慢的部分。相比之下,内存处理非常快。</li> <li>克隆现有的内存中事件序列总是比读取模板文件,解析模板文件并为其创建新的事件序列快得多。</li> <li>Web应用程序通常只有几十个模板。</li> <li>模板文件是中小型的,并且在应用程序运行时不会修改它们。</li> </ul> <p style="margin-left:0px;">这一切都导致了这样的想法:在不浪费大量内存的情况下缓存Web应用程序中最常用的模板是可行的,并且它还将节省大量时间,这些时间将花费在一小组文件上的输入/输出操作上事实上,这永远不会改变。</p> <p style="margin-left:0px;">我们如何控制这个缓存?首先,我们之前已经了解到,我们可以在模板解析器中启用或禁用它,甚至只对特定模板执行操作:</p> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">// Default is true</span> templateResolver<span style="color:#b9bdb6;">.</span>setCacheable<span style="color:#b9bdb6;">(</span><span style="color:#8bd1ff;">false</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> templateResolver<span style="color:#b9bdb6;">.</span>getCacheablePatternSpec<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">.</span>addPattern<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">"/users/*"</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> <p style="margin-left:0px;">此外,我们可以通过建立自己的<em>缓存管理器</em>对象来修改其配置,该对象可以是默认<code>StandardCacheManager</code>实现的实例:</p> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">// Default is 200</span> StandardCacheManager cacheManager = <span style="color:#99cc33;">new</span> StandardCacheManager<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> cacheManager<span style="color:#b9bdb6;">.</span>setTemplateCacheMaxSize<span style="color:#b9bdb6;">(</span><span style="color:#8bd1ff;">100</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> <span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span> templateEngine<span style="color:#b9bdb6;">.</span>setCacheManager<span style="color:#b9bdb6;">(</span>cacheManager<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> <p style="margin-left:0px;"><code>org.thymeleaf.cache.StandardCacheManager</code>有关配置缓存的更多信息,请参阅javadoc API 。</p> <p style="margin-left:0px;">可以从模板缓存中手动删除条目:</p> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">// Clear the cache completely</span> templateEngine<span style="color:#b9bdb6;">.</span>clearTemplateCache<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> <span style="color:#cf9a49;">// Clear a specific template from the cache</span> templateEngine<span style="color:#b9bdb6;">.</span>clearTemplateCacheFor<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">"/users/userList"</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> <h1 id="17%E8%A7%A3%E8%80%A6%E6%A8%A1%E6%9D%BF%E9%80%BB%E8%BE%91" style="margin-left:0px;"><em><strong>17解耦模板逻辑</strong></em></h1> <h2 id="17.1%E8%A7%A3%E8%80%A6%E9%80%BB%E8%BE%91%EF%BC%9A%E6%A6%82%E5%BF%B5" style="margin-left:-2em;"><em><span style="color:#ffffff;">17.1解耦逻辑:概念</span></em></h2> <p style="margin-left:0px;">到目前为止,我们已经为我们的Grocery Store工作,模板以<em>通常的方式</em>完成,逻辑以属性的形式插入到我们的模板中。</p> <p style="margin-left:0px;">但Thymeleaf也让我们彻底<em>脱钩</em>从逻辑模板标记,允许创建<strong>完全逻辑较少标记模板</strong>在<code>HTML</code>和<code>XML</code>模板模式。</p> <p style="margin-left:0px;">主要思想是模板逻辑将在单独的<em>逻辑文件中</em>定义(更确切地说是<em>逻辑资源</em>,因为它不需要是<em>文件</em>)。默认情况下,该逻辑资源将是与模板文件位于同一位置(例如文件夹)的附加文件,具有相同的名称但具有<code>.th.xml</code>扩展名:</p> <pre class="has"><code>/templates +->/home.html +->/home.th.xml</code></pre> <p style="margin-left:0px;">因此该<code>home.html</code>文件可以完全无逻辑。它可能看起来像这样:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#cf9a49;"><!DOCTYPE html></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>html</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>body</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>table</span> <span style="color:#e0e8ff;">id</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>usersTable<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>username<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Jeremy Grapefruit<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>usertype<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Normal User<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>username<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Alice Watermelon<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>usertype<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Administrator<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>body</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>html</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">绝对没有Thymeleaf代码。这是一个模板文件,没有Thymeleaf或模板知识的设计师可以创建,编辑和/或理解。或者由某些外部系统提供的HTML片段,根本没有Thymeleaf挂钩。</p> <p style="margin-left:0px;">现在让我们<code>home.html</code>通过创建我们的附加<code>home.th.xml</code>文件将该模板转换为Thymeleaf模板:</p> <pre class="language-xml"><code class="language-xml"><span style="color:#cf9a49;"><?xml version="1.0"?></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>thlogic</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>attr</span> <span style="color:#e0e8ff;">sel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>#usersTable<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:remove</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>all-but-first<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>attr</span> <span style="color:#e0e8ff;">sel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>/tr[0]<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:each</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>user : ${users}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>attr</span> <span style="color:#e0e8ff;">sel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>td.username<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${user.name}<span style="color:#b9bdb6;">"</span></span> <span style="color:#b9bdb6;">/></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>attr</span> <span style="color:#e0e8ff;">sel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>td.usertype<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>#{|user.type.${user.type}|}<span style="color:#b9bdb6;">"</span></span> <span style="color:#b9bdb6;">/></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>attr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>attr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>thlogic</span><span style="color:#b9bdb6;">></span></span></code></pre> <p style="margin-left:0px;">在这里,我们可以<code><attr></code>在<code>thlogic</code>块内看到很多标签。这些<code><attr></code>标签通过其属性选择在原始模板的节点上执行<em>属性注入</em>,这些<code>sel</code>属性包含Thymeleaf <em>标记选择器</em>(实际上是<em>AttoParser标记选择器</em>)。</p> <p style="margin-left:0px;">另请注意,<code><attr></code>可以嵌套标记,以便<em>附加</em>其选择器。即<code>sel="/tr[0]"</code>上述中,例如,将被处理为<code>sel="#usersTable/tr[0]"</code>。并且用户名的选择器<code><td></code>将被处理为<code>sel="#usersTable/tr[0]//td.username"</code>。</p> <p style="margin-left:0px;">所以一旦合并,上面看到的两个文件都将是:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#cf9a49;"><!DOCTYPE html></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>html</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>body</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>table</span> <span style="color:#e0e8ff;">id</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>usersTable<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:remove</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>all-but-first<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span> <span style="color:#e0e8ff;">th:each</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>user : ${users}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>username<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>${user.name}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Jeremy Grapefruit<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>usertype<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">th:text</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>#{|user.type.${user.type}|}<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Normal User<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>username<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Alice Watermelon<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>td</span> <span style="color:#e0e8ff;">class</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>usertype<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>Administrator<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>td</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>tr</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>table</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>body</span><span style="color:#b9bdb6;">></span></span> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>html</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">这看起来更熟悉,并且确实比创建两个单独的文件更<em>简洁</em>。但是,<em>解耦模板</em>的优势在于我们可以为我们的模板提供完全独立于Thymeleaf的独立性,因此从设计角度来看,它具有更好的可维护性。</p> <p style="margin-left:0px;">当然,仍然需要设计人员或开发人员之间的一些<em>合同</em> - 例如用户<code><table></code>需要的<em>合同</em><code>id="usersTable"</code> - 但在许多情况下,纯HTML模板将是设计和开发团队之间更好的通信工件。</p> <h2 id="17.2%E9%85%8D%E7%BD%AE%E8%A7%A3%E8%80%A6%E6%A8%A1%E6%9D%BF" style="margin-left:-2em;"><em><span style="color:#ffffff;">17.2配置解耦模板</span></em></h2> <h3 id="%E5%90%AF%E7%94%A8%E8%A7%A3%E8%80%A6%E6%A8%A1%E6%9D%BF" style="margin-left:0px;"><em><strong>启用解耦模板</strong></em></h3> <p style="margin-left:0px;">默认情况下,每个模板都不会出现解耦逻辑。相反,配置的模板解析器(实现<code>ITemplateResolver</code>)需要<em>使用解耦逻辑</em>专门标记它们解析的模板。</p> <p style="margin-left:0px;">除了<code>StringTemplateResolver</code>(不允许解耦逻辑)之外,所有其他开箱即用的实现都<code>ITemplateResolver</code>将提供一个标记<code>useDecoupledLogic</code>,该标记将标记由该解析器解析的所有模板,因为它可能将其全部或部分逻辑生活在单独的资源中:</p> <pre><code class="language-java"> <code class="language-java"><span style="color:#99cc33;">final</span> ServletContextTemplateResolver templateResolver = <span style="color:#99cc33;">new</span> ServletContextTemplateResolver<span style="color:#b9bdb6;">(</span>servletContext<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> <span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span> templateResolver<span style="color:#b9bdb6;">.</span>setUseDecoupledLogic<span style="color:#b9bdb6;">(</span><span style="color:#8bd1ff;">true</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> <h3 id="%E6%B7%B7%E5%90%88%E8%80%A6%E5%90%88%E5%92%8C%E8%A7%A3%E8%80%A6%E9%80%BB%E8%BE%91" style="margin-left:0px;"><em><strong>混合耦合和解耦逻辑</strong></em></h3> <p style="margin-left:0px;">启用时,解耦模板逻辑不是必需的。启用后,这意味着引擎将<em>查找</em>包含解耦逻辑的资源,解析并将其与原始模板(如果存在)合并。如果解耦逻辑资源不存在,则不会引发错误。</p> <p style="margin-left:0px;">此外,在同一模板中,我们可以混合<em>耦合</em>和<em>解耦</em>逻辑,例如通过在原始模板文件中添加一些Thymeleaf属性,但将其他属性留给单独的解耦逻辑文件。最常见的情况是使用new(in v3.0)<code>th:ref</code>属性。</p> <h2 id="17.3%20th%EF%BC%9Aref%E5%B1%9E%E6%80%A7" style="margin-left:-2em;"><em><span style="color:#ffffff;">17.3 th:ref属性</span></em></h2> <p style="margin-left:0px;"><code>th:ref</code>只是一个标记属性。它从处理的角度来看并没有做任何事情,只是在处理模板时就消失了,但它的用处在于它充当<em>标记引用</em>,即它可以通过名称从<em>标记选择器中</em>解析,就像<em>标记名称</em>或<em>片段一样</em>(<code>th:fragment</code>)。</p> <p style="margin-left:0px;">所以,如果我们有一个选择器,如:</p> <pre class="language-xml"><code class="language-xml"> <span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>attr</span> <span style="color:#e0e8ff;">sel</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>whatever<span style="color:#b9bdb6;">"</span></span> <span style="color:#e0e8ff;">...</span><span style="color:#b9bdb6;">/></span></span></code></pre> <p style="margin-left:0px;">这将匹配:</p> <ul style="margin-left:2em;"> <li>任何<code><whatever></code>标签。</li> <li>任何带有<code>th:fragment="whatever"</code>属性的标签。</li> <li>任何带有<code>th:ref="whatever"</code>属性的标签。</li> </ul> <p style="margin-left:0px;"><code>th:ref</code>例如,使用纯HTML <code>id</code>属性的优点是什么?仅仅是事实,我们可能不希望添加这么多<code>id</code>和<code>class</code>属性,我们的标记作为<em>逻辑锚</em>,这最终可能会<em>污染</em>我们的产量。</p> <p style="margin-left:0px;">从同样的意义上讲,有什么缺点<code>th:ref</code>?好吧,显然我们会在模板中添加一些Thymeleaf逻辑(<em>“逻辑”</em>)。</p> <p style="margin-left:0px;">请注意,该<code>th:ref</code>属性的适用性<strong>不仅适用于解耦的逻辑模板文件</strong>:它在其他类型的场景中也是如此,例如片段表达式(<code>~{...}</code>)。</p> <h2 id="17.4%E8%A7%A3%E8%80%A6%E6%A8%A1%E6%9D%BF%E7%9A%84%E6%80%A7%E8%83%BD%E5%BD%B1%E5%93%8D" style="margin-left:-2em;"><em><span style="color:#ffffff;">17.4解耦模板的性能影响</span></em></h2> <p style="margin-left:0px;">影响非常小。当已解析的模板被标记为使用解耦逻辑并且未缓存时,模板逻辑资源将首先被解析,解析并处理成内存中指令的序列:基本上是要注入每个标记选择器的属性列表。</p> <p style="margin-left:0px;">但这是唯一需要的<em>额外步骤</em>,因为在此之后,真正的模板将被解析,并且在解析时,这些属性将由解析器本身<em>即时</em>注入,这得益于AttoParser中节点选择的高级功能。因此,解析后的节点将从解析器中出来,就好像它们将注入的属性写入原始模板文件中一样。</p> <p style="margin-left:0px;">这个的最大优点是什么?将模板配置为高速缓存时,它将被缓存,其中包含已注入的属性。因此,一旦缓存<em>模板</em>的缓存模板使用<em>解耦模板</em>的开销将绝对<em>为零</em>。</p> <h2 id="17.5%E8%A7%A3%E8%80%A6%E9%80%BB%E8%BE%91%E7%9A%84%E5%88%86%E8%BE%A8%E7%8E%87" style="margin-left:-2em;"><em><span style="color:#ffffff;">17.5解耦逻辑的分辨率</span></em></h2> <p style="margin-left:0px;">Thymeleaf解析对应于每个模板的解耦逻辑资源的方式可由用户配置。它由扩展点确定<code>org.thymeleaf.templateparser.markup.decoupled.IDecoupledTemplateLogicResolver</code>,为其提供<em>默认实现</em>:<code>StandardDecoupledTemplateLogicResolver</code>。</p> <p style="margin-left:0px;">这个标准实现有什么作用?</p> <ul style="margin-left:2em;"> <li>首先,它将a <code>prefix</code>和a 应用于模板资源<code>suffix</code>的<em>基本名称</em>(通过其<code>ITemplateResource#getBaseName()</code>方法获得)。前缀和后缀都可以配置,默认情况下,前缀为空,后缀为<code>.th.xml</code>。</li> <li>其次,它要求模板资源通过其方法解析具有计算名称的<em>相对资源</em><code>ITemplateResource#relative(String relativeLocation)</code>。</li> </ul> <p style="margin-left:0px;"><code>IDecoupledTemplateLogicResolver</code>可以<code>TemplateEngine</code>轻松配置要使用的具体实现:</p> <pre><code class="language-java"> <code class="language-java"><span style="color:#99cc33;">final</span> StandardDecoupledTemplateLogicResolver decoupledresolver = <span style="color:#99cc33;">new</span> StandardDecoupledTemplateLogicResolver<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> decoupledResolver<span style="color:#b9bdb6;">.</span>setPrefix<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">"../viewlogic/"</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span> <span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span> templateEngine<span style="color:#b9bdb6;">.</span>setDecoupledTemplateLogicResolver<span style="color:#b9bdb6;">(</span>decoupledResolver<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">;</span></code></code></pre> <h1 id="18%E9%99%84%E5%BD%95A%EF%BC%9A%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%9F%BA%E6%9C%AC%E5%AF%B9%E8%B1%A1" style="margin-left:0px;"><em><strong>18附录A:表达式基本对象</strong></em></h1> <p style="margin-left:0px;">始终可以调用某些对象和变量映射。我们来看看他们:</p> <h3 id="%E5%9F%BA%E7%A1%80%E5%AF%B9%E8%B1%A1" style="margin-left:0px;"><em><strong>基础对象</strong></em></h3> <ul style="margin-left:2em;"> <li> <p style="margin-left:0px;"><strong>#ctx</strong>:上下文对象。实施<code>org.thymeleaf.context.IContext</code>或<code>org.thymeleaf.context.IWebContext</code>依赖于我们的环境(独立或Web)。</p> <p style="margin-left:0px;">注意<code>#vars</code>并且<code>#root</code>是同一对象的同义词,但<code>#ctx</code>建议使用。</p> </li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.context.IContext * ====================================================================== */</span> $<span style="color:#b9bdb6;">{</span>#ctx<span style="color:#b9bdb6;">.</span>locale<span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#ctx<span style="color:#b9bdb6;">.</span>variableNames<span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.context.IWebContext * ====================================================================== */</span> $<span style="color:#b9bdb6;">{</span>#ctx<span style="color:#b9bdb6;">.</span>request<span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#ctx<span style="color:#b9bdb6;">.</span>response<span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#ctx<span style="color:#b9bdb6;">.</span>session<span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#ctx<span style="color:#b9bdb6;">.</span>servletContext<span style="color:#b9bdb6;">}</span></code></code></pre> <ul style="margin-left:2em;"> <li><strong>#locale</strong>:直接访问<code>java.util.Locale</code>与当前请求关联的。</li> </ul> <pre><code class="language-java"> <code class="language-java">$<span style="color:#b9bdb6;">{</span>#locale<span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E8%AF%B7%E6%B1%82%2F%E4%BC%9A%E8%AF%9D%E5%B1%9E%E6%80%A7%E7%9A%84Web%E4%B8%8A%E4%B8%8B%E6%96%87%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E7%AD%89%E3%80%82" style="margin-left:0px;"><em><strong>请求/会话属性的Web上下文命名空间等。</strong></em></h3> <p style="margin-left:0px;">在Web环境中使用Thymeleaf时,我们可以使用一系列快捷方式来访问请求参数,会话属性和应用程序属性:</p> <blockquote> <p style="margin-left:0px;">请注意,这些不是<em>上下文对象</em>,而是作为变量添加到上下文中的映射,因此我们不使用它们<code>#</code>。在某种程度上,它们充当<em>命名空间</em>。</p> </blockquote> <ul style="margin-left:2em;"> <li><strong>param</strong>:用于检索请求参数。<code>${param.foo}</code>是一个<code>String[]</code>带有<code>foo</code>请求参数值的,因此<code>${param.foo[0]}</code>通常用于获取第一个值。</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ============================================================================ * See javadoc API for class org.thymeleaf.context.WebRequestParamsVariablesMap * ============================================================================ */</span> $<span style="color:#b9bdb6;">{</span>param<span style="color:#b9bdb6;">.</span>foo<span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// Retrieves a String[] with the values of request parameter 'foo'</span> $<span style="color:#b9bdb6;">{</span>param<span style="color:#b9bdb6;">.</span>size<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>param<span style="color:#b9bdb6;">.</span>isEmpty<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>param<span style="color:#b9bdb6;">.</span>containsKey<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'foo'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span></code></code></pre> <ul style="margin-left:2em;"> <li><strong>session</strong>:用于检索会话属性。</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.context.WebSessionVariablesMap * ====================================================================== */</span> $<span style="color:#b9bdb6;">{</span>session<span style="color:#b9bdb6;">.</span>foo<span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// Retrieves the session atttribute 'foo'</span> $<span style="color:#b9bdb6;">{</span>session<span style="color:#b9bdb6;">.</span>size<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>session<span style="color:#b9bdb6;">.</span>isEmpty<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>session<span style="color:#b9bdb6;">.</span>containsKey<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'foo'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span></code></code></pre> <ul style="margin-left:2em;"> <li><strong>application</strong>:用于检索应用程序/ servlet上下文属性。</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ============================================================================= * See javadoc API for class org.thymeleaf.context.WebServletContextVariablesMap * ============================================================================= */</span> $<span style="color:#b9bdb6;">{</span>application<span style="color:#b9bdb6;">.</span>foo<span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// Retrieves the ServletContext atttribute 'foo'</span> $<span style="color:#b9bdb6;">{</span>application<span style="color:#b9bdb6;">.</span>size<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>application<span style="color:#b9bdb6;">.</span>isEmpty<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>application<span style="color:#b9bdb6;">.</span>containsKey<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'foo'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span></code></code></pre> <p style="margin-left:0px;">请注意,<strong>无需为访问请求属性</strong>(与<em>请求参数</em>相对)<strong>指定名称空间,</strong>因为所有请求属性都会自动作为上下文根中的变量添加到上下文中:</p> <pre><code class="language-java"> <code class="language-java">$<span style="color:#b9bdb6;">{</span>myRequestAttribute<span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="Web%E4%B8%8A%E4%B8%8B%E6%96%87%E5%AF%B9%E8%B1%A1" style="margin-left:0px;"><em><strong>Web上下文对象</strong></em></h3> <p style="margin-left:0px;">在Web环境中,还可以直接访问以下对象(请注意这些是对象,而不是映射/命名空间):</p> <ul style="margin-left:2em;"> <li><strong>#request</strong>:直接访问<code>javax.servlet.http.HttpServletRequest</code>与当前请求关联的对象。</li> </ul> <pre><code class="language-java"> <code class="language-java">$<span style="color:#b9bdb6;">{</span>#request<span style="color:#b9bdb6;">.</span>getAttribute<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'foo'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#request<span style="color:#b9bdb6;">.</span>getParameter<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'foo'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#request<span style="color:#b9bdb6;">.</span>getContextPath<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#request<span style="color:#b9bdb6;">.</span>getRequestName<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span></code></code></pre> <ul style="margin-left:2em;"> <li><strong>#session</strong>:直接访问<code>javax.servlet.http.HttpSession</code>与当前请求关联的对象。</li> </ul> <pre><code class="language-java"> <code class="language-java">$<span style="color:#b9bdb6;">{</span>#session<span style="color:#b9bdb6;">.</span>getAttribute<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'foo'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#session<span style="color:#b9bdb6;">.</span>id<span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#session<span style="color:#b9bdb6;">.</span>lastAccessedTime<span style="color:#b9bdb6;">}</span> <span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span></code></code></pre> <ul style="margin-left:2em;"> <li><strong>#servletContext</strong>:直接访问<code>javax.servlet.ServletContext</code>与当前请求关联的对象。</li> </ul> <pre><code class="language-java"> <code class="language-java">$<span style="color:#b9bdb6;">{</span>#servletContext<span style="color:#b9bdb6;">.</span>getAttribute<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'foo'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#servletContext<span style="color:#b9bdb6;">.</span>contextPath<span style="color:#b9bdb6;">}</span> <span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span></code></code></pre> <h1 id="19%E9%99%84%E5%BD%95B%EF%BC%9A%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%AE%9E%E7%94%A8%E7%A8%8B%E5%BA%8F%E5%AF%B9%E8%B1%A1" style="margin-left:0px;"><em><strong>19附录B:表达式实用程序对象</strong></em></h1> <h3 id="%E6%89%A7%E8%A1%8C%E4%BF%A1%E6%81%AF" style="margin-left:0px;"><em><strong>执行信息</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#execInfo</strong>:表达式对象,提供有关在Thymeleaf标准表达式中处理的模板的有用信息。</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.ExecutionInfo * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Return the name and mode of the 'leaf' template. This means the template * from where the events being processed were parsed. So if this piece of * code is not in the root template "A" but on a fragment being inserted * into "A" from another template called "B", this will return "B" as a * name, and B's mode as template mode. */</span> $<span style="color:#b9bdb6;">{</span>#execInfo<span style="color:#b9bdb6;">.</span>templateName<span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#execInfo<span style="color:#b9bdb6;">.</span>templateMode<span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Return the name and mode of the 'root' template. This means the template * that the template engine was originally asked to process. So if this * piece of code is not in the root template "A" but on a fragment being * inserted into "A" from another template called "B", this will still * return "A" and A's template mode. */</span> $<span style="color:#b9bdb6;">{</span>#execInfo<span style="color:#b9bdb6;">.</span>processedTemplateName<span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#execInfo<span style="color:#b9bdb6;">.</span>processedTemplateMode<span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Return the stacks (actually, List<String> or List<TemplateMode>) of * templates being processed. The first element will be the * 'processedTemplate' (the root one), the last one will be the 'leaf' * template, and in the middle all the fragments inserted in nested * manner to reach the leaf from the root will appear. */</span> $<span style="color:#b9bdb6;">{</span>#execInfo<span style="color:#b9bdb6;">.</span>templateNames<span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#execInfo<span style="color:#b9bdb6;">.</span>templateModes<span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Return the stack of templates being processed similarly (and in the * same order) to 'templateNames' and 'templateModes', but returning * a List<TemplateData> with the full template metadata. */</span> $<span style="color:#b9bdb6;">{</span>#execInfo<span style="color:#b9bdb6;">.</span>templateStack<span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E6%B6%88%E6%81%AF" style="margin-left:0px;"><em><strong>消息</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#messages</strong>:用于在变量表达式中获取外部化消息的实用程序方法,与使用<code>#{...}</code>语法获取它们的方式相同。</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Messages * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Obtain externalized messages. Can receive a single key, a key plus arguments, * or an array/list/set of keys (in which case it will return an array/list/set of * externalized messages). * If a message is not found, a default message (like '??msgKey??') is returned. */</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>msg<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'msgKey'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>msg<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'msgKey'</span><span style="color:#b9bdb6;">,</span> param1<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>msg<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'msgKey'</span><span style="color:#b9bdb6;">,</span> param1<span style="color:#b9bdb6;">,</span> param2<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>msg<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'msgKey'</span><span style="color:#b9bdb6;">,</span> param1<span style="color:#b9bdb6;">,</span> param2<span style="color:#b9bdb6;">,</span> param3<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>msgWithParams<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'msgKey'</span><span style="color:#b9bdb6;">,</span> <span style="color:#99cc33;">new</span> Object<span style="color:#b9bdb6;">[</span><span style="color:#b9bdb6;">]</span> <span style="color:#b9bdb6;">{</span>param1<span style="color:#b9bdb6;">,</span> param2<span style="color:#b9bdb6;">,</span> param3<span style="color:#b9bdb6;">,</span> param4<span style="color:#b9bdb6;">}</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>arrayMsg<span style="color:#b9bdb6;">(</span>messageKeyArray<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>listMsg<span style="color:#b9bdb6;">(</span>messageKeyList<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>setMsg<span style="color:#b9bdb6;">(</span>messageKeySet<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Obtain externalized messages or null. Null is returned instead of a default * message if a message for the specified key is not found. */</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>msgOrNull<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'msgKey'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>msgOrNull<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'msgKey'</span><span style="color:#b9bdb6;">,</span> param1<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>msgOrNull<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'msgKey'</span><span style="color:#b9bdb6;">,</span> param1<span style="color:#b9bdb6;">,</span> param2<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>msgOrNull<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'msgKey'</span><span style="color:#b9bdb6;">,</span> param1<span style="color:#b9bdb6;">,</span> param2<span style="color:#b9bdb6;">,</span> param3<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>msgOrNullWithParams<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'msgKey'</span><span style="color:#b9bdb6;">,</span> <span style="color:#99cc33;">new</span> Object<span style="color:#b9bdb6;">[</span><span style="color:#b9bdb6;">]</span> <span style="color:#b9bdb6;">{</span>param1<span style="color:#b9bdb6;">,</span> param2<span style="color:#b9bdb6;">,</span> param3<span style="color:#b9bdb6;">,</span> param4<span style="color:#b9bdb6;">}</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>arrayMsgOrNull<span style="color:#b9bdb6;">(</span>messageKeyArray<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>listMsgOrNull<span style="color:#b9bdb6;">(</span>messageKeyList<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#messages<span style="color:#b9bdb6;">.</span>setMsgOrNull<span style="color:#b9bdb6;">(</span>messageKeySet<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E7%9A%84URI%20%2F%E7%BD%91%E5%9D%80" style="margin-left:0px;"><em><strong>的URI /网址</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#uris</strong>:用于在Thymeleaf标准表达式中执行URI / URL操作(尤其是转义/转义)的实用程序对象。</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Uris * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Escape/Unescape as a URI/URL path */</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>escapePath<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>escapePath<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">,</span> encoding<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>unescapePath<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>unescapePath<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">,</span> encoding<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Escape/Unescape as a URI/URL path segment (between '/' symbols) */</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>escapePathSegment<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>escapePathSegment<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">,</span> encoding<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>unescapePathSegment<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>unescapePathSegment<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">,</span> encoding<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Escape/Unescape as a Fragment Identifier (#frag) */</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>escapeFragmentId<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>escapeFragmentId<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">,</span> encoding<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>unescapeFragmentId<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>unescapeFragmentId<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">,</span> encoding<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Escape/Unescape as a Query Parameter (?var=value) */</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>escapeQueryParam<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>escapeQueryParam<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">,</span> encoding<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>unescapeQueryParam<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#uris<span style="color:#b9bdb6;">.</span>unescapeQueryParam<span style="color:#b9bdb6;">(</span>uri<span style="color:#b9bdb6;">,</span> encoding<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E8%BD%AC%E6%8D%A2" style="margin-left:0px;"><em><strong>转换</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#conversions</strong>:允许在模板的任何位置执行<em>转换服务的</em>实用程序对象:</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Conversions * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Execute the desired conversion of the 'object' value into the * specified class. */</span> $<span style="color:#b9bdb6;">{</span>#conversions<span style="color:#b9bdb6;">.</span>convert<span style="color:#b9bdb6;">(</span>object<span style="color:#b9bdb6;">,</span> <span style="color:#e0e8ff;">'java.util.TimeZone'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#conversions<span style="color:#b9bdb6;">.</span>convert<span style="color:#b9bdb6;">(</span>object<span style="color:#b9bdb6;">,</span> targetClass<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E6%97%A5%E6%9C%9F" style="margin-left:0px;"><em><strong>日期</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#dates</strong>:<code>java.util.Date</code>对象的实用方法:</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Dates * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Format date with the standard locale format * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>format<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>arrayFormat<span style="color:#b9bdb6;">(</span>datesArray<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>listFormat<span style="color:#b9bdb6;">(</span>datesList<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>setFormat<span style="color:#b9bdb6;">(</span>datesSet<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Format date with the ISO8601 format * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>formatISO<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>arrayFormatISO<span style="color:#b9bdb6;">(</span>datesArray<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>listFormatISO<span style="color:#b9bdb6;">(</span>datesList<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>setFormatISO<span style="color:#b9bdb6;">(</span>datesSet<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Format date with the specified pattern * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>format<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">,</span> <span style="color:#e0e8ff;">'dd/MMM/yyyy HH:mm'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>arrayFormat<span style="color:#b9bdb6;">(</span>datesArray<span style="color:#b9bdb6;">,</span> <span style="color:#e0e8ff;">'dd/MMM/yyyy HH:mm'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>listFormat<span style="color:#b9bdb6;">(</span>datesList<span style="color:#b9bdb6;">,</span> <span style="color:#e0e8ff;">'dd/MMM/yyyy HH:mm'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>setFormat<span style="color:#b9bdb6;">(</span>datesSet<span style="color:#b9bdb6;">,</span> <span style="color:#e0e8ff;">'dd/MMM/yyyy HH:mm'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Obtain date properties * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>day<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayDay(...), listDay(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>month<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayMonth(...), listMonth(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>monthName<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayMonthName(...), listMonthName(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>monthNameShort<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayMonthNameShort(...), listMonthNameShort(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>year<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayYear(...), listYear(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>dayOfWeek<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayDayOfWeek(...), listDayOfWeek(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>dayOfWeekName<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayDayOfWeekName(...), listDayOfWeekName(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>dayOfWeekNameShort<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayDayOfWeekNameShort(...), listDayOfWeekNameShort(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>hour<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayHour(...), listHour(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>minute<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayMinute(...), listMinute(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>second<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arraySecond(...), listSecond(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>millisecond<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayMillisecond(...), listMillisecond(...), etc.</span> <span style="color:#cf9a49;">/* * Create date (java.util.Date) objects from its components */</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>create<span style="color:#b9bdb6;">(</span>year<span style="color:#b9bdb6;">,</span>month<span style="color:#b9bdb6;">,</span>day<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>create<span style="color:#b9bdb6;">(</span>year<span style="color:#b9bdb6;">,</span>month<span style="color:#b9bdb6;">,</span>day<span style="color:#b9bdb6;">,</span>hour<span style="color:#b9bdb6;">,</span>minute<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>create<span style="color:#b9bdb6;">(</span>year<span style="color:#b9bdb6;">,</span>month<span style="color:#b9bdb6;">,</span>day<span style="color:#b9bdb6;">,</span>hour<span style="color:#b9bdb6;">,</span>minute<span style="color:#b9bdb6;">,</span>second<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>create<span style="color:#b9bdb6;">(</span>year<span style="color:#b9bdb6;">,</span>month<span style="color:#b9bdb6;">,</span>day<span style="color:#b9bdb6;">,</span>hour<span style="color:#b9bdb6;">,</span>minute<span style="color:#b9bdb6;">,</span>second<span style="color:#b9bdb6;">,</span>millisecond<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Create a date (java.util.Date) object for the current date and time */</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>createNow<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>createNowForTimeZone<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Create a date (java.util.Date) object for the current date (time set to 00:00) */</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>createToday<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#dates<span style="color:#b9bdb6;">.</span>createTodayForTimeZone<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E6%97%A5%E5%8E%86" style="margin-left:0px;"><em><strong>日历</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#calendars</strong>:类似于<code>#dates</code>,但对于<code>java.util.Calendar</code>对象:</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Calendars * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Format calendar with the standard locale format * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>format<span style="color:#b9bdb6;">(</span>cal<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>arrayFormat<span style="color:#b9bdb6;">(</span>calArray<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>listFormat<span style="color:#b9bdb6;">(</span>calList<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>setFormat<span style="color:#b9bdb6;">(</span>calSet<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Format calendar with the ISO8601 format * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>formatISO<span style="color:#b9bdb6;">(</span>cal<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>arrayFormatISO<span style="color:#b9bdb6;">(</span>calArray<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>listFormatISO<span style="color:#b9bdb6;">(</span>calList<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>setFormatISO<span style="color:#b9bdb6;">(</span>calSet<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Format calendar with the specified pattern * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>format<span style="color:#b9bdb6;">(</span>cal<span style="color:#b9bdb6;">,</span> <span style="color:#e0e8ff;">'dd/MMM/yyyy HH:mm'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>arrayFormat<span style="color:#b9bdb6;">(</span>calArray<span style="color:#b9bdb6;">,</span> <span style="color:#e0e8ff;">'dd/MMM/yyyy HH:mm'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>listFormat<span style="color:#b9bdb6;">(</span>calList<span style="color:#b9bdb6;">,</span> <span style="color:#e0e8ff;">'dd/MMM/yyyy HH:mm'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>setFormat<span style="color:#b9bdb6;">(</span>calSet<span style="color:#b9bdb6;">,</span> <span style="color:#e0e8ff;">'dd/MMM/yyyy HH:mm'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Obtain calendar properties * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>day<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayDay(...), listDay(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>month<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayMonth(...), listMonth(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>monthName<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayMonthName(...), listMonthName(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>monthNameShort<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayMonthNameShort(...), listMonthNameShort(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>year<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayYear(...), listYear(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>dayOfWeek<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayDayOfWeek(...), listDayOfWeek(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>dayOfWeekName<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayDayOfWeekName(...), listDayOfWeekName(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>dayOfWeekNameShort<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayDayOfWeekNameShort(...), listDayOfWeekNameShort(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>hour<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayHour(...), listHour(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>minute<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayMinute(...), listMinute(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>second<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arraySecond(...), listSecond(...), etc.</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>millisecond<span style="color:#b9bdb6;">(</span>date<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also arrayMillisecond(...), listMillisecond(...), etc.</span> <span style="color:#cf9a49;">/* * Create calendar (java.util.Calendar) objects from its components */</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>create<span style="color:#b9bdb6;">(</span>year<span style="color:#b9bdb6;">,</span>month<span style="color:#b9bdb6;">,</span>day<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>create<span style="color:#b9bdb6;">(</span>year<span style="color:#b9bdb6;">,</span>month<span style="color:#b9bdb6;">,</span>day<span style="color:#b9bdb6;">,</span>hour<span style="color:#b9bdb6;">,</span>minute<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>create<span style="color:#b9bdb6;">(</span>year<span style="color:#b9bdb6;">,</span>month<span style="color:#b9bdb6;">,</span>day<span style="color:#b9bdb6;">,</span>hour<span style="color:#b9bdb6;">,</span>minute<span style="color:#b9bdb6;">,</span>second<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>create<span style="color:#b9bdb6;">(</span>year<span style="color:#b9bdb6;">,</span>month<span style="color:#b9bdb6;">,</span>day<span style="color:#b9bdb6;">,</span>hour<span style="color:#b9bdb6;">,</span>minute<span style="color:#b9bdb6;">,</span>second<span style="color:#b9bdb6;">,</span>millisecond<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>createForTimeZone<span style="color:#b9bdb6;">(</span>year<span style="color:#b9bdb6;">,</span>month<span style="color:#b9bdb6;">,</span>day<span style="color:#b9bdb6;">,</span>timeZone<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>createForTimeZone<span style="color:#b9bdb6;">(</span>year<span style="color:#b9bdb6;">,</span>month<span style="color:#b9bdb6;">,</span>day<span style="color:#b9bdb6;">,</span>hour<span style="color:#b9bdb6;">,</span>minute<span style="color:#b9bdb6;">,</span>timeZone<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>createForTimeZone<span style="color:#b9bdb6;">(</span>year<span style="color:#b9bdb6;">,</span>month<span style="color:#b9bdb6;">,</span>day<span style="color:#b9bdb6;">,</span>hour<span style="color:#b9bdb6;">,</span>minute<span style="color:#b9bdb6;">,</span>second<span style="color:#b9bdb6;">,</span>timeZone<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>createForTimeZone<span style="color:#b9bdb6;">(</span>year<span style="color:#b9bdb6;">,</span>month<span style="color:#b9bdb6;">,</span>day<span style="color:#b9bdb6;">,</span>hour<span style="color:#b9bdb6;">,</span>minute<span style="color:#b9bdb6;">,</span>second<span style="color:#b9bdb6;">,</span>millisecond<span style="color:#b9bdb6;">,</span>timeZone<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Create a calendar (java.util.Calendar) object for the current date and time */</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>createNow<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>createNowForTimeZone<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Create a calendar (java.util.Calendar) object for the current date (time set to 00:00) */</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>createToday<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#calendars<span style="color:#b9bdb6;">.</span>createTodayForTimeZone<span style="color:#b9bdb6;">(</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E6%95%B0%E5%AD%97" style="margin-left:0px;"><em><strong>数字</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#numbers</strong>:数字对象的实用方法:</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Numbers * ====================================================================== */</span> <span style="color:#cf9a49;">/* * ========================== * Formatting integer numbers * ========================== */</span> <span style="color:#cf9a49;">/* * Set minimum integer digits. * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>formatInteger<span style="color:#b9bdb6;">(</span>num<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>arrayFormatInteger<span style="color:#b9bdb6;">(</span>numArray<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>listFormatInteger<span style="color:#b9bdb6;">(</span>numList<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>setFormatInteger<span style="color:#b9bdb6;">(</span>numSet<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Set minimum integer digits and thousands separator: * 'POINT', 'COMMA', 'WHITESPACE', 'NONE' or 'DEFAULT' (by locale). * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>formatInteger<span style="color:#b9bdb6;">(</span>num<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'POINT'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>arrayFormatInteger<span style="color:#b9bdb6;">(</span>numArray<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'POINT'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>listFormatInteger<span style="color:#b9bdb6;">(</span>numList<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'POINT'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>setFormatInteger<span style="color:#b9bdb6;">(</span>numSet<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'POINT'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * ========================== * Formatting decimal numbers * ========================== */</span> <span style="color:#cf9a49;">/* * Set minimum integer digits and (exact) decimal digits. * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>formatDecimal<span style="color:#b9bdb6;">(</span>num<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>arrayFormatDecimal<span style="color:#b9bdb6;">(</span>numArray<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>listFormatDecimal<span style="color:#b9bdb6;">(</span>numList<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>setFormatDecimal<span style="color:#b9bdb6;">(</span>numSet<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Set minimum integer digits and (exact) decimal digits, and also decimal separator. * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>formatDecimal<span style="color:#b9bdb6;">(</span>num<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'COMMA'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>arrayFormatDecimal<span style="color:#b9bdb6;">(</span>numArray<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'COMMA'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>listFormatDecimal<span style="color:#b9bdb6;">(</span>numList<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'COMMA'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>setFormatDecimal<span style="color:#b9bdb6;">(</span>numSet<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'COMMA'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Set minimum integer digits and (exact) decimal digits, and also thousands and * decimal separator. * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>formatDecimal<span style="color:#b9bdb6;">(</span>num<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'POINT'</span><span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'COMMA'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>arrayFormatDecimal<span style="color:#b9bdb6;">(</span>numArray<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'POINT'</span><span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'COMMA'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>listFormatDecimal<span style="color:#b9bdb6;">(</span>numList<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'POINT'</span><span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'COMMA'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>setFormatDecimal<span style="color:#b9bdb6;">(</span>numSet<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'POINT'</span><span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'COMMA'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * ===================== * Formatting currencies * ===================== */</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>formatCurrency<span style="color:#b9bdb6;">(</span>num<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>arrayFormatCurrency<span style="color:#b9bdb6;">(</span>numArray<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>listFormatCurrency<span style="color:#b9bdb6;">(</span>numList<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>setFormatCurrency<span style="color:#b9bdb6;">(</span>numSet<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * ====================== * Formatting percentages * ====================== */</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>formatPercent<span style="color:#b9bdb6;">(</span>num<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>arrayFormatPercent<span style="color:#b9bdb6;">(</span>numArray<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>listFormatPercent<span style="color:#b9bdb6;">(</span>numList<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>setFormatPercent<span style="color:#b9bdb6;">(</span>numSet<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Set minimum integer digits and (exact) decimal digits. */</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>formatPercent<span style="color:#b9bdb6;">(</span>num<span style="color:#b9bdb6;">,</span> <span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span> <span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>arrayFormatPercent<span style="color:#b9bdb6;">(</span>numArray<span style="color:#b9bdb6;">,</span> <span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span> <span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>listFormatPercent<span style="color:#b9bdb6;">(</span>numList<span style="color:#b9bdb6;">,</span> <span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span> <span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>setFormatPercent<span style="color:#b9bdb6;">(</span>numSet<span style="color:#b9bdb6;">,</span> <span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span> <span style="color:#8bd1ff;">2</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * =============== * Utility methods * =============== */</span> <span style="color:#cf9a49;">/* * Create a sequence (array) of integer numbers going * from x to y */</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>sequence<span style="color:#b9bdb6;">(</span>from<span style="color:#b9bdb6;">,</span>to<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#numbers<span style="color:#b9bdb6;">.</span>sequence<span style="color:#b9bdb6;">(</span>from<span style="color:#b9bdb6;">,</span>to<span style="color:#b9bdb6;">,</span>step<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E5%AD%97%E7%AC%A6%E4%B8%B2" style="margin-left:0px;"><em><strong>字符串</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#strings</strong>:<code>String</code>对象的实用方法:</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Strings * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Null-safe toString() */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>toString<span style="color:#b9bdb6;">(</span>obj<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> <span style="color:#cf9a49;">/* * Check whether a String is empty (or null). Performs a trim() operation before check * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>isEmpty<span style="color:#b9bdb6;">(</span>name<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>arrayIsEmpty<span style="color:#b9bdb6;">(</span>nameArr<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>listIsEmpty<span style="color:#b9bdb6;">(</span>nameList<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>setIsEmpty<span style="color:#b9bdb6;">(</span>nameSet<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Perform an 'isEmpty()' check on a string and return it if false, defaulting to * another specified string if true. * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>defaultString<span style="color:#b9bdb6;">(</span>text<span style="color:#b9bdb6;">,</span><span style="color:#99cc33;">default</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>arrayDefaultString<span style="color:#b9bdb6;">(</span>textArr<span style="color:#b9bdb6;">,</span><span style="color:#99cc33;">default</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>listDefaultString<span style="color:#b9bdb6;">(</span>textList<span style="color:#b9bdb6;">,</span><span style="color:#99cc33;">default</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>setDefaultString<span style="color:#b9bdb6;">(</span>textSet<span style="color:#b9bdb6;">,</span><span style="color:#99cc33;">default</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Check whether a fragment is contained in a String * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>contains<span style="color:#b9bdb6;">(</span>name<span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'ez'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>containsIgnoreCase<span style="color:#b9bdb6;">(</span>name<span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'ez'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> <span style="color:#cf9a49;">/* * Check whether a String starts or ends with a fragment * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>startsWith<span style="color:#b9bdb6;">(</span>name<span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'Don'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>endsWith<span style="color:#b9bdb6;">(</span>name<span style="color:#b9bdb6;">,</span>endingFragment<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> <span style="color:#cf9a49;">/* * Substring-related operations * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>indexOf<span style="color:#b9bdb6;">(</span>name<span style="color:#b9bdb6;">,</span>frag<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>substring<span style="color:#b9bdb6;">(</span>name<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">3</span><span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">5</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>substringAfter<span style="color:#b9bdb6;">(</span>name<span style="color:#b9bdb6;">,</span>prefix<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>substringBefore<span style="color:#b9bdb6;">(</span>name<span style="color:#b9bdb6;">,</span>suffix<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>replace<span style="color:#b9bdb6;">(</span>name<span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'las'</span><span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">'ler'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> <span style="color:#cf9a49;">/* * Append and prepend * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>prepend<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">,</span>prefix<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>append<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">,</span>suffix<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> <span style="color:#cf9a49;">/* * Change case * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>toUpperCase<span style="color:#b9bdb6;">(</span>name<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>toLowerCase<span style="color:#b9bdb6;">(</span>name<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> <span style="color:#cf9a49;">/* * Split and join */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>arrayJoin<span style="color:#b9bdb6;">(</span>namesArray<span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">','</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>listJoin<span style="color:#b9bdb6;">(</span>namesList<span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">','</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>setJoin<span style="color:#b9bdb6;">(</span>namesSet<span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">','</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>arraySplit<span style="color:#b9bdb6;">(</span>namesStr<span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">','</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// returns String[]</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>listSplit<span style="color:#b9bdb6;">(</span>namesStr<span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">','</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// returns List<String></span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>setSplit<span style="color:#b9bdb6;">(</span>namesStr<span style="color:#b9bdb6;">,</span><span style="color:#e0e8ff;">','</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// returns Set<String></span> <span style="color:#cf9a49;">/* * Trim * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>trim<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> <span style="color:#cf9a49;">/* * Compute length * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>length<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> <span style="color:#cf9a49;">/* * Abbreviate text making it have a maximum size of n. If text is bigger, it * will be clipped and finished in "..." * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>abbreviate<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">,</span><span style="color:#8bd1ff;">10</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> <span style="color:#cf9a49;">/* * Convert the first character to upper-case (and vice-versa) */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>capitalize<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>unCapitalize<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> <span style="color:#cf9a49;">/* * Convert the first character of every word to upper-case */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>capitalizeWords<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>capitalizeWords<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">,</span>delimiters<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> <span style="color:#cf9a49;">/* * Escape the string */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>escapeXml<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>escapeJava<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>escapeJavaScript<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>unescapeJava<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>unescapeJavaScript<span style="color:#b9bdb6;">(</span>str<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">// also array*, list* and set*</span> <span style="color:#cf9a49;">/* * Null-safe comparison and concatenation */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>equals<span style="color:#b9bdb6;">(</span>first<span style="color:#b9bdb6;">,</span> second<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>equalsIgnoreCase<span style="color:#b9bdb6;">(</span>first<span style="color:#b9bdb6;">,</span> second<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>concat<span style="color:#b9bdb6;">(</span>values<span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>concatReplaceNulls<span style="color:#b9bdb6;">(</span>nullValue<span style="color:#b9bdb6;">,</span> values<span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">.</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Random */</span> $<span style="color:#b9bdb6;">{</span>#strings<span style="color:#b9bdb6;">.</span>randomAlphanumeric<span style="color:#b9bdb6;">(</span>count<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E5%AF%B9%E8%B1%A1" style="margin-left:0px;"><em><strong>对象</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#objects</strong>:一般对象的实用程序方法</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Objects * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Return obj if it is not null, and default otherwise * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#objects<span style="color:#b9bdb6;">.</span>nullSafe<span style="color:#b9bdb6;">(</span>obj<span style="color:#b9bdb6;">,</span><span style="color:#99cc33;">default</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#objects<span style="color:#b9bdb6;">.</span>arrayNullSafe<span style="color:#b9bdb6;">(</span>objArray<span style="color:#b9bdb6;">,</span><span style="color:#99cc33;">default</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#objects<span style="color:#b9bdb6;">.</span>listNullSafe<span style="color:#b9bdb6;">(</span>objList<span style="color:#b9bdb6;">,</span><span style="color:#99cc33;">default</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#objects<span style="color:#b9bdb6;">.</span>setNullSafe<span style="color:#b9bdb6;">(</span>objSet<span style="color:#b9bdb6;">,</span><span style="color:#99cc33;">default</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E5%B8%83%E5%B0%94" style="margin-left:0px;"><em><strong>布尔</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#bools</strong>:布尔评估的实用程序方法</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Bools * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Evaluate a condition in the same way that it would be evaluated in a th:if tag * (see conditional evaluation chapter afterwards). * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>isTrue<span style="color:#b9bdb6;">(</span>obj<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>arrayIsTrue<span style="color:#b9bdb6;">(</span>objArray<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>listIsTrue<span style="color:#b9bdb6;">(</span>objList<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>setIsTrue<span style="color:#b9bdb6;">(</span>objSet<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Evaluate with negation * Also works with arrays, lists or sets */</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>isFalse<span style="color:#b9bdb6;">(</span>cond<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>arrayIsFalse<span style="color:#b9bdb6;">(</span>condArray<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>listIsFalse<span style="color:#b9bdb6;">(</span>condList<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>setIsFalse<span style="color:#b9bdb6;">(</span>condSet<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Evaluate and apply AND operator * Receive an array, a list or a set as parameter */</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>arrayAnd<span style="color:#b9bdb6;">(</span>condArray<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>listAnd<span style="color:#b9bdb6;">(</span>condList<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>setAnd<span style="color:#b9bdb6;">(</span>condSet<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Evaluate and apply OR operator * Receive an array, a list or a set as parameter */</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>arrayOr<span style="color:#b9bdb6;">(</span>condArray<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>listOr<span style="color:#b9bdb6;">(</span>condList<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#bools<span style="color:#b9bdb6;">.</span>setOr<span style="color:#b9bdb6;">(</span>condSet<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E6%95%B0%E7%BB%84" style="margin-left:0px;"><em><strong>数组</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#arrays</strong>:数组的实用程序方法</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Arrays * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Converts to array, trying to infer array component class. * Note that if resulting array is empty, or if the elements * of the target object are not all of the same class, * this method will return Object[]. */</span> $<span style="color:#b9bdb6;">{</span>#arrays<span style="color:#b9bdb6;">.</span>toArray<span style="color:#b9bdb6;">(</span>object<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Convert to arrays of the specified component class. */</span> $<span style="color:#b9bdb6;">{</span>#arrays<span style="color:#b9bdb6;">.</span>toStringArray<span style="color:#b9bdb6;">(</span>object<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#arrays<span style="color:#b9bdb6;">.</span>toIntegerArray<span style="color:#b9bdb6;">(</span>object<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#arrays<span style="color:#b9bdb6;">.</span>toLongArray<span style="color:#b9bdb6;">(</span>object<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#arrays<span style="color:#b9bdb6;">.</span>toDoubleArray<span style="color:#b9bdb6;">(</span>object<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#arrays<span style="color:#b9bdb6;">.</span>toFloatArray<span style="color:#b9bdb6;">(</span>object<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#arrays<span style="color:#b9bdb6;">.</span>toBooleanArray<span style="color:#b9bdb6;">(</span>object<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Compute length */</span> $<span style="color:#b9bdb6;">{</span>#arrays<span style="color:#b9bdb6;">.</span>length<span style="color:#b9bdb6;">(</span>array<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Check whether array is empty */</span> $<span style="color:#b9bdb6;">{</span>#arrays<span style="color:#b9bdb6;">.</span>isEmpty<span style="color:#b9bdb6;">(</span>array<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Check if element or elements are contained in array */</span> $<span style="color:#b9bdb6;">{</span>#arrays<span style="color:#b9bdb6;">.</span>contains<span style="color:#b9bdb6;">(</span>array<span style="color:#b9bdb6;">,</span> element<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#arrays<span style="color:#b9bdb6;">.</span>containsAll<span style="color:#b9bdb6;">(</span>array<span style="color:#b9bdb6;">,</span> elements<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E6%B8%85%E5%8D%95" style="margin-left:0px;"><em><strong>清单</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#lists</strong>:列表的实用程序方法</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Lists * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Converts to list */</span> $<span style="color:#b9bdb6;">{</span>#lists<span style="color:#b9bdb6;">.</span>toList<span style="color:#b9bdb6;">(</span>object<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Compute size */</span> $<span style="color:#b9bdb6;">{</span>#lists<span style="color:#b9bdb6;">.</span>size<span style="color:#b9bdb6;">(</span>list<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Check whether list is empty */</span> $<span style="color:#b9bdb6;">{</span>#lists<span style="color:#b9bdb6;">.</span>isEmpty<span style="color:#b9bdb6;">(</span>list<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Check if element or elements are contained in list */</span> $<span style="color:#b9bdb6;">{</span>#lists<span style="color:#b9bdb6;">.</span>contains<span style="color:#b9bdb6;">(</span>list<span style="color:#b9bdb6;">,</span> element<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#lists<span style="color:#b9bdb6;">.</span>containsAll<span style="color:#b9bdb6;">(</span>list<span style="color:#b9bdb6;">,</span> elements<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Sort a copy of the given list. The members of the list must implement * comparable or you must define a comparator. */</span> $<span style="color:#b9bdb6;">{</span>#lists<span style="color:#b9bdb6;">.</span>sort<span style="color:#b9bdb6;">(</span>list<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#lists<span style="color:#b9bdb6;">.</span>sort<span style="color:#b9bdb6;">(</span>list<span style="color:#b9bdb6;">,</span> comparator<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E9%9B%86" style="margin-left:0px;"><em><strong>集</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#sets</strong>:集合的实用程序方法</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Sets * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Converts to set */</span> $<span style="color:#b9bdb6;">{</span>#sets<span style="color:#b9bdb6;">.</span>toSet<span style="color:#b9bdb6;">(</span>object<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Compute size */</span> $<span style="color:#b9bdb6;">{</span>#sets<span style="color:#b9bdb6;">.</span>size<span style="color:#b9bdb6;">(</span>set<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Check whether set is empty */</span> $<span style="color:#b9bdb6;">{</span>#sets<span style="color:#b9bdb6;">.</span>isEmpty<span style="color:#b9bdb6;">(</span>set<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Check if element or elements are contained in set */</span> $<span style="color:#b9bdb6;">{</span>#sets<span style="color:#b9bdb6;">.</span>contains<span style="color:#b9bdb6;">(</span>set<span style="color:#b9bdb6;">,</span> element<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#sets<span style="color:#b9bdb6;">.</span>containsAll<span style="color:#b9bdb6;">(</span>set<span style="color:#b9bdb6;">,</span> elements<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E5%9C%B0%E5%9B%BE" style="margin-left:0px;"><em><strong>地图</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#maps</strong>:地图的实用程序方法</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Maps * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Compute size */</span> $<span style="color:#b9bdb6;">{</span>#maps<span style="color:#b9bdb6;">.</span>size<span style="color:#b9bdb6;">(</span>map<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Check whether map is empty */</span> $<span style="color:#b9bdb6;">{</span>#maps<span style="color:#b9bdb6;">.</span>isEmpty<span style="color:#b9bdb6;">(</span>map<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Check if key/s or value/s are contained in maps */</span> $<span style="color:#b9bdb6;">{</span>#maps<span style="color:#b9bdb6;">.</span>containsKey<span style="color:#b9bdb6;">(</span>map<span style="color:#b9bdb6;">,</span> key<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#maps<span style="color:#b9bdb6;">.</span>containsAllKeys<span style="color:#b9bdb6;">(</span>map<span style="color:#b9bdb6;">,</span> keys<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#maps<span style="color:#b9bdb6;">.</span>containsValue<span style="color:#b9bdb6;">(</span>map<span style="color:#b9bdb6;">,</span> value<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#maps<span style="color:#b9bdb6;">.</span>containsAllValues<span style="color:#b9bdb6;">(</span>map<span style="color:#b9bdb6;">,</span> value<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E9%AA%A8%E6%96%99" style="margin-left:0px;"><em><strong>骨料</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#aggregates</strong>:用于在数组或集合上创建聚合的实用程序方法</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Aggregates * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Compute sum. Returns null if array or collection is empty */</span> $<span style="color:#b9bdb6;">{</span>#aggregates<span style="color:#b9bdb6;">.</span>sum<span style="color:#b9bdb6;">(</span>array<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#aggregates<span style="color:#b9bdb6;">.</span>sum<span style="color:#b9bdb6;">(</span>collection<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Compute average. Returns null if array or collection is empty */</span> $<span style="color:#b9bdb6;">{</span>#aggregates<span style="color:#b9bdb6;">.</span>avg<span style="color:#b9bdb6;">(</span>array<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#aggregates<span style="color:#b9bdb6;">.</span>avg<span style="color:#b9bdb6;">(</span>collection<span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h3 id="%E6%A0%87%E8%AF%86" style="margin-left:0px;"><em><strong>标识</strong></em></h3> <ul style="margin-left:2em;"> <li><strong>#ids</strong>:用于处理<code>id</code>可能重复的属性的实用程序方法(例如,作为迭代的结果)。</li> </ul> <pre><code class="language-java"> <code class="language-java"><span style="color:#cf9a49;">/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Ids * ====================================================================== */</span> <span style="color:#cf9a49;">/* * Normally used in th:id attributes, for appending a counter to the id attribute value * so that it remains unique even when involved in an iteration process. */</span> $<span style="color:#b9bdb6;">{</span>#ids<span style="color:#b9bdb6;">.</span>seq<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'someId'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> <span style="color:#cf9a49;">/* * Normally used in th:for attributes in <label> tags, so that these labels can refer to Ids * generated by means if the #ids.seq(...) function. * * Depending on whether the <label> goes before or after the element with the #ids.seq(...) * function, the "next" (label goes before "seq") or the "prev" function (label goes after * "seq") function should be called. */</span> $<span style="color:#b9bdb6;">{</span>#ids<span style="color:#b9bdb6;">.</span>next<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'someId'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span> $<span style="color:#b9bdb6;">{</span>#ids<span style="color:#b9bdb6;">.</span>prev<span style="color:#b9bdb6;">(</span><span style="color:#e0e8ff;">'someId'</span><span style="color:#b9bdb6;">)</span><span style="color:#b9bdb6;">}</span></code></code></pre> <h1 id="20%E9%99%84%E5%BD%95C%EF%BC%9A%E6%A0%87%E8%AE%B0%E9%80%89%E6%8B%A9%E5%99%A8%E8%AF%AD%E6%B3%95" style="margin-left:0px;"><em><strong>20附录C:标记选择器语法</strong></em></h1> <p style="margin-left:0px;">Thymeleaf的标记选择器直接从Thymeleaf的解析库中借用:AttoParser。</p> <p style="margin-left:0px;">此选择器的语法与XPath,CSS和jQuery中的选择器具有很大的相似性,这使得它们易于用于大多数用户。您可以在AttoParser文档中查看完整的语法参考。</p> <p style="margin-left:0px;">例如,以下选择器将在标记内的每个位置选择每个<code><div></code>类<code>content</code>(注意这不是尽可能简洁,请继续阅读以了解原因):</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:insert</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>mytemplate :: //div[@class<span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">'</span>content<span style="color:#b9bdb6;">'</span>]<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">基本语法包括:</p> <ul style="margin-left:2em;"> <li> <p style="margin-left:0px;"><code>/x</code> 表示当前节点的名为x的直接子节点。</p> </li> <li> <p style="margin-left:0px;"><code>//x</code> 表示任意深度的名为x的当前节点的子节点。</p> </li> <li> <p style="margin-left:0px;"><code>x[@z="v"]</code> 表示名称为x的元素和名为z且值为“v”的属性。</p> </li> <li> <p style="margin-left:0px;"><code>x[@z1="v1" and @z2="v2"]</code> 表示名称为x的元素,属性z1和z2分别为值“v1”和“v2”。</p> </li> <li> <p style="margin-left:0px;"><code>x[i]</code> 表示名称为x的元素,位于其兄弟姐妹中的数字i中。</p> </li> <li> <p style="margin-left:0px;"><code>x[@z="v"][i]</code> 表示名称为x的元素,属性z的值为“v”,并且在其兄弟姐妹中的数字i中也与该条件匹配。</p> </li> </ul> <p style="margin-left:0px;">但也可以使用更简洁的语法:</p> <ul style="margin-left:2em;"> <li> <p style="margin-left:0px;"><code>x</code>完全等同于<code>//x</code>(<code>x</code>在任何深度级别搜索具有名称或引用的元素,<em>引用</em>是属性<code>th:ref</code>或<code>th:fragment</code>属性)。</p> </li> <li> <p style="margin-left:0px;">选择器也允许没有元素名称/引用,只要它们包含参数规范。因此<code>[@class='oneclass']</code>是一个有效的选择器,它使用带有值的class属性查找任何元素(标记)<code>"oneclass"</code>。</p> </li> </ul> <p style="margin-left:0px;">高级属性选择功能:</p> <ul style="margin-left:2em;"> <li> <p style="margin-left:0px;">除了<code>=</code>(相等)之外,其他比较运算符也是有效的:( <code>!=</code>不等于),<code>^=</code>(以...开头)和<code>$=</code>(以...结尾)。例如:<code>x[@class^='section']</code>表示具有名称的元素<code>x</code>和以... <code>class</code>开头的属性值<code>section</code>。</p> </li> <li> <p style="margin-left:0px;">可以从<code>@</code>(XPath样式)和不带(jQuery样式)开始指定属性。所以<code>x[z='v']</code>相当于<code>x[@z='v']</code>。</p> </li> <li> <p style="margin-left:0px;">多属性修饰符既可以与<code>and</code>(XPath样式)连接,也可以通过链接多个修饰符(jQuery样式)来连接。所以<code>x[@z1='v1' and @z2='v2']</code>实际上相当于<code>x[@z1='v1'][@z2='v2']</code>(也是<code>x[z1='v1'][z2='v2']</code>)。</p> </li> </ul> <p style="margin-left:0px;"><em>类似jQuery的</em>直接选择器:</p> <ul style="margin-left:2em;"> <li> <p style="margin-left:0px;"><code>x.oneclass</code>相当于<code>x[class='oneclass']</code>。</p> </li> <li> <p style="margin-left:0px;"><code>.oneclass</code>相当于<code>[class='oneclass']</code>。</p> </li> <li> <p style="margin-left:0px;"><code>x#oneid</code>相当于<code>x[id='oneid']</code>。</p> </li> <li> <p style="margin-left:0px;"><code>#oneid</code>相当于<code>[id='oneid']</code>。</p> </li> <li> <p style="margin-left:0px;"><code>x%oneref</code>表示<code><x></code>具有<code>th:ref="oneref"</code>或<code>th:fragment="oneref"</code>属性的标记。</p> </li> <li> <p style="margin-left:0px;"><code>%oneref</code>表示具有<code>th:ref="oneref"</code>或<code>th:fragment="oneref"</code>属性的任何标记。请注意,这实际上相当于<code>oneref</code>因为可以使用引用而不是元素名称。</p> </li> <li> <p style="margin-left:0px;">直接选择器和属性选择器可以混合使用:<code>a.external[@href^='https']</code>。</p> </li> </ul> <p style="margin-left:0px;">所以上面的Markup Selector表达式:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:insert</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>mytemplate :: //div[@class<span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">'</span>content<span style="color:#b9bdb6;">'</span>]<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">可以写成:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:insert</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>mytemplate :: div.content<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">检查一个不同的例子,这个:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:replace</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>mytemplate :: myfrag<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">将寻找<code>th:fragment="myfrag"</code>片段签名(或<code>th:ref</code>引用)。但是<code>myfrag</code>如果它们存在的话,它们也会寻找带有名称的标签(它们不是HTML格式的标签)。注意区别:</p> <pre><code class="language-html"> <code class="language-html"><span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"><</span>div</span> <span style="color:#e0e8ff;">th:replace</span><span style="color:#99cc33;"><span style="color:#b9bdb6;">=</span><span style="color:#b9bdb6;">"</span>mytemplate :: .myfrag<span style="color:#b9bdb6;">"</span></span><span style="color:#b9bdb6;">></span></span>...<span style="color:#8bd1ff;"><span style="color:#8bd1ff;"><span style="color:#b9bdb6;"></</span>div</span><span style="color:#b9bdb6;">></span></span></code></code></pre> <p style="margin-left:0px;">...实际上会查找任何元素<code>class="myfrag"</code>,而不关心<code>th:fragment</code>签名(或<code>th:ref</code>引用)。</p> <h3 id="%E5%A4%9A%E5%80%BC%E7%B1%BB%E5%8C%B9%E9%85%8D" style="margin-left:0px;"><em><strong>多值类匹配</strong></em></h3> <p style="margin-left:0px;">标记选择器将类属性理解为<strong>多值</strong>,因此即使元素具有多个类值,也允许在此属性上应用选择器。</p> <p style="margin-left:0px;">例如,<code>div.two</code>将匹配<code><div class="one two three" /></code></p> <p><span style="color:#3399ea;">本文翻译自:Thymeleaf[官方]文档</span></p> <p>https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html</p> <p style="margin-left:0px;"> </p> </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1287612608202977280"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(Thymeleaf)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1834231934142738432.htm" title="Springboot2 thymeleaf 静态资源加版本号控制缓存更新" target="_blank">Springboot2 thymeleaf 静态资源加版本号控制缓存更新</a> <span class="text-muted">VIAE</span> <div>最近写了一个前后端不分离的项目了,用的Springboot2thymeleaf用的js原生,没有用到webpack,所以不能在每次js变更以后打包自动给静态文件加上hash后缀关于静态资源缓存不更新的问题,用了以下几种解决方案方法一在静态资源引用的时候加上版本号,最开始我就是这么做的,因为当时确实没几个文件index.htmlbug:文件多了以后,这种方法就不太适合了方法二动态添加静态资源,加时间</div> </li> <li><a href="/article/1833930517116973056.htm" title="SpringBoot:Thymeleaf集成" target="_blank">SpringBoot:Thymeleaf集成</a> <span class="text-muted">dingcho</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/SpringCloud/1.htm">SpringCloud</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/Thymeleaf%E9%9B%86%E6%88%90/1.htm">Thymeleaf集成</a> <div>org.springframework.bootspring-boot-starter-thymeleaf配置ClassLoaderTemplateResolver:/***Function:todo**@program:TemplateConfig*@Package:com.kingbal.tohtml.tst*@author:dingcho*@date:2024/09/06*@version:</div> </li> <li><a href="/article/1833921819556540416.htm" title="毕设/私活/bigold必备项目,一个挣钱的免费的全开源标准前后端分离后台管理权限系统【springboot+vue+redis+Spring Security】脚手架搭建:若依Ruo框架具体使用教程" target="_blank">毕设/私活/bigold必备项目,一个挣钱的免费的全开源标准前后端分离后台管理权限系统【springboot+vue+redis+Spring Security】脚手架搭建:若依Ruo框架具体使用教程</a> <span class="text-muted">南北极之间</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/1.htm">前端开发</a><a class="tag" taget="_blank" href="/search/springboot/1.htm">springboot</a><a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a><a class="tag" taget="_blank" href="/search/springboot%2Bvue/1.htm">springboot+vue</a><a class="tag" taget="_blank" href="/search/%E5%85%8D%E8%B4%B9%E5%90%8E%E5%8F%B0%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F/1.htm">免费后台管理系统</a><a class="tag" taget="_blank" href="/search/%E6%AF%95%E4%B8%9A%E7%A7%81%E6%B4%BB%E5%90%8E%E5%8F%B0%E6%9D%83%E9%99%90%E7%B3%BB%E7%BB%9F/1.htm">毕业私活后台权限系统</a> <div>【建议收藏】毕设/私活/大佬必备,一个挣钱的标准开源前后端分离【springboot+vue+redis+SpringSecurity】脚手架一个免费的开源后台管理系统:若依框架(具体使用教程:具体怎样下载?怎样使用?怎样配置后台接口地址?超详细)简介RuoYi是一个JavaEE企业级快速开发平台,基于经典技术组合(SpringBoot、ApacheShiro、MyBatis、Thymeleaf、</div> </li> <li><a href="/article/1833694371300601856.htm" title="基于spring boot的旅游管理系统" target="_blank">基于spring boot的旅游管理系统</a> <span class="text-muted">鹿屿二向箔</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/%E6%97%85%E6%B8%B8/1.htm">旅游</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>一个简单的SpringBoot应用的基础结构示例,以及如何设置一个基本的旅游管理系统。这个例子将包含用户注册和登录的基本功能。首先,你需要设置一个新的SpringBoot项目。可以通过SpringInitializr网站(https://start.spring.io/)来快速生成一个基础项目结构,选择必要的依赖项,比如Web、Thymeleaf、SpringDataJPA和MySQLDriver</div> </li> <li><a href="/article/1833583548318183424.htm" title="SpringMVC的架构有什么优势?——视图与模型(二)" target="_blank">SpringMVC的架构有什么优势?——视图与模型(二)</a> <span class="text-muted">不会编程的小孩子</span> <a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a> <div>#SpringMVC的架构有什么优势?——视图与模型(二)前言关键字:机器学习人工智能AIchatGPT学习实现使用搭建深度python事件远程dockermysql安全技术部署技术自动化代码视图(View)视图是展示结果的组件,它们负责渲染模型数据并生成HTML输出。SpringMVC支持多种视图技术,包括JSP、Thymeleaf等。视图(View)是SpringMVC中渲染并呈现结果的组件,</div> </li> <li><a href="/article/1831182475678806016.htm" title="springboot使用thymeleaf" target="_blank">springboot使用thymeleaf</a> <span class="text-muted">汤飞</span> <a class="tag" taget="_blank" href="/search/springboot/1.htm">springboot</a> <div>1.引入依赖        org.springframework.boot        spring‐boot‐starter‐thymeleaf        3.0.9.RELEASE        2.2.2thymeleaf会自动渲染resource/templates下的html文件,静态资源存放在resource/static中2.新建测试htmlTitle这是显示欢迎信息id:n</div> </li> <li><a href="/article/1829742874372173824.htm" title="Springboot+Mybatis+jpa+thymeleaf实现增删改查" target="_blank">Springboot+Mybatis+jpa+thymeleaf实现增删改查</a> <span class="text-muted">柒麒</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a> <div>Springboot+Mybatis+jpa+thymeleaf项目结构pom文件Application配置文件实体类controller层实现类service层接口service层实现类dao层接口启动类index.html首页add.html添加页面update.html更新页面创建user表添加表数据首页展示添加修改删除总结项目结构pom文件配置相关依赖:UTF-8UTF-81.8org.s</div> </li> <li><a href="/article/1828994825433739264.htm" title="项目在idea中运行正常,打包jar后运行就报错Template might not exist or might not be accessible的解决方法" target="_blank">项目在idea中运行正常,打包jar后运行就报错Template might not exist or might not be accessible的解决方法</a> <span class="text-muted">技术菜鸟—淡定万</span> <a class="tag" taget="_blank" href="/search/Springboot/1.htm">Springboot</a><a class="tag" taget="_blank" href="/search/Java/1.htm">Java</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/maven/1.htm">maven</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a> <div>报错情况[http-nio-80-exec-15]ERRORo.t.TemplateEngine-[process,1136]-[THYMELEAF][http-nio-80-exec</div> </li> <li><a href="/article/1759754472554328064.htm" title="SpringBoot常见问题" target="_blank">SpringBoot常见问题</a> <span class="text-muted">一朝风月S</span> <a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95%E5%AE%9D%E5%85%B8/1.htm">面试宝典</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>1引言SpringBoot是一个基于Spring框架的快速开发脚手架,它简化了Spring应用的初始化和搭建过程,提供了众多便利的功能和特性,比如自动配置、嵌入式Tomcat等,让开发人员可以更加专注于业务逻辑的实现。  SpringBoot还提供了强大的插件体系和广泛的集成,可以轻松地与其他技术栈集成,比如Thymeleaf模板、JPA、MyBatis、Redis、MongoDB等,同时也支持对</div> </li> <li><a href="/article/1759602704864342016.htm" title="2.18日学习打卡----初学Dubbo(三)" target="_blank">2.18日学习打卡----初学Dubbo(三)</a> <span class="text-muted">中北萌新程序员</span> <a class="tag" taget="_blank" href="/search/%E6%AF%8F%E6%97%A5%E5%AD%A6%E4%B9%A0/1.htm">每日学习</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/dubbo/1.htm">dubbo</a> <div>2.18日学习打卡目录:2.18日学习打卡Dubbo实战项目介绍创建dubbo_parent父项目创建子项目user_api项目创建子项目user_consumer项目创建子项目user_provider项目模块用户实体类构建创建添加用户接口查询用户业务接口更新用户业务接口删除用户业务接口集成Thymeleaf用户添加业务消费者实现用户查询业务消费者实现在Consumer中调用更新用户业务用户删除</div> </li> <li><a href="/article/1759573664543633408.htm" title="【Java】电子凭证-Java生成PDF" target="_blank">【Java】电子凭证-Java生成PDF</a> <span class="text-muted">hkk666123</span> <a class="tag" taget="_blank" href="/search/Java/1.htm">Java</a><a class="tag" taget="_blank" href="/search/HTML/1.htm">HTML</a><a class="tag" taget="_blank" href="/search/%E8%BD%AC/1.htm">转</a><a class="tag" taget="_blank" href="/search/PDF/1.htm">PDF</a><a class="tag" taget="_blank" href="/search/htmlTOPDF/1.htm">htmlTOPDF</a> <div>文章目录背景实现思路技术方案图TemplateEngines(模板引擎)`Thymeleaf``ApacheFreemarker``GroovyTemplates``velocity``HTMLTOPDF`技术各实现对比表WKhtmlTOpdfiTextPhantomJS技术核心:HTML生成PDF背景在某些业务场景中,需要提供相关的电子凭证,比如网银/支付宝中转账的电子回单,签约的电子合同等。方</div> </li> <li><a href="/article/1759558451224211456.htm" title="JAVA后端主流开发框架" target="_blank">JAVA后端主流开发框架</a> <span class="text-muted">理查德.克莱德曼</span> <a class="tag" taget="_blank" href="/search/JavaWeb/1.htm">JavaWeb</a><a class="tag" taget="_blank" href="/search/SpringBoot/1.htm">SpringBoot</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>项目介绍一款Java语言基于SpringBoot2.x、Layui、Thymeleaf、MybatisPlus、Shiro、MySQL等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架,可用于快速搭建后台管理系统,本着简化开发、提升开发效率的初衷,框架自研了一套个性化的组件,实现了可插拔的组件式开发方式:单图上传、多图上传、下拉选择、开关按钮、单选按钮、多选按钮、图片裁剪、富文</div> </li> <li><a href="/article/1759550778600681472.htm" title="详解Springboot整合Shiro加盐加散列实现登陆注册小案例" target="_blank">详解Springboot整合Shiro加盐加散列实现登陆注册小案例</a> <span class="text-muted">鱼小洲</span> <a class="tag" taget="_blank" href="/search/%E6%8A%80%E6%9C%AF%E6%9D%82%E8%B0%88/1.htm">技术杂谈</a><a class="tag" taget="_blank" href="/search/shiro/1.htm">shiro</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a><a class="tag" taget="_blank" href="/search/hash/1.htm">hash</a><a class="tag" taget="_blank" href="/search/springboot/1.htm">springboot</a><a class="tag" taget="_blank" href="/search/boot-shiro/1.htm">boot-shiro</a> <div>前言Springboot和Shiro的基本介绍我就不多说了,能看到这篇文章的相信也都会用。这篇文章主要是分享一下我在学习Shiro和Springboot的整合的小阶段。目前是复习,很感谢B站的up主——编程不良人的视频让我有了一个学习Shiro的基本方向。目前是实现了用户认证的功能。依赖整合的时候使用的是jsp,其实和thymeleaf一个道理,而且不涉及到作用域传值。我们需要导入的依赖有:mys</div> </li> <li><a href="/article/1757341799661191168.htm" title="基于JAVA+Springboot+Thymeleaf前后端分离项目:在线婚纱租赁系统设计与实现" target="_blank">基于JAVA+Springboot+Thymeleaf前后端分离项目:在线婚纱租赁系统设计与实现</a> <span class="text-muted">黄菊华老师</span> <a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F%E6%88%90%E5%93%81/1.htm">计算机系统成品</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E5%9C%A8%E7%BA%BF%E5%A9%9A%E7%BA%B1%E7%A7%9F%E8%B5%81%E7%B3%BB%E7%BB%9F/1.htm">在线婚纱租赁系统</a> <div>博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。所有项目都配有从入门到精通的基础知识视频课程,学习后应对毕业设计答辩。项目配有对应开发文档、开题报告、任务书、PPT、论文模版等项目都录了发布和功能操作演示视频;项目的界面和功能都可以定制,包安装运行!!!如果需要联系我,可以在CSD</div> </li> <li><a href="/article/1757214626006712320.htm" title="新手入门------SpringBoot文件上传实现" target="_blank">新手入门------SpringBoot文件上传实现</a> <span class="text-muted">布吉岛-</span> <a class="tag" taget="_blank" href="/search/%E5%85%A5%E9%97%A8SpringBoot/1.htm">入门SpringBoot</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/idea/1.htm">idea</a> <div>本次的内容是实现文件上传,小案例要达到的效果是在浏览器选择好文件,然后上传,最后返回结果(失败或成功),分为单文件和多文件上传。一.案例准备首先还是进行springboot项目的创建,这个就不进行演示了。本次需要添加的依赖是springweb和thymeleaf。如果已经有项目但是没有选择这两个依赖,可以点击pom.xml,在中手动添加如下依赖:org.springframework.bootsp</div> </li> <li><a href="/article/1757214621946626048.htm" title="java入门-springboot整合mybatis+layui" target="_blank">java入门-springboot整合mybatis+layui</a> <span class="text-muted">wwwzhouzy</span> <a class="tag" taget="_blank" href="/search/java%E5%85%A5%E9%97%A8/1.htm">java入门</a><a class="tag" taget="_blank" href="/search/java%E8%BF%9B%E9%98%B6-%E6%A1%86%E6%9E%B6%E7%AF%87/1.htm">java进阶-框架篇</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/ssm/1.htm">ssm</a><a class="tag" taget="_blank" href="/search/layui/1.htm">layui</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a><a class="tag" taget="_blank" href="/search/springboot/1.htm">springboot</a> <div>源码地址:https://codechina.csdn.net/wwwzhouzy/springboot-ssm先看看项目启动,访问页面的效果图:需要注意的地方:1、引入layui相关资源文件时注意路径,尤其是引用Thymeleaf标签时静态资源默认从static目录下查找2、注意json传送数据的编码问题,不然会有乱码继承WebMvcConfigurationSupport类,重写方法:@Bea</div> </li> <li><a href="/article/1757015522777513984.htm" title="Spring Boot 与 Kotlin 使用JdbcTemplate连接MySQL" target="_blank">Spring Boot 与 Kotlin 使用JdbcTemplate连接MySQL</a> <span class="text-muted">全科</span> <div>之前介绍了一些Web层的例子,包括构建RESTfulAPI、使用Thymeleaf模板引擎渲染Web视图,但是这些内容还不足以构建一个动态的应用。通常我们做App也好,做Web应用也好,都需要内容,而内容通常存储于各种类型的数据库,服务端在接收到访问请求之后需要访问数据库获取并处理成展现给用户使用的数据形式。本文介绍在SpringBoot基础下配置数据源和通过JdbcTemplate编写数据访问的</div> </li> <li><a href="/article/1756805116863725568.htm" title="基于Springboot开发实现的图书管理系统(附源码)" target="_blank">基于Springboot开发实现的图书管理系统(附源码)</a> <span class="text-muted">weixin_46668302</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/Springboot/1.htm">Springboot</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%9B%BE%E4%B9%A6%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F/1.htm">图书管理系统</a> <div>图书管理系统,使用当前最为流行的SpringBoot框架,可作为springboot的入门项目练习使用,也可稍加改进做一个毕业设计项目。一、相关技术栈前端:Thymeleaf、Layui、Ajax、JQuery后端:springboot,mybatis开发环境:IDEA、SpringBoot2.3、Maven数据库:MySQL5.7默认用户当您运行初始脚本后,默认存在以下用户,便于测试:登录名密码</div> </li> <li><a href="/article/1756327896160419840.htm" title="Java高并发秒杀系统总结" target="_blank">Java高并发秒杀系统总结</a> <span class="text-muted">成为更好的qyk嘻嘻</span> <a class="tag" taget="_blank" href="/search/Redis/1.htm">Redis</a><a class="tag" taget="_blank" href="/search/SpringBoot/1.htm">SpringBoot</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>项目框架搭建:1.SpringBoot环境搭建2.集成thymeleaf,封装公共返回beanRespBean3.MybatisPlus分布式会话:1.用户登录a.设计数据库b.明文密码二次MD5加密c.参数校验+全局异常处理2.共享Sessiona.redis功能开发:1.商品列表2.商品详情3.秒杀4.订单详情系统压测:1.JMeter2.自定义变量模拟多用户3.正式压测a.商品列表b.秒杀页</div> </li> <li><a href="/article/1756275882579738624.htm" title="【Bug解决】themleaf 相对路径引用 js 静态文件失效" target="_blank">【Bug解决】themleaf 相对路径引用 js 静态文件失效</a> <span class="text-muted">wzz2333</span> <a class="tag" taget="_blank" href="/search/bug/1.htm">bug</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>原生HTML文件test.html:测试项目结构:使用SpringBoot+themleaf模板后,位于相对路径处../scripts/目录下的js文件无法成功加载,导致echarts绘制的词云图未显示。解决方案:在标签中添加xmlns:th="http://www.thymeleaf.org",这是使用Thymeleaf所必需的。标签中的src属性替换为th:src,并使用@{}语法来指定资源的</div> </li> <li><a href="/article/1756017026389786624.htm" title="【SpringBoot】SpringBoot+mysql+thymeleaf+mybatis实现一个Demo" target="_blank">【SpringBoot】SpringBoot+mysql+thymeleaf+mybatis实现一个Demo</a> <span class="text-muted">谦风(主Java)(接口开发)</span> <a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/SpringBoot/1.htm">SpringBoot</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a><a class="tag" taget="_blank" href="/search/ajax/1.htm">ajax</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a> <div>SpringBoot的数据库连接配置已经在上一篇博客说完啦,现在我们来进行一个Demo的实现,我们使用到的是SpringBoot+mysql+thymeleaf+mybatis首先先看一下我Demo程序的格局:我们逐步来看,首先要在数据库建表,这就不用多说了,我的user表对应的是User类属性packagecom.mybatis.demo.po;publicclassUser{privatein</div> </li> <li><a href="/article/1755616167902330880.htm" title="SpringBoot整合Thymeleaf模板引擎" target="_blank">SpringBoot整合Thymeleaf模板引擎</a> <span class="text-muted">天乔巴夏丶</span> <div>[toc]SpringBoot整合Thymeleaf零、本片要点介绍Thymeleaf的概念,理解Thymeleaf的便利且强大。介绍如何快速整合SpringBoot和Thymeleaf。介绍自动配置原理。一、Thymeleaf简介Thymeleaf是适用于Web和独立环境的现代服务器端Java模板引擎,能够处理HTML,XML,JavaScript,CSS甚至纯文本。Thymeleaf的主要目标</div> </li> <li><a href="/article/1755535022959378432.htm" title="哆啦A梦主题网站(HTML5+CSS3+Javascript)" target="_blank">哆啦A梦主题网站(HTML5+CSS3+Javascript)</a> <span class="text-muted">cycyong</span> <a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/html5/1.htm">html5</a><a class="tag" taget="_blank" href="/search/css3/1.htm">css3</a> <div>哆啦A梦主题网站1简介2技术介绍3项目演示和获取方式4打开方式5页面图片展示6部分代码展示1简介作为一名哆啦A梦的粉丝,也可以说是哆啦A梦的爱好者。我小时候特别喜欢看哆啦A梦的动画片,因此上大一的时候突发奇想做一个关于小哆啦的主题网站,以此致敬。2技术介绍本项目全程采用HTML5进行编写,有能力的小伙伴也可以将其改成Thymeleaf做成动态网站,静态资源等文件都是齐全的。HTML5CSS3Jav</div> </li> <li><a href="/article/1755476613031542784.htm" title="Springboot实现文件上传" target="_blank">Springboot实现文件上传</a> <span class="text-muted">Joe14103</span> <a class="tag" taget="_blank" href="/search/%E5%B8%B8%E7%94%A8%E4%BB%A3%E7%A0%81%E5%9D%97%E4%B8%8E%E7%AC%94%E8%AE%B0/1.htm">常用代码块与笔记</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/upload/1.htm">upload</a><a class="tag" taget="_blank" href="/search/intellij/1.htm">intellij</a><a class="tag" taget="_blank" href="/search/idea/1.htm">idea</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a> <div>一、新建Springboot项目并配置1.pom.xml核心依赖org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-thymeleaf2.全局配置文件application.yml,注意yml文件格式spring:servlet:multipart:max-file-s</div> </li> <li><a href="/article/1755396578937421824.htm" title="基于javaweb+mysql的springboot前台+后台在线考试系统设计和实现(java+springboot+ssm+mysql+thymeleaf+html+maven)" target="_blank">基于javaweb+mysql的springboot前台+后台在线考试系统设计和实现(java+springboot+ssm+mysql+thymeleaf+html+maven)</a> <span class="text-muted">m0_71046928</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a> <div>基于javaweb+mysql的springboot前台+后台在线考试系统设计和实现(java+springboot+ssm+mysql+thymeleaf+html+maven)运行环境Java≥8、MySQL≥5.7开发工具eclipse/idea/myeclipse/sts等均可配置运行适用课程设计,大作业,毕业设计,项目练习,学习演示等功能说明基于javaweb+mysql的SpringB</div> </li> <li><a href="/article/1755359783151484928.htm" title="SpringBoot+MyBatisPlus+thymeleaf增删改查" target="_blank">SpringBoot+MyBatisPlus+thymeleaf增删改查</a> <span class="text-muted">dxjzs</span> <a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a> <div>SpringBoot+MyBatisPlus+thymeleaf增删改查一、基本介绍建议在写之前会熟练使用vue脚手架,以及掌握vue相关知识本文章会教你构建一个springboot+mybatisplus+thymeleaf+mysql的增删改查二、数据层1.导入SQL数据库名称edocmanagement/*NavicatPremiumDataTransferSourceServer:loca</div> </li> <li><a href="/article/1755340262835503104.htm" title="springboot Thymeleaf基本使用" target="_blank">springboot Thymeleaf基本使用</a> <span class="text-muted">忘忧记</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>文章目录什么是Thymeleaf集成Thymeleaf模板引入依赖编辑配置编写controller测试访问Thymeleaf基础用法1).html文件使用thymeleaf语法必须导入thymeleaf的头才能使用相关语法2).在html中通过thymeleaf语法获取数据获取单个属性获取对象属性传递集合对象传递条件对象获取session作用域Thymeleaf如何引入静态资源使用thymelea</div> </li> <li><a href="/article/1755340263879884800.htm" title="springboot基础案例(二)" target="_blank">springboot基础案例(二)</a> <span class="text-muted">忘忧记</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>文章目录前言一.需求分析:分析这个项目含有哪些功能模块二.库表设计(概要设计):1.分析系统有哪些表2.分析表与表关系3.确定表中字段(显性字段隐性字段(业务字段))2.1创建一个库:ems-thymeleaf2.2创建2张表三.编码(环境搭建)1.创建一个springboot项目项目名字:ems-thymeleaf2.修改配置文件为application.ymlpom.xml3.修改端口9999</div> </li> <li><a href="/article/1755266756949065728.htm" title="SpringBoot:web开发" target="_blank">SpringBoot:web开发</a> <span class="text-muted">ChinaDragonDreamer</span> <a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/Spring/1.htm">Spring</a><a class="tag" taget="_blank" href="/search/Boot/1.htm">Boot</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a><a class="tag" taget="_blank" href="/search/bootstrap/1.htm">bootstrap</a> <div>web开发demo:点击查看LearnSpringBoot05Web点击查看更多的SpringBoot教程技术摘要webjarsBootstrap模板引擎thymeleaf嵌入式Servlet容器注册web三大组件一、webjarswebjars官网简介简介翻译WebJars是打包到JAR(JavaArchive)文件中的客户端Web库(例如jQuery和Bootstrap)。显式且轻松地管理基于</div> </li> <li><a href="/article/1755170923612225536.htm" title="【Java】使用springbook、thymeleaf、mybatis、mysql等技术实现员工管理系统的制作" target="_blank">【Java】使用springbook、thymeleaf、mybatis、mysql等技术实现员工管理系统的制作</a> <span class="text-muted">db_lcz_2014</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a> <div>目录一、项目搭建二、项目实现2.1项目结构:2.2Controller层2.3model层2.4repository层2.5service层EmployeeService接口:EmployeeServiceImpl类:三、效果图展示(部分)四、学习心得一、项目搭建1、因要打印文档,故仅展示部分代码,详细请看代码源或者csdn博客网站2、项目搭建用到的技术是:springbook、thymeleaf</div> </li> <li><a href="/article/103.htm" title="SAX解析xml文件" target="_blank">SAX解析xml文件</a> <span class="text-muted">小猪猪08</span> <a class="tag" taget="_blank" href="/search/xml/1.htm">xml</a> <div>1.创建SAXParserFactory实例 2.通过SAXParserFactory对象获取SAXParser实例 3.创建一个类SAXParserHander继续DefaultHandler,并且实例化这个类 4.SAXParser实例的parse来获取文件     public static void main(String[] args) { //</div> </li> <li><a href="/article/230.htm" title="为什么mysql里的ibdata1文件不断的增长?" target="_blank">为什么mysql里的ibdata1文件不断的增长?</a> <span class="text-muted">brotherlamp</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/linux%E8%BF%90%E7%BB%B4/1.htm">linux运维</a><a class="tag" taget="_blank" href="/search/linux%E8%B5%84%E6%96%99/1.htm">linux资料</a><a class="tag" taget="_blank" href="/search/linux%E8%A7%86%E9%A2%91/1.htm">linux视频</a><a class="tag" taget="_blank" href="/search/linux%E8%BF%90%E7%BB%B4%E8%87%AA%E5%AD%A6/1.htm">linux运维自学</a> <div>我们在 Percona 支持栏目经常收到关于 MySQL 的 ibdata1 文件的这个问题。 当监控服务器发送一个关于 MySQL 服务器存储的报警时,恐慌就开始了 —— 就是说磁盘快要满了。 一番调查后你意识到大多数地盘空间被 InnoDB 的共享表空间 ibdata1 使用。而你已经启用了 innodbfileper_table,所以问题是: ibdata1存了什么? 当你启用了 i</div> </li> <li><a href="/article/357.htm" title="Quartz-quartz.properties配置" target="_blank">Quartz-quartz.properties配置</a> <span class="text-muted">eksliang</span> <a class="tag" taget="_blank" href="/search/quartz/1.htm">quartz</a> <div>其实Quartz JAR文件的org.quartz包下就包含了一个quartz.properties属性配置文件并提供了默认设置。如果需要调整默认配置,可以在类路径下建立一个新的quartz.properties,它将自动被Quartz加载并覆盖默认的设置。   下面是这些默认值的解释 #-----集群的配置 org.quartz.scheduler.instanceName =</div> </li> <li><a href="/article/484.htm" title="informatica session的使用" target="_blank">informatica session的使用</a> <span class="text-muted">18289753290</span> <a class="tag" taget="_blank" href="/search/workflow/1.htm">workflow</a><a class="tag" taget="_blank" href="/search/session/1.htm">session</a><a class="tag" taget="_blank" href="/search/log/1.htm">log</a><a class="tag" taget="_blank" href="/search/Informatica/1.htm">Informatica</a> <div>如果希望workflow存储最近20次的log,在session里的Config  Object设置,log  options做配置,save  session log :sessions  run  ;savesessio log for  these runs:20 session下面的source 里面有个tracing </div> </li> <li><a href="/article/611.htm" title="Scrapy抓取网页时出现CRC check failed 0x471e6e9a != 0x7c07b839L的错误" target="_blank">Scrapy抓取网页时出现CRC check failed 0x471e6e9a != 0x7c07b839L的错误</a> <span class="text-muted">酷的飞上天空</span> <a class="tag" taget="_blank" href="/search/scrapy/1.htm">scrapy</a> <div>Scrapy版本0.14.4 出现问题现象: ERROR: Error downloading <GET http://xxxxx  CRC check failed   解决方法   1.设置网络请求时的header中的属性'Accept-Encoding': '*;q=0'   明确表示不支持任何形式的压缩格式,避免程序的解压</div> </li> <li><a href="/article/738.htm" title="java Swing小集锦" target="_blank">java Swing小集锦</a> <span class="text-muted">永夜-极光</span> <a class="tag" taget="_blank" href="/search/java+swing/1.htm">java swing</a> <div>1.关闭窗体弹出确认对话框   1.1   this.setDefaultCloseOperation (JFrame.DO_NOTHING_ON_CLOSE);   1.2   this.addWindowListener ( new WindowAdapter () { public void windo</div> </li> <li><a href="/article/865.htm" title="强制删除.svn文件夹" target="_blank">强制删除.svn文件夹</a> <span class="text-muted">随便小屋</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>          在windows上,从别处复制的项目中可能带有.svn文件夹,手动删除太麻烦,并且每个文件夹下都有。所以写了个程序进行删除。因为.svn文件夹在windows上是只读的,所以用File中的delete()和deleteOnExist()方法都不能将其删除,所以只能采用windows命令方式进行删除</div> </li> <li><a href="/article/992.htm" title="GET和POST有什么区别?及为什么网上的多数答案都是错的。" target="_blank">GET和POST有什么区别?及为什么网上的多数答案都是错的。</a> <span class="text-muted">aijuans</span> <a class="tag" taget="_blank" href="/search/get+post/1.htm">get post</a> <div>     如果有人问你,GET和POST,有什么区别?你会如何回答? 我的经历      前几天有人问我这个问题。我说GET是用于获取数据的,POST,一般用于将数据发给服务器之用。     这个答案好像并不是他想要的。于是他继续追问有没有别的区别?我说这就是个名字而已,如果服务器支持,他完全可以把G</div> </li> <li><a href="/article/1119.htm" title="谈谈新浪微博背后的那些算法" target="_blank">谈谈新浪微博背后的那些算法</a> <span class="text-muted">aoyouzi</span> <a class="tag" taget="_blank" href="/search/%E8%B0%88%E8%B0%88%E6%96%B0%E6%B5%AA%E5%BE%AE%E5%8D%9A%E8%83%8C%E5%90%8E%E7%9A%84%E9%82%A3%E4%BA%9B%E7%AE%97%E6%B3%95/1.htm">谈谈新浪微博背后的那些算法</a> <div>本文对微博中常见的问题的对应算法进行了简单的介绍,在实际应用中的算法比介绍的要复杂的多。当然,本文覆盖的主题并不全,比如好友推荐、热点跟踪等就没有涉及到。但古人云“窥一斑而见全豹”,希望本文的介绍能帮助大家更好的理解微博这样的社交网络应用。 微博是一个很多人都在用的社交应用。天天刷微博的人每天都会进行着这样几个操作:原创、转发、回复、阅读、关注、@等。其中,前四个是针对短博文,最后的关注和@则针</div> </li> <li><a href="/article/1246.htm" title="Connection reset 连接被重置的解决方法" target="_blank">Connection reset 连接被重置的解决方法</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%AD%97%E7%AC%A6%E6%B5%81/1.htm">字符流</a><a class="tag" taget="_blank" href="/search/%E8%BF%9E%E6%8E%A5%E8%A2%AB%E9%87%8D%E7%BD%AE/1.htm">连接被重置</a> <div>流是java的核心部分,,昨天在做android服务器连接服务器的时候出了问题,就将代码放到java中执行,结果还是一样连接被重置   被重置的代码如下;   客户端代码; package 通信软件服务器; import java.io.BufferedWriter; import java.io.OutputStream; import java.io.O</div> </li> <li><a href="/article/1373.htm" title="web.xml配置详解之filter" target="_blank">web.xml配置详解之filter</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/web.xml/1.htm">web.xml</a><a class="tag" taget="_blank" href="/search/filter/1.htm">filter</a> <div>一.定义 <filter> <filter-name>encodingfilter</filter-name> <filter-class>com.my.app.EncodingFilter</filter-class> <init-param> <param-name>encoding<</div> </li> <li><a href="/article/1500.htm" title="Heritrix" target="_blank">Heritrix</a> <span class="text-muted">Bill_chen</span> <a class="tag" taget="_blank" href="/search/%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">多线程</a><a class="tag" taget="_blank" href="/search/xml/1.htm">xml</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E5%88%B6%E9%80%A0/1.htm">制造</a><a class="tag" taget="_blank" href="/search/%E9%85%8D%E7%BD%AE%E7%AE%A1%E7%90%86/1.htm">配置管理</a> <div>作为纯Java语言开发的、功能强大的网络爬虫Heritrix,其功能极其强大,且扩展性良好,深受热爱搜索技术的盆友们的喜爱,但它配置较为复杂,且源码不好理解,最近又使劲看了下,结合自己的学习和理解,跟大家分享Heritrix的点点滴滴。 Heritrix的下载(http://sourceforge.net/projects/archive-crawler/)安装、配置,就不罗嗦了,可以自己找找资</div> </li> <li><a href="/article/1627.htm" title="【Zookeeper】FAQ" target="_blank">【Zookeeper】FAQ</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/zookeeper/1.htm">zookeeper</a> <div>1.脱离IDE,运行简单的Java客户端程序 #ZkClient是简单的Zookeeper~$ java -cp "./:zookeeper-3.4.6.jar:./lib/*" ZKClient    1. Zookeeper是的Watcher回调是同步操作,需要添加异步处理的代码 2. 如果Zookeeper集群跨越多个机房,那么Leader/</div> </li> <li><a href="/article/1754.htm" title="The user specified as a definer ('aaa'@'localhost') does not exist" target="_blank">The user specified as a definer ('aaa'@'localhost') does not exist</a> <span class="text-muted">白糖_</span> <a class="tag" taget="_blank" href="/search/localhost/1.htm">localhost</a> <div>今天遇到一个客户BUG,当前的jdbc连接用户是root,然后部分删除操作都会报下面这个错误:The user specified as a definer ('aaa'@'localhost') does not exist 最后找原因发现删除操作做了触发器,而触发器里面有这样一句 /*!50017 DEFINER = ''aaa@'localhost' */  原来最初</div> </li> <li><a href="/article/1881.htm" title="javascript中showModelDialog刷新父页面" target="_blank">javascript中showModelDialog刷新父页面</a> <span class="text-muted">bozch</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/%E5%88%B7%E6%96%B0%E7%88%B6%E9%A1%B5%E9%9D%A2/1.htm">刷新父页面</a><a class="tag" taget="_blank" href="/search/showModalDialog/1.htm">showModalDialog</a> <div>在页面中使用showModalDialog打开模式子页面窗口的时候,如果想在子页面中操作父页面中的某个节点,可以通过如下的进行:       window.showModalDialog('url',self,‘status...’); // 首先中间参数使用self       在子页面使用w</div> </li> <li><a href="/article/2008.htm" title="编程之美-买书折扣" target="_blank">编程之美-买书折扣</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BE%8E/1.htm">编程之美</a> <div> import java.util.Arrays; public class BookDiscount { /**编程之美 买书折扣 书上的贪心算法的分析很有意思,我看了半天看不懂,结果作者说,贪心算法在这个问题上是不适用的。。 下面用动态规划实现。 哈利波特这本书一共有五卷,每卷都是8欧元,如果读者一次购买不同的两卷可扣除5%的折扣,三卷10%,四卷20%,五卷</div> </li> <li><a href="/article/2135.htm" title="关于struts2.3.4项目跨站执行脚本以及远程执行漏洞修复概要" target="_blank">关于struts2.3.4项目跨站执行脚本以及远程执行漏洞修复概要</a> <span class="text-muted">chenbowen00</span> <a class="tag" taget="_blank" href="/search/struts/1.htm">struts</a><a class="tag" taget="_blank" href="/search/WEB%E5%AE%89%E5%85%A8/1.htm">WEB安全</a> <div>因为近期负责的几个银行系统软件,需要交付客户,因此客户专门请了安全公司对系统进行了安全评测,结果发现了诸如跨站执行脚本,远程执行漏洞以及弱口令等问题。 下面记录下本次解决的过程以便后续 1、首先从最简单的开始处理,服务器的弱口令问题,首先根据安全工具提供的测试描述中发现应用服务器中存在一个匿名用户,默认是不需要密码的,经过分析发现服务器使用了FTP协议, 而使用ftp协议默认会产生一个匿名用</div> </li> <li><a href="/article/2262.htm" title="[电力与暖气]煤炭燃烧与电力加温" target="_blank">[电力与暖气]煤炭燃烧与电力加温</a> <span class="text-muted">comsci</span> <div>       在宇宙中,用贝塔射线观测地球某个部分,看上去,好像一个个马蜂窝,又像珊瑚礁一样,原来是某个国家的采煤区.....       不过,这个采煤区的煤炭看来是要用完了.....那么依赖将起燃烧并取暖的城市,在极度严寒的季节中...该怎么办呢?   &nbs</div> </li> <li><a href="/article/2389.htm" title="oracle O7_DICTIONARY_ACCESSIBILITY参数" target="_blank">oracle O7_DICTIONARY_ACCESSIBILITY参数</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a> <div>O7_DICTIONARY_ACCESSIBILITY参数控制对数据字典的访问.设置为true,如果用户被授予了如select any table等any table权限,用户即使不是dba或sysdba用户也可以访问数据字典.在9i及以上版本默认为false,8i及以前版本默认为true.如果设置为true就可能会带来安全上的一些问题.这也就为什么O7_DICTIONARY_ACCESSIBIL</div> </li> <li><a href="/article/2516.htm" title="比较全面的MySQL优化参考" target="_blank">比较全面的MySQL优化参考</a> <span class="text-muted">dengkane</span> <a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a> <div>本文整理了一些MySQL的通用优化方法,做个简单的总结分享,旨在帮助那些没有专职MySQL DBA的企业做好基本的优化工作,至于具体的SQL优化,大部分通过加适当的索引即可达到效果,更复杂的就需要具体分析了,可以参考本站的一些优化案例或者联系我,下方有我的联系方式。这是上篇。   1、硬件层相关优化   1.1、CPU相关   在服务器的BIOS设置中,可</div> </li> <li><a href="/article/2643.htm" title="C语言homework2,有一个逆序打印数字的小算法" target="_blank">C语言homework2,有一个逆序打印数字的小算法</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/c/1.htm">c</a> <div>#h1#   0、完成课堂例子 1、将一个四位数逆序打印 1234 ==> 4321 实现方法一: # include <stdio.h> int main(void) { int i = 1234; int one = i%10; int two = i / 10 % 10; int three = i / 100 % 10; </div> </li> <li><a href="/article/2770.htm" title="apacheBench对网站进行压力测试" target="_blank">apacheBench对网站进行压力测试</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/apachebench/1.htm">apachebench</a> <div>   ab 的全称是 ApacheBench , 是 Apache 附带的一个小工具 , 专门用于 HTTP Server 的 benchmark testing , 可以同时模拟多个并发请求。前段时间看到公司的开发人员也在用它作一些测试,看起来也不错,很简单,也很容易使用,所以今天花一点时间看了一下。 通过下面的一个简单的例子和注释,相信大家可以更容易理解这个工具的使用。 </div> </li> <li><a href="/article/2897.htm" title="2种办法让HashMap线程安全" target="_blank">2种办法让HashMap线程安全</a> <span class="text-muted">flyfoxs</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/jdk/1.htm">jdk</a><a class="tag" taget="_blank" href="/search/jni/1.htm">jni</a> <div>多线程之--2种办法让HashMap线程安全 多线程之--synchronized 和reentrantlock的优缺点 多线程之--2种JAVA乐观锁的比较( NonfairSync VS. FairSync)     HashMap不是线程安全的,往往在写程序时需要通过一些方法来回避.其实JDK原生的提供了2种方法让HashMap支持线程安全.   </div> </li> <li><a href="/article/3024.htm" title="Spring Security(04)——认证简介" target="_blank">Spring Security(04)——认证简介</a> <span class="text-muted">234390216</span> <a class="tag" taget="_blank" href="/search/Spring+Security/1.htm">Spring Security</a><a class="tag" taget="_blank" href="/search/%E8%AE%A4%E8%AF%81/1.htm">认证</a><a class="tag" taget="_blank" href="/search/%E8%BF%87%E7%A8%8B/1.htm">过程</a> <div>认证简介 目录 1.1     认证过程 1.2     Web应用的认证过程 1.2.1    ExceptionTranslationFilter 1.2.2    在request之间共享SecurityContext   1</div> </li> <li><a href="/article/3151.htm" title="Java 位运算" target="_blank">Java 位运算</a> <span class="text-muted">Javahuhui</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E4%BD%8D%E8%BF%90%E7%AE%97/1.htm">位运算</a> <div>// 左移( << ) 低位补0 // 0000 0000 0000 0000 0000 0000 0000 0110 然后左移2位后,低位补0: // 0000 0000 0000 0000 0000 0000 0001 1000 System.out.println(6 << 2);// 运行结果是24 // 右移( >> ) 高位补"</div> </li> <li><a href="/article/3278.htm" title="mysql免安装版配置" target="_blank">mysql免安装版配置</a> <span class="text-muted">ldzyz007</span> <a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a> <div>1、my-small.ini是为了小型数据库而设计的。不应该把这个模型用于含有一些常用项目的数据库。 2、my-medium.ini是为中等规模的数据库而设计的。如果你正在企业中使用RHEL,可能会比这个操作系统的最小RAM需求(256MB)明显多得多的物理内存。由此可见,如果有那么多RAM内存可以使用,自然可以在同一台机器上运行其它服务。 3、my-large.ini是为专用于一个SQL数据</div> </li> <li><a href="/article/3405.htm" title="MFC和ado数据库使用时遇到的问题" target="_blank">MFC和ado数据库使用时遇到的问题</a> <span class="text-muted">你不认识的休道人</span> <a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/C%2B%2B/1.htm">C++</a><a class="tag" taget="_blank" href="/search/mfc/1.htm">mfc</a> <div>=================================================================== 第一个 =================================================================== try{ CString sql; sql.Format("select * from p</div> </li> <li><a href="/article/3532.htm" title="表单重复提交Double Submits" target="_blank">表单重复提交Double Submits</a> <span class="text-muted">rensanning</span> <a class="tag" taget="_blank" href="/search/double/1.htm">double</a> <div>可能发生的场景: *多次点击提交按钮 *刷新页面 *点击浏览器回退按钮 *直接访问收藏夹中的地址 *重复发送HTTP请求(Ajax) (1)点击按钮后disable该按钮一会儿,这样能避免急躁的用户频繁点击按钮。 这种方法确实有些粗暴,友好一点的可以把按钮的文字变一下做个提示,比如Bootstrap的做法: http://getbootstrap.co</div> </li> <li><a href="/article/3659.htm" title="Java String 十大常见问题" target="_blank">Java String 十大常见问题</a> <span class="text-muted">tomcat_oracle</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1.htm">正则表达式</a> <div> 1.字符串比较,使用“==”还是equals()?   "=="判断两个引用的是不是同一个内存地址(同一个物理对象)。   equals()判断两个字符串的值是否相等。   除非你想判断两个string引用是否同一个对象,否则应该总是使用equals()方法。   如果你了解字符串的驻留(String Interning)则会更好地理解这个问题。    </div> </li> <li><a href="/article/3786.htm" title="SpringMVC 登陆拦截器实现登陆控制" target="_blank">SpringMVC 登陆拦截器实现登陆控制</a> <span class="text-muted">xp9802</span> <a class="tag" taget="_blank" href="/search/springMVC/1.htm">springMVC</a> <div>思路,先登陆后,将登陆信息存储在session中,然后通过拦截器,对系统中的页面和资源进行访问拦截,同时对于登陆本身相关的页面和资源不拦截。   实现方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 </div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html>