Spring Boot教程(三):Thymeleaf详解

一、简介

  我们将在这一节学习 Thymeleaf 模板引擎技术,首先会介绍 Thymeleaf 的基本概念,然后再详细介绍 Thymeleaf 模板引擎的属性和表达式语法,并结合实际的代码进行页面功能开发。

  首先,我们得有一个spring boot项目,通过spring initializer创建一个项目,选择web依赖,可以也选择thymeleaf依赖,当然也可以在pom中手动添加依赖:

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

实例1:thymeleaf初步展示

  我们在template下创建一个thymeleaf.html文件,用来初步展示thymeleaf:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Thymeleaf demo</title>
  </head>
  <body>
    <p>description字段值为:</p>
    <p th:text="${description}">这里显示的是 description 字段内容</p>
  </body>
</html>

  当然,controller也是得写的,我们在controller包下创建ThymeleafController类:

@Controller
public class ThymeleafController {
    
    
    @GetMapping("/thymeleaf")
    public String hello(HttpServletRequest request,@RequestParam(value = "description", required = false,
              defaultValue = "springboot-thymeleaf") String description){
    
    
        request.setAttribute("description", description);
        return "thymeleaf";
    }
}

  启动项目之后,就可以在浏览器中访问服务了:

在这里插入图片描述

二、语法详解

1.属性

  th:text 对应的是 HTML5 中的 text 属性,除 th:text 属性外,Thymeleaf 也提供了其他的标签属性来替换 HTML5 原生属性的值,属性节选如下:

在这里插入图片描述

  • th:background 对应 HTML5 中的背景属性
  • th:class 对应 HTML5 中的 class 属性
  • th:href 对应 HTML5 中的链接地址属性
  • th:id 和 th:name 分别对应 HTML5 中的 id 和 name 属性…
  • th:block 比较特殊,它是 Thymeleaf 提供的唯一的一个 Thymeleaf 块级元素,其特殊性在于 Thymeleaf 模板引擎在处理th:block的时候会删掉它本身,而保留其内容。

  这里只列举了部分属性,完整内容可以查看 thymeleaf-attributes

实例2:属性

  在templates目录下创建attributes.html ,用于展示thymeleaf中属性与html属性语法的不同,其中生效的是thymeleaf语法,html原本的属性代码仅做对照和参考:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Thymeleaf setting-value-to-specific-attributes</title>
    <meta charset="UTF-8" />
  </head>
  <!-- background 标签-->
  <body th:background="${th_bgcolor}" background="#B0C4DE">
    <!-- text 标签-->
    <h1 th:text="${title}">html标签演示</h1>
    <div>
      <h5>id、name、value标签:</h5>
      <!-- id、name、value标签-->
      <input
        id="input1"
        name="input1"
        value="1"
        th:id="${th_id}"
        th:name="${th_name}"
        th:value="${th_value}"
      />
    </div>
    <br />
    <div class="div1" th:class="${th_class}">
      <h5>class、href标签:</h5>
      <!-- class、href标签-->
      <a th:href="${th_href}" href="##/">链接地址</a>
    </div>
  </body>
</html>

  controller中对应方法如下:

@GetMapping("/attributes")
    public String attributes(ModelMap map) {
    
    
        //更改background
        map.put("th_bgcolor","#B0C4DE");
        // 更改 h1 内容
        map.put("title", "Thymeleaf 标签演示");
        // 更改 id、name、value
        map.put("th_id", "thymeleaf-input");
        map.put("th_name", "thymeleaf-input");
        map.put("th_value", "13");
        // 更改 class、href
        map.put("th_class", "thymeleaf-class");
        map.put("th_href", "http://www.hao123.com");
        return "attributes";
    }

  效果:

在这里插入图片描述

2.语法规则

  • 表达式语法

    变量表达式: ${…}
    选择变量表达式: *{…}
    信息表达式: #{…}
    链接 URL 表达式: @{…}
    分段表达式: ~{…}

  • 字面量

    字符串: ‘one text’, ‘Another one!’ …
    数字: 0, 34, 3.0, 12.3 …
    布尔值: true, false
    Null 值: null
    字面量标记:one, sometext, main …

  • 文本运算

    字符串拼接: +
    字面量置换: |The name is ${name}|

  • 算术运算

    二元运算符: +, -, *, /, %
    负号(一元运算符): (unary operator): -

  • 布尔运算

    二元运算符: and, or
    布尔非(一元运算符): !, not

  • 比较运算

    比较: >, <, >=, <= (gt, lt, ge, le)
    相等运算符: ==, != (eq, ne)
    比较运算符也可以使用转义字符,比如大于号,可以使用 Thymeleaf 语法 gt 也可以使用转义字符>

  • 条件运算符

    If-then: (if) ? (then)
    If-then-else: (if) ? (then) : (else)
    Default: (value) ?: (defaultvalue)

  • 特殊语法

    无操作: _

