Thymeleaf 相关
参考: Thymeleaf 教程 | 範宗雲 (fanlychie.github.io)(非常高质量的Blog, 感谢此大佬的分享!)
供个人学习使用, 侵删
文章目录
介绍
Thymeleaf
是目前SpringBoot
主推的一种视图渲染技术.
与JSP
一样用于在前端页面中根据后端响应的数据(在Request,Session,Application
等域中)来动态显示相关数据.
但作为SpringBoot
主推的视图渲染技术, 自然有JSP
不可相比的优点.
在本文中, 我们暂且不讲过多精力放在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 表达式
${} 取出上下文变量的值
${}
用于取出上下文中变量的值
@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
支持5种路径写法
-
绝对路径
<!-- 绝对路径即完整路径 --> <a th:href="@{https://www.baidu.com}" class="btn btn-sm btn-danger">测试1-绝对路径</a>
一般项目中都以相对路径访问资源, 基本用不到
-
请求相对路径 容易出现
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 使用
JSP中怎么做 ?
th:* 指令
th:*
可以被data-th-*
替代, 其中后者是html5标准属性, 不过我们一般还是使用th:*
特性: 动静结合
<span th:text="${msg}">静态页面显示的内容</span>
@RequestMapping("/toPage6")
public String toPage6(Model model){
model.addAttribute("msg","后端添加的内容");
return "page6";
}
-
如果直接运行静态页面
-
运行项目, 但控制器不向控制器中添加
msg
数据 -
运行项目, 但控制器向控制器中添加
msg
数据
值得注意的是, 在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}"/>
内联表达式
[()]
相当于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>
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
用于遍历集合, 可以是以下类型:
@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>
遍历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
可以设置启用或禁用内联表达式
-
在
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:attrappend
和th: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 表达式对象
<!--
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 字面值
-
文本字面值
<!-- 用''包裹, 可以有空格.--> <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)
<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>
-