Spring Boot 模板引擎Thymeleaf使用介绍

Thymeleaf
placeholder image
admin 发布于:2022-05-09 10:15:12
阅读:loading

背景介绍

博客2.0建站之初对于Spring官方推荐的模板引擎Thymeleaf还一点没有使用过,虽然看过一些视频教程,但是并没有实际的取实践过,但是不要紧,对于同类模板引擎的JSP则非常熟悉,而且对于FreeMarker也略有使用(Velocity同样非常浅的略有使用),于是本着可以学习深入的年头选择了并不熟悉的Thymeleaf,克难攻坚迎难而上。

为什么Spring Boot官方推荐使用Thymeleaf呢,或者说简单的给大家扫个盲,Thymeleaf最大的区别在于它的模板标记全是依靠自定义属性的方式来实现模板标记的循环、判断、属性输出覆盖等,它(基本上)不增加新的标签,所有的模板交互全是依仗属性,即它的动态输出全部绑定在一些原生的html标签上,与原生的html属性不冲突,所以使用Thymeleaf构建的模板引擎可以直接在浏览器中预览,特别是配合IDEA在开发过程中,可以常规启动项目后的访问,也可以直接打开页面预览(端口为63342的应用服务)。

本文主要介绍Thymeself模板引擎在Spring Boot中的整合配置,同时将本站博客系统中使用到的知识点细节进行整理分享,至于maven坐标的依赖就省略了,贴出yml配置文件中的配置以及页面输出示例,参考过程如下:

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
    <version>2.2.7.RELEASE</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>

application.yaml

spring:
  thymeleaf:
    mode: HTML
    encoding: UTF-8
    servlet:
      content-type: text/html
    cache: false
    prefix: classpath:/templates
    suffix: .html

simple.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf简单使用</title>
</head>
<body>
  <fieldset>
    <legend>输出参数值</legend>
    <p th:text="${hello}">基本输出</p>
    <p th:text="${notExist}">不存在时空白输出</p>
    <p th:text="${notExist?.key}">多级属性不存在时忽略报错输出</p>
    <p th:utext="${helloHtml}">html富文本输出</p>
    <p th:text="${hello + ' 666'}">字符串拼接输出</p>
    <p th:text="${hello} + ' 666'">字符串拼接输出</p>
    <p th:text="${hello eq 'chendd' ? 'Yes' : 'No'}">三目运算符输出1</p>
    <p th:text="${hello == 'chendd' ? 'Yes' : 'No'}">三目运算符输出2</p>
  </fieldset>

  <fieldset>
    <legend>循环</legend>
    <ul th:each="item : ${userList}">
        <li th:text="${item.userName}">userName</li>
    </ul>
  </fieldset>

  <fieldset>
    <legend>带下标的循环</legend>
    <ul th:each="item , itemStatus : ${userList}">
        <li th:text="${itemStatus} + '===' + ${item.userName}">userName</li>
    </ul>
  </fieldset>

  <fieldset>
    <legend>判断</legend>
    <h3 th:if="${hello} == 'chendd'">if 判断使用 == 判断</h3>
    <h3 th:if="${hello eq 'chendd'}">if 判断使用 eq 判断</h3>
  </fieldset>

  <fieldset>
    <legend>循环加判断</legend>
    <ul th:each="item , itemStatus : ${userList}">
        <li th:text="${itemStatus.count} + '.' + ${item.userName}" th:if="${item.userId == 1002}">userName</li>
    </ul>
  </fieldset>
  

  <fieldset>
    <legend>Switch-Case</legend>
    <th:block th:switch="cdd">
      <th:block th:case="a" th:text="'A'"></th:block>
      <th:block th:case="b" th:text="'B'"></th:block>
      <th:block th:case="c" th:text="'c'"></th:block>
      <th:block th:case="*" th:text="'default cdd'"></th:block>
    </th:block>
  </fieldset>

  <fieldset>
    <legend>自定义属性</legend>
    <a th:attr="href='javascript:void(0);'">自定义属性</a><br/>
    <a th:attr="href='javascript:void(0);',id='abcde',cdd='cdd'">自定义多个属性</a><br/>
  </fieldset>

  <fieldset>
    <legend>特殊标签&lt;th:block&gt;</legend>
    <th:block th:text="${hello}" />
    <th:block th:if="${hello eq 'chendd'}">
      <h3>&lt;th:block&gt;第二种用法</h3>
    </th:block>
  </fieldset>

  <fieldset>
    <legend>整合art-template-web插件使用</legend>
    &lt;script type="text/template" id="directory_template_id"&gt;&gt;![CDATA[
      <br/><br/>
    ]]&gt;&lt;/script&gt;
  </fieldset>

  <fieldset>
    <legend>模板引用一</legend>
    <th:block th:include="/usage/template :: temp">temp</th:block>
  </fieldset>

</body>
</html>

template.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Template模板</title>
</head>
<body>

    <template th:fragment="temp">
        <h3>temp内容模板</h3>
    </template>

</body>
</html>

ThymeleafUsageController.java

package cn.chendd.modules.thymeleaf.controller;

import ...;

/**
 * Thymeleaf 基本使用
 *
 * @author chendd
 * @date 2022/6/3 17:23
 */
@Controller
@RequestMapping(value = "/thymeleaf" , produces = MediaType.APPLICATION_JSON_VALUE)
@Api(value = "测试thymeleaf解析响应验证接口" , tags = {"Thymeleaf解析响应验证"})
public class ThymeleafUsageController extends BaseController {

    @GetMapping("/simple")
    @ApiOperation(value = "thymeleaf基本应用",notes = "测试响应结果集(<b>thymeleaf基本应用</b>)",
            consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    @ApiOperationSupport(order = 10)
    public String usage() {
        super.addAttribute("hello" , "chendd")
                .addAttribute("helloHtml" , "<h3>chendd</h3>");
        List<UserBo> userList = Lists.newArrayList(
                new UserBo(1001 , "chenzy" ,
                    Date.from(LocalDate.of(2016 , 11, 10).atStartOfDay(ZoneId.systemDefault()).toInstant())) ,
                new UserBo(1002 , "chenyt" ,
                    Date.from(LocalDate.of(2021 , 7, 9).atStartOfDay(ZoneId.systemDefault()).toInstant())));
        super.addAttribute("userList" , userList);
        return "/usage/simple";
    }

}

页面预览

image.png

知识点说明

(1)引入<html xmlns:th="http://www.thymeleaf.org">空间,th为空间中的标签或属性;

(2)thymeleaf模板的表达式语法与jsp中el表达式一致,与spring el表达式一致,包含字符串的判断使用 == 或者 使用 eq 及 ne 等;三目运算符的使用语法也一致;

(3)th:text是输出标签文本,th:utext是输出富文本,支持html标签,输出的属性若不存在不会报错,若输出的属性不存在时又引用不存在的属性的属性则会报错,可以使用?.的方式来解决;

(4)表达式中字符串的拼接输出有两种方式,如:th:text="${hello} + ' world'" 和 th:text="${hello + ' world'}" 输出的结果一致;

(5)th:each为循环输出标签,同jstl的c:forEach标签,同时也存在index和count属性用户获取下标的序号;

(6)th:if为判断标签,当if的条件为true时输出当前标签和子标签,否则直接忽略此标签的从开始至结束部分;

(7)th:switch和th:case配合使用组成的switch case语句使用,*为默认default分支;

(8)th:attr为属性标签,可随意输出键值对的属性,包含标签的标准属性或自定义的属性,多个属性以逗号“,”分割;

(9)th只是一些属性标签的空间命名,对应的是一些标准的html标签,在thymeleaf中有个特殊标签为<th:block/>,表示空白标签,在输出时直接输出子标签中的内容,跳过当前的标签,在很多使用比较有用;

(10)在thymeleaf模板页面中使用art-template(前端模板引擎)时,由于本站使用的是art-templateweb版本的jsp语法的模板使用,出现了应用时语法不兼容的问题,经过各种尝试后最终还是使用xml标签中的纯文本写法解决,即:<![CDATA[]]>,thymeleaf 中使用art-template的兼容JSP语法的问题,不能同时存在多个 var、=、;等多种特色字符,否则会提示标签中的属性重复错误,两种解决办法:1是防止出现一个标签中出现多种,采用少用空格隔开的方式,或者每一行都使用一个<%%>特色表达式赋值处理;2是使用<-[[CDATA]]>解决;;

(11)使用template标签的th:fragment属性定义一个模板块,使用th:include标签引用模板块,实现公共代码的公共定义;

(12)使用th:with可以定义变量,参考变量定义的代码使用如下:

<div class="row" th:with="fileStoreProgress=${100 - fileStore.usableSpace * 100 / fileStore.totalSpace}">
    <div class="col-lg-8 col-md-6 col-sm-6" th:with="fileStoreTheme60=${fileStoreProgress <= 65},
    fileStoreTheme60_80=${fileStoreProgress > 65 && fileStoreProgress < 85},
    fileStoreTheme90=${fileStoreProgress >= 85}
    ">
        <div class="progress progress-sm m-0">
            <div th:class="${fileStoreTheme90 ? 'progress-bar bg-danger' : (fileStoreTheme60_80 ? 'progress-bar bg-warning' : 'progress-bar bg-success')}" 
                 class="progress-bar bg-danger" role="progressbar" aria-valuenow="50"
                 th:attr="aria-valuenow=${fileStoreProgress},style='width:' + ${fileStoreProgress}+'%'"
                 aria-valuemin="0" aria-valuemax="100" >
            </div>
        </div>
    </div>
    <div class="col-lg-4 col-md-6 col-sm-6" style="margin-top:-7px;" th:text="${fileStoreProgress} + '%'"></div>
</div>

(13)特殊字符'英文单引号的转义,若存在多个'需要转义时,尝试了各种写法均报错,后来琢磨着按照Oracle的特殊字符写法,果然可以:th:attr="onclick=${oneLevel.values.url != '' ? 'window.location.href = ' + '''' + neLevel.values.url + ''';' : ''}",如上输出来的结果为:onclick="window.location.href='/index.html';";

源码下载

源码工程下载:源码下载.zip


 点赞


 发表评论

当前回复:作者

 评论列表


留言区