1、Thymeleaf简介

Thymeleaf 是一个跟Velocity、FreeMarker类似的模板引擎,它完全可以代替JSP。相比较于其他的模板引擎,它具有如下三个吸引人的特点:

  • Thymeleaf在有网络和无网络的环境下即可运行,它即可用让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态效果。这是由于它支持HTML原型,然后在HTML标签里增加额外的属性来达到模板+数据的展示方式。浏览器解析HTML时会忽略未定义的标签属性,所以Thymeleaf的模板可以静态的运行;当有数据返回到页面时,Thymeleaf标签会动态地替换掉静态内容,使页面动态显示。
  • Thymeleaf开箱即用的特性。他提供标准和Spring 标准两种方言,可以直接套用模板实现JSTL、OGNL表达式效果,避免每天套用模板、改JSTL、改标签的困扰,同时开发人员可以扩展和创建自定义的方言。
  • Thymeleaf提供Spring标准方言和一个与SpringMVC完美集成的可选模板,可以快速地实现表单绑定、属性编辑器、国际化等功能。
如:<span th:text="${username}">张三</span>

静态时,th:text="${username}" 被忽略,显示“张三”,动态时,th:text="${username}" 加载成功,覆盖 “张三

2、为什么使用Thymeleaf

如果希望以Jar形式发布模块,则尽量不要使用JSP知识,这是因为JSP在内嵌的Servlet容器上运行有一些问题(内嵌Tomcat、Jetty不支持Jar形式运行JSP,Undertow不支持JSP)。

Spring Boot中推荐使用Thymeleaf作为模板引擎,这是因为Thymeleaf提供了完美的Spring MVC支持。

Spring Boot提供了大量的模板引擎,包括:

  • FreeMarker
  • Groovy
  • Mustache
  • Thymeleaf
  • Velocity
  • Beetl(官网号称最快的模板引擎)

3、第一个Thymeleaf模板页

3.1 创建项目

直接看图,图中有标注

【Spring Boot】3. Spring Boot整合Thymeleaf_spring boot

【Spring Boot】3. Spring Boot整合Thymeleaf_spring boot_02

【Spring Boot】3. Spring Boot整合Thymeleaf_Thymeleaf_03

【Spring Boot】3. Spring Boot整合Thymeleaf_Thymeleaf_04

此时,项目就创建完毕了。

3.2 相关配置

此处建议添加一个依赖:nekohtml,其作用主要是允许使用非严格的 HTML 语法。

pom.xml中添加以下依赖即可添加nekohtml依赖:

        <!--提供非严格HTML模式支持-->
        <dependency>
            <groupId>net.sourceforge.nekohtml</groupId>
            <artifactId>nekohtml</artifactId>
            <version>1.9.22</version>
        </dependency>

完整的pom.xml如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.13.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cxhit</groupId>
    <artifactId>hello-spring-boot-thymeleaf</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <name>hello-spring-boot-thymeleaf</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--thymeleaf模板引擎-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!--提供非严格HTML模式支持-->
        <dependency>
            <groupId>net.sourceforge.nekohtml</groupId>
            <artifactId>nekohtml</artifactId>
            <version>1.9.22</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

修改**application.propertiesapplication.yml**,配置 Thymeleaf

spring:
  thymeleaf:
    cache: false  #开发时关闭缓存,不然没法实时看到页面
    mode: LEGACYHTML5  #用非严格的HTML(标签不必严格遵守W3C标准)
    encoding: UTF-8
    servlet:
      content-type: text/html #内容类型为HTML

3.3 创建测试用JavaBean

如下:

【Spring Boot】3. Spring Boot整合Thymeleaf_Thymeleaf_05

源码如下:

package com.cxhit.hello.spring.boot.thymeleaf.entity;

import java.io.Serializable;

/*实现序列化接口*/
public class User implements Serializable {

    private String username;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

3.4 创建测试用Controller

如下:

【Spring Boot】3. Spring Boot整合Thymeleaf_Thymeleaf_06

package com.cxhit.hello.spring.boot.thymeleaf.controller;

import com.cxhit.hello.spring.boot.thymeleaf.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class MainController {

    @RequestMapping(value = {"","index"},method = RequestMethod.GET)
    public String index(Model model){
        User user = new User();
        user.setUsername("张三");

        model.addAttribute("user",user);

        return "index";
    }


}

3.5 创建测试页面

首选创建一个HTML页面,如下:

【Spring Boot】3. Spring Boot整合Thymeleaf_spring boot_07

修改前面HTML标签用于引入Thymeleaf引擎,这样才可以在其他标签中使用th:*语法,声明如下:

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">

完整的HTML代码如下:

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<span th:text="${user.username}" >李四</span>

</body>
</html>

3.6 测试结果

如果直接访问,显示“李四”,如果启动Spring Boot访问,显示“张三”,如下:

【Spring Boot】3. Spring Boot整合Thymeleaf_spring boot_08

4、Thymeleaf常用语法

4.1 引入 Thymeleaf

修改 html 标签用于引入 thymeleaf 引擎,这样才可以在其他标签里使用 th:* 语法,这是下面语法的前提。

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">

4.2 获取变量值

<p th:text="'Hello!, ' + ${name} + '!'" >name</p>

可以看出获取变量值用 $ 符号,对于javaBean的话使用 变量名.属性名 方式获取,这点和 EL 表达式一样.

另外 $ 表达式只能写在th标签内部,不然不会生效,上面例子就是使用 th:text 标签的值替换 p 标签里面的值,至于 p 里面的原有的值只是为了给前端开发时做展示用的.这样的话很好的做到了前后端分离.

4.3 引入 URL

Thymeleaf 对于 URL 的处理是通过语法 @{…} 来处理的

<a th:href="@{http://www.baidu.com}">绝对路径</a>
<a th:href="@{/}">相对路径</a>
<a th:href="@{css/bootstrap.min.css}">Content路径,默认访问static下的css文件夹</a>

类似的标签有:th:hrefth:src

4.4 字符串替换

很多时候可能我们只需要对一大段文字中的某一处地方进行替换,可以通过字符串拼接操作完成:

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

一种更简洁的方式是:

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

当然这种形式限制比较多,|…|中只能包含变量表达式${…},不能包含其他常量、条件表达式等。

4.5 运算符

在表达式中可以使用各类算术运算符,例如+, -, *, /, %

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

逻辑运算符>, <, <=,>=,==,!=都可以使用,唯一需要注意的是使用<,>时需要用它的HTML转义符:

th:if="${prodStat.count} &gt; 1"
th:text="'Execution mode is ' + ( (${execMode} == 'dev')? 'Development' : 'Production')"

4.6 条件

if/unless

Thymeleaf 中使用 th:ifth:unless 属性进行条件判断,下面的例子中,标签只有在 th:if 中条件成立时才显示:

<a th:href="@{/login}" th:unless=${session.user != null}>Login</a>

th:unlessth:if 恰好相反,只有表达式中的条件不成立,才会显示其内容。

switch

Thymeleaf 同样支持多路选择 Switch 结构:

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

默认属性 default 可以用 * 表示:

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

4.7 循环

渲染列表数据是一种非常常见的场景,例如现在有 n 条记录需要渲染成一个表格,该数据集合必须是可以遍历的,使用 th:each 标签:

<body>
  <h1>Product list</h1>

  <table>
    <tr>
      <th>NAME</th>
      <th>PRICE</th>
      <th>IN STOCK</th>
    </tr>
    <tr th:each="prod : ${prods}">
      <td th:text="${prod.name}">Onions</td>
      <td th:text="${prod.price}">2.41</td>
      <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
    </tr>
  </table>

  <p>
    <a href="../home.html" th:href="@{/}">Return to home</a>
  </p>
</body>

可以看到,需要在被循环渲染的元素(这里是)中加入 th:each 标签,其中 th:each="prod : ${prods}" 意味着对集合变量 prods 进行遍历,循环变量是 prod 在循环体中可以通过表达式访问。