Thymeleaf 中文文档----全译版

文章目录

  • 1 引入Thymeleaf
    • 1.1 Thymeleaf是什么?
    • 1.2 Thymeleaf可以处理什么样的模板?
    • 1.3 方言:标准方言
  • 2 一个很棒的虚拟杂货店设计
    • 2.1 一个杂货店的网站
    • 2.2 创建和配置模板引擎
      • 模板解析器
      • 模板引擎
  • 3 使用文本
    • 3.1 多语言的欢迎
      • 使用`th:text`和 externalizing text
      • 语境(上下文)
      • 执行模板引擎
    • 3.2 有关文本和变量的更多信息
      • 未转义的文本
      • 使用和显示变量
  • 4 标准表达式语法
    • 4.1 消息
    • 4.2 变量
      • 表达式基本对象
      • 表达工具对象
      • 在我们的主页中重新格式化日期
    • 4.3 选择表达式(星号语法)
    • 4.4 链接网址
      • 主页的菜单
      • 服务器根目录相对URL
    • 4.5 碎片
    • 4.6 文本
      • 文字文本
      • 数字文本
      • 布尔文本
      • 空文本
      • 文字代币
    • 4.7 附加文本
    • 4.8 文本替代
    • 4.9 算术运算
    • 4.10 比较器和平等
    • 4.11 条件表达式
    • 4.12 默认表达式(Elvis运算符)
    • 4.13 无操作令牌
    • 4.14 数据转换/格式化
    • 4.15 预处理
  • 5 设置属性值
    • 5.1 设置任何属性的值
    • 5.2 将值设置为特定属性
    • 5.3 一次设置多个值
    • 5.4 追加和前置
    • 5.5 固定值布尔属性
    • 5.6 设置任何属性的值(默认属性处理器)
    • 5.7 支持HTML5友好的属性和元素名称
  • 6 迭代
    • 6.1 迭代基础
      • 每个使用
      • 迭代值
    • 6.2 保持迭代状态
    • 6.3 通过延迟检索数据进行优化
  • 7 条件评估
    • 7.1 简单条件:“如果”和“除非”
    • 7.2 切换语句
  • 8 模板布局
    • 8.1 包括模板片段
      • 定义和引用片段
      • 片段规范语法
      • 引用片段不带 th:fragment
      • th:insert和th:replace(和th:include)之间的差异
    • 8.2 可参数化的片段签名
      • 片段局部变量,不带片段参数
      • 声明模板内断言
    • 8.3 灵活的布局:不仅仅是插入片段
      • 使用空片段
      • 使用无操作令牌
      • 片段的高级条件插入
    • 8.4 删除模板片段
    • 8.5 布局继承
  • 9 局部变量
  • 10 属性优先级
  • 11 注释和块(Comments and Blocks)
    • 11.1 标准HTML / XML注释
    • 11.2 Thymeleaf解析器级注释块
    • 11.3 Thymeleaf仅原型注释块
    • 11.4 合成th:block标签
  • 12 内联
    • 12.1 表达式内联
      • 内联与自然模板
      • 禁用内联
    • 12.2 文字内联
    • 12.3 JavaScript内联
      • JavaScript自然模板
      • 高级内联评估和JavaScript序列化
    • 12.4 CSS内联
      • 进阶功能:CSS自然模板等
  • 13 文字模板模式
    • 13.1 文字语法
      • 转义的元素属性
    • 13.2 可扩展性
    • 13.3 纯文本原型注释块:添加代码
    • 13.4 文本解析器级注释块:删除代码
    • 13.5 自然的JavaScript和CSS模板
  • 14 杂货店的更多页面
    • 14.1 订单清单
    • 14.2 订单明细
  • 15 有关配置的更多信息
    • 15.1 模板解析器
      • 链模板解析器
    • 15.2 邮件解析器
      • 标准消息解析器
      • 配置消息解析器
    • 15.3 转换服务
    • 15.4 记录
  • 16 模板缓存
  • 17 解耦模板逻辑
    • 17.1 解耦逻辑:概念
    • 17.2 配置解耦的模板
      • 启用解耦的模板
      • 混合耦合和解耦逻辑
    • 17.3 `th:ref`属性
    • 17.4 解耦模板的性能影响
    • 17.5 解耦逻辑的解析
  • 18 附录A:表达式基本对象
    • 基础对象
    • 请求/会话属性等的Web上下文名称空间
    • Web上下文对象
  • 19 附录B:Expression Utility对象
    • Execution Info
    • Messages
    • URI / URL
    • Conversions
    • Dates
    • Calendars
    • Numbers
    • Strings
    • Objects
    • Booleans
    • Arrays
    • Lists
    • Sets
    • Maps
    • Aggregates
    • IDs
  • 20 附录C:标记选择器语法
    • 多值类匹配

1 引入Thymeleaf

1.1 Thymeleaf是什么?

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

Thymeleaf的主要目标是提供一种优雅的和高度可维护的方式来创建模板。为了实现这一点,它构建在自然模板的概念上,以不影响模板作为设计原型使用的方式将其逻辑注入模板文件。这改进了设计的交流,并在设计和开发团队之间架起了桥梁。

Thymeleaf的设计从一开始就考虑了Web标准——尤其是HTML5——允许你创建完全验证模板,如果你需要的话。

1.2 Thymeleaf可以处理什么样的模板?

开箱即用,Thymeleaf允许您处理六种模板,其中每一种被称为模板模式:

  • HTML
  • XML
  • TEXT
  • JAVASCRIPT
  • CSS
  • RAW

有两种标记模板模式(HTML和XML)、三种文本模板模式(文本、JAVASCRIPT和CSS)和一种无操作模板模式(RAW)。

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

XML模板模式将允许XML输入。在这种情况下,代码应该是格式良好的—没有未关闭的标记,没有未引用的属性,等等—如果发现格式良好性违规,解析器将抛出异常。注意,将不执行任何验证(针对DTD或XML模式)。

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

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

CSS模板模式将允许处理Thymeleaf应用程序中涉及的CSS文件。与JAVASCRIPT模式类似,CSS模板模式也是一种文本模式,并使用来自文本模板模式的特殊处理语法。

原始模板模式根本不会处理模板。它用于将未触及的资源(文件、URL响应等)插入正在处理的模板中。例如,可以将HTML格式的外部非控制资源包含到应用程序模板中,但要确保这些资源可能包含的任何Thymeleaf代码都不会被执行。

1.3 方言:标准方言

Thymeleaf是一个非常可扩展的模板引擎(事实上它可以被称为模板引擎框架),它允许你定义和自定义的方式,你的模板将被处理到一个精细的细节级别。

将一些逻辑应用到标记工件(标记、一些文本、注释,如果模板不是标记,则仅仅是占位符)的对象称为处理程序,这些处理程序的集合—加上一些额外的工件—通常是方言的组成部分。Thymeleaf的核心库提供了一种称为标准方言的方言,这对大多数用户来说应该足够了。

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

本教程介绍标准方言。在下面的页面中,您将了解到的每个属性和语法特性都是由这种方言定义的,即使没有明确提到。

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

官方thymeleaf-spring3和thymeleaf-spring4集成包都定义一个方言称为“SpringStandard方言”,大部分是一样的标准方言,但小适应更好地利用Spring框架的一些特性(例如,通过使用Spring表达式语言或图像代替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 一个很棒的虚拟杂货店设计

本文所示示例的源代码,以及本指南的后续章节,可以在 Good Thymes Virtual Grocery GitHub repository.

2.1 一个杂货店的网站

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

这个应用程序是一个虚拟杂货店的web站点,它将为我们提供许多场景来展示Thymeleaf的许多特性。

首先,我们的应用程序需要一组简单的模型实体:通过创建订单向客户销售的产品。我们还将管理这些产品的评论:
Thymeleaf 中文文档----全译版_第1张图片

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

public class ProductService {
     
 
    ...
 
    public List<Product> 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 中文文档----全译版_第2张图片

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

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<String, 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对象来管理默认缓存来定义缓存行为和大小。

关于模板解析器还有很多要学习的,但是现在让我们来看看模板引擎对象的创建。

模板引擎

模板引擎对象是org.thymeleaf.ITemplateEngine接口的实现。其中一个实现是由Thymeleaf核心:org.thymeleaf.ITemplateEngine,我们创建了一个实例,它在这里:

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的东西:

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

它在模板处理中没有任何影响,但是作为一个incantation,这就避免了我们的IDE抱怨th:*这些属性缺少命名空间定义。

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


 
<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模板模式(XML,文本…),而数据符号只允许在HTML模式。

使用th:text和 externalizing text

外部化文本是从模板文件中提取模板代码片段,以便将它们保存在单独的文件中(通常是.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将使用基于文件的实现,但是例如,如果我们想从数据库中获取消息,则可以创建自己的实现。

但是,我们尚未在初始化期间为模板引擎指定消息解析器,这意味着我们的应用程序使用的是由实现的 标准消息解析器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<String> 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 有关文本和变量的更多信息

未转义的文本

主页的最简单版本现在似乎已经准备就绪,但是有些事情我们还没有想到……如果我们收到这样的消息怎么办?

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,现在我们可以在模板中显示它:


 
  

Welcome to our grocery store!

Today is: 13 February 2011

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

${today}表达式仅表示“获取今天调用的变量”,但是这些表达式可能更复杂(例如${user.name}“获取称为用户的变量并调用其getName()方法”)。

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

4 标准表达式语法

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

我们已经看到了用这种语法表示的两种有效属性值:消息和变量表达式:

<p th:utext="#{home.welcome}">Welcome to our grocery store!p>
 
<p>Today is: <span th:text="${today}">13 february 2011span>p>

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

  • 简单表达式:
    • 变量表达式: ${…}
    • 选择变量表达式: *{…}
    • 消息表达: #{...}
    • 链接URL表达式: @{…}
    • 片段表达式: ~{…}
  • 文字
    • 文本文字:‘one text’,‘Another one!’,…
    • 号码文字:0,34,3.0,12.3,…
    • 布尔文字:true,false
    • 空文字: null
    • 文字标记:one,sometext,main,…
  • 文字操作:
    • 字符串串联: +
    • 文字替换: |The name is ${name}|
  • 算术运算:
    • 二元运算符:+,-,*,/,%
    • 减号(一元运算符): -
  • 布尔运算:
    • 二元运算符:and,or
    • 布尔否定(一元运算符): !,not
  • 比较和相等:
    • 比较:>,<,>=,<=(gt,lt,ge,le)
    • 等号运算符:==,!=(eq,ne)
  • 条件运算符:
    • 如果-则: (if) ? (then)
    • 如果-则-否则: (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标准语法指定的,这意味着您可以按照API文档中为java.text.*包中类指定的格式格式化数字和日期。

为了给我们的参数指定一个值,并给定一个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允许我们创建功能更强大的表达式,这就是这种方式:

Welcome to our grocery store, Sebastian Pepper!

…通过执行以下操作获取用户名:

((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上下文中)HttpServletRequest对象。
  • #response:(仅在Web上下文中)HttpServletResponse对象。
  • #session:(仅在Web上下文中)HttpSession对象。
  • #servletContext:(仅在Web上下文中)ServletContext对象。

因此,我们可以这样做:

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

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

表达工具对象

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

  • #execInfo:有关正在处理的模板的信息。
  • #messages:用于获取变量表达式内的外部化消息的方法,与使用#{…}语法获得消息的方法相同。
  • #uris:用于转义部分URL / URI的方法
  • #conversions:用于执行已配置的转换服务(如果有)的方法。
  • #datesjava.util.Date对象的方法:格式化,组件提取等。
  • #calendars:类似于#dates,但用于java.util.Calendar对象。
  • #numbers:格式化数字对象的方法。
  • #strings:String对象的方法:包含,startsWith,前置/追加等。
  • #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是Web应用程序模板中的一等公民,而Thymeleaf Standard Dialect对它们有一种特殊的语法,该@语法为:@{...}

URL有不同类型:

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

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

默认情况下,该类的该接口的单个实现被注册org.thymeleaf.linkbuilder.StandardLinkBuilder,这对于脱机(非Web)和基于Servlet API的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,如何在主页中为站点中的其他页面添加一个小菜单?

Please select an option

  1. Product List
  2. Order List
  3. Subscribe to our Newsletter
  4. See User Profile

服务器根目录相对URL

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

4.5 碎片

片段表达式是表示标记片段并将其在模板中移动的简便方法。这使我们能够复制它们,并将它们作为参数传递给其他模板,依此类推。

最常见的用途是使用th:insertth: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 y是写在花括号外的,因此Thymeleaf负责处理。如果将其写在花括号内,则OGNL / SpringEL引擎应负责:

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

空文本

该null文本也可用于:

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

文字代币

实际上,数字,布尔值和null文字是文字标记的一种特殊情况。

这些标记允许在标准表达式中进行一些简化。它们的工作原理与文本文字('...')完全相同,但是它们仅允许使用字母(A-Z和a-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(==)neq/ ne(!=)

4.11 条件表达式

条件表达式旨在仅根据两个条件的求值结果来求值(它本身就是另一个表达式)。
让我们来看一个例子片段(引入另一个属性修改器,th:class):

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

条件表达式的所有三个部分(condition,then和else)本身的表达式,这意味着它们可以是变量(${...},*{...})消息(#{...})网址(@{...})文字('...')

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

<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 为变量()和选择()表达式定义了双括号语法,使我们能够通过配置的转换服务来应用数据转换。${...} *{...}

它基本上是这样的:

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

注意到那里有双括号了吗?:${ {...}}。指示Thymeleaf将user.lastAccessDate表达式的结果传递给转换服务,并要求它执行格式操作(将转换为String),然后再写入结果。

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

IStandardConversionService(StandardConversionService该类)的默认实现仅对.toString()转换为的任何对象执行String。有关如何注册自定义转换服务实现的更多信息,请参见 更多关于配置部分。

官方的thymeleaf-spring3和thymeleaf-spring4集成软件包将Thymeleaf的转换服务机制与Spring自己的转换服务基础结构透明地集成在一起,以便在Spring配置中声明的转换服务和格式化程序将自动提供给${ {...}}*{ {...}}表达式。

4.15 预处理

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

预处理是在普通表达式之前执行的表达式的执行,该表达式允许修改最终将要执行的表达式。

预处理表达式与普通表达式完全一样,但是出现了一个双下划线符号(如__${expression}__)。

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

[email protected]@translateToFrench({0})

Messages_es.properties equivalent

[email protected]@translateToSpanish({0})

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

Some text here...

请注意,法语语言环境的预处理步骤将创建以下等效项:

Some text here...

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

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>

除了新的属性值,您还可以看到应用程序上下文名称已自动前缀为中的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}"/>

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

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

您还记得th:href我们home.html以前放过的那些吗?它们是完全一样的属性:

  • Product List
  • 有很多这样的属性,每个属性都针对特定的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具有布尔属性的概念,即没有值的属性,并且首字母缩写为1表示值是“ 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

    每个使用

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

    public void process(
            final HttpServletRequest request, final HttpServletResponse response,
            final ServletContext servletContext, final ITemplateEngine templateEngine)
            throws Exception {
         
        
        ProductService productService = new ProductService();
        List<Product> 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},重复模板的该片段中,使用一个称为PROD可变当前元素”。让我们给每一个看到的事物命名:

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

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

    迭代值

    java.util.List班是不是可以在Thymeleaf用于迭代onlyvalue。有相当完整的一组对象,这些对象被属性视为可迭代的th:each

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

    6.2 保持迭代状态

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

    状态变量在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变量一样,status变量的范围也由持有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<List<User>>() {
         
             @Override
             protected List<User> loadValue() {
         
                 return databaseRepository.findAllUsers();
             }
         });
    

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

    • user name

    但是同时,loadValue()如果在以下代码中condition计算为,则将永远不会初始化(永远不会调用其方法)false:

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

    7 条件评估

    7.1 简单条件:“如果”和“除非”

    有时,您需要模板的一部分才能仅在满足特定条件的情况下出现在结果中。

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

    为了做到这一点,我们将使用以下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:switch/ th: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="*":

    User is an administrator

    User is a manager

    User is some other thing

    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:insert或th: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:insert/ th:replace标记中使用的模板名称必须由模板引擎当前正在使用的模板解析器解析。

    • {::selector}“或”{this::selector}"从同一模板插入一个片段,匹配selector。如果在出现表达式的模板上未找到,则将模板调用(插入)堆栈遍历到原始处理的模板(root),直到selector在某个级别上匹配为止。

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

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

    再次注意周围的~{…}信封在th:insert/中是可选的th:replace。

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

    这种片段处理方法的一大优势是,您可以将片段写在浏览器可以完美显示的页面中,并具有完整甚至有效的标记结构,同时仍保留使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:insert和th:replace(和th:include)之间的差异

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

    th:insert 最简单:它将简单地将指定的片段作为其host标签的主体插入。

    th:replace实际上将其主机标签替换为指定的片段。

    th:include与相似th:insert,但不插入片段,而是仅插入该片段的内容。

    因此,HTML片段如下所示:

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

    …在主机

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

    <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:replace和th:with:

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

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

    声明模板内断言

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

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

    这对于验证片段签名中的参数非常有用:

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

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

    借助片段表达式,我们可以为片段指定参数,这些参数不是文本,数字,bean对象……而是标记片段。

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

    请注意以下片段中title和links变量的使用:

    <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>标记作为title和links变量的值,从而导致我们的片段在插入过程中被自定义:</p> <pre><code class="prism language-html">... <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Awesome - Main<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Common styles and scripts --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text/css<span class="token punctuation">"</span></span> <span class="token attr-name">media</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>all<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/awe/css/awesomeapp.css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>shortcut icon<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/awe/images/favicon.ico<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text/javascript<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/awe/sh/scripts/codebase.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script language-javascript"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/awe/css/bootstrap.min.css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/awe/themes/smoothness/jquery-ui.css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> ... </code></pre> <h3>使用空片段</h3> <p>一个特殊的片段表达式,空片段(~{}),可用于指定无标记。使用前面的示例:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span> <span class="token attr-name"><span class="token namespace">th:</span>replace</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>base :: common_header(~{::title},~{})<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Awesome - Main<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> ... </code></pre> <p>请注意片段(links)的第二个参数如何设置为空片段,因此没有为该<code><th:block th:replace="${links}" /></code>块编写任何内容:</p> <pre><code class="prism language-html">... <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Awesome - Main<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Common styles and scripts --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text/css<span class="token punctuation">"</span></span> <span class="token attr-name">media</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>all<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/awe/css/awesomeapp.css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>shortcut icon<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/awe/images/favicon.ico<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text/javascript<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/awe/sh/scripts/codebase.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script language-javascript"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> ... </code></pre> <h3>使用无操作令牌</h3> <p>如果我们只想让我们的片段使用其当前标记作为默认值,那么no-op也可以用作片段的参数。再次使用common_header示例:</p> <pre><code class="prism language-html">... <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span> <span class="token attr-name"><span class="token namespace">th:</span>replace</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>base :: common_header(_,~{::link})<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Awesome - Main<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@{/css/bootstrap.min.css}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@{/themes/smoothness/jquery-ui.css}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> ... </code></pre> <p>查看title参数(common_header片段的第一个参数)如何设置为no-op(_),这将导致片段的这一部分根本不执行(title= no-operation):</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span> <span class="token attr-name"><span class="token namespace">th:</span>replace</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${title}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>The awesome application<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> </code></pre> <p>因此结果是:</p> <pre><code class="prism language-html">... <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>The awesome application<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token comment"><!-- Common styles and scripts --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text/css<span class="token punctuation">"</span></span> <span class="token attr-name">media</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>all<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/awe/css/awesomeapp.css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>shortcut icon<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/awe/images/favicon.ico<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text/javascript<span class="token punctuation">"</span></span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/awe/sh/scripts/codebase.js<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script language-javascript"></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/awe/css/bootstrap.min.css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/awe/themes/smoothness/jquery-ui.css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> ... </code></pre> <h3>片段的高级条件插入</h3> <p>空片段和无操作令牌的可用性使我们能够以非常容易且优雅的方式有条件地插入片段。</p> <p>例如,我们可以做到这一点,以便插入我们的<code>common :: adminhead</code>片段只有当用户是管理员,并插入任何内容(空片段)如果不是:</p> <pre><code class="prism language-html">... <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>insert</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${user.isAdmin()} ? ~{common :: adminhead} : ~{}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> ... </code></pre> <p>同样,我们可以使用no-operation令牌来仅在满足指定条件时插入片段,而在不满足条件的情况下不做任何修改就保留标记:</p> <pre><code class="prism language-html">... <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>insert</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${user.isAdmin()} ? ~{common :: adminhead} : _<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Welcome [[${user.name}]], click <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@{/support}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>here<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> for help-desk support. <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> ... </code></pre> <p>另外,如果我们已经配置了模板解析器以通过其标志- 检查模板资源checkExistence的存在,我们可以使用片段本身的存在作为默认操作中的条件:</p> <pre><code>... <!-- The body of the <div> will be used if the "common :: salutation" fragment --> <!-- does not exist (or is empty). --> <div th:insert="~{common :: salutation} ?: _"> Welcome [[${user.name}]], click <a th:href="@{/support}">here</a> for help-desk support. </div> ... </code></pre> <h2>8.4 删除模板片段</h2> <p>回到示例应用程序,让我们重新访问产品列表模板的最新版本:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>table</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>NAME<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>PRICE<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>IN STOCK<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>COMMENTS<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>prod : ${prods}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${prodStat.odd}? <span class="token punctuation">'</span>odd<span class="token punctuation">'</span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${prod.name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Onions<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${prod.price}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>2.41<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${prod.inStock}? #{true} : #{false}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>yes<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${#lists.size(prod.comments)}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> comment/s <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>comments.html<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@{/product/comments(prodId=${prod.id})}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>unless</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${#lists.isEmpty(prod.comments)}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>view<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>table</span><span class="token punctuation">></span></span> </code></pre> <p>这段代码作为模板很好用,但是作为静态页面(当浏览器直接打开而不由Thymeleaf处理时)将不能成为一个好的原型。</p> <p>为什么?因为尽管该表可被浏览器完美显示,但该表仅具有一行,并且该行具有模拟数据。作为原型,它看起来根本不够现实……我们应该有多个产品,我们需要更多行。</p> <p>因此,我们添加一些:</p> <pre><code><table> <tr> <th>NAME</th> <th>PRICE</th> <th>IN STOCK</th> <th>COMMENTS</th> </tr> <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'"> <td th:text="${prod.name}">Onions</td> <td th:text="${prod.price}">2.41</td> <td th:text="${prod.inStock}? #{true} : #{false}">yes</td> <td> <span th:text="${#lists.size(prod.comments)}">2</span> comment/s <a href="comments.html" th:href="@{/product/comments(prodId=${prod.id})}" th:unless="${#lists.isEmpty(prod.comments)}">view</a> </td> </tr> <tr class="odd"> <td>Blue Lettuce</td> <td>9.55</td> <td>no</td> <td> <span>0</span> comment/s </td> </tr> <tr> <td>Mild Cinnamon</td> <td>1.99</td> <td>yes</td> <td> <span>3</span> comment/s <a href="comments.html">view</a> </td> </tr> </table> </code></pre> <p>好的,现在我们有三个,对于原型来说绝对更好。但是……当我们用Thymeleaf处理它时会发生什么?:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>table</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>NAME<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>PRICE<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>IN STOCK<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>COMMENTS<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>Fresh Sweet Basil<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>4.99<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>yes<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> comment/s <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>odd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>Italian Tomato<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>1.25<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>no<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> comment/s <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/gtvg/product/comments?prodId=2<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>view<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>Yellow Bell Pepper<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>2.50<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>yes<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> comment/s <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>odd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>Old Cheddar<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>18.75<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>yes<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> comment/s <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/gtvg/product/comments?prodId=4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>view<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>odd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>Blue Lettuce<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>9.55<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>no<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> comment/s <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>Mild Cinnamon<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>1.99<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>yes<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>3<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> comment/s <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>comments.html<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>view<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>table</span><span class="token punctuation">></span></span> </code></pre> <p>最后两行是模拟行!好吧,它们当然是:迭代仅应用于第一行,因此没有理由Thymeleaf应该删除其他两行。</p> <p>我们需要一种在模板处理期间删除这两行的方法。让我们th:remove在第二个和第三个<code><tr></code>标记上使用该属性:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>table</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>NAME<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>PRICE<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>IN STOCK<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>COMMENTS<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>prod : ${prods}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${prodStat.odd}? <span class="token punctuation">'</span>odd<span class="token punctuation">'</span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${prod.name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Onions<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${prod.price}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>2.41<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${prod.inStock}? #{true} : #{false}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>yes<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${#lists.size(prod.comments)}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> comment/s <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>comments.html<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@{/product/comments(prodId=${prod.id})}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>unless</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${#lists.isEmpty(prod.comments)}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>view<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>odd<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>remove</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>all<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>Blue Lettuce<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>9.55<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>no<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> comment/s <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name"><span class="token namespace">th:</span>remove</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>all<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>Mild Cinnamon<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>1.99<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>yes<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>3<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> comment/s <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>comments.html<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>view<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>table</span><span class="token punctuation">></span></span> </code></pre> <p>处理后,所有内容将重新显示为:</p> <pre><code class="prism language-2009年"><table> <tr> <th>NAME</th> <th>PRICE</th> <th>IN STOCK</th> <th>COMMENTS</th> </tr> <tr> <td>Fresh Sweet Basil</td> <td>4.99</td> <td>yes</td> <td> <span>0</span> comment/s </td> </tr> <tr class="odd"> <td>Italian Tomato</td> <td>1.25</td> <td>no</td> <td> <span>2</span> comment/s <a href="/gtvg/product/comments?prodId=2">view</a> </td> </tr> <tr> <td>Yellow Bell Pepper</td> <td>2.50</td> <td>yes</td> <td> <span>0</span> comment/s </td> </tr> <tr class="odd"> <td>Old Cheddar</td> <td>18.75</td> <td>yes</td> <td> <span>1</span> comment/s <a href="/gtvg/product/comments?prodId=4">view</a> </td> </tr> </table> </code></pre> <p>all该属性中的值是什么意思?th:remove可以根据其值以五种不同的方式表现:</p> <ul> <li>all:删除包含标签及其所有子标签。</li> <li>body:请勿删除包含标签,而是删除其所有子标签。</li> <li>tag:删除包含的标签,但不要删除其子级。</li> <li>all-but-first:除去第一个标签以外的所有包含标签的子标签。</li> <li>none: 没做什么。该值对于动态评估很有用。</li> </ul> <p>该all-but-first值有什么用?这将使我们th:remove="all"在制作原型时节省一些:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>table</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>thead</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>NAME<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>PRICE<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>IN STOCK<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>COMMENTS<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>thead</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tbody</span> <span class="token attr-name"><span class="token namespace">th:</span>remove</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>all-but-first<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>prod : ${prods}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${prodStat.odd}? <span class="token punctuation">'</span>odd<span class="token punctuation">'</span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${prod.name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Onions<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${prod.price}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>2.41<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${prod.inStock}? #{true} : #{false}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>yes<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${#lists.size(prod.comments)}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>2<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> comment/s <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>comments.html<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@{/product/comments(prodId=${prod.id})}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>unless</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${#lists.isEmpty(prod.comments)}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>view<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>odd<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>Blue Lettuce<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>9.55<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>no<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>0<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> comment/s <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>Mild Cinnamon<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>1.99<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span>yes<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>3<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> comment/s <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>comments.html<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>view<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tbody</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>table</span><span class="token punctuation">></span></span> </code></pre> <p>该th:remove属性可采取任何Thymeleaf标准表示,只要它返回所允许的字符串值中的一个(all,tag,body,all-but-first或none)。</p> <p>这意味着删除可能是有条件的,例如:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/something<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>remove</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${condition}? tag : none<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Link text not to be removed<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> </code></pre> <p>还要注意,它th:remove考虑null了的同义词none,因此以下内容与上面的示例相同:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/something<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>remove</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${condition}? tag<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Link text not to be removed<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> </code></pre> <p>在这种情况下,如果${condition}为false,null将被返回,因此不会执行删除。</p> <h2>8.5 布局继承</h2> <p>为了能够将单个文件作为布局,可以使用片段。具有title和content使用th:fragment和的简单布局的示例th:replace:</p> <pre><code class="prism language-html"><span class="token doctype"><!DOCTYPE html></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name"><span class="token namespace">th:</span>fragment</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>layout (title, content)<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">xmlns:</span>th</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>http://www.thymeleaf.org<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span> <span class="token attr-name"><span class="token namespace">th:</span>replace</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${title}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Layout Title<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Layout H1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>replace</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${content}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>Layout content<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>footer</span><span class="token punctuation">></span></span> Layout footer <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>footer</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span> </code></pre> <p>此示例声明一个名为layout的片段,其中标题和内容为参数。在下面的示例中,这两者都将在页面上被继承的片段表达式替换,并继承它。</p> <pre><code class="prism language-html"><span class="token doctype"><!DOCTYPE html></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name"><span class="token namespace">th:</span>replace</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>~{layoutFile :: layout(~{::title}, ~{::section})}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Page Title<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>section</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>Page content<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span>Included on page<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>section</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span> </code></pre> <p>在这个文件中,该html标签将被替换的布局,但在布局title和content将已被替换title,并section分别块。</p> <p>如果需要,布局可以由几个片段组成,例如header和footer。</p> <h1>9 局部变量</h1> <p>Thymeleaf将局部变量称为为模板的特定片段定义的变量,并且仅可用于该片段内部的评估。</p> <p>我们已经看到的示例是prod产品列表页面中的iter变量:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>prod : ${prods}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> ... <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> </code></pre> <p>该prod变量仅在<code><tr></code>标记范围内可用。特别:</p> <ul> <li>该th:*标签可用于在该标签中执行的所有其他属性,该属性的优先级低于th:each(这意味着它们将在之后执行th:each)。</li> <li>它将可用于<code><tr></code>标签的任何子<code><td></code>元素,例如任何元素。</li> </ul> <p>Thymeleaf为您提供了一种使用th:with属性声明局部变量而无需迭代的方法,其语法类似于属性值分配的语法:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>with</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>firstPer=${persons[0]}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span> The name of the first person is <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${firstPer.name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Julius Caesar<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span>. <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> </code></pre> <p>当th:with被处理时,该firstPer变量被创建为一个局部变量,并加入到变量映射从上下文来,使得它可用于评估与在上下文中声明的任何其它变量一起,但仅在含有的边界<code><div></code>标记。</p> <p>您可以使用通常的多重赋值语法同时定义几个变量:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>with</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>firstPer=${persons[0]},secondPer=${persons[1]}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span> The name of the first person is <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${firstPer.name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Julius Caesar<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span>. <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span> But the name of the second person is <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${secondPer.name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Marcus Antonius<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span>. <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> </code></pre> <p>该th:with属性允许重用在同一属性中定义的变量:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>with</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>company=${user.company + <span class="token punctuation">'</span> Co.<span class="token punctuation">'</span>},account=${accounts[company]}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> </code></pre> <p>让我们在杂货店的首页中使用它!还记得我们编写的用于输出格式化日期的代码吗?</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span> Today is: <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${#calendars.format(today,<span class="token punctuation">'</span>dd MMMM yyyy<span class="token punctuation">'</span>)}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>13 february 2011<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <p>好吧,如果我们希望它"dd MMMM yyyy"实际上取决于语言环境呢?例如,我们可能想向我们添加以下消息home_en.properties:</p> <pre><code>date.format=MMMM dd'','' yyyy </code></pre> <p>…和我们的同等产品home_es.properties:</p> <pre><code>date.format=dd ''de'' MMMM'','' yyyy </code></pre> <p>现在,让我们使用th:with将本地化的日期格式转换为变量,然后在th:text表达式中使用它:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name"><span class="token namespace">th:</span>with</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>df=#{date.format}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> Today is: <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${#calendars.format(today,df)}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>13 February 2011<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <p>那很干净很容易。实际上,考虑到th:with具有precedence大于的事实th:text,我们可以在span标记中解决所有问题:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span> Today is: <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>with</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>df=#{date.format}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${#calendars.format(today,df)}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>13 February 2011<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <p>您可能在想:优先?我们还没有谈论这个!好吧,不用担心,因为这正是下一章的内容。</p> <h1>10 属性优先级</h1> <p>当您th:*在同一个标记中写入多个属性时会发生什么?例如:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>ul</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span> <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>item : ${items}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${item.description}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Item description here...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>ul</span><span class="token punctuation">></span></span> </code></pre> <p>我们希望该th:each属性在之前执行,th:text以便获得所需的结果,但是考虑到HTML / XML标准没有给标记中的属性写入顺序赋予任何含义,因此优先必须在属性本身中建立机制,以确保这将按预期工作。</p> <p>因此,所有Thymeleaf属性都定义了数字优先级,从而确定了它们在标签中执行的顺序。该顺序是:<br> <a href="http://img.e-com-net.com/image/info8/57ed0fa654ac4344985c674189b4f917.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/57ed0fa654ac4344985c674189b4f917.jpg" alt="Thymeleaf 中文文档----全译版_第3张图片" width="650" height="534" style="border:1px solid black;"></a></p> <p>这种优先机制意味着,如果属性位置反转,则上述迭代片段将给出完全相同的结果(尽管可读性稍差):</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>ul</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>li</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${item.description}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>item : ${items}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Item description here...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>li</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>ul</span><span class="token punctuation">></span></span> </code></pre> <h1>11 注释和块(Comments and Blocks)</h1> <h2>11.1 标准HTML / XML注释</h2> <p><code><!-- ... --></code>Thymeleaf模板中的任何位置都可以使用标准的HTML / XML注释。这些注释中的所有内容均不会被Thymeleaf处理,并将逐字复制到结果中:</p> <pre><code class="prism language-html"><span class="token comment"><!-- User info follows --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${...}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> ... <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> </code></pre> <h2>11.2 Thymeleaf解析器级注释块</h2> <p>解析器级别的注释块是在Thymeleaf对其进行解析时,将从模板中简单删除的代码。他们看起来像这样:</p> <pre><code class="prism language-html"><span class="token comment"><!--/* This code will be removed at Thymeleaf parsing time! */--></span> </code></pre> <p>Thymeleaf将删除<code><!--/*和之间的所有内容*/--></code>,因此,当模板静态打开时,这些注释块也可用于显示代码,因为知道Thymeleaf处理模板时会将其删除:</p> <pre><code class="prism language-html"><span class="token comment"><!--/*--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span> you can see me only before Thymeleaf processes me! <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token comment"><!--*/--></span> </code></pre> <p><code><tr></code>例如,对于带有很多的表进行原型制作可能会非常方便:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>table</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>x : ${xs}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> ... <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token comment"><!--/*--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> ... <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> ... <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token comment"><!--*/--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>table</span><span class="token punctuation">></span></span> </code></pre> <h2>11.3 Thymeleaf仅原型注释块</h2> <p>Thymeleaf允许定义特殊注释块的定义,当模板静态打开(即作为原型)时,标记为注释,但Thymeleaf在执行模板时将其视为正常标记。</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>hello!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token comment"><!--/*/ <div th:text="${...}"> ... </div> /*/--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>goodbye!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> </code></pre> <p>Thymeleaf的解析系统将仅删除<code><!--/*/</code>和<code>/*/--></code>标记,但不会删除其内容,因此不会对其进行注释。因此,在执行模板时,Thymeleaf实际上会看到以下内容:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>hello!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${...}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> ... <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span><span class="token punctuation">></span></span>goodbye!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> </code></pre> <p>与解析器级注释块一样,此功能与方言无关。</p> <h2>11.4 合成th:block标签</h2> <p>Thymeleaf的标准方言中唯一的元素处理器(不是属性)是th:block。</p> <p>th:block仅是一个属性容器,允许模板开发人员指定所需的任何属性。Thymeleaf将执行这些属性,然后简单地使该块(而不是其内容)消失。</p> <p>因此,例如在创建<code><tr></code>每个表都需要多个表的迭代表时,它可能会很有用:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>table</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span><span class="token namespace">th:</span>block</span> <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>user : ${users}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${user.login}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${user.name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name">colspan</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${user.address}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span><span class="token namespace">th:</span>block</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>table</span><span class="token punctuation">></span></span> </code></pre> <p>与仅原型注释块结合使用时特别有用:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>table</span><span class="token punctuation">></span></span> <span class="token comment"><!--/*/ <th:block th:each="user : ${users}"> /*/--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${user.login}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${user.name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name">colspan</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>2<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${user.address}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token comment"><!--/*/ </th:block> /*/--></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>table</span><span class="token punctuation">></span></span> </code></pre> <p>请注意,此解决方案如何使模板成为有效的HTML(无需<code><div></code>在内添加禁止块<code><table></code>),并且当在浏览器中作为原型静态打开时,仍可以正常使用!</p> <h1>12 内联</h1> <h2>12.1 表达式内联</h2> <p>尽管标准方言允许我们使用标记属性来执行几乎所有操作,但是在某些情况下,我们更喜欢直接将表达式写到HTML文本中。例如,我们可能更喜欢这样编写:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>Hello, [[${session.user.name}]]!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <p>…代替此:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>Hello, <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${session.user.name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Sebastian<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span>!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <p>在Thymeleaf中,<code>[[...]]</code>或之间的表达式<code>[(...)]</code>被认为是内联表达式,在它们内部,我们可以使用在th:textor th:utext属性中也有效的任何类型的表达式。</p> <p>请注意,尽管<code>[[...]]</code>对应于th:text(即结果将被HTML转义),但<code>[(...)]</code>对应于th:utext并且将不执行任何HTML转义。因此<code>msg = 'This is <b>great!</b>'</code>,给定该片段,使用诸如的变量:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>The message is "[(${msg})]"<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <p>结果将使那些<code><b></code>标签未转义,因此:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>The message is "This is <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>b</span><span class="token punctuation">></span></span>great!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>b</span><span class="token punctuation">></span></span>"<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <p>而如果像这样逃脱了:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>The message is "[[${msg}]]"<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <p>结果将转义为HTML:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>The message is "This is <span class="token entity"><</span>b<span class="token entity">></span>great!<span class="token entity"><</span>/b<span class="token entity">></span>"<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <p>请注意,默认情况下,文本内联在标记中每个标签的主体(而不是标签本身)中处于活动状态,因此我们无需执行任何操作即可启用它。</p> <h3>内联与自然模板</h3> <p>如果您来自以这种方式输出文本为标准的其他模板引擎,您可能会问:我们为什么不从一开始就这样做?比所有这些 属性更少的代码th:text !</p> <p>好吧,要小心,因为尽管您可能会发现内联非常有趣,但是您应该始终记住,当静态打开内联表达式时,它们会逐字显示在HTML文件中,因此您可能无法将它们用作设计原型不再!</p> <p>浏览器不使用内联静态显示代码片段的方式之间的区别…</p> <pre><code>Hello, Sebastian! </code></pre> <p>…并使用它…</p> <pre><code>Hello, [[${session.user.name}]]! </code></pre> <p>……在设计实用性方面非常清楚。</p> <h3>禁用内联</h3> <p>不过,可以禁用此机制,因为实际上在某些情况下,我们确实希望输出<code>[[...]]</code>or <code>[(...)]</code>序列而不将其内容作为表达式处理。为此,我们将使用th:inline=“none”:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>none<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>A double array looks like this: [[1, 2, 3], [4, 5]]!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <p>这将导致:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>A double array looks like this: [[1, 2, 3], [4, 5]]!<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <h2>12.2 文字内联</h2> <p>文本内联与我们刚刚看到的表达式内联功能非常相似,但实际上增加了更多功能。必须使用明确启用它th:inline=“text”。</p> <p>文本内联不仅使我们能够使用与刚才看到的相同的内联表达式,而且实际上就像在模板模式下处理标签主体一样处理标签主体TEXT,这使我们能够执行基于文本的模板逻辑(不仅是输出表达式)。</p> <p>我们将在下一章有关文本模板模式的内容中看到更多有关此内容的信息。</p> <h2>12.3 JavaScript内联</h2> <p>JavaScript内联允许<code><script></code>在以HTML模板方式处理的模板中更好地集成JavaScript 块。</p> <p>与文本内联一样,这实际上等同于将脚本内容当作JAVASCRIPT模板模式下的模板来处理,因此,文本模板模式的所有功能(请参阅下一章)将近在咫尺。但是,在本节中,我们将重点介绍如何使用它将Thymeleaf表达式的输出添加到JavaScript块中。</p> <p>必须使用<code>th:inline="javascript"</code>以下命令显式启用此模式:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script language-javascript"> <span class="token operator">...</span> <span class="token keyword">var</span> username <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">[</span>$<span class="token punctuation">{ </span>session<span class="token punctuation">.</span>user<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token operator">...</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> </code></pre> <p>这将导致:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script language-javascript"> <span class="token operator">...</span> <span class="token keyword">var</span> username <span class="token operator">=</span> <span class="token string">"Sebastian \"Fruity\" Applejuice"</span><span class="token punctuation">;</span> <span class="token operator">...</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> </code></pre> <p>上面的代码中有两点需要注意:</p> <p>首先,JavaScript内联不仅会输出所需的文本,而且还会用引号将其括起来,并对其内容进行JavaScript转义,以便将表达式结果输出为格式良好的JavaScript文字。</p> <p>其次,发生这种情况是因为我们将<code>${session.user.name}</code>表达式输出为转义的,即使用双括号表达式:<code>[[${session.user.name}]]</code>。如果相反,我们使用未转义的形式:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script language-javascript"> <span class="token operator">...</span> <span class="token keyword">var</span> username <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">(</span>$<span class="token punctuation">{ </span>session<span class="token punctuation">.</span>user<span class="token punctuation">.</span>name<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token operator">...</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> </code></pre> <p>结果如下所示:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script language-javascript"> <span class="token operator">...</span> <span class="token keyword">var</span> username <span class="token operator">=</span> Sebastian <span class="token string">"Fruity"</span> Applejuice<span class="token punctuation">;</span> <span class="token operator">...</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> </code></pre> <p>…这是格式错误的JavaScript代码。但是,如果我们通过附加内联表达式来构建脚本的某些部分,则可能需要输出未转义的内容,因此手头有此工具是件好事。</p> <h3>JavaScript自然模板</h3> <p>所提到的JavaScript内联机制的智能远不止于应用特定于JavaScript的转义并将表达式结果输出为有效文字。</p> <p>例如,我们可以将(转义的)内联表达式包装在JavaScript注释中,例如:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script language-javascript"> <span class="token operator">...</span> <span class="token keyword">var</span> username <span class="token operator">=</span> <span class="token comment">/*[[${session.user.name}]]*/</span> <span class="token string">"Gertrud Kiwifruit"</span><span class="token punctuation">;</span> <span class="token operator">...</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> </code></pre> <p>而且Thymeleaf将忽略注释之后和分号之前的所有内容(在本例中为’Gertrud Kiwifruit’),因此执行此操作的结果将与未使用包装注释时的情况完全相同:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script language-javascript"> <span class="token operator">...</span> <span class="token keyword">var</span> username <span class="token operator">=</span> <span class="token string">"Sebastian \"Fruity\" Applejuice"</span><span class="token punctuation">;</span> <span class="token operator">...</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> </code></pre> <p>但是,请仔细查看原始模板代码:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script language-javascript"> <span class="token operator">...</span> <span class="token keyword">var</span> username <span class="token operator">=</span> <span class="token comment">/*[[${session.user.name}]]*/</span> <span class="token string">"Gertrud Kiwifruit"</span><span class="token punctuation">;</span> <span class="token operator">...</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> </code></pre> <p>注意这是有效的JavaScript代码。当您以静态方式打开模板文件(无需在服务器上执行)时,它将完美执行。</p> <p>因此,这里提供的是一种制作JavaScript自然模板的方法!</p> <h3>高级内联评估和JavaScript序列化</h3> <p>关于JavaScript内联的重要注意事项是,此表达式求值是智能的,并且不仅限于字符串。Thymeleaf将使用JavaScript语法正确编写以下类型的对象:</p> <ul> <li>Strings</li> <li>Numbers</li> <li>Booleans</li> <li>Arrays</li> <li>Collections</li> <li>Maps</li> <li>Beans (objects with getter and setter methods)<br> 例如,如果我们有以下代码:</li> </ul> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script language-javascript"> <span class="token operator">...</span> <span class="token keyword">var</span> user <span class="token operator">=</span> <span class="token comment">/*[[${session.user}]]*/</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token operator">...</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> </code></pre> <p>该<code>${session.user}</code>表达式将求值为User对象,Thymeleaf会将其正确转换为Javascript语法:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>javascript<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script language-javascript"> <span class="token operator">...</span> <span class="token keyword">var</span> user <span class="token operator">=</span> <span class="token punctuation">{ </span><span class="token string">"age"</span><span class="token punctuation">:</span><span class="token keyword">null</span><span class="token punctuation">,</span><span class="token string">"firstName"</span><span class="token punctuation">:</span><span class="token string">"John"</span><span class="token punctuation">,</span><span class="token string">"lastName"</span><span class="token punctuation">:</span><span class="token string">"Apricot"</span><span class="token punctuation">,</span> <span class="token string">"name"</span><span class="token punctuation">:</span><span class="token string">"John Apricot"</span><span class="token punctuation">,</span><span class="token string">"nationality"</span><span class="token punctuation">:</span><span class="token string">"Antarctica"</span><span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token operator">...</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span> </code></pre> <p>完成该JavaScript序列化的方式是通过<code>org.thymeleaf.standard.serializer.IStandardJavaScriptSerializer</code>接口的实现,该接口可以StandardDialect在模板引擎使用实例的实例中进行配置。</p> <p>该JS序列化机制的默认实现将在类路径中查找Jackson库,如果有的话,将使用它。如果没有,它将应用内置的序列化机制,该机制可以满足大多数方案的需求并产生相似的结果(但灵活性较差)。</p> <h2>12.4 CSS内联</h2> <p>Thymeleaf还允许在CSS <code><style></code>标签中使用内联,例如:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token style language-css"> ... </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span> </code></pre> <p>例如,假设我们将两个变量设置为两个不同的String值:</p> <pre><code>classname = 'main elems' align = 'center' </code></pre> <p>我们可以像这样使用它们:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token style language-css"> <span class="token selector">.[[$</span><span class="token punctuation">{ </span>classname<span class="token punctuation">}</span><span class="token selector">]]</span> <span class="token punctuation">{ </span> <span class="token selector">text-align: [[$</span><span class="token punctuation">{ </span>align<span class="token punctuation">}</span>]]<span class="token punctuation">;</span> <span class="token punctuation">}</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span> </code></pre> <p>结果将是:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token style language-css"> <span class="token selector">.main\ elems</span> <span class="token punctuation">{ </span> <span class="token property">text-align</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span> <span class="token punctuation">}</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span> </code></pre> <p>请注意,CSS内联也像JavaScript一样具有一定的智能。具体来说,通过转义的表达式(例如)输出的表达式<code>[[${classname}]]</code>将作为CSS标识符转义。这就是为什么我们classname = 'main elems’变成了main\ elems上面的代码片段。</p> <h3>进阶功能:CSS自然模板等</h3> <p>与之前解释JavaScript的方式相同,CSS内联还允许我们的<code><style></code>标签静态和动态地工作,即通过将内联表达式包装在注释中而成为CSS自然模板。看到:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>style</span> <span class="token attr-name"><span class="token namespace">th:</span>inline</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>css<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token style language-css"> <span class="token selector">.main\ elems</span> <span class="token punctuation">{ </span> <span class="token property">text-align</span><span class="token punctuation">:</span> <span class="token comment">/*[[${align}]]*/</span> left<span class="token punctuation">;</span> <span class="token punctuation">}</span> </span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>style</span><span class="token punctuation">></span></span> </code></pre> <h1>13 文字模板模式</h1> <h2>13.1 文字语法</h2> <p>在Thymeleaf的三种模板模式被认为是文字:TEXT,JAVASCRIPT和CSS。这将它们与标记模板模式区分开:HTML和XML。</p> <p>文本模板模式和标记模式之间的主要区别在于,在文本模板中,没有标签可以插入属性形式的逻辑,因此我们必须依靠其他机制。</p> <p>这些机制的第一个也是最基本的是内联,我们已经在上一章中进行了详细介绍。内联语法是在文本模板模式下输出表达式结果的最简单方法,因此,这是文本电子邮件的完美有效模板。</p> <pre><code>Dear [(${name})], Please find attached the results of the report you requested with name "[(${report.name})]". Sincerely, The Reporter. </code></pre> <p>即使没有标签,上面的示例也是一个完整且有效的Thymeleaf模板,可以在TEXT模板模式下执行。</p> <p>但是,为了包含比单纯的输出表达式更复杂的逻辑,我们需要一种新的非基于标记的语法:</p> <pre><code>[# th:each="item : ${items}"] - [(${item})] [/] </code></pre> <p>实际上是更冗长的精简版本:</p> <pre><code>[#th:block th:each="item : ${items}"] - [#th:block th:utext="${item}" /] [/th:block] </code></pre> <p>请注意,这种新语法是如何基于声明为的元素(即可处理标签)<code>[#element ...]</code>的<code><element ...></code>。元素的打开方式类似于<code>[#element ...]</code>和闭合的方式一样<code>[/element]</code>,并且可以通过将open元素最小化来声明独立标签/,该方式几乎等同于XML标签:<code>[#element ... /]</code>。</p> <p>标准方言仅包含以下元素之一的处理器:众所周知的th:block,尽管我们可以在方言中扩展它并以通常的方式创建新元素。另外,th:block元素(<code>[#th:block ...]</code> … <code>[/th:block]</code>)可以缩写为空字符串(<code>[# ...]</code> … <code>[/]</code>),因此上述代码块实际上等效于:</p> <pre><code>[# th:each="item : ${items}"] - [# th:utext="${item}" /] [/] </code></pre> <p>给定<code>[# th:utext="${item}" /]</code>等效于内联的未转义表达式,我们可以使用它来减少代码量。因此,我们结束了上面看到的代码的第一个片段:</p> <pre><code>[# th:each="item : ${items}"] - [(${item})] [/] </code></pre> <p>请注意,文本语法要求元素平衡(没有未关闭的标签)和带引号的属性 – XML样式比HTML样式更多。</p> <p>我们来看一个更完整的TEXT模板示例,即纯文本电子邮件模板:</p> <pre><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>执行后,其结果可能类似于:</p> <pre><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>JAVASCRIPT模板模式下的另一个示例(greeter.js文件)将作为文本模板进行处理,然后从HTML页面调用该结果。请注意,这不是<code><script></code> HTML模板中的块,而是.js单独作为模板处理的文件:</p> <pre><code>var greeter = function() { var username = [[${session.user.name}]]; [# th:each="salut : ${salutations}"] alert([[${salut}]] + " " + username); [/] }; </code></pre> <p>执行后,其结果可能类似于:</p> <pre><code>var greeter = function() { var username = "Bertrand \"Crunchy\" Pear"; alert("Hello" + " " + username); alert("Ol\u00E1" + " " + username); alert("Hola" + " " + username); }; </code></pre> <h3>转义的元素属性</h3> <p>为了避免与模板的其他部分可能会以其他方式处理的交互(例如,text在HTML模板内部的-mode内联),Thymeleaf 3.0允许转义其文本语法中元素的属性。所以:</p> <ul> <li>TEXT模板模式下的属性将采用HTML转换格式。</li> <li>JAVASCRIPT模板模式下的属性将是JavaScript非转义的。</li> <li>CSS模板模式下的属性将采用CSS换码。</li> </ul> <p>因此,这在<code>TEXT-mode</code>模板中是完全可以的(请注意<code>></code>):</p> <pre><code>[# th:if="${120<user.age}"] Congratulations! [/] </code></pre> <p>当然,<code><</code>在实际的文本模板中这没有任何意义,但是如果我们正在使用<code>th:inline="text"</code>包含上面代码的代码块处理HTML模板,并且要确保我们的浏览器不会将它<code><user.age</code>用作名称的话,这是一个好主意。静态打开文件作为原型时的open标签。</p> <h2>13.2 可扩展性</h2> <p>这种语法的优点之一是它与标记语法一样可扩展。开发人员仍然可以使用自定义元素和属性来定义自己的方言,为它们应用前缀(可选),然后在文本模板模式下使用它们:</p> <pre><code> [#myorg:dosomething myorg:importantattr="211"]some text[/myorg:dosomething] </code></pre> <h2>13.3 纯文本原型注释块:添加代码</h2> <p>在JAVASCRIPT和CSS模板模式(不适用于TEXT),允许包括一个特殊的注释语法之间的代码<code>/*[+...+]*/</code>,这样Thymeleaf会处理模板时自动取消注释这样的代码:</p> <pre><code>var x = 23; /*[+ var msg = "This is a working application"; +]*/ var f = function() { ... </code></pre> <p>将执行为:</p> <pre><code>var x = 23; var msg = "This is a working application"; var f = function() { ... </code></pre> <p>您可以在这些注释中包含表达式,它们将被评估:</p> <pre><code>var x = 23; /*[+ var msg = "Hello, " + [[${session.user.name}]]; +]*/ var f = function() { ... </code></pre> <h2>13.4 文本解析器级注释块:删除代码</h2> <p>在类似于仅原型的注释块的方式,所有三个文本模板模式(TEXT,JAVASCRIPT和CSS)使其能够指示Thymeleaf特殊之间移除代码<code>/*[- */</code>和<code>/* -]*/</code>标志,就像这样:</p> <pre><code>var x = 23; /*[- */ var msg = "This is shown only when executed statically!"; /* -]*/ var f = function() { ... </code></pre> <p>或在TEXT模式下:</p> <pre><code>... /*[- Note the user is obtained from the session, which must exist -]*/ Welcome [(${session.user.name})]! ... </code></pre> <h2>13.5 自然的JavaScript和CSS模板</h2> <p>如上一章所述,JavaScript和CSS内联提供了将内联表达式包含在JavaScript / CSS注释中的可能性,例如:</p> <pre><code>... var username = /*[[${session.user.name}]]*/ "Sebastian Lychee"; ... </code></pre> <p>…这是有效的JavaScript,执行后的外观如下:</p> <pre><code>... var username = "John Apricot"; ... </code></pre> <p>实际上,可以将这种将内联表达式包含在注释中的相同技巧可用于整个文本模式语法:</p> <pre><code> /*[# th:if="${user.admin}"]*/ alert('Welcome admin'); /*[/]*/ </code></pre> <p>如果模板是静态打开的(因为它是100%有效的JavaScript),并且如果用户是管理员运行模板,则将在上面的代码中显示该警报。它等效于:</p> <pre><code>[# th:if="${user.admin}"] alert('Welcome admin'); [/] </code></pre> <p>…实际上是模板解析期间将初始版本转换为的代码。</p> <p>但是请注意,在注释中包装元素并不会;像内联输出表达式那样清除它们所在的行(直到找到a为止,一直在右边)。该行为仅保留给内联输出表达式。</p> <p>因此Thymeleaf 3.0允许以自然模板的形式开发复杂的JavaScript脚本和CSS样式表,这些模板既可以作为原型也可以作为工作模板使用。</p> <h1>14 杂货店的更多页面</h1> <p>现在我们对使用Thymeleaf有了很多了解,我们可以在我们的网站上添加一些新页面以进行订单管理。</p> <p>请注意,我们将专注于HTML代码,但是如果您想查看相应的控制器,则可以查看捆绑的源代码。</p> <h2>14.1 订单清单</h2> <p>让我们从创建订单列表页面开始<code>/WEB-INF/templates/order/list.html</code></p> <pre><code class="prism language-html"><span class="token doctype"><!DOCTYPE html></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>th</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>http://www.thymeleaf.org<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Good Thymes Virtual Grocery<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Content-Type<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text/html; charset=UTF-8<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text/css<span class="token punctuation">"</span></span> <span class="token attr-name">media</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>all<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>../../../css/gtvg.css<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@{/css/gtvg.css}<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Order list<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>table</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>DATE<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>CUSTOMER<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>TOTAL<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>o : ${orders}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${oStat.odd}? <span class="token punctuation">'</span>odd<span class="token punctuation">'</span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${#calendars.format(o.date,<span class="token punctuation">'</span>dd/MMM/yyyy<span class="token punctuation">'</span>)}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>13 jan 2011<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${o.customer.name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Frederic Tomato<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${#aggregates.sum(o.orderLines.{purchasePrice * amount})}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>23.32<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>details.html<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@{/order/details(orderId=${o.id})}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>view<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>table</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>../home.html<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@{/}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Return to home<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span> </code></pre> <p>除了这点OGNL魔法外,这里没有什么让我们感到惊讶的:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${#aggregates.sum(o.orderLines.{purchasePrice * amount})}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>23.32<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> </code></pre> <p>这样做是针对订单中的每个订单行(OrderLine对象),将其purchasePrice和amount属性相乘(通过调用相应的getPurchasePrice()和getAmount()方法),然后将结果返回到数字列表中,然后由该<code>#aggregates.sum(...)</code>函数进行汇总,以获取订单总数价钱。</p> <p>您必须喜欢OGNL的强大功能。</p> <h2>14.2 订单明细</h2> <p>现在进入订单详细信息页面,在该页面中,我们将大量使用星号语法:</p> <pre><code class="prism language-html"><span class="token doctype"><!DOCTYPE html></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name"><span class="token namespace">xmlns:</span>th</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>http://www.thymeleaf.org<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Good Thymes Virtual Grocery<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>Content-Type<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text/html; charset=UTF-8<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>stylesheet<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>text/css<span class="token punctuation">"</span></span> <span class="token attr-name">media</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>all<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>../../../css/gtvg.css<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@{/css/gtvg.css}<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span> <span class="token attr-name"><span class="token namespace">th:</span>object</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${order}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h1</span><span class="token punctuation">></span></span>Order details<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h1</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>b</span><span class="token punctuation">></span></span>Code:<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>b</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*{id}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>99<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>b</span><span class="token punctuation">></span></span>Date:<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>b</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*{#calendars.format(date,<span class="token punctuation">'</span>dd MMM yyyy<span class="token punctuation">'</span>)}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>13 jan 2011<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h2</span><span class="token punctuation">></span></span>Customer<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h2</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>object</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*{customer}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>b</span><span class="token punctuation">></span></span>Name:<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>b</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*{name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Frederic Tomato<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>b</span><span class="token punctuation">></span></span>Since:<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>b</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*{#calendars.format(customerSince,<span class="token punctuation">'</span>dd MMM yyyy<span class="token punctuation">'</span>)}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>1 jan 2011<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>h2</span><span class="token punctuation">></span></span>Products<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>h2</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>table</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>PRODUCT<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>AMOUNT<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>th</span><span class="token punctuation">></span></span>PURCHASE PRICE<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>th</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>ol,row : *{orderLines}<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${row.odd}? <span class="token punctuation">'</span>odd<span class="token punctuation">'</span><span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${ol.product.name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Strawberries<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${ol.amount}<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>number<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>3<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${ol.purchasePrice}<span class="token punctuation">"</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>number<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>23.32<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>table</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>b</span><span class="token punctuation">></span></span>TOTAL:<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>b</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*{#aggregates.sum(orderLines.{purchasePrice * amount})}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>35.23<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>list.html<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>href</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@{/order/list}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Return to order list<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span> </code></pre> <p>除了嵌套对象选择之外,这里没有太多新的东西:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span> <span class="token attr-name"><span class="token namespace">th:</span>object</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${order}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> ... <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>object</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*{customer}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>b</span><span class="token punctuation">></span></span>Name:<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>b</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>*{name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Frederic Tomato<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> ... <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> ... <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> </code></pre> <p>… <code>*{name}</code>等于</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>b</span><span class="token punctuation">></span></span>Name:<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>b</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>span</span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${order.customer.name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Frederic Tomato<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>span</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span> </code></pre> <h1>15 有关配置的更多信息</h1> <h2>15.1 模板解析器</h2> <p>对于我们的Good Thymes虚拟杂货店,我们选择了一个ITemplateResolver实现ServletContextTemplateResolver,该实现允许我们从Servlet上下文中获取模板作为资源。</p> <p>除了使我们能够通过实现ITemplateResolver,Thymeleaf 来创建自己的模板解析器之外,还包括以下四种实现:</p> <ul> <li>org.thymeleaf.templateresolver.ClassLoaderTemplateResolver,它将模板解析为类加载器资源,例如:</li> </ul> <pre><code class="prism language-java"><span class="token keyword">return</span> Thread<span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getContextClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getResourceAsStream</span><span class="token punctuation">(</span>template<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <ul> <li>org.thymeleaf.templateresolver.FileTemplateResolver,它将模板解析为来自文件系统的文件,例如:</li> </ul> <pre><code class="prism language-java"><span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">FileInputStream</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">File</span><span class="token punctuation">(</span>template<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <ul> <li>org.thymeleaf.templateresolver.UrlTemplateResolver,它将模板解析为URL(甚至是非本地的URL),例如:</li> </ul> <pre><code class="prism language-java"><span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">URL</span><span class="token punctuation">(</span>template<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">openStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <ul> <li>org.thymeleaf.templateresolver.StringTemplateResolver,它直接将模板解析String为指定为的名称template(或模板名称,在这种情况下,显然不仅仅是一个简单的名称):</li> </ul> <pre><code class="prism language-java"><span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">StringReader</span><span class="token punctuation">(</span>templateName<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>所有预先捆绑的实现都ITemplateResolver允许使用相同的配置参数集,其中包括:</p> <ul> <li>前缀和后缀(如前所述):</li> </ul> <pre><code class="prism language-java">templateResolver<span class="token punctuation">.</span><span class="token function">setPrefix</span><span class="token punctuation">(</span><span class="token string">"/WEB-INF/templates/"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> templateResolver<span class="token punctuation">.</span><span class="token function">setSuffix</span><span class="token punctuation">(</span><span class="token string">".html"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <ul> <li>模板别名允许使用与文件名不直接对应的模板名。如果后缀/前缀和别名都存在,则别名将在前缀/后缀之前应用:</li> </ul> <pre><code class="prism language-java">templateResolver<span class="token punctuation">.</span><span class="token function">addTemplateAlias</span><span class="token punctuation">(</span><span class="token string">"adminHome"</span><span class="token punctuation">,</span><span class="token string">"profiles/admin/home"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> templateResolver<span class="token punctuation">.</span><span class="token function">setTemplateAliases</span><span class="token punctuation">(</span>aliasesMap<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <ul> <li>读取模板时要应用的编码:</li> </ul> <pre><code class="prism language-java">templateResolver<span class="token punctuation">.</span><span class="token function">setEncoding</span><span class="token punctuation">(</span><span class="token string">"UTF-8"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <ul> <li>使用的模板模式:</li> </ul> <pre><code class="prism language-java"><span class="token comment">// Default is HTML</span> templateResolver<span class="token punctuation">.</span><span class="token function">setTemplateMode</span><span class="token punctuation">(</span><span class="token string">"XML"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <ul> <li>模板缓存的默认模式,以及用于定义特定模板是否可缓存的模式:</li> </ul> <pre><code class="prism language-java"><span class="token comment">// Default is true</span> templateResolver<span class="token punctuation">.</span><span class="token function">setCacheable</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> templateResolver<span class="token punctuation">.</span><span class="token function">getCacheablePatternSpec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addPattern</span><span class="token punctuation">(</span><span class="token string">"/users/*"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <ul> <li>源自此模板解析器的已解析模板缓存条目的TTL(以毫秒为单位)。如果未设置,则从缓存中删除条目的唯一方法是超过缓存的最大大小(最旧的条目将被删除)。</li> </ul> <pre><code class="prism language-java"><span class="token comment">// Default is no TTL (only cache size exceeded would remove entries)</span> templateResolver<span class="token punctuation">.</span><span class="token function">setCacheTTLMs</span><span class="token punctuation">(</span><span class="token number">60000</span>L<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <blockquote> <p>Thymeleaf + Spring集成软件包提供了一个SpringResourceTemplateResolver实现,该实现使用所有Spring基础结构来访问和读取应用程序中的资源,这是在支持Spring的应用程序中推荐的实现。</p> </blockquote> <h3>链模板解析器</h3> <p>此外,模板引擎可以指定多个模板解析器,在这种情况下,可以在它们之间建立顺序以进行模板解析,这样,如果第一个解析器无法解析模板,则要求第二个解析器,依此类推:</p> <pre><code class="prism language-java">ClassLoaderTemplateResolver classLoaderTemplateResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ClassLoaderTemplateResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> classLoaderTemplateResolver<span class="token punctuation">.</span><span class="token function">setOrder</span><span class="token punctuation">(</span>Integer<span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> ServletContextTemplateResolver servletContextTemplateResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ServletContextTemplateResolver</span><span class="token punctuation">(</span>servletContext<span class="token punctuation">)</span><span class="token punctuation">;</span> servletContextTemplateResolver<span class="token punctuation">.</span><span class="token function">setOrder</span><span class="token punctuation">(</span>Integer<span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> templateEngine<span class="token punctuation">.</span><span class="token function">addTemplateResolver</span><span class="token punctuation">(</span>classLoaderTemplateResolver<span class="token punctuation">)</span><span class="token punctuation">;</span> templateEngine<span class="token punctuation">.</span><span class="token function">addTemplateResolver</span><span class="token punctuation">(</span>servletContextTemplateResolver<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>当应用多个模板解析器时,建议为每个模板解析器指定模式,以便Thymeleaf可以快速丢弃那些不打算解析模板的模板解析器,从而提高性能。并不是必须这样做,而是建议:</p> <pre><code class="prism language-java">ClassLoaderTemplateResolver classLoaderTemplateResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ClassLoaderTemplateResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> classLoaderTemplateResolver<span class="token punctuation">.</span><span class="token function">setOrder</span><span class="token punctuation">(</span>Integer<span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// This classloader will not be even asked for any templates not matching these patterns </span> classLoaderTemplateResolver<span class="token punctuation">.</span><span class="token function">getResolvablePatternSpec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addPattern</span><span class="token punctuation">(</span><span class="token string">"/layout/*.html"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> classLoaderTemplateResolver<span class="token punctuation">.</span><span class="token function">getResolvablePatternSpec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addPattern</span><span class="token punctuation">(</span><span class="token string">"/menu/*.html"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> ServletContextTemplateResolver servletContextTemplateResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ServletContextTemplateResolver</span><span class="token punctuation">(</span>servletContext<span class="token punctuation">)</span><span class="token punctuation">;</span> servletContextTemplateResolver<span class="token punctuation">.</span><span class="token function">setOrder</span><span class="token punctuation">(</span>Integer<span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>如果未指定这些可解析的模式,我们将依赖于ITemplateResolver我们所使用的每个实现的特定功能。请注意,并非所有的实现都能够在解析之前确定模板的存在,因此始终可以将模板视为可解析的,并打破了解析链(不允许其他解析器检查同一模板),但是却无法阅读实际资源。</p> <p>所有ITemplateResolver附带核心Thymeleaf实现包括一种机制,将使我们能够使解析器真正检查如果资源考虑之前存在解析。它是checkExistence标志,其工作方式如下:</p> <pre><code class="prism language-java">ClassLoaderTemplateResolver classLoaderTemplateResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ClassLoaderTemplateResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> classLoaderTemplateResolver<span class="token punctuation">.</span><span class="token function">setOrder</span><span class="token punctuation">(</span>Integer<span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> classLoaderTempalteResolver<span class="token punctuation">.</span><span class="token function">setCheckExistence</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>该checkExistence标志强制解析器在解析阶段对资源是否存在进行真正的检查(如果存在检查返回false,则调用链中的以下解析器)。尽管这在每种情况下听起来都不错,但在大多数情况下,这将意味着对资源本身的双重访问(一次检查是否存在,另一次读取它),并且在某些情况下可能会成为性能问题,例如,基于远程URL模板资源–潜在的性能问题可能会通过使用模板缓存而在很大程度上得到缓解(在这种情况下,仅在首次访问模板时才能解决模板问题)。</p> <h2>15.2 邮件解析器</h2> <p>我们没有为Grocery应用程序明确指定Message Resolver实现,并且如前所述,这意味着所使用的实现是一个org.thymeleaf.messageresolver.StandardMessageResolver对象。</p> <p>StandardMessageResolver是IMessageResolver接口的标准实现,但是如果需要,我们可以创建自己的接口,以适应应用程序的特定需求。</p> <blockquote> <p>Thymeleaf + Spring集成软件包默认提供一种IMessageResolver实现,该实现使用标准Spring方法来检索外部化消息,方法是使用MessageSource在Spring Application Context声明的bean。</p> </blockquote> <h3>标准消息解析器</h3> <p>那么,如何StandardMessageResolver查找在特定模板上请求的消息?</p> <p>如果模板名称为home,并且位于中/WEB-INF/templates/home.html,并且请求的语言环境为,gl_ES则此解析器将按以下顺序在以下文件中查找消息:</p> <pre><code>/WEB-INF/templates/home_gl_ES.properties /WEB-INF/templates/home_gl.properties /WEB-INF/templates/home.properties </code></pre> <p>StandardMessageResolver有关完整的消息解析机制如何工作的更多详细信息,请参阅该类的JavaDoc文档。</p> <h3>配置消息解析器</h3> <p>如果我们想向模板引擎添加消息解析器(或更多)怎么办?简单:</p> <pre><code class="prism language-java"><span class="token comment">// For setting only one</span> templateEngine<span class="token punctuation">.</span><span class="token function">setMessageResolver</span><span class="token punctuation">(</span>messageResolver<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// For setting more than one</span> templateEngine<span class="token punctuation">.</span><span class="token function">addMessageResolver</span><span class="token punctuation">(</span>messageResolver<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>为什么我们要拥有多个消息解析器?出于与模板解析器相同的原因:订购了消息解析器,如果第一个无法解析特定的消息,则将询问第二个,然后询问第三个,依此类推。</p> <h2>15.3 转换服务</h2> <p>该转换服务,使我们用的手段来进行数据转换和格式化操作双括号语法(<code>${ {...}}</code>)实际上是标准方言的特点,而不是Thymeleaf模板引擎本身。</p> <p>这样,配置它的方法是通过IStandardConversionService直接将我们的接口的自定义实现设置StandardDialect为正配置到模板引擎中的接口的实例。喜欢:</p> <pre><code>IStandardConversionService customConversionService = ... StandardDialect dialect = new StandardDialect(); dialect.setConversionService(customConversionService); templateEngine.setDialect(dialect); </code></pre> <blockquote> <p>请注意,thymeleaf-spring3和thymeleaf-spring4软件包包含SpringStandardDialect,并且该方言已经预先配置了IStandardConversionService将Spring自己的Conversion Service基础结构集成到Thymeleaf中的实现。</p> </blockquote> <h2>15.4 记录</h2> <p>Thymeleaf非常重视日志记录,并始终尝试通过其日志记录界面提供尽可能多的有用信息。</p> <p>slf4j,实际上,所使用的日志记录库实际上充当了我们想要在应用程序中使用的任何日志记录实现的桥梁(例如log4j)。</p> <p>Thymeleaf班会记录TRACE,DEBUG并INFO-level信息,这取决于我们希望的详细程度,并且除了一般的记录它会使用与TemplateEngine类,我们可以为不同的目的而单独配置相关的三个特殊记录器:</p> <ul> <li>org.thymeleaf.TemplateEngine.CONFIG 在初始化期间将输出库的详细配置。</li> <li>org.thymeleaf.TemplateEngine.TIMER 将输出有关处理每个模板所需时间的信息(可用于基准测试!)</li> <li>org.thymeleaf.TemplateEngine.cache是一组记录器的前缀,该记录器输出有关缓存的特定信息。尽管缓存记录器的名称可由用户配置,因此可以更改,但是默认情况下它们是:<br> *org.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE<br> *org.thymeleaf.TemplateEngine.cache.EXPRESSION_CACHE</li> </ul> <p>使用的Thymeleaf日志记录基础结构的示例配置log4j可能是:</p> <pre><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>16 模板缓存</h1> <p>Thymeleaf的工作要归功于一组解析器(用于标记和文本),该解析器将模板解析为事件序列(打开标签,文本,关闭标签,注释等)和一系列处理器(每种需要一种行为)应用–修改模板解析的事件序列,以便通过将原始模板与我们的数据结合来创建我们期望的结果。</p> <p>默认情况下,它还包括存储已解析模板的缓存;在处理模板文件之前读取和解析模板文件所导致的事件顺序。在Web应用程序中工作时,此功能特别有用,它基于以下概念:</p> <ul> <li>输入/输出几乎始终是所有应用程序中最慢的部分。相比之下,内存中处理非常快。</li> <li>克隆现有的内存中事件序列总是比读取模板文件,对其进行解析并为其创建新的事件序列要快得多。</li> <li>Web应用程序通常只有几十个模板。</li> <li>模板文件大小不一,在应用程序运行时不会被修改。</li> </ul> <p>所有这些都导致了这样的想法,即在不浪费大量内存的情况下在Web应用程序中缓存最常用的模板是可行的,并且这将节省大量时间,而这些时间将花费在少量文件的输入/输出操作上实际上,它永远不会改变。</p> <p>以及我们如何控制此缓存?首先,我们已经了解到可以在模板解析器上启用或禁用它,甚至只对特定模板起作用:</p> <pre><code class="prism language-java"><span class="token comment">// Default is true</span> templateResolver<span class="token punctuation">.</span><span class="token function">setCacheable</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> templateResolver<span class="token punctuation">.</span><span class="token function">getCacheablePatternSpec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addPattern</span><span class="token punctuation">(</span><span class="token string">"/users/*"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>同样,我们可以通过建立自己的缓存管理器对象来修改其配置,该对象可以是默认StandardCacheManager实现的一个实例:</p> <pre><code class="prism language-java"><span class="token comment">// Default is 200</span> StandardCacheManager cacheManager <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StandardCacheManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> cacheManager<span class="token punctuation">.</span><span class="token function">setTemplateCacheMaxSize</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> templateEngine<span class="token punctuation">.</span><span class="token function">setCacheManager</span><span class="token punctuation">(</span>cacheManager<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>org.thymeleaf.cache.StandardCacheManager有关配置缓存的更多信息,请参考的Javadoc API 。</p> <p>可以从模板缓存中手动删除条目:</p> <pre><code class="prism language-java"><span class="token comment">// Clear the cache completely</span> templateEngine<span class="token punctuation">.</span><span class="token function">clearTemplateCache</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Clear a specific template from the cache</span> templateEngine<span class="token punctuation">.</span><span class="token function">clearTemplateCacheFor</span><span class="token punctuation">(</span><span class="token string">"/users/userList"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <h1>17 解耦模板逻辑</h1> <h2>17.1 解耦逻辑:概念</h2> <p>到目前为止,我们已经为食品杂货店工作,模板以通常的方式完成,逻辑以属性的形式插入模板中。</p> <p>但是Thymeleaf还允许我们将模板标记与其逻辑完全分离,从而允许在和模板模式下创建完全无逻辑的标记模板。HTMLXML</p> <p>主要思想是模板逻辑将在单独的逻辑文件中定义(更确切地说是逻辑资源,因为它不必是file)。默认情况下,该逻辑资源将是与模板文件位于同一位置(例如,文件夹)的附加文件,其名称相同,但.th.xml扩展名为:</p> <pre><code>/templates +->/home.html +->/home.th.xml </code></pre> <p>因此,该home.html文件可以完全没有逻辑。它可能看起来像这样:</p> <pre><code class="prism language-html"><span class="token doctype"><!DOCTYPE html></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>table</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>usersTable<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>username<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Jeremy Grapefruit<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>usertype<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Normal User<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>username<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Alice Watermelon<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>usertype<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Administrator<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>table</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span> </code></pre> <p>那里绝对没有Thymeleaf代码。这是没有Thymeleaf或模板知识的设计人员可以创建,编辑和/或理解的模板文件。或某些外部系统完全没有Thymeleaf钩子提供的HTML片段。</p> <p>现在,home.html通过创建如下所示的其他home.th.xml文件,将该模板转换为Thymeleaf模板:</p> <pre><code class="prism language-html"><span class="token prolog"><?xml version="1.0"?></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>thlogic</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>attr</span> <span class="token attr-name">sel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#usersTable<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>remove</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>all-but-first<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>attr</span> <span class="token attr-name">sel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>/tr[0]<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>user : ${users}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>attr</span> <span class="token attr-name">sel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>td.username<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${user.name}<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>attr</span> <span class="token attr-name">sel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>td.usertype<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#{|user.type.${user.type}|}<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>attr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>attr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>thlogic</span><span class="token punctuation">></span></span> </code></pre> <p>在这里,我们可以看到<code><attr></code>一个thlogic块内有很多标签。这些<code><attr></code>标签对通过其属性选择的原始模板的节点执行属性注入,这些sel属性包含Thymeleaf 标记选择器(实际上是AttoParser标记选择器)。</p> <p>另请注意,<code><attr></code>可以嵌套标签,以便附加选择器。即sel="/tr[0]“上述中,例如,将被处理为sel=”#usersTable/tr[0]"。用户名的选择器<code><td></code>将被处理为sel="#usersTable/tr[0]//td.username"。</p> <p>因此,一旦合并,上面看到的两个文件将与以下内容相同:</p> <pre><code class="prism language-html"><span class="token doctype"><!DOCTYPE html></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>table</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>usersTable<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>remove</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>all-but-first<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span> <span class="token attr-name"><span class="token namespace">th:</span>each</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>user : ${users}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>username<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>${user.name}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Jeremy Grapefruit<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>usertype<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">th:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>#{|user.type.${user.type}|}<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Normal User<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>username<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Alice Watermelon<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>td</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>usertype<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Administrator<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>td</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>tr</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>table</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span> </code></pre> <p>与创建两个单独的文件相比,这看起来更熟悉,并且确实不那么冗长。但是,解耦模板的优势在于,我们可以使模板完全独立于Thymeleaf,因此从设计的角度来看,它具有更好的可维护性。</p> <p>当然,仍然需要设计人员或开发人员之间的一些合同,例如,用户<code><table></code>将需要一个合同id=“usersTable”,但是在许多情况下,纯HTML模板将是设计团队和开发团队之间更好的沟通工具。</p> <h2>17.2 配置解耦的模板</h2> <h3>启用解耦的模板</h3> <p>默认情况下,不会期望每个模板都使用去耦逻辑。取而代之的是,配置的模板解析器(的实现ITemplateResolver)将需要使用解耦逻辑将要解析的模板专门标记为。</p> <p>除了StringTemplateResolver(不允许解耦逻辑)外,的所有其他现成实现都ITemplateResolver将提供一个称为的标志useDecoupledLogic,该标志将将该解析器解析的所有模板标记为可能将其全部或部分逻辑存储在单独的资源中:</p> <pre><code class="prism language-java"><span class="token keyword">final</span> ServletContextTemplateResolver templateResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ServletContextTemplateResolver</span><span class="token punctuation">(</span>servletContext<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> templateResolver<span class="token punctuation">.</span><span class="token function">setUseDecoupledLogic</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <h3>混合耦合和解耦逻辑</h3> <p>启用后,解耦模板逻辑不是必需的。启用后,这意味着引擎将查找包含解耦逻辑的资源,如果存在,则将其解析并与原始模板合并。如果解耦的逻辑资源不存在,则不会引发任何错误。</p> <p>同样,在同一模板中,我们可以混合使用耦合逻辑和解耦逻辑,例如,通过在原始模板文件中添加一些Thymeleaf属性,而将其他属性留给单独的解耦逻辑文件。最常见的情况是使用new(在v3.0中)th:ref属性。</p> <h2>17.3 <code>th:ref</code>属性</h2> <p>th:ref只是标记属性。从处理的角度来看,它什么也没做,只是在处理模板后消失,但是它的作用在于它充当标记引用,即可以通过标记选择器中的名称来解析,就像标记名或片段一样。(th:fragment)。</p> <p>因此,如果我们有一个选择器,例如:</p> <pre><code class="prism language-html"> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>attr</span> <span class="token attr-name">sel</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>whatever<span class="token punctuation">"</span></span> <span class="token attr-name">...</span><span class="token punctuation">/></span></span> </code></pre> <p>这将匹配:</p> <ul> <li>任何<code><whatever></code>标签。</li> <li>具有th:fragment="whatever"属性的任何标签。</li> <li>具有th:ref="whatever"属性的任何标签。</li> </ul> <p>锚,这一事实最终可能会污染我们的输出。</p> <p>从同样的意义上说,它的缺点是th:ref什么?好吧,很显然,我们将在模板中添加一些Thymeleaf逻辑(“逻辑”)。</p> <p>请注意,该th:ref属性的适用性不仅适用于解耦的逻辑模板文件:它在其他类型的场景中也一样工作,例如在片段表达式(~{…})中。</p> <h2>17.4 解耦模板的性能影响</h2> <p>影响极小。当一个已解析的模板被标记为使用解耦逻辑并且不被缓存时,该模板逻辑资源将首先被解析,解析并处理为一系列内存中的指令:基本上是要注入到每个标记选择器的属性列表。</p> <p>但这是唯一需要执行的附加步骤,因为在此之后,将解析真实模板,并且在解析这些模板时,由于AttoParser中节点选择的高级功能,这些属性将由解析器本身即时注入。。因此,已解析的节点将从解析器中出来,就像它们的注入属性写在原始模板文件中一样。</p> <p>这样最大的优势?将模板配置为要缓存时,它将缓存已包含注入属性的模板。因此,一旦对高速缓存的模板使用解耦的模板进行缓存,其开销将绝对为零。</p> <h2>17.5 解耦逻辑的解析</h2> <p>Thymeleaf解析与每个模板相对应的解耦逻辑资源的方式可由用户配置。它由扩展点决定org.thymeleaf.templateparser.markup.decoupled.IDecoupledTemplateLogicResolver,为其提供了默认实现:StandardDecoupledTemplateLogicResolver。</p> <p>此标准实现有什么作用?</p> <ul> <li>首先,它将a prefix和a 应用于模板资源suffix的基本名称(通过其ITemplateResource#getBaseName()方法获得)。前缀和后缀都可以配置,默认情况下,前缀为空,后缀为.th.xml。</li> <li>其次,它要求模板资源通过其方法来解析具有所计算名称的相对资源ITemplateResource#relative(String relativeLocation)。</li> </ul> <p>IDecoupledTemplateLogicResolver可以TemplateEngine轻松配置要使用的具体实现:</p> <pre><code class="prism language-java"><span class="token keyword">final</span> StandardDecoupledTemplateLogicResolver decoupledresolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StandardDecoupledTemplateLogicResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> decoupledResolver<span class="token punctuation">.</span><span class="token function">setPrefix</span><span class="token punctuation">(</span><span class="token string">"../viewlogic/"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> templateEngine<span class="token punctuation">.</span><span class="token function">setDecoupledTemplateLogicResolver</span><span class="token punctuation">(</span>decoupledResolver<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <h1>18 附录A:表达式基本对象</h1> <p>某些对象和变量映射始终可被调用。让我们看看他们:</p> <h2>基础对象</h2> <ul> <li><code>#ctx</code>:上下文对象。一种实现org.thymeleaf.context.IContext或org.thymeleaf.context.IWebContext取决于我们的环境(独立或网络)。<br> 注意#vars和#root是同一个对象的同义字,但<code>#ctx</code>建议使用。</li> </ul> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.context.IContext * ====================================================================== */ ${#ctx.locale} ${#ctx.variableNames} /* * ====================================================================== * See javadoc API for class org.thymeleaf.context.IWebContext * ====================================================================== */ ${#ctx.request} ${#ctx.response} ${#ctx.session} ${#ctx.servletContext} </code></pre> <ul> <li><code>#locale</code>:直接访问java.util.Locale与当前请求关联的内容。</li> </ul> <pre><code>${#locale} </code></pre> <h2>请求/会话属性等的Web上下文名称空间</h2> <p>在Web环境中使用Thymeleaf时,我们可以使用一系列快捷方式来访问请求参数,会话属性和应用程序属性:</p> <blockquote> <p>请注意,这些不是上下文对象,而是作为变量添加到上下文中的映射,因此我们不使用即可访问它们#。它们以某种方式充当命名空间。</p> </blockquote> <ul> <li><code>param</code>:用于检索请求参数。param.foo是String[]带有foorequest参数值的a,因此param.foo是String[]带有foorequest参数值的a,因此{param.foo[0]}通常用于获取第一个值。</li> </ul> <pre><code>/* * ============================================================================ * See javadoc API for class org.thymeleaf.context.WebRequestParamsVariablesMap * ============================================================================ */ ${param.foo} // Retrieves a String[] with the values of request parameter 'foo' ${param.size()} ${param.isEmpty()} ${param.containsKey('foo')} ... </code></pre> <ul> <li><code>session</code>:用于获取会话属性。</li> </ul> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.context.WebSessionVariablesMap * ====================================================================== */ ${session.foo} // Retrieves the session atttribute 'foo' ${session.size()} ${session.isEmpty()} ${session.containsKey('foo')} ... </code></pre> <ul> <li><code>application</code>:用于检索应用程序/ servlet上下文属性。</li> </ul> <pre><code>/* * ============================================================================= * See javadoc API for class org.thymeleaf.context.WebServletContextVariablesMap * ============================================================================= */ ${application.foo} // Retrieves the ServletContext atttribute 'foo' ${application.size()} ${application.isEmpty()} ${application.containsKey('foo')} ... </code></pre> <p>请注意,无需指定用于访问请求属性的名称空间(与request参数相反),因为所有请求属性都作为变量自动添加到上下文根目录中的上下文中:</p> <pre><code>${myRequestAttribute} </code></pre> <h2>Web上下文对象</h2> <p>在Web环境中,还可以直接访问以下对象(请注意,这些是对象,而不是映射/命名空间):</p> <ul> <li><code>#request</code>:直接访问javax.servlet.http.HttpServletRequest与当前请求关联的对象。</li> </ul> <pre><code>${#request.getAttribute('foo')} ${#request.getParameter('foo')} ${#request.getContextPath()} ${#request.getRequestName()} ... </code></pre> <ul> <li><code>#session</code>:直接访问javax.servlet.http.HttpSession与当前请求关联的对象。</li> </ul> <pre><code>${#session.getAttribute('foo')} ${#session.id} ${#session.lastAccessedTime} ... </code></pre> <ul> <li><code>#servletContext</code>:直接访问javax.servlet.ServletContext与当前请求关联的对象。</li> </ul> <pre><code>${#servletContext.getAttribute('foo')} ${#servletContext.contextPath} ... </code></pre> <h1>19 附录B:Expression Utility对象</h1> <h2>Execution Info</h2> <p><code>#execInfo</code>:表达式对象,提供有关Thymeleaf标准表达式中正在处理的模板的有用信息。</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.ExecutionInfo * ====================================================================== */ /* * 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. */ ${#execInfo.templateName} ${#execInfo.templateMode} /* * 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. */ ${#execInfo.processedTemplateName} ${#execInfo.processedTemplateMode} /* * 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. */ ${#execInfo.templateNames} ${#execInfo.templateModes} /* * 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. */ ${#execInfo.templateStack} </code></pre> <h2>Messages</h2> <p><code>#messages</code>:实用程序方法,用于获取变量表达式内的外部化消息,其方式与使用#{…}语法获得消息的方式相同。</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Messages * ====================================================================== */ /* * 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. */ ${#messages.msg('msgKey')} ${#messages.msg('msgKey', param1)} ${#messages.msg('msgKey', param1, param2)} ${#messages.msg('msgKey', param1, param2, param3)} ${#messages.msgWithParams('msgKey', new Object[] {param1, param2, param3, param4})} ${#messages.arrayMsg(messageKeyArray)} ${#messages.listMsg(messageKeyList)} ${#messages.setMsg(messageKeySet)} /* * Obtain externalized messages or null. Null is returned instead of a default * message if a message for the specified key is not found. */ ${#messages.msgOrNull('msgKey')} ${#messages.msgOrNull('msgKey', param1)} ${#messages.msgOrNull('msgKey', param1, param2)} ${#messages.msgOrNull('msgKey', param1, param2, param3)} ${#messages.msgOrNullWithParams('msgKey', new Object[] {param1, param2, param3, param4})} ${#messages.arrayMsgOrNull(messageKeyArray)} ${#messages.listMsgOrNull(messageKeyList)} ${#messages.setMsgOrNull(messageKeySet)} </code></pre> <h2>URI / URL</h2> <p><code>#uris</code>:在Thymeleaf标准表达式内执行URI / URL操作(尤其是转义/转义)的实用程序对象。</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Uris * ====================================================================== */ /* * Escape/Unescape as a URI/URL path */ ${#uris.escapePath(uri)} ${#uris.escapePath(uri, encoding)} ${#uris.unescapePath(uri)} ${#uris.unescapePath(uri, encoding)} /* * Escape/Unescape as a URI/URL path segment (between '/' symbols) */ ${#uris.escapePathSegment(uri)} ${#uris.escapePathSegment(uri, encoding)} ${#uris.unescapePathSegment(uri)} ${#uris.unescapePathSegment(uri, encoding)} /* * Escape/Unescape as a Fragment Identifier (#frag) */ ${#uris.escapeFragmentId(uri)} ${#uris.escapeFragmentId(uri, encoding)} ${#uris.unescapeFragmentId(uri)} ${#uris.unescapeFragmentId(uri, encoding)} /* * Escape/Unescape as a Query Parameter (?var=value) */ ${#uris.escapeQueryParam(uri)} ${#uris.escapeQueryParam(uri, encoding)} ${#uris.unescapeQueryParam(uri)} ${#uris.unescapeQueryParam(uri, encoding)} </code></pre> <h2>Conversions</h2> <p><code>#conversions</code>:实用程序对象,允许在模板的任何位置执行转换服务:</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Conversions * ====================================================================== */ /* * Execute the desired conversion of the 'object' value into the * specified class. */ ${#conversions.convert(object, 'java.util.TimeZone')} ${#conversions.convert(object, targetClass)} </code></pre> <h2>Dates</h2> <p><code>#dates</code>:java.util.Date对象的实用程序方法:</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Dates * ====================================================================== */ /* * Format date with the standard locale format * Also works with arrays, lists or sets */ ${#dates.format(date)} ${#dates.arrayFormat(datesArray)} ${#dates.listFormat(datesList)} ${#dates.setFormat(datesSet)} /* * Format date with the ISO8601 format * Also works with arrays, lists or sets */ ${#dates.formatISO(date)} ${#dates.arrayFormatISO(datesArray)} ${#dates.listFormatISO(datesList)} ${#dates.setFormatISO(datesSet)} /* * Format date with the specified pattern * Also works with arrays, lists or sets */ ${#dates.format(date, 'dd/MMM/yyyy HH:mm')} ${#dates.arrayFormat(datesArray, 'dd/MMM/yyyy HH:mm')} ${#dates.listFormat(datesList, 'dd/MMM/yyyy HH:mm')} ${#dates.setFormat(datesSet, 'dd/MMM/yyyy HH:mm')} /* * Obtain date properties * Also works with arrays, lists or sets */ ${#dates.day(date)} // also arrayDay(...), listDay(...), etc. ${#dates.month(date)} // also arrayMonth(...), listMonth(...), etc. ${#dates.monthName(date)} // also arrayMonthName(...), listMonthName(...), etc. ${#dates.monthNameShort(date)} // also arrayMonthNameShort(...), listMonthNameShort(...), etc. ${#dates.year(date)} // also arrayYear(...), listYear(...), etc. ${#dates.dayOfWeek(date)} // also arrayDayOfWeek(...), listDayOfWeek(...), etc. ${#dates.dayOfWeekName(date)} // also arrayDayOfWeekName(...), listDayOfWeekName(...), etc. ${#dates.dayOfWeekNameShort(date)} // also arrayDayOfWeekNameShort(...), listDayOfWeekNameShort(...), etc. ${#dates.hour(date)} // also arrayHour(...), listHour(...), etc. ${#dates.minute(date)} // also arrayMinute(...), listMinute(...), etc. ${#dates.second(date)} // also arraySecond(...), listSecond(...), etc. ${#dates.millisecond(date)} // also arrayMillisecond(...), listMillisecond(...), etc. /* * Create date (java.util.Date) objects from its components */ ${#dates.create(year,month,day)} ${#dates.create(year,month,day,hour,minute)} ${#dates.create(year,month,day,hour,minute,second)} ${#dates.create(year,month,day,hour,minute,second,millisecond)} /* * Create a date (java.util.Date) object for the current date and time */ ${#dates.createNow()} ${#dates.createNowForTimeZone()} /* * Create a date (java.util.Date) object for the current date (time set to 00:00) */ ${#dates.createToday()} ${#dates.createTodayForTimeZone()} </code></pre> <h2>Calendars</h2> <p><code>#calendars</code>:类似于<code>#dates</code>,但对于java.util.Calendar对象:</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Calendars * ====================================================================== */ /* * Format calendar with the standard locale format * Also works with arrays, lists or sets */ ${#calendars.format(cal)} ${#calendars.arrayFormat(calArray)} ${#calendars.listFormat(calList)} ${#calendars.setFormat(calSet)} /* * Format calendar with the ISO8601 format * Also works with arrays, lists or sets */ ${#calendars.formatISO(cal)} ${#calendars.arrayFormatISO(calArray)} ${#calendars.listFormatISO(calList)} ${#calendars.setFormatISO(calSet)} /* * Format calendar with the specified pattern * Also works with arrays, lists or sets */ ${#calendars.format(cal, 'dd/MMM/yyyy HH:mm')} ${#calendars.arrayFormat(calArray, 'dd/MMM/yyyy HH:mm')} ${#calendars.listFormat(calList, 'dd/MMM/yyyy HH:mm')} ${#calendars.setFormat(calSet, 'dd/MMM/yyyy HH:mm')} /* * Obtain calendar properties * Also works with arrays, lists or sets */ ${#calendars.day(date)} // also arrayDay(...), listDay(...), etc. ${#calendars.month(date)} // also arrayMonth(...), listMonth(...), etc. ${#calendars.monthName(date)} // also arrayMonthName(...), listMonthName(...), etc. ${#calendars.monthNameShort(date)} // also arrayMonthNameShort(...), listMonthNameShort(...), etc. ${#calendars.year(date)} // also arrayYear(...), listYear(...), etc. ${#calendars.dayOfWeek(date)} // also arrayDayOfWeek(...), listDayOfWeek(...), etc. ${#calendars.dayOfWeekName(date)} // also arrayDayOfWeekName(...), listDayOfWeekName(...), etc. ${#calendars.dayOfWeekNameShort(date)} // also arrayDayOfWeekNameShort(...), listDayOfWeekNameShort(...), etc. ${#calendars.hour(date)} // also arrayHour(...), listHour(...), etc. ${#calendars.minute(date)} // also arrayMinute(...), listMinute(...), etc. ${#calendars.second(date)} // also arraySecond(...), listSecond(...), etc. ${#calendars.millisecond(date)} // also arrayMillisecond(...), listMillisecond(...), etc. /* * Create calendar (java.util.Calendar) objects from its components */ ${#calendars.create(year,month,day)} ${#calendars.create(year,month,day,hour,minute)} ${#calendars.create(year,month,day,hour,minute,second)} ${#calendars.create(year,month,day,hour,minute,second,millisecond)} ${#calendars.createForTimeZone(year,month,day,timeZone)} ${#calendars.createForTimeZone(year,month,day,hour,minute,timeZone)} ${#calendars.createForTimeZone(year,month,day,hour,minute,second,timeZone)} ${#calendars.createForTimeZone(year,month,day,hour,minute,second,millisecond,timeZone)} /* * Create a calendar (java.util.Calendar) object for the current date and time */ ${#calendars.createNow()} ${#calendars.createNowForTimeZone()} /* * Create a calendar (java.util.Calendar) object for the current date (time set to 00:00) */ ${#calendars.createToday()} ${#calendars.createTodayForTimeZone()} </code></pre> <h2>Numbers</h2> <p><code>#numbers</code>:用于数字对象的实用方法:</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Numbers * ====================================================================== */ /* * ========================== * Formatting integer numbers * ========================== */ /* * Set minimum integer digits. * Also works with arrays, lists or sets */ ${#numbers.formatInteger(num,3)} ${#numbers.arrayFormatInteger(numArray,3)} ${#numbers.listFormatInteger(numList,3)} ${#numbers.setFormatInteger(numSet,3)} /* * Set minimum integer digits and thousands separator: * 'POINT', 'COMMA', 'WHITESPACE', 'NONE' or 'DEFAULT' (by locale). * Also works with arrays, lists or sets */ ${#numbers.formatInteger(num,3,'POINT')} ${#numbers.arrayFormatInteger(numArray,3,'POINT')} ${#numbers.listFormatInteger(numList,3,'POINT')} ${#numbers.setFormatInteger(numSet,3,'POINT')} /* * ========================== * Formatting decimal numbers * ========================== */ /* * Set minimum integer digits and (exact) decimal digits. * Also works with arrays, lists or sets */ ${#numbers.formatDecimal(num,3,2)} ${#numbers.arrayFormatDecimal(numArray,3,2)} ${#numbers.listFormatDecimal(numList,3,2)} ${#numbers.setFormatDecimal(numSet,3,2)} /* * Set minimum integer digits and (exact) decimal digits, and also decimal separator. * Also works with arrays, lists or sets */ ${#numbers.formatDecimal(num,3,2,'COMMA')} ${#numbers.arrayFormatDecimal(numArray,3,2,'COMMA')} ${#numbers.listFormatDecimal(numList,3,2,'COMMA')} ${#numbers.setFormatDecimal(numSet,3,2,'COMMA')} /* * Set minimum integer digits and (exact) decimal digits, and also thousands and * decimal separator. * Also works with arrays, lists or sets */ ${#numbers.formatDecimal(num,3,'POINT',2,'COMMA')} ${#numbers.arrayFormatDecimal(numArray,3,'POINT',2,'COMMA')} ${#numbers.listFormatDecimal(numList,3,'POINT',2,'COMMA')} ${#numbers.setFormatDecimal(numSet,3,'POINT',2,'COMMA')} /* * ===================== * Formatting currencies * ===================== */ ${#numbers.formatCurrency(num)} ${#numbers.arrayFormatCurrency(numArray)} ${#numbers.listFormatCurrency(numList)} ${#numbers.setFormatCurrency(numSet)} /* * ====================== * Formatting percentages * ====================== */ ${#numbers.formatPercent(num)} ${#numbers.arrayFormatPercent(numArray)} ${#numbers.listFormatPercent(numList)} ${#numbers.setFormatPercent(numSet)} /* * Set minimum integer digits and (exact) decimal digits. */ ${#numbers.formatPercent(num, 3, 2)} ${#numbers.arrayFormatPercent(numArray, 3, 2)} ${#numbers.listFormatPercent(numList, 3, 2)} ${#numbers.setFormatPercent(numSet, 3, 2)} /* * =============== * Utility methods * =============== */ /* * Create a sequence (array) of integer numbers going * from x to y */ ${#numbers.sequence(from,to)} ${#numbers.sequence(from,to,step)} </code></pre> <h2>Strings</h2> <p><code>#strings</code>:String对象的实用方法:</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Strings * ====================================================================== */ /* * Null-safe toString() */ ${#strings.toString(obj)} // also array*, list* and set* /* * Check whether a String is empty (or null). Performs a trim() operation before check * Also works with arrays, lists or sets */ ${#strings.isEmpty(name)} ${#strings.arrayIsEmpty(nameArr)} ${#strings.listIsEmpty(nameList)} ${#strings.setIsEmpty(nameSet)} /* * 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 */ ${#strings.defaultString(text,default)} ${#strings.arrayDefaultString(textArr,default)} ${#strings.listDefaultString(textList,default)} ${#strings.setDefaultString(textSet,default)} /* * Check whether a fragment is contained in a String * Also works with arrays, lists or sets */ ${#strings.contains(name,'ez')} // also array*, list* and set* ${#strings.containsIgnoreCase(name,'ez')} // also array*, list* and set* /* * Check whether a String starts or ends with a fragment * Also works with arrays, lists or sets */ ${#strings.startsWith(name,'Don')} // also array*, list* and set* ${#strings.endsWith(name,endingFragment)} // also array*, list* and set* /* * Substring-related operations * Also works with arrays, lists or sets */ ${#strings.indexOf(name,frag)} // also array*, list* and set* ${#strings.substring(name,3,5)} // also array*, list* and set* ${#strings.substringAfter(name,prefix)} // also array*, list* and set* ${#strings.substringBefore(name,suffix)} // also array*, list* and set* ${#strings.replace(name,'las','ler')} // also array*, list* and set* /* * Append and prepend * Also works with arrays, lists or sets */ ${#strings.prepend(str,prefix)} // also array*, list* and set* ${#strings.append(str,suffix)} // also array*, list* and set* /* * Change case * Also works with arrays, lists or sets */ ${#strings.toUpperCase(name)} // also array*, list* and set* ${#strings.toLowerCase(name)} // also array*, list* and set* /* * Split and join */ ${#strings.arrayJoin(namesArray,',')} ${#strings.listJoin(namesList,',')} ${#strings.setJoin(namesSet,',')} ${#strings.arraySplit(namesStr,',')} // returns String[] ${#strings.listSplit(namesStr,',')} // returns List<String> ${#strings.setSplit(namesStr,',')} // returns Set<String> /* * Trim * Also works with arrays, lists or sets */ ${#strings.trim(str)} // also array*, list* and set* /* * Compute length * Also works with arrays, lists or sets */ ${#strings.length(str)} // also array*, list* and set* /* * 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 */ ${#strings.abbreviate(str,10)} // also array*, list* and set* /* * Convert the first character to upper-case (and vice-versa) */ ${#strings.capitalize(str)} // also array*, list* and set* ${#strings.unCapitalize(str)} // also array*, list* and set* /* * Convert the first character of every word to upper-case */ ${#strings.capitalizeWords(str)} // also array*, list* and set* ${#strings.capitalizeWords(str,delimiters)} // also array*, list* and set* /* * Escape the string */ ${#strings.escapeXml(str)} // also array*, list* and set* ${#strings.escapeJava(str)} // also array*, list* and set* ${#strings.escapeJavaScript(str)} // also array*, list* and set* ${#strings.unescapeJava(str)} // also array*, list* and set* ${#strings.unescapeJavaScript(str)} // also array*, list* and set* /* * Null-safe comparison and concatenation */ ${#strings.equals(first, second)} ${#strings.equalsIgnoreCase(first, second)} ${#strings.concat(values...)} ${#strings.concatReplaceNulls(nullValue, values...)} /* * Random */ ${#strings.randomAlphanumeric(count)} </code></pre> <h2>Objects</h2> <p><code>#objects</code>:一般对象的实用方法</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Objects * ====================================================================== */ /* * Return obj if it is not null, and default otherwise * Also works with arrays, lists or sets */ ${#objects.nullSafe(obj,default)} ${#objects.arrayNullSafe(objArray,default)} ${#objects.listNullSafe(objList,default)} ${#objects.setNullSafe(objSet,default)} </code></pre> <h2>Booleans</h2> <p><code>#bools</code>:用于布尔值评估的实用方法</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Bools * ====================================================================== */ /* * 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 */ ${#bools.isTrue(obj)} ${#bools.arrayIsTrue(objArray)} ${#bools.listIsTrue(objList)} ${#bools.setIsTrue(objSet)} /* * Evaluate with negation * Also works with arrays, lists or sets */ ${#bools.isFalse(cond)} ${#bools.arrayIsFalse(condArray)} ${#bools.listIsFalse(condList)} ${#bools.setIsFalse(condSet)} /* * Evaluate and apply AND operator * Receive an array, a list or a set as parameter */ ${#bools.arrayAnd(condArray)} ${#bools.listAnd(condList)} ${#bools.setAnd(condSet)} /* * Evaluate and apply OR operator * Receive an array, a list or a set as parameter */ ${#bools.arrayOr(condArray)} ${#bools.listOr(condList)} ${#bools.setOr(condSet)} </code></pre> <h2>Arrays</h2> <p><code>#arrays</code>:数组的实用方法</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Arrays * ====================================================================== */ /* * 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[]. */ ${#arrays.toArray(object)} /* * Convert to arrays of the specified component class. */ ${#arrays.toStringArray(object)} ${#arrays.toIntegerArray(object)} ${#arrays.toLongArray(object)} ${#arrays.toDoubleArray(object)} ${#arrays.toFloatArray(object)} ${#arrays.toBooleanArray(object)} /* * Compute length */ ${#arrays.length(array)} /* * Check whether array is empty */ ${#arrays.isEmpty(array)} /* * Check if element or elements are contained in array */ ${#arrays.contains(array, element)} ${#arrays.containsAll(array, elements)} </code></pre> <h2>Lists</h2> <p><code>#lists</code>:清单的实用方法</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Lists * ====================================================================== */ /* * Converts to list */ ${#lists.toList(object)} /* * Compute size */ ${#lists.size(list)} /* * Check whether list is empty */ ${#lists.isEmpty(list)} /* * Check if element or elements are contained in list */ ${#lists.contains(list, element)} ${#lists.containsAll(list, elements)} /* * Sort a copy of the given list. The members of the list must implement * comparable or you must define a comparator. */ ${#lists.sort(list)} ${#lists.sort(list, comparator)} </code></pre> <h2>Sets</h2> <p><code>#sets</code>:集合的实用方法</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Sets * ====================================================================== */ /* * Converts to set */ ${#sets.toSet(object)} /* * Compute size */ ${#sets.size(set)} /* * Check whether set is empty */ ${#sets.isEmpty(set)} /* * Check if element or elements are contained in set */ ${#sets.contains(set, element)} ${#sets.containsAll(set, elements)} </code></pre> <h2>Maps</h2> <p><code>#maps</code> : utility methods for maps</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Maps * ====================================================================== */ /* * Compute size */ ${#maps.size(map)} /* * Check whether map is empty */ ${#maps.isEmpty(map)} /* * Check if key/s or value/s are contained in maps */ ${#maps.containsKey(map, key)} ${#maps.containsAllKeys(map, keys)} ${#maps.containsValue(map, value)} ${#maps.containsAllValues(map, value)} </code></pre> <h2>Aggregates</h2> <p><code>#aggregates</code> : utility methods for creating aggregates on arrays or collections</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Aggregates * ====================================================================== */ /* * Compute sum. Returns null if array or collection is empty */ ${#aggregates.sum(array)} ${#aggregates.sum(collection)} /* * Compute average. Returns null if array or collection is empty */ ${#aggregates.avg(array)} ${#aggregates.avg(collection)} </code></pre> <h2>IDs</h2> <p><code>#ids</code> : utility methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).</p> <pre><code>/* * ====================================================================== * See javadoc API for class org.thymeleaf.expression.Ids * ====================================================================== */ /* * 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. */ ${#ids.seq('someId')} /* * 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. */ ${#ids.next('someId')} ${#ids.prev('someId')} </code></pre> <h1>20 附录C:标记选择器语法</h1> <p>Thymeleaf的标记选择器直接从Thymeleaf的解析库AttoParser借用。</p> <p>该选择器的语法与XPath,CSS和jQuery中的选择器的语法有很大相似之处,这使它们对于大多数用户而言易于使用。您可以在AttoParser文档中查看完整的语法参考。</p> <p>例如,以下选择器将在标记内的每个位置选择</p> <p>class content的每个对象(请注意,这样做并不那么简洁,请继续阅读以了解原因):</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>insert</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mytemplate :: //div[@class=<span class="token punctuation">'</span>content<span class="token punctuation">'</span>]<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> </code></pre> <p>基本语法包括:</p> <ul> <li><code>/x</code> 表示名称为x的当前节点的直接子代。</li> <li><code>//x</code> 表示任意深度的名称为x的当前节点的子代。</li> <li><code>x[@z="v"]</code> 表示名称为x的元素和名为z的属性,其值为“ v”。</li> <li><code>x[@z1="v1" and @z2="v2"]</code> 表示具有名称x的元素以及具有值“ v1”和“ v2”的属性z1和z2。</li> <li><code>x[i]</code> 表示名称x处于其兄弟姐妹中的第i个元素。</li> <li><code>x[@z="v"][i]</code> 表示元素名称为x,属性z的值为“ v”,并且在与该条件匹配的同级元素中位于第i个位置。</li> </ul> <p>但是也可以使用更简洁的语法:</p> <ul> <li>x完全等同于//x(x在任何深度级别搜索具有名称或引用的元素,引用是a th:ref或th:fragment属性)。</li> <li>选择器也可以不带元素名称/引用,只要它们包含参数说明即可。因此[@class=‘oneclass’],一个有效的选择器将查找具有value的class属性的任何元素(标签)“oneclass”。</li> </ul> <p>高级属性选择功能:</p> <ul> <li>除=(等于)外,其他比较运算符也有效:(!=不等于),=(以开头)和$=(以结束)。例如:x[@class=‘section’]表示具有名称x和以class开头的属性值的元素section。</li> <li>既可以以@(XPath样式)开始也可以不以(jQuery样式)开始指定属性。所以x[z=‘v’]等于x[@z=‘v’]。</li> <li>多属性修饰符既可以与and(XPath样式)结合,也可以通过链接多个修饰符(jQuery样式)来结合。因此x[@z1=‘v1’ and @z2=‘v2’]实际上等效于x[@z1=‘v1’][@z2=‘v2’](并且也等效于x[z1=‘v1’][z2=‘v2’])。</li> </ul> <p>直接类似于jQuery的选择器:</p> <ul> <li><code>x.oneclass</code>等同于x[class=‘oneclass’]。</li> <li><code>.oneclass</code>等同于[class=‘oneclass’]。</li> <li><code>x#oneid</code>等同于x[id=‘oneid’]。</li> <li><code>#oneid</code>等同于[id=‘oneid’]。</li> <li><code>x%oneref</code>表示<code><x></code>具有th:ref="oneref"或th:fragment="oneref"属性的标签。</li> <li><code>%oneref</code>表示任何具有th:ref="oneref"或th:fragment="oneref"属性的标签。请注意,这实际上等效于简单的oneref原因,因为可以使用引用代替元素名称。</li> <li>直接选择器和属性选择器可以混合使用:a.external[@href^=‘https’]。</li> </ul> <p>因此,上面的标记选择器表达式:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>insert</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mytemplate :: //div[@class=<span class="token punctuation">'</span>content<span class="token punctuation">'</span>]<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> </code></pre> <p>可以写成:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>insert</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mytemplate :: div.content<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> </code></pre> <p>检查另一个示例,这是:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>replace</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mytemplate :: myfrag<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> </code></pre> <p>将寻找th:fragment="myfrag"片段签名(或th:ref引用)。但是,myfrag如果存在则还会搜索带有名称的标签(在HTML中不存在)。注意与以下内容的区别:</p> <pre><code class="prism language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name"><span class="token namespace">th:</span>replace</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>mytemplate :: .myfrag<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>...<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span> </code></pre> <p>…实际上将查找带有的任何元素class=“myfrag”,而无需关心th:fragment签名(或th:ref引用)。</p> <h2>多值类匹配</h2> <p>标记选择器了解要多值化的类属性,因此即使元素具有多个class值,也可以在该属性上应用选择器。</p> <p>例如,div.two将匹配<code><div class="one two three" ></div></code></p> </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1385529795437219840"></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/1895254049285009408.htm" title="DeepSeek R1 简单指南:架构、训练、本地部署和硬件要求" target="_blank">DeepSeek R1 简单指南:架构、训练、本地部署和硬件要求</a> <span class="text-muted">爱喝白开水a</span> <a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/AI%E5%A4%A7%E6%A8%A1%E5%9E%8B/1.htm">AI大模型</a><a class="tag" taget="_blank" href="/search/DeepSeek/1.htm">DeepSeek</a><a class="tag" taget="_blank" href="/search/R1/1.htm">R1</a><a class="tag" taget="_blank" href="/search/DeepSeek/1.htm">DeepSeek</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E8%AE%AD%E7%BB%83/1.htm">人工智能训练</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%A8%A1%E5%9E%8B%E9%83%A8%E7%BD%B2/1.htm">大模型部署</a> <div>DeepSeek推出的LLM推理新策略DeepSeek最近发表的论文DeepSeek-R1中介绍了一种创新的方法,通过强化学习(RL)提升大型语言模型(LLM)的推理能力。这项研究在如何仅依靠强化学习而不是过分依赖监督式微调的情况下,增强LLM解决复杂问题的能力上,取得了重要进展。DeepSeek-R1技术概述模型架构DeepSeek-R1不是一个单独的模型,而是包括DeepSeek-R1-Zer</div> </li> <li><a href="/article/1895249255841460224.htm" title="Python—kafka操作" target="_blank">Python—kafka操作</a> <span class="text-muted">蓝魔Y</span> <a class="tag" taget="_blank" href="/search/Python%E7%BC%96%E7%A8%8B/1.htm">Python编程</a><a class="tag" taget="_blank" href="/search/kafka/1.htm">kafka</a> <div>文档结构1、概念简介2、环境搭建3、操作实践1、概念简介2、环境搭建接口手册:https://kafka-python.readthedocs.io/en/master/Python操作kafka的模块为:kafka-python模块安装pipinstallkafka-python3、操作实践=============================================over====</div> </li> <li><a href="/article/1895248877183889408.htm" title="Empowering LLMs with Logical Reasoning: 从“语言大师”到“逻辑大师”的进化之路" target="_blank">Empowering LLMs with Logical Reasoning: 从“语言大师”到“逻辑大师”的进化之路</a> <span class="text-muted">步子哥</span> <a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a> <div>“逻辑是智慧的骨架,而语言是智慧的血肉。让大语言模型(LLMs)既能说会道,又能逻辑严谨,是AI发展的下一座高峰。”开篇:语言模型的“逻辑盲区”近年来,大语言模型(LLMs)在自然语言处理(NLP)任务中取得了令人瞩目的成就。从生成流畅的文章到翻译复杂的句子,这些模型似乎无所不能。然而,当我们试图让它们回答逻辑推理问题时,却发现它们的表现常常令人失望。比如,某顶尖LLM在回答以下问题时出现了自相矛</div> </li> <li><a href="/article/1895246105055129600.htm" title="C#:强大编程语言的多面魅力" target="_blank">C#:强大编程语言的多面魅力</a> <span class="text-muted">热爱技术。</span> <a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a><a class="tag" taget="_blank" href="/search/c%23/1.htm">c#</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>C#:强大编程语言的多面魅力一、C#语言的特点与优势(一)简洁的语法与精心设计C#在继承C和C++的强大功能的同时,去掉了一些复杂特性,如宏和多重继承,使得语言更加简洁易懂。C#是一种面向对象的语言,使用类、对象和继承来组织代码,使得代码结构清晰,易于维护。例如,属性初始化器可以为属性设置默认值,字符串插入可以直接将变量插入到字符串中,无需使用字符串连接符,空合并运算符可以在变量为null时提供默</div> </li> <li><a href="/article/1895244841919508480.htm" title="nginx 安装(下载解压就行,免安装)" target="_blank">nginx 安装(下载解压就行,免安装)</a> <span class="text-muted">当归1024</span> <a class="tag" taget="_blank" href="/search/nginx/1.htm">nginx</a><a class="tag" taget="_blank" href="/search/nginx/1.htm">nginx</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a> <div>nginx是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。nginx由C语言编写,内存占用少,性能稳定,并发能力强,功能丰富;可以在大多数UnixLinuxOS上编译运行,并有Windows移植版。1、nginx下载地址:nginx:download2、windows安装及启动nginx是绿色免安装的,解压后可以直接启动双击nginx.exe即可启动服务</div> </li> <li><a href="/article/1895240150275911680.htm" title="The Rust Programming Language 学习 (四)" target="_blank">The Rust Programming Language 学习 (四)</a> <span class="text-muted"></span> <a class="tag" taget="_blank" href="/search/rust%E7%BB%93%E6%9E%84%E4%BD%93c%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/1.htm">rust结构体c编程语言</a> <div>结构体struct,或者structure,是一个自定义数据类型,允许你命名和包装多个相关的值,从而形成一个有意义的组合。如果你熟悉一门面向对象语言,struct就像对象中的数据属性。定义并实例化结构体和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。定义结构体,</div> </li> <li><a href="/article/1895236518625210368.htm" title="《Python入门+Python爬虫》——6Day 数据库可视化——Flask框架应用" target="_blank">《Python入门+Python爬虫》——6Day 数据库可视化——Flask框架应用</a> <span class="text-muted">不摆烂的小劉</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/flask/1.htm">flask</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a> <div>Python学习版本:Python3.X观看:Python入门+Python爬虫+Python数据分析1.Flask入门1.1关于Flask1.1.1了解框架Flask作为Web框架,它的作用主要是为了开发Web应用程序。那么我们首先来了解下Web应用程序。Web应用程序(WorldWideWeb)诞生最初的目的,是为了利用互联网交流工作文档。一切从客户端发起请求开始。所有Flask程序都必须创建</div> </li> <li><a href="/article/1895228580628066304.htm" title="非关系型数据库和关系型数据库的区别" target="_blank">非关系型数据库和关系型数据库的区别</a> <span class="text-muted">纠结哥_Shrek</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/nosql/1.htm">nosql</a> <div>非关系型数据库(NoSQL)和关系型数据库(SQL)的主要区别体现在以下几个方面:数据模型:关系型数据库(SQL):数据以表格形式存储,数据行和列组成,每个表都有固定的模式(Schema)。常见的关系型数据库有MySQL、PostgreSQL、Oracle等。非关系型数据库(NoSQL):数据没有固定的模式,存储方式更加灵活。可以是键值对、文档、列族、图等形式。常见的非关系型数据库有MongoDB</div> </li> <li><a href="/article/1895227193164886016.htm" title="使用 Microsoft OneDrive 加载文档的指南" target="_blank">使用 Microsoft OneDrive 加载文档的指南</a> <span class="text-muted">shuoac</span> <a class="tag" taget="_blank" href="/search/microsoft/1.htm">microsoft</a><a class="tag" taget="_blank" href="/search/onedrive/1.htm">onedrive</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>技术背景介绍MicrosoftOneDrive(以前称为SkyDrive)是由微软运营的文件托管服务。通过OneDrive,你可以在云端存储和共享文档、照片、视频等数据。本文将介绍如何从OneDrive加载文档,目前支持的文件格式包括docx、doc和pdf。核心原理解析为了能够从OneDrive加载文档,需要进行以下几个步骤:注册应用程序以获取客户端ID和密钥。获取OneDrive的DriveI</div> </li> <li><a href="/article/1895224417470967808.htm" title="Python -- asyncio库" target="_blank">Python -- asyncio库</a> <span class="text-muted">鹿夏</span> <div>asyncio协程前言问题的引出多线程版本多进程版本生成器版本事件循环协程FutureTask任务协程的使用回调的使用多个任务执行使用回调,如下新语法TCPEchoServer举例aiohttp库安装文档开发前言3.4版本加入标准库。asyncio底层基于selectors实现,看似库,其实就是个框架,包含异步IO、事件循环、协程、任务等内容问题的引出defa():forxinrange(3):p</div> </li> <li><a href="/article/1895220760914489344.htm" title="使用Python或R语言重新拟合模型" target="_blank">使用Python或R语言重新拟合模型</a> <span class="text-muted">pk_xz123456</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/r%E8%AF%AD%E8%A8%80/1.htm">r语言</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>以下分别给出使用Python和R语言完成该任务的示例代码,假设我们有一个包含被试编号、实验条件和反应时的数据,并且要拟合一个线性回归模型。Python实现importpandasaspdimportnumpyasnpimportstatsmodels.apiassm#生成示例数据data={'subject':np.repeat(range(1,11),5),'condition':np.tile</div> </li> <li><a href="/article/1895219375208722432.htm" title="【云原生】Docker搭建知识库文档协作平台Confluence" target="_blank">【云原生】Docker搭建知识库文档协作平台Confluence</a> <span class="text-muted">逆风飞翔的小叔</span> <a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a><a class="tag" taget="_blank" href="/search/Confluence/1.htm">Confluence</a><a class="tag" taget="_blank" href="/search/Confluence%E6%90%AD%E5%BB%BA/1.htm">Confluence搭建</a><a class="tag" taget="_blank" href="/search/Confluence%E4%BD%BF%E7%94%A8/1.htm">Confluence使用</a><a class="tag" taget="_blank" href="/search/Confluence%E6%90%AD%E5%BB%BA%E4%B8%8E%E4%BD%BF%E7%94%A8/1.htm">Confluence搭建与使用</a><a class="tag" taget="_blank" href="/search/Confluence%E4%BD%BF%E7%94%A8%E8%AF%A6%E8%A7%A3/1.htm">Confluence使用详解</a> <div>目录一、前言二、企业级知识库文档工具部署形式2.1开源工具平台2.1.1开源工具优点2.1.2开源工具缺点2.2私有化部署2.3混合部署三、如何选择合适的知识库平台工具3.1明确目标和需求3.2选择合适的知识库平台工具四、Confluence介绍4.2confluence特点4.3Confluence中的几个概念4.3.1空间(Space)4.3.2Dashboard4.3.3页面(Page)4.</div> </li> <li><a href="/article/1895218868952035328.htm" title="【C语言】解决初始化数组时报错“undefined reference to `memcpy‘”" target="_blank">【C语言】解决初始化数组时报错“undefined reference to `memcpy‘”</a> <span class="text-muted">玉米子禾</span> <a class="tag" taget="_blank" href="/search/C%E8%AF%AD%E8%A8%80/1.htm">C语言</a><a class="tag" taget="_blank" href="/search/c%E8%AF%AD%E8%A8%80/1.htm">c语言</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>【C语言】解决初始化数组时报错“undefinedreferenceto`memcpy’”零、报错代码:charstart[]={0xd,0xa,0xb3,0xcc,0xd0,0xf2,0xd2,0xd1,0xc6,0xf4,0xb6,0xaf,0xa1,0xad,0xa1,0xad,0xd,0xa,0};报错:interface.o:Infunction`main':/home/yu/fs441</div> </li> <li><a href="/article/1895216598667554816.htm" title="OpenCV开源机器视觉软件" target="_blank">OpenCV开源机器视觉软件</a> <span class="text-muted">视觉人机器视觉</span> <a class="tag" taget="_blank" href="/search/%E6%9D%82%E8%AF%B4/1.htm">杂说</a><a class="tag" taget="_blank" href="/search/opencv/1.htm">opencv</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E6%BA%90/1.htm">开源</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a> <div>OpenCV(OpenSourceComputerVisionLibrary)是一个开源的计算机视觉和机器学习软件库,广泛应用于实时图像处理、视频分析、物体检测、人脸识别等领域。它由英特尔实验室于1999年发起,现已成为计算机视觉领域最流行的工具之一,支持多种编程语言(如C++、Python、Java)和操作系统(Windows、Linux、macOS、Android、iOS)。核心功能图像处理基</div> </li> <li><a href="/article/1895211807086276608.htm" title="利用DSPy优化LangChain RAG系统的实战指南" target="_blank">利用DSPy优化LangChain RAG系统的实战指南</a> <span class="text-muted">scaFHIO</span> <a class="tag" taget="_blank" href="/search/langchain/1.htm">langchain</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>利用DSPy优化LangChainRAG系统的实战指南技术背景介绍DSPy是一个用于大语言模型(LLMs)的出色框架,它引入了一个自动编译器,能够教会模型如何执行你程序中的声明性步骤。具体来说,DSPy编译器会在内部追踪你的程序,然后为大型语言模型(LLMs)创建高质量的提示(或为小型LLMs训练自动微调),以教会它们任务的步骤。感谢OmarKhattab的努力,现在DSPy可以与LangChai</div> </li> <li><a href="/article/1895211427732451328.htm" title="硅基流动api" target="_blank">硅基流动api</a> <span class="text-muted">Zswdhy</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>官方文档内提供的API未列出ststem和user两个角色,且未提供事例文本fromopenaiimportOpenAIdefmodel_siliconflow(s_content,u_content):token="sk-xxxxxxxxxxxxxxxxxxxxxxxx"deepseek_mode="deepseek-ai/DeepSeek-V2.5"#硅基流动内的模型client=OpenAI</div> </li> <li><a href="/article/1895210291877179392.htm" title="向量数据库milvus部署" target="_blank">向量数据库milvus部署</a> <span class="text-muted">一方有点方</span> <a class="tag" taget="_blank" href="/search/milvus/1.htm">milvus</a> <div>官方文档MilvusvectordatabasedocumentationRunMilvusinDocker(Linux)|MilvusDocumentationMilvusvectordatabasedocumentation按部署比较简单,这里说一下遇到的问题一:DockerCompose方式部署1、镜像无法拉取,(docker.io被禁)只能获取以下镜像,image:quay.io/core</div> </li> <li><a href="/article/1895208021852745728.htm" title="GPT-4提示词冠军如何写 prompt:CO-STAR 框架、文本分段、系统提示" target="_blank">GPT-4提示词冠军如何写 prompt:CO-STAR 框架、文本分段、系统提示</a> <span class="text-muted">天涯倦客的美丽人生</span> <a class="tag" taget="_blank" href="/search/prompt/1.htm">prompt</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a> <div>CO-STAR框架CO-STAR框架用来构建提示词(prompt),分隔符对提示词进行文本分段。©上下文:为任务提供背景信息通过为大语言模型(LLM)提供详细的背景信息,可以帮助它精确理解讨论的具体场景,确保提供的反馈具有相关性。(O)目标:明确你要求大语言模型完成的任务清晰地界定任务目标,可以使大语言模型更专注地调整其回应,以实现这一具体目标。(S)风格:明确你期望的写作风格你可以指定一个特定的</div> </li> <li><a href="/article/1895207895490949120.htm" title="使用LangChain与GPT4All模型进行交互" target="_blank">使用LangChain与GPT4All模型进行交互</a> <span class="text-muted">bavDHAUO</span> <a class="tag" taget="_blank" href="/search/langchain/1.htm">langchain</a><a class="tag" taget="_blank" href="/search/%E4%BA%A4%E4%BA%92/1.htm">交互</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>技术背景介绍近年来,开源模型和框架在AI技术领域迅猛发展。GPT4All是一个开源的对话机器人生态系统,旨在为用户提供干净的助手数据,包括代码、故事和对话。这篇文章将介绍如何使用LangChain与GPT4All模型进行交互,以实现智能问答功能。核心原理解析GPT4All是基于大型语言模型(LLMs)的开源项目,通过训练大量干净的数据,能够生成高质量的对话和回答。LangChain是一种用于简化与</div> </li> <li><a href="/article/1895203609449132032.htm" title="程序员如何阅读英文文档" target="_blank">程序员如何阅读英文文档</a> <span class="text-muted">zcswl7961</span> <a class="tag" taget="_blank" href="/search/%E5%88%86%E5%B8%83%E5%BC%8F%E6%9E%B6%E6%9E%84/1.htm">分布式架构</a><a class="tag" taget="_blank" href="/search/%E9%98%85%E8%AF%BB%E6%8A%80%E5%B7%A7/1.htm">阅读技巧</a><a class="tag" taget="_blank" href="/search/%E8%8B%B1%E6%96%87%E6%96%87%E6%A1%A3/1.htm">英文文档</a> <div>文章目录为什么要看英文文档谈经验阅读方法语法词汇如何去记单词对全文的把握批判的观点读英语文章如何利用google来搜索答案转载为什么要看英文文档在回答怎么做之前,我想说说为什么要这么做。在我们学习新技术的过程中不是有中文文档吗?既然有中文文档,为什么还要去学习阅读英文文档呢,这不是多此一举吗?我想说的是,这绝对不算多此一举。很多的英文文档虽然有对应翻译的中文文档。但是很多东西的翻译质量是不敢恭维的</div> </li> <li><a href="/article/1895203105088270336.htm" title="前言:什么是大模型微调" target="_blank">前言:什么是大模型微调</a> <span class="text-muted">伯牙碎琴</span> <a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%A8%A1%E5%9E%8B%E5%BE%AE%E8%B0%83/1.htm">大模型微调</a><a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/1.htm">深度学习</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/1.htm">机器学习</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%A8%A1%E5%9E%8B/1.htm">大模型</a><a class="tag" taget="_blank" href="/search/%E5%BE%AE%E8%B0%83/1.htm">微调</a><a class="tag" taget="_blank" href="/search/%E8%AE%AD%E7%BB%83/1.htm">训练</a> <div>一、大模型微调的基础知识1.什么是大模型微调?大模型微调(Fine-tuning)是指在预训练模型的基础上,针对特定的任务或数据集进行进一步训练的过程。预训练模型通常在大规模的通用数据上训练,具备广泛的语言理解和生成能力。通过微调,我们可以让模型更好地适应特定的领域或任务,例如情感分析、问答系统、文本生成等。2.为什么需要微调?适应特定任务:通用模型虽然功能强大,但在特定任务上可能表现不够精准。微</div> </li> <li><a href="/article/1895202851974606848.htm" title="比较RPC和RESTful API的优缺点" target="_blank">比较RPC和RESTful API的优缺点</a> <span class="text-muted">事业运财运爆棚</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>RPC和RESTfulAPI是两种不同的远程调用方式,它们各自具有不同的优缺点。RPC的优点包括:高效:RPC使用自定义的通信协议,可以减少报文传输量,提高传输效率。灵活:RPC支持多种语言,不同的编程语言可以方便地调用远程接口。通用:RPC可以基于XML、JSON等标准化的数据格式进行通信,使得不同语言之间可以正确地传递数据。RPC的缺点包括:实现复杂:RPC需要实现编码、序列化、网络传输等功能</div> </li> <li><a href="/article/1895202095473160192.htm" title="HarmonyOS NEXT 原生应用/元服务调试概述" target="_blank">HarmonyOS NEXT 原生应用/元服务调试概述</a> <span class="text-muted">李洋-蛟龙腾飞公司</span> <a class="tag" taget="_blank" href="/search/%E5%8D%8E%E4%B8%BA/1.htm">华为</a> <div>一、概述DevEcoStudio提供了丰富的HarmonyOS应用/元服务调试能力,支持JS、ArkTS、C/C单语言调试和ArkTS/JS+C/C跨语言调试能力,并且支持三方库源码调试,帮助开发者更方便、高效地调试应用/元服务。HarmonyOS应用/元服务调试支持使用真机设备、模拟器、预览器调试。接下来以使用真机设备为例进行说明,详细的调试流程如下图所示:1.配置签名信息:使用真机设备进行调试</div> </li> <li><a href="/article/1895201717461512192.htm" title="鸿蒙HarmonyOS应用开发 | 仓颉在 HarmonyOS 开发中的应用与创新实战" target="_blank">鸿蒙HarmonyOS应用开发 | 仓颉在 HarmonyOS 开发中的应用与创新实战</a> <span class="text-muted">一键难忘</span> <a class="tag" taget="_blank" href="/search/harmonyos/1.htm">harmonyos</a><a class="tag" taget="_blank" href="/search/%E5%8D%8E%E4%B8%BA/1.htm">华为</a><a class="tag" taget="_blank" href="/search/%E5%88%86%E5%B8%83%E5%BC%8F%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/1.htm">分布式操作系统</a><a class="tag" taget="_blank" href="/search/%E4%BB%93%E9%A2%89/1.htm">仓颉</a><a class="tag" taget="_blank" href="/search/%E9%B8%BF%E8%92%99%E5%BC%80%E5%8F%91/1.htm">鸿蒙开发</a> <div>鸿蒙HarmonyOS应用开发|仓颉在HarmonyOS开发中的应用与创新实战一、引言HarmonyOS作为一款面向全场景的分布式操作系统,为开发者提供了丰富的开发工具和技术。其中,仓颉作为HarmonyOS的自研编程语言,具有独特的优势和潜力。本文将深入探讨仓颉在HarmonyOS开发中的应用与创新。二、仓颉语言的特点(一)简洁高效的语法仓颉的语法简洁明了,易于学习和使用。它采用了现代化的编程风</div> </li> <li><a href="/article/1895197554988085248.htm" title="Nacos作为配置中心怎么玩,以及Nacos为何启动就挂,Nacos配置中心有多简单。" target="_blank">Nacos作为配置中心怎么玩,以及Nacos为何启动就挂,Nacos配置中心有多简单。</a> <span class="text-muted">YourStarYang</span> <a class="tag" taget="_blank" href="/search/Nacos/1.htm">Nacos</a><a class="tag" taget="_blank" href="/search/Centos7%E4%B8%AD%E9%81%87%E5%88%B0%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B/1.htm">Centos7中遇到的那些事</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>首先从GitHub去找文档Nacos主要资源配置项application.properties(主要配置)汉化部分如下:#***************SpringBoot相关配置***************####默认的Web上下文路径:server.servlet.contextPath=/nacos###默认的Web服务器端口:server.port=8848#**************</div> </li> <li><a href="/article/1895194651783131136.htm" title="【多线程-第三天-NSOperation的练习-tableView异步下载网络图片-解决断网不停下载问题-封装下载操作 Objective-C语言】" target="_blank">【多线程-第三天-NSOperation的练习-tableView异步下载网络图片-解决断网不停下载问题-封装下载操作 Objective-C语言】</a> <span class="text-muted">清风清晨</span> <a class="tag" taget="_blank" href="/search/Objective-C/1.htm">Objective-C</a><a class="tag" taget="_blank" href="/search/objective-c/1.htm">objective-c</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/macos/1.htm">macos</a> <div>一、解决断网不停下载问题1.刚刚,我们写了一个自定义cell,下边我们接着来看,刚刚我们遇到一个问题,断网的情况下,是不是就出事儿了,我们来看一下啊,为什么,我现在先把网断了啊,已经把网断了,把网给断掉了,断掉之后,我们来运行,这个时候会不停的会去下载,但是又没网,永远下不完,为什么会这样呢,我们看一下执行的过程,那不停的在下载网络图片,肯定是不停的在返回cell,因为在返回cell的时候,是不是</div> </li> <li><a href="/article/1895194525429723136.htm" title="【多线程-第三天-NSOperation的练习-tableView异步下载网络图片-图片缓存池 Objective-C语言】" target="_blank">【多线程-第三天-NSOperation的练习-tableView异步下载网络图片-图片缓存池 Objective-C语言】</a> <span class="text-muted">清风清晨</span> <a class="tag" taget="_blank" href="/search/Objective-C/1.htm">Objective-C</a><a class="tag" taget="_blank" href="/search/%E7%BC%93%E5%AD%98/1.htm">缓存</a><a class="tag" taget="_blank" href="/search/objective-c/1.htm">objective-c</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>一、图片缓存池1.下面我们该解决什么问题了,运行一下试试,往上拽,图片慢慢儿去下载,下载完成以后,会把这个图片缓存到内存中来,假设你手机内存特别小,我手机内存是1G的内存,开了好多个应用,好,现在内存不够用了,收到内存警告了,我们要干什么,处理内存警告,我们是不是得清理出来一部分内存,清理哪部分内存呢,哪部分内存不需要用了呢,没有显示的那些图片,这些图片,是不是都在内存中存着呢,这些图片,是不是在</div> </li> <li><a href="/article/1895194524217569280.htm" title="【多线程-第三天-NSOperation的练习-tableView异步下载网络图片-解决错行问题 Objective-C语言】" target="_blank">【多线程-第三天-NSOperation的练习-tableView异步下载网络图片-解决错行问题 Objective-C语言】</a> <span class="text-muted">清风清晨</span> <a class="tag" taget="_blank" href="/search/Objective-C/1.htm">Objective-C</a><a class="tag" taget="_blank" href="/search/objective-c/1.htm">objective-c</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/macos/1.htm">macos</a> <div>一、刚刚,我们做了图片缓存,图片缓存解决了什么问题1.图片缓存解决了什么问题//5图片缓存-----把网络上下载的图片,保存到内存//解决,图片重复下载,把图片缓存到内存中,节省用户的流量(拿空间换取执行时间)这就是缓存啊,这才是真正的缓存,缓存是什么意思,就是拿空间换时间,好,这件事情搞定,我们继续来往下看,看还有什么问题呢,2.看,瞬间就演示出来了,这张图片是对的吗,植物大战僵尸是这张图片吗,</div> </li> <li><a href="/article/1895190866885144576.htm" title="Azure AI Search Retriever 深度指南" target="_blank">Azure AI Search Retriever 深度指南</a> <span class="text-muted">bBADAS</span> <a class="tag" taget="_blank" href="/search/azure/1.htm">azure</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/flask/1.htm">flask</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a> <div>技术背景介绍AzureAISearch(前称AzureCognitiveSearch)是微软提供的云端搜索服务,为开发者提供了强大的基础设施、API和工具,以扩展性地进行向量、关键词和混合查询的信息检索。AzureAISearchRetriever是一个集成模块,能够从非结构化查询中返回文档。它基于BaseRetriever类,并针对AzureAISearch的2023-11-01稳定RESTAP</div> </li> <li><a href="/article/1895183806877462528.htm" title="freemarker解析html标签,【转】Freemarker输出$和html标签等特殊符号" target="_blank">freemarker解析html标签,【转】Freemarker输出$和html标签等特殊符号</a> <span class="text-muted">weixin_39970689</span> <div>原文:http://blog.csdn.net/achilles12345/article/details/41820507场景:程序员都不喜欢看文档,而更喜欢抄例子。所以,我们把平台组的组件都做成例子供别人参考。我们前端展示层使用的是freemarker,所以遇到这个问题,比如我们要让前端显示freemarker自己的源码时就有问题了(因为我们例子程序的页面也是使用freemarker)。遇到的</div> </li> <li><a href="/article/38.htm" title="ASM系列六 利用TreeApi 添加和移除类成员" target="_blank">ASM系列六 利用TreeApi 添加和移除类成员</a> <span class="text-muted">lijingyao8206</span> <a class="tag" taget="_blank" href="/search/jvm/1.htm">jvm</a><a class="tag" taget="_blank" href="/search/%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86/1.htm">动态代理</a><a class="tag" taget="_blank" href="/search/ASM/1.htm">ASM</a><a class="tag" taget="_blank" href="/search/%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF/1.htm">字节码技术</a><a class="tag" taget="_blank" href="/search/TreeAPI/1.htm">TreeAPI</a> <div>    同生成的做法一样,添加和移除类成员只要去修改fields和methods中的元素即可。这里我们拿一个简单的类做例子,下面这个Task类,我们来移除isNeedRemove方法,并且添加一个int 类型的addedField属性。   package asm.core; /** * Created by yunshen.ljy on 2015/6/</div> </li> <li><a href="/article/165.htm" title="Springmvc-权限设计" target="_blank">Springmvc-权限设计</a> <span class="text-muted">bee1314</span> <a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/jsp/1.htm">jsp</a> <div> 万丈高楼平地起。 权限管理对于管理系统而言已经是标配中的标配了吧,对于我等俗人更是不能免俗。同时就目前的项目状况而言,我们还不需要那么高大上的开源的解决方案,如Spring Security,Shiro。小伙伴一致决定我们还是从基本的功能迭代起来吧。 目标: 1.实现权限的管理(CRUD) 2.实现部门管理 (CRUD) 3.实现人员的管理 (CRUD) 4.实现部门和权限</div> </li> <li><a href="/article/292.htm" title="算法竞赛入门经典(第二版)第2章习题" target="_blank">算法竞赛入门经典(第二版)第2章习题</a> <span class="text-muted">CrazyMizzz</span> <a class="tag" taget="_blank" href="/search/c/1.htm">c</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a> <div>2.4.1 输出技巧 #include <stdio.h> int main() { int i, n; scanf("%d", &n); for (i = 1; i <= n; i++) printf("%d\n", i); return 0; } 习题2-2 水仙花数(daffodil</div> </li> <li><a href="/article/419.htm" title="struts2中jsp自动跳转到Action" target="_blank">struts2中jsp自动跳转到Action</a> <span class="text-muted">麦田的设计者</span> <a class="tag" taget="_blank" href="/search/jsp/1.htm">jsp</a><a class="tag" taget="_blank" href="/search/webxml/1.htm">webxml</a><a class="tag" taget="_blank" href="/search/struts2/1.htm">struts2</a><a class="tag" taget="_blank" href="/search/%E8%87%AA%E5%8A%A8%E8%B7%B3%E8%BD%AC/1.htm">自动跳转</a> <div>1、在struts2的开发中,经常需要用户点击网页后就直接跳转到一个Action,执行Action里面的方法,利用mvc分层思想执行相应操作在界面上得到动态数据。毕竟用户不可能在地址栏里输入一个Action(不是专业人士)   2、<jsp:forward page="xxx.action" /> ,这个标签可以实现跳转,page的路径是相对地址,不同与jsp和j</div> </li> <li><a href="/article/546.htm" title="php 操作webservice实例" target="_blank">php 操作webservice实例</a> <span class="text-muted">IT独行者</span> <a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/webservice/1.htm">webservice</a> <div>首先大家要简单了解了何谓webservice,接下来就做两个非常简单的例子,webservice还是逃不开server端与client端。我测试的环境为:apache2.2.11 php5.2.10做这个测试之前,要确认你的php配置文件中已经将soap扩展打开,即extension=php_soap.dll; OK 现在我们来体验webservice //server端 serve</div> </li> <li><a href="/article/673.htm" title="Windows下使用Vagrant安装linux系统" target="_blank">Windows下使用Vagrant安装linux系统</a> <span class="text-muted">_wy_</span> <a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a><a class="tag" taget="_blank" href="/search/vagrant/1.htm">vagrant</a> <div>准备工作: 下载安装 VirtualBox :https://www.virtualbox.org/ 下载安装 Vagrant :http://www.vagrantup.com/ 下载需要使用的 box : 官方提供的范例:http://files.vagrantup.com/precise32.box 还可以在 http://www.vagrantbox.es/ </div> </li> <li><a href="/article/800.htm" title="更改linux的文件拥有者及用户组(chown和chgrp)" target="_blank">更改linux的文件拥有者及用户组(chown和chgrp)</a> <span class="text-muted">无量</span> <a class="tag" taget="_blank" href="/search/c/1.htm">c</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/chgrp/1.htm">chgrp</a><a class="tag" taget="_blank" href="/search/chown/1.htm">chown</a> <div>本文(转) http://blog.163.com/yanenshun@126/blog/static/128388169201203011157308/ http://ydlmlh.iteye.com/blog/1435157 一、基本使用: 使用chown命令可以修改文件或目录所属的用户:        命令</div> </li> <li><a href="/article/927.htm" title="linux下抓包工具" target="_blank">linux下抓包工具</a> <span class="text-muted">矮蛋蛋</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a> <div>原文地址: http://blog.chinaunix.net/uid-23670869-id-2610683.html tcpdump -nn -vv -X udp port 8888 上面命令是抓取udp包、端口为8888 netstat -tln 命令是用来查看linux的端口使用情况 13 . 列出所有的网络连接 lsof -i 14. 列出所有tcp 网络连接信息 l</div> </li> <li><a href="/article/1054.htm" title="我觉得mybatis是垃圾!:“每一个用mybatis的男纸,你伤不起”" target="_blank">我觉得mybatis是垃圾!:“每一个用mybatis的男纸,你伤不起”</a> <span class="text-muted">alafqq</span> <a class="tag" taget="_blank" href="/search/mybatis/1.htm">mybatis</a> <div>最近看了  每一个用mybatis的男纸,你伤不起 原文地址 :http://www.iteye.com/topic/1073938 发表一下个人看法。欢迎大神拍砖; 个人一直使用的是Ibatis框架,公司对其进行过小小的改良; 最近换了公司,要使用新的框架。听说mybatis不错;就对其进行了部分的研究; 发现多了一个mapper层;个人感觉就是个dao; </div> </li> <li><a href="/article/1181.htm" title="解决java数据交换之谜" target="_blank">解决java数据交换之谜</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E4%BA%A4%E6%8D%A2/1.htm">数据交换</a> <div>交换两个数字的方法有以下三种 ,其中第一种最常用   /* 输出最小的一个数 */ public class jiaohuan1 { public static void main(String[] args) { int a =4; int b = 3; if(a<b){ // 第一种交换方式 int tmep =</div> </li> <li><a href="/article/1308.htm" title="渐变显示" target="_blank">渐变显示</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a> <div><style type="text/css"> #wxf { FILTER: progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#ffffff, EndColorStr=#97FF98); height: 25px; } </style></div> </li> <li><a href="/article/1435.htm" title="探索JUnit4扩展:断言语法assertThat" target="_blank">探索JUnit4扩展:断言语法assertThat</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/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/1.htm">单元测试</a><a class="tag" taget="_blank" href="/search/assertThat/1.htm">assertThat</a> <div>一.概述         JUnit 设计的目的就是有效地抓住编程人员写代码的意图,然后快速检查他们的代码是否与他们的意图相匹配。 JUnit 发展至今,版本不停的翻新,但是所有版本都一致致力于解决一个问题,那就是如何发现编程人员的代码意图,并且如何使得编程人员更加容易地表达他们的代码意图。JUnit 4.4 也是为了如何能够</div> </li> <li><a href="/article/1562.htm" title="【Gson三】Gson解析{"data":{"IM":["MSN","QQ","Gtalk"]}}" target="_blank">【Gson三】Gson解析{"data":{"IM":["MSN","QQ","Gtalk"]}}</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/gson/1.htm">gson</a> <div>  如何把如下简单的JSON字符串反序列化为Java的POJO对象? {"data":{"IM":["MSN","QQ","Gtalk"]}}   下面的POJO类Model无法完成正确的解析:   import com.google.gson.Gson;</div> </li> <li><a href="/article/1689.htm" title="【Kafka九】Kafka High Level API vs. Low Level API" target="_blank">【Kafka九】Kafka High Level API vs. Low Level API</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/kafka/1.htm">kafka</a> <div>1. Kafka提供了两种Consumer API High Level Consumer API Low Level Consumer API(Kafka诡异的称之为Simple Consumer API,实际上非常复杂) 在选用哪种Consumer API时,首先要弄清楚这两种API的工作原理,能做什么不能做什么,能做的话怎么做的以及用的时候,有哪些可能的问题  </div> </li> <li><a href="/article/1816.htm" title="在nginx中集成lua脚本:添加自定义Http头,封IP等" target="_blank">在nginx中集成lua脚本:添加自定义Http头,封IP等</a> <span class="text-muted">ronin47</span> <a class="tag" taget="_blank" href="/search/nginx+lua/1.htm">nginx lua</a> <div>Lua是一个可以嵌入到Nginx配置文件中的动态脚本语言,从而可以在Nginx请求处理的任何阶段执行各种Lua代码。刚开始我们只是用Lua 把请求路由到后端服务器,但是它对我们架构的作用超出了我们的预期。下面就讲讲我们所做的工作。 强制搜索引擎只索引mixlr.com Google把子域名当作完全独立的网站,我们不希望爬虫抓取子域名的页面,降低我们的Page rank。 location /{</div> </li> <li><a href="/article/1943.htm" title="java-归并排序" target="_blank">java-归并排序</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div> import java.util.Arrays; public class MergeSort { public static void main(String[] args) { int[] a={20,1,3,8,5,9,4,25}; mergeSort(a,0,a.length-1); System.out.println(Arrays.to</div> </li> <li><a href="/article/2070.htm" title="Netty源码学习-CompositeChannelBuffer" target="_blank">Netty源码学习-CompositeChannelBuffer</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/netty/1.htm">netty</a> <div>CompositeChannelBuffer体现了Netty的“Transparent Zero Copy” 查看API( http://docs.jboss.org/netty/3.2/api/org/jboss/netty/buffer/package-summary.html#package_description) 可以看到,所谓“Transparent Zero Copy”是通</div> </li> <li><a href="/article/2197.htm" title="Android中给Activity添加返回键" target="_blank">Android中给Activity添加返回键</a> <span class="text-muted">hotsunshine</span> <a class="tag" taget="_blank" href="/search/Activity/1.htm">Activity</a> <div> // this need android:minSdkVersion="11" getActionBar().setDisplayHomeAsUpEnabled(true); @Override public boolean onOptionsItemSelected(MenuItem item) { </div> </li> <li><a href="/article/2324.htm" title="静态页面传参" target="_blank">静态页面传参</a> <span class="text-muted">ctrain</span> <a class="tag" taget="_blank" href="/search/%E9%9D%99%E6%80%81/1.htm">静态</a> <div> $(document).ready(function () { var request = { QueryString : function (val) { var uri = window.location.search; var re = new RegExp("" + val + "=([^&?]*)", &</div> </li> <li><a href="/article/2451.htm" title="Windows中查找某个目录下的所有文件中包含某个字符串的命令" target="_blank">Windows中查找某个目录下的所有文件中包含某个字符串的命令</a> <span class="text-muted">daizj</span> <a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a><a class="tag" taget="_blank" href="/search/%E6%9F%A5%E6%89%BE%E6%9F%90%E4%B8%AA%E7%9B%AE%E5%BD%95%E4%B8%8B%E7%9A%84%E6%89%80%E6%9C%89%E6%96%87%E4%BB%B6/1.htm">查找某个目录下的所有文件</a><a class="tag" taget="_blank" href="/search/%E5%8C%85%E5%90%AB%E6%9F%90%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2/1.htm">包含某个字符串</a> <div>findstr可以完成这个工作。   [html]  view plain copy   >findstr /s /i "string" *.*   上面的命令表示,当前目录以及当前目录的所有子目录下的所有文件中查找"string&qu</div> </li> <li><a href="/article/2578.htm" title="改善程序代码质量的一些技巧" target="_blank">改善程序代码质量的一些技巧</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a><a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/%E9%87%8D%E6%9E%84/1.htm">重构</a> <div>有很多理由都能说明为什么我们应该写出清晰、可读性好的程序。最重要的一点,程序你只写一次,但以后会无数次的阅读。当你第二天回头来看你的代码 时,你就要开始阅读它了。当你把代码拿给其他人看时,他必须阅读你的代码。因此,在编写时多花一点时间,你会在阅读它时节省大量的时间。让我们看一些基本的编程技巧:    尽量保持方法简短    尽管很多人都遵</div> </li> <li><a href="/article/2705.htm" title="SharedPreferences对数据的存储" target="_blank">SharedPreferences对数据的存储</a> <span class="text-muted">dcj3sjt126com</span> <div>SharedPreferences简介:                                                   &nbs</div> </li> <li><a href="/article/2832.htm" title="linux复习笔记之bash shell (2) bash基础" target="_blank">linux复习笔记之bash shell (2) bash基础</a> <span class="text-muted">eksliang</span> <a class="tag" taget="_blank" href="/search/bash/1.htm">bash</a><a class="tag" taget="_blank" href="/search/bash+shell/1.htm">bash shell</a> <div>转载请出自出处: http://eksliang.iteye.com/blog/2104329 1.影响显示结果的语系变量(locale)  1.1locale这个命令就是查看当前系统支持多少种语系,命令使用如下: [root@localhost shell]# locale LANG=en_US.UTF-8 LC_CTYPE="en_US.UTF-8" </div> </li> <li><a href="/article/2959.htm" title="Android零碎知识总结" target="_blank">Android零碎知识总结</a> <span class="text-muted">gqdy365</span> <a class="tag" taget="_blank" href="/search/android/1.htm">android</a> <div>1、CopyOnWriteArrayList add(E) 和remove(int index)都是对新的数组进行修改和新增。所以在多线程操作时不会出现java.util.ConcurrentModificationException错误。 所以最后得出结论:CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。发生修改时候做copy,新老版本分离,保证读的高</div> </li> <li><a href="/article/3086.htm" title="HoverTree.Model.ArticleSelect类的作用" target="_blank">HoverTree.Model.ArticleSelect类的作用</a> <span class="text-muted">hvt</span> <a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a><a class="tag" taget="_blank" href="/search/hovertree/1.htm">hovertree</a><a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a> <div>ArticleSelect类在命名空间HoverTree.Model中可以认为是文章查询条件类,用于存放查询文章时的条件,例如HvtId就是文章的id。HvtIsShow就是文章的显示属性,当为-1是,该条件不产生作用,当为0时,查询不公开显示的文章,当为1时查询公开显示的文章。HvtIsHome则为是否在首页显示。HoverTree系统源码完全开放,开发环境为Visual Studio 2013</div> </li> <li><a href="/article/3213.htm" title="PHP 判断是否使用代理 PHP Proxy Detector" target="_blank">PHP 判断是否使用代理 PHP Proxy Detector</a> <span class="text-muted">天梯梦</span> <a class="tag" taget="_blank" href="/search/proxy/1.htm">proxy</a> <div>1. php 类 I found this class looking for something else actually but I remembered I needed some while ago something similar and I never found one. I'm sure it will help a lot of developers who try to </div> </li> <li><a href="/article/3340.htm" title="apache的math库中的回归——regression(翻译)" target="_blank">apache的math库中的回归——regression(翻译)</a> <span class="text-muted">lvdccyb</span> <a class="tag" taget="_blank" href="/search/Math/1.htm">Math</a><a class="tag" taget="_blank" href="/search/apache/1.htm">apache</a> <div>这个Math库,虽然不向weka那样专业的ML库,但是用户友好,易用。 多元线性回归,协方差和相关性(皮尔逊和斯皮尔曼),分布测试(假设检验,t,卡方,G),统计。   数学库中还包含,Cholesky,LU,SVD,QR,特征根分解,真不错。   基本覆盖了:线代,统计,矩阵, 最优化理论 曲线拟合 常微分方程 遗传算法(GA), 还有3维的运算。。。 </div> </li> <li><a href="/article/3467.htm" title="基础数据结构和算法十三:Undirected Graphs (2)" target="_blank">基础数据结构和算法十三:Undirected Graphs (2)</a> <span class="text-muted">sunwinner</span> <a class="tag" taget="_blank" href="/search/Algorithm/1.htm">Algorithm</a> <div>  Design pattern for graph processing. Since we consider a large number of graph-processing algorithms, our initial design goal is to decouple our implementations from the graph representation</div> </li> <li><a href="/article/3594.htm" title="云计算平台最重要的五项技术" target="_blank">云计算平台最重要的五项技术</a> <span class="text-muted">sumapp</span> <a class="tag" taget="_blank" href="/search/%E4%BA%91%E8%AE%A1%E7%AE%97/1.htm">云计算</a><a class="tag" taget="_blank" href="/search/%E4%BA%91%E5%B9%B3%E5%8F%B0/1.htm">云平台</a><a class="tag" taget="_blank" href="/search/%E6%99%BA%E5%9F%8E%E4%BA%91/1.htm">智城云</a> <div>云计算平台最重要的五项技术 1、云服务器 云服务器提供简单高效,处理能力可弹性伸缩的计算服务,支持国内领先的云计算技术和大规模分布存储技术,使您的系统更稳定、数据更安全、传输更快速、部署更灵活。 特性 机型丰富 通过高性能服务器虚拟化为云服务器,提供丰富配置类型虚拟机,极大简化数据存储、数据库搭建、web服务器搭建等工作; 仅需要几分钟,根据CP</div> </li> <li><a href="/article/3721.htm" title="《京东技术解密》有奖试读获奖名单公布" target="_blank">《京东技术解密》有奖试读获奖名单公布</a> <span class="text-muted">ITeye管理员</span> <a class="tag" taget="_blank" href="/search/%E6%B4%BB%E5%8A%A8/1.htm">活动</a> <div>ITeye携手博文视点举办的12月技术图书有奖试读活动已圆满结束,非常感谢广大用户对本次活动的关注与参与。  12月试读活动回顾: http://webmaster.iteye.com/blog/2164754 本次技术图书试读活动获奖名单及相应作品如下: 一等奖(两名) Microhardest:http://microhardest.ite</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><script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>