实例3:字面量、运算

  新建 simple.html 模板页面,该案例主要介绍字面量及简单的运算操作,包括字符串、数字、布尔值等常用的字面量及常用的运算和拼接操作,代码如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Thymeleaf simple syntax</title>
    <meta charset="UTF-8" />
</head>
<body>
<h1>Thymeleaf简单语法</h1>
<div>
    <h5>基本类型操作(字符串):</h5>
    <p>
        一个简单的字符串:<span th:text="'thymeleaf text'">default text</span>.
    </p>
    <p>
        字符串连接:<span th:text="'thymeleaf text concat, '+${thymeleafText}"
    >default text</span
    >.
    </p>
    <p>
        字符串连接:<span th:text="|thymeleaf text concat,${thymeleafText}|"
    >default text</span
    >.
    </p>
</div>
<div>
    <h5>基本类型操作(数字):</h5>
    <p>一个简单的神奇的数字:<span th:text="2019">1000</span>.</p>
    <p>算术运算: 2021+1=<span th:text="${number1}+1">0</span>.</p>
    <p>算术运算: 14-1=<span th:text="14-1">0</span>.</p>
    <p>算术运算: 673 * 3=<span th:text="673*${number2}">0</span>.</p>
    <p>算术运算: 39 ÷ 3=<span th:text="39/3">0</span>.</p>
</div>
<div>
    <h5>基本类型操作(布尔值):</h5>
    <p>
        一个简单的数字比较:2019 > 2018=<span th:text="2019>2018"> </span>.
    </p>
    <p>
        字符串比较:兔兔 == '兔兔',结果为<span
            th:text="${thymeleafText} == '兔兔'"
    >0</span
    >.
    </p>
    <p>数字比较:13 == 39/3 结果为: <span th:text="13 == 39/3">0</span>.</p>
</div>
</body>
</html>

  对应的controller方法:

@GetMapping("/simple")
    public String simple(ModelMap map) {
    
    
        map.put("thymeleafText", "兔兔");
        map.put("number1", 2021);
        map.put("number2", 3);
        return "simple";
    }

  效果:

在这里插入图片描述

实例4:表达式语法

  • 变量表达式:

  变量表达式即 OGNL 表达式或 Spring EL 表达式,作用是获取模板中与后端返回数据所绑定对象的值,写法为 ${…},这是最常见的一个表达式,在取值赋值、逻辑判断、循环语句中都可以使用该表达式,示例如下:

<!-- 读取参数 -->
<p>算术运算: 2018+1=<span th:text="${number1}+1">0</span>.</p>
<!-- 读取参数并运算 -->
<div th:class="${path}=='links'?'nav-link active':'nav-link'"></div>
<!-- 读取对象中的属性 -->
<p>
  读取blog对象中title字段:<span th:text="${blog.blogTitle}">default text</span
  >.
</p>
<!-- 循环遍历 -->
<li th:each="blog : ${blogs}"></li>

  变量表达式也可以使用内置的基本对象:

ctx : the context object.
vars : the context variables.
locale : the context locale.
request : web 环境下的 HttpServletRequest 对象.
response :web 环境下的 HttpServletResponse 对象 .
session : web 环境下的 HttpSession 对象.
servletContext : web 环境下的 ServletContext 对象.

  示例如下:

<p>
  读取内置对象中 request 中的内容:<span
    th:text="${#request.getAttribute('requestObject')}"
    >default text</span
  >.
</p>
<p>
  读取内置对象中 session 中的内容:<span
    th:text="${#session.getAttribute('sessionObject')}"
    >default text</span
  >.
</p>

  同时,Thymeleaf 还提供了一系列 Utility 工具对象(内置于 Context 中),可以通过 # 直接访问,工具类如下:

dates : java.util.Date 的功能方法类。
calendars : 类似 #dates,面向 java.util.Calendar
numbers : 格式化数字的工具方法类
strings : 字符串对象的工具方法类,contains,startWiths,prepending/appending 等等。
bools:对布尔值求值的工具方法。
arrays:对数组的工具方法。
lists:对 java.util.List 的工具方法
sets:对 java.util.Set 的工具方法
maps:对 java.util.Map 的工具方法

  你可以将这些方法视为工具类,通过这些方法可以使得 Thymeleaf 在操作变量时更加方便。

  • 选择(星号)表达式:

  选择表达式与变量表达式类似,不过它会用一个预先选择的对象来代替上下文变量容器(map)来执行,语法如下: *{blog.blogId},被指定的对象由 th:object 标签属性进行定义,前文中读取 blog 对象的 title 字段可以替换为:

<p th:object="${blog}">
  读取blog对象中title字段:<span th:text="*{blogTitle}">text</span>.
</p>
copy
如果不考虑上下文的情况下,两者没有区别,使用 ${
    
    ...}读取的内容也完全可以替换为使用*{
    
    ...}进行读取,唯一的区别是使用*{
    
    ...}前可以预先在父标签中通过 th:object 定义一个对象并进行操作。

<p>
  读取blog对象中title字段:<span th:text="*{blog.blogTitle}">default text</span>
</p>
<p>读取text字段:<span th:text="*{text}">default text</span>.</p>
  • URL 表达式:

  th:href 对应的是 html 中的 href 标签,它将计算并替换 href 标签中的链接 URL 地址,th:href 中可以直接设置为静态地址,也可以使用表达式语法读取到的变量值进行动态拼接 URL 地址。

  比如一个详情页 URL 地址:http://localhost:8080/blog/1,当使用 URL 表达式时,可以写成这样:

<a th:href="@{'http://localhost:8080/blog/1'}">详情页</a>

  也可以根据 id 值进行替换,写法为:

<a th:href="@{'/blog/'+${blog.blogId}}">详情页</a>

  或者也可以写成这样:

<a th:href="@{/blog/{blogId}(blogId=${blog.blogId})">详情页</a>

  以上三种表达式写法生成 URL 的最终结果都是相同的,开发者可以自己使用字符串拼接的方法组装 URL (第二种写法),也可以使用 URL 表达式提供的语法进行 URL 组装(第三种写法)。如果有多个参数可以自行拼装字符串,或者使用逗号进行分隔,写法如下:

<a th:href="@{/blog/{blogId}(blogId=${blog.blogId},title=${blog.blogTitle},tag='java')}">详情页</a>

  最终生成的 URL 为 http://localhost:8080/blog/1?title=lou-springboot&tag=java 另外,URL 中以 “/” 开头的路径(比如 /blog/1 ),默认生成的 URL 会加上项目的当前地址形成完整的 URL 。

实例4:复杂语法

  test.html代码:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title th:text="${title}">语法测试</title>
</head>
<body>
<h3>#strings 工具类测试</h3>
<div th:if="${not #strings.isEmpty(testString)}">
    <p>testString初始值 : <span th:text="${testString}" /></p>
    <p>
        toUpperCase : <span th:text="${#strings.toUpperCase(testString)}" />
    </p>
    <p>
        toLowerCase : <span th:text="${#strings.toLowerCase(testString)}" />
    </p>
    <p>
        equalsIgnoreCase:
        <span th:text="${#strings.equalsIgnoreCase(testString, '团团')}" />
    </p>
    <p>indexOf : <span th:text="${#strings.indexOf(testString, 'r')}" /></p>
    <p>
        substring : <span th:text="${#strings.substring(testString, 5, 9)}" />
    </p>
    <p>
        startsWith :
        <span th:text="${#strings.startsWith(testString, 'Spring')}" />
    </p>
    <p>
        contains : <span th:text="${#strings.contains(testString, 'Boot')}" />
    </p>
</div>
<h3>#bools 工具类测试</h3>
<!-- 如果 bool 的值为false的话,该div将不会显示-->
<div th:if="${#bools.isTrue(bool)}">
    <p th:text="${bool}"></p>
</div>
<h3>#arrays 工具类测试</h3>
<div th:if="${not #arrays.isEmpty(testArray)}">
    <p>length : <span th:text="${#arrays.length(testArray)}" /></p>
    <p>contains : <span th:text="${#arrays.contains(testArray, 5)}" /></p>
    <p>
        containsAll :
        <span th:text="${#arrays.containsAll(testArray, testArray)}" />
    </p>
    <p>循环读取 : <span th:each="i:${testArray}" th:text="${i+' '}" /></p>
</div>
<h3>#lists 工具类测试</h3>
<div th:unless="${#lists.isEmpty(testList)}">
    <p>size : <span th:text="${#lists.size(testList)}" /></p>
    <p>contains : <span th:text="${#lists.contains(testList, 0)}" /></p>
    <p>sort : <span th:text="${#lists.sort(testList)}" /></p>
    <p>循环读取 : <span th:each="i:${testList}" th:text="${i+' '}" /></p>
</div>
<h3>#maps 工具类测试</h3>
<div th:if="${not #maps.isEmpty(testMap)}">
    <p>size : <span th:text="${#maps.size(testMap)}" /></p>
    <p>
        containsKey :
        <span th:text="${#maps.containsKey(testMap, 'platform')}" />
    </p>
    <p>
        containsValue : <span th:text="${#maps.containsValue(testMap, '13')}" />
    </p>
    <p>
        读取map中键为title的值 :
        <span
                th:if="${#maps.containsKey(testMap,'title')}"
                th:text="${testMap.get('title')}"
        />
    </p>
</div>
<h3>#dates 工具类测试</h3>
<div>
    <p>year : <span th:text="${#dates.year(testDate)}" /></p>
    <p>month : <span th:text="${#dates.month(testDate)}" /></p>
    <p>day : <span th:text="${#dates.day(testDate)}" /></p>
    <p>hour : <span th:text="${#dates.hour(testDate)}" /></p>
    <p>minute : <span th:text="${#dates.minute(testDate)}" /></p>
    <p>second : <span th:text="${#dates.second(testDate)}" /></p>
    <p>格式化: <span th:text="${#dates.format(testDate)}" /></p>
    <p>
        yyyy-MM-dd HH:mm:ss 格式化:
        <span th:text="${#dates.format(testDate, 'yyyy-MM-dd HH:mm:ss')}" />
    </p>
</div>
</body>
</html>

  controller中对应方法的代码:

@GetMapping("/test")
    public String test(ModelMap map) {
    
    
        map.put("title", "Thymeleaf 语法测试");
        map.put("testString", "玩转 Spring Boot");
        map.put("bool", true);
        map.put("testArray", new Integer[]{
    
    2018,2019,2020,2021});
        map.put("testList", Arrays.asList("Spring", "Spring Boot", "Thymeleaf", "MyBatis", "Java"));
        Map testMap = new HashMap();
        testMap.put("platform", "大夫地");
        testMap.put("title", "玩转 Spring Boot");
        testMap.put("author", "团团");
        map.put("testMap", testMap);
        map.put("testDate", new Date());
        return "test";
    }

  展示效果(未截取完):

在这里插入图片描述

  在 strings 工具类测试中,我们首先使用了 th:if 标签进行逻辑判断,th:if="${not #strings.isEmpty(testString)}"即为一条判断语句,${…} 表达式中会返回一个布尔值结果,如果为 true 则该 div 中的内容会继续显示,否则将不会显示 th:if 所在的主标签。

  #strings.isEmpty 的作用为字符串判空,如果 testString 为空则会返回 true,而表达式前面的 not 则表示逻辑非运算,即如果 testString 不为空则继续展示该 div 中的内容。

  与 th:if 类似的判断标签为 th:unless ,它与 th:if 刚好相反,当表达式中返回的结果为 false 时,它所在标签中的内容才会继续显示,在 #lists 工具类测试中我们使用了 th:unless ,在调试代码时可以比较二者的区别。

  Thymeleaf 模板引擎中的循环语句语法为 th:each=“i:${testList}” ,类似于 JSP 中的 c:foreach 表达式,主要是做循环的逻辑,很多页面逻辑在生成时会使用到该语法。

  还有读取 Map 对象的方式为 ${testMap.get(‘title’)} ,与 Java 语言中也很类似。逻辑判断、循环语句这两个知识点是系统开发中比较常用也比较重要的内容,应当结合代码练习并牢牢掌握。

三、注意事项

1.必须引入名称空间

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

2.IDEA 中爆红色下划线问题

  如下图所示,在刚开始使用 Thymeleaf 开发时可能会碰到这种问题,在模板文件中通过 Thymeleaf 语法读取变量时,该变量名称下会出现红色波浪线,也就是错误的标志。

在这里插入图片描述

  如果不熟的人可能会认为自己的模板文件有问题,但其实并不是那么严重,只是由于 IDEA 中默认开启了表达式参数验证,即使在后端的 model 数据中添加了该变量,但是对于前端文件是无法感知的,因此会报这个错误,可以在 IDEA 中默认将验证关闭或者将提示级别修改掉也可以。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Tracycoder/article/details/113916758