Thymeleaf 简单入门

Thymeleaf 相关

参考: Thymeleaf 教程 | 範宗雲 (fanlychie.github.io)(非常高质量的Blog, 感谢此大佬的分享!)

供个人学习使用, 侵删

介绍

​ 参考: Thymeleaf入门到吃灰 - 鞋破露脚尖儿 - 博客园 (cnblogs.com)

Thymeleaf是目前SpringBoot主推的一种视图渲染技术.

JSP一样用于在前端页面中根据后端响应的数据(在Request,Session,Application等域中)来动态显示相关数据.

但作为SpringBoot主推的视图渲染技术, 自然有JSP不可相比的优点.

image-20211101185818263

在本文中, 我们暂且不讲过多精力放在Thymeleaf的原理,特点上.

而是先来学习Thymeleaf的语法, 掌握它是怎么用的. 在实战过程中, 再来逐步了解其原理

使用Thymeleaf

  • 引入相应依赖

    <!-- 其传递依赖 Thymeleaf, 也就是说除了会引入thymeleaf-spring5的整合包外, 还会引入thymeleaf包 -->
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring5</artifactId>
        <version>3.0.12.RELEASE</version>
    </dependency>
    
  • HTML页面上引入Thymeleaf的命名空间

<html xmlns:th="http://www.thymeleaf.org">
  • 如果使用SpringMVC则需要配置Thymeleaf的视图解析器

    使用SpringBoot, 则无需配置

    @Bean
    public SpringResourceTemplateResolver templateResolver() {
        SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        // 在开发时, 可以禁止页面缓存, 这样在热部署时, 如果html页面有改动,刷新页面就会看到变化
        // 在产品上线时, 可以开启页面缓存, 加快页面的加载速度
        templateResolver.setCacheable(false);
        templateResolver.setCharacterEncoding("UTF-8");
        return templateResolver;
    }
    
    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);
        return templateEngine;
    }
    
    @Bean
    public ThymeleafViewResolver viewResolver() {
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        viewResolver.setTemplateEngine(templateEngine());
        viewResolver.setCharacterEncoding("UTF-8");
        return viewResolver;
    }
    

Thymeleaf 表达式

image-20211101194704340

${} 取出上下文变量的值

${}用于取出上下文中变量的值

@RequestMapping("/")
public String index(Model model) {
    model.addAttribute("user", new User("a-shy-coder", "123456", "男"));
    return "index";
}
<!-- 默认取出 request域 中的变量 -->
<p>
    user1属性值:
    <!-- a-shy-coder -->
    <span th:text="${user.username}"></span> |
    <!-- 123456 -->
    <span th:text="${user.password}"></span> |
    <!-- 男 -->
    <span th:text="${user.gender}"></span>
</p>

th:text是一个Thymeleaf指令, 用于替换当前标签内的内容

${}内使用OGNL语法解析, 其内部同样支持[Thymeleaf运算](#Thymeleaf 运算])

<span th:text="${student.grade ≥ 60 ? '及格' : '不及格'}"

*{} 取出父对象的值

*{}可以取出父标签中使用th:object绑定的对象的值

<p th:object="${user}">
    user1属性值:
    <span th:text="*{username}"></span> |
    <span th:text="*{password}"></span> |
    <span th:text="*{gender}"></span>
    <!-- 省去了前缀 user -->
</p>

@{} 链接表达式

假设我们想要在页面中访问lxh01.gif

image-20211103113522359

支持5种路径写法

  • 绝对路径

    <!-- 绝对路径即完整路径 -->
    <a th:href="@{https://www.baidu.com}" class="btn btn-sm btn-danger">测试1-绝对路径</a> &nbsp;
    

    一般项目中都以相对路径访问资源, 基本用不到

  • 请求相对路径 容易出现404问题

    <!-- 请求相对路径(直接写资源的路径), 但是请求路径会以当前页面的父路径为前缀 http://localhost:8080/thymeleaf_demo_war_exploded/test/static/img/lxh01.gif-->
    <!--当前页面的路径: http://localhost:8080/thymeleaf_demo_war_exploded/test/toPage1
        所以前缀为:    http://localhost:8080/thymeleaf_demo_war_exploded/test/-->
    <!-- 所以会404,访问不到资源 -->
    <a th:href="@{static/img/lxh01.gif}" class="btn btn-sm btn-warning">测试2-页面相对路径(请求相对路径)</a>
    

    通过设置<base th:href="@{/}">规定页面中所有相对链接的父路径为程序的上下文路径, 就不用担心出现404

    但还是推荐使用下面介绍的上下文相对路径

  • 上下文相对路径 推荐使用

    <!-- 上下文路径(以/开头) 以程序的上下文路径作为根路径 http://localhost:8080/thymeleaf_demo_war_exploded/static/img/lxh01.gif-->
    <!-- 上下文路径为 http://localhost:8080/thymeleaf_demo_war_exploded -->
    <a th:href="@{/static/img/lxh01.gif}" class="btn btn-sm btn-success">测试3-上下文相对路径</a>
    
  • 服务器相对路径

    <!-- 服务器相对路径(以 ~/ 开头), 以服务器路径作为根路径 
    http://localhost:8080/static/img/lxh01.gif-->
    <a th:href="@{~/static/img/lxh01.gif}" class="btn btn-sm btn-primary">测试4-服务器相对路径</a>
    
  • 协议相对路径

    <!-- 协议相对路径(以 // 开头), 以协议作为根路径 
    http://static/img/lxh01.gif -->
    <a th:href="@{//static/img/lxh01.gif}" class="btn btn-sm btn-info">测试5-协议相对路径</a>
    

#{} 显示属性文件中的值

#{}可以显示来自.properties文件中的属性, 主要用来实现国际化

<p th:text="#{msg.welcome}"></p>
# messages_en_US.properties
msg.welcome=Hi, how are you doing?
# messages_zh_CN.properties
msg.welcome=你好,你吃饭了吗?
// 需要用Spring管理这些资源文件,才可以在前端正确显示
@Bean
public ResourceBundleMessageSource messageSource() {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    messageSource.setBasenames("properties.messages","properties.i18n");
    messageSource.setDefaultEncoding("UTF-8");
    return messageSource;
}

~{} 片段表达式

~{} 可以在页面中插入其他页面(如为每个页面插入 footer header), 或者页面中的片段

通常结合 th:fragment th:insert th:replace 使用

image-20211102112111476

JSP中怎么做 ?

th:* 指令

th:* 可以被data-th-*替代, 其中后者是html5标准属性, 不过我们一般还是使用th:*

特性: 动静结合

<span th:text="${msg}">静态页面显示的内容</span>
@RequestMapping("/toPage6")
public String toPage6(Model model){
    model.addAttribute("msg","后端添加的内容");
    return "page6";
}
  • 如果直接运行静态页面

    image-20211101201444384

    image-20211101201801236

  • 运行项目, 但控制器不向控制器中添加msg数据

    image-20211101201541003

    image-20211101201826135

  • 运行项目, 但控制器向控制器中添加msg数据

image-20211101201647504

image-20211101201904406

值得注意的是, 在Thymeleaf解析过程中, 若某一部分出错, 则该部分和以下页面均不会显示(包括html)

th:text

运行在服务器上时, th:text中属性的值会替换所在标签中的文本内容

<span th:text="${msg}">静态页面显示的内容</span>

内联表达式 [[]] 相当于 th:text, 这样可以直接在标签中写代码.

<p>[[${message}]]</p>

th:utext

th:text不同, th:utext不会对含有 HTML 标签的内容进行转义

model.addAttribute("message","<h1>这是标题<h1>");
<p th:text="${message}"/>
<p th:utext="${message}"/>
image-20211101203139409

内联表达式 [()] 相当于 th:utext

<p>[(${message})]</p>

th:object

th:object用于在父标签中绑定上下文中的对象, 以便在子标签中使用*{}取出该对象属性的值

<p th:object="${user}">
    user1属性值:
    <span th:text="*{username}"></span> |
    <span th:text="*{password}"></span> |
    <span th:text="*{gender}"></span>
    <!-- 省去了前缀 user -->
</p>

th:if

表达式的评估结果为真时则显示内容,否则不显示

<p th:if="${age >= 18}">恭喜你,成为大人了!!!</p>
image-20211103085251607

th:unless

表达式的评估结果为假时则显示内容,否则不显示

<p th:unless="${age} < 18">恭喜你,成为大人了!!!</p>

th:switch

switch-case, 当case取值为*时, 表示default

<div th:switch="${type}">
    <p th:case="1">type = 1</p>
    <p th:case="2">type = 2</p>
    <p th:case="*">type 为其他值</p>
</div>

th:each

th:each用于遍历集合, 可以是以下类型:

image-20211101205347798
@RequestMapping("/toPage6")
public String toPage6(Model model){
    List<Student> studentList = new ArrayList<>();
    studentList.add(new Student("2019205555", "小胖", "男"));
    studentList.add(new Student("2019206666", "小瘦", "男"));
    studentList.add(new Student("2019207777", "小花", "女"));
    studentList.add(new Student("2019208888", "小丽", "女"));
    model.addAttribute("studentList",studentList);
    return "page6";
}

语法:th:each="自定义元素变量名称, 自定义状态变量名称(默认为'元素变量名称Stat') : ${集合变量名称}"

<table>
    <tr th:each="student,studentStat:${studentList}">
        <td th:text="${studentStat.index}">序号</td>
        <td th:text="${student.sid}">学号</td>
        <td th:text="${student.sname}">姓名</td>
        <td th:text="${student.sgender}">性别</td>
    </tr>
</table>
image-20211101205716082

遍历Map

<!-- 直接使用 内联表达式 [[]] 在遍历集合时方便 -->
<div th:each="entry,status:${map1}">
    [[${entry.key}]] | [[${entry.value}]] | [[status.index]]
</div>

th:fragment

th:fragment用来定义一个片段, 以便~{}引用该片段

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>footer 模板页面</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
	<div class="bg-danger padding10">
		这是footer.html页面内容.................
		<div th:fragment="fragment1" id="fragment1" class="bg-primary padding10 margin10">
			这是模板片段1内容~~~~~~~~~~~~~~~~~~~<br> 
			这是模板片段1内容~~~~~~~~~~~~~~~~~~~<br>
			这是模板片段1内容~~~~~~~~~~~~~~~~~~~<br>
		</div>
		<div th:fragment="fragment2" id="fragment2" class="bg-success padding10 margin10">
			这是模板片段2内容~~~~~~~~~~~~~~~~~~~<br> 
			这是模板片段2内容~~~~~~~~~~~~~~~~~~~<br>
			这是模板片段2内容~~~~~~~~~~~~~~~~~~~<br>
		</div>
		这是footer.html页面内容.................
	</div>
</body>
</html>

th:insert & th:replace

  • th:insert

    th:insert将指定的片段插入主标签内, 主标签内的内容会被替换

    <div th:insert="~{footer::#fragment1}"></div>
    
  • th:replace

    th:replace将主标签替换为指定的片段

    <div th:replace="~{footer::#fragment1}"></div>
    
  • 二者区别

    假设插入的片段为

    <footer th:fragment="fragment1">
      hello world
    </footer>
    

    结果为

    <!-- th:insert -->
    <div>
        <footer>
            hello world
        </footer>
    </div>
    
    <!-- th:replace -->
    <footer>
        hello world
    </footer>
    

th:with

th:with可以定义一个或者多个局部变量, 只能在当前标签内使用

<div th:with="firstStudent=${studentList[0]},secondStudent=${studentList[1]}">
  <p>第一个学生:[[${firstStudent.sid}]] | [[${firstStudent.sname}]] | [[${firstStudent.sgender}]]</p>
  <p>第二个学生:[[${secondStudent.sid}]] | [[${secondStudent.sname}]] | [[${secondStudent.sgender}]]</p>
</div>

th:inline

前面我们已经了解到了内联表达式 [[]], [()], 而th:inline可以设置启用或禁用内联表达式

image-20211103093636507
  • css样式中, 内联表达式默认可以使用

  • javascript中, 内联表达式默认不可使用, 需要开启

    <script th:inline="javascript">
        console.log([[${user.name}]])
    </script>
    

th:*-*

th:*-*为标签的多个不同属性设置相同的值

<img src="logo.png" th:alt-title="LOGO图片">

th:attrappend & th:attrprepend

th:attrappendth:attrprepend可以将表达式的结果分别追加到指定的属性值之后和之前

<!-- <button class="btn enable">购买</button> -->
<button class="btn" th:attrappend="class=${outOfStock} ? ' enable' : ' disable'">购买</button>
<!-- <button class="enable btn">购买</button> -->
<button class="btn" th:attrprepend="class=${outOfStock} ? 'enable ' : 'disable '">购买</button>

拼接字符串

Thymeleaf支持两种拼接字符串的方式

  • '字符串'+'字符串'

    <p th:text="'name:' + ${name}"/>
    
  • |字符串|

    <p th:text="|name:${name}|"/>
    

Thymeleaf 表达式对象

image-20211103094400456
<!-- 
        model.addAttribute("num1", 100);
        httpServletRequest.setAttribute("num2", 200);
        session.setAttribute("num3", 300);
        httpServletRequest.getServletContext().setAttribute("num4", 400);
-->
<p th:text="${#request.getAttribute('num1')}"></p>
<p th:text="${#request.getAttribute('num2')}"></p>
<p th:text="${#session.getAttribute('num3')}"></p>
<p th:text="${#servletContext.getAttribute('num4')}"></p>

表达式对象除了能获取各个范围的对象外, 还可以获取其他信息

<p th:text="${#session.getId()}"></p>

Thymeleaf 名称空间

<!--获取请求范围属性(默认为请求返回)-->
<p th:text="${num1}"></p>
<!--获取会话范围属性-->
<p th:text="${session.num2}"></p>
<!--获取应用程序范围属性-->
<p th:text="${application.num3}"></p>
<!--获取一个请求参数的单个值-->
<p th:text="${param.name}"></p>
<!--获取一个请求参数的多个值-->
<p th:text="${param.hobbies}"></p>
<!--获取一个请求参数的多个值中的某个值-->
<p th:text="${param.hobbies[0]}"></p>

Thymeleaf 工具类

更多内容, 参考官方文档 Thymeleaf官方文档-工具类源码

Thymeleaf官方文档-工具类

image-20211103121827763

Thymeleaf 字面值

image-20211103120127364
  • 文本字面值

    <!-- 用''包裹, 可以有空格.-->
    <span th:text="'hello sir'"></span><br>
    
  • 数值字面值

    <!--数值字面值即正数和小数, 使用运算符时,会执行运算, 可以使用()改变括号的优先级-->
    <span th:text="10.2*(3+5)">
    
  • 布尔字面值

    <!-- 布尔字面值即 true 和 false -->
    <span th:text="3>2"></span><br> <!-- 结果为true -->
    <span th:text="false"></span><br>
    <span th:text="true"></span><br>
    
  • 空字面值(null)

    <p th:text="${user == null}"></p> <!-- false -->
    
  • 字面标记 (Literal Tokens)

    image-20211102114306389
<span th:text="a-shy-coder"></span><br>

Thymeleaf 运算

注意合理使用()改变运算的优先级, 取得期望的结果

  • 算术运算

    支持+,-,*,/ (div),% (mod)

    <p th:text="5 / 2"></p>   <!-- 2.5 -->
    <p th:text="5 div 2"></p> <!-- 2.5 -->
    <p th:text="5 % 2"></p>
    <p th:text="5 mod 2"></p>
    
  • 比较运算

    支持<lt)、>gt)、<=le)、>=ge)、==eq)、!=ne

    <p th:text="${user.age < 60}"></p>
    <p th:text="${user.age lt 60}"></p>
    
  • 条件表达式

    • 三元运算符

      <p th:text="${number} % 2 ? '奇数' : '偶数' "/>
      
    • 二元运算符 (value) ?: (defaultValue)

      value非空时输出value,否则输出defaultValue

      <p th:text="${user.email} ?: '邮箱地址不能为空' "/>
      
    • 无操作符_

      value非空时输出value,否则输出标签内的内容

      <p th:text="${user.email} ?:_ ">邮箱地址不能为空</p>
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值