在SpringBoot【SSM+JSP篇】中使用了JSP来作为视图,需要我们自己将项目打成war包,并且部署到Tomcat上,随后项目才可以访问,觉得这有点麻烦,对于SpringBoot这个微服务框架来说,如果使用Thymeleaf或者FreeMarker模板引擎,那么就可以直接打成jar包运行了,而且使用模板引擎,相对于JSP来说,优点多多,那么就来看看什么是Thymeleaf。
本文只是简单的入门Thymeleaf,具体详细文档参考官方:
Documentation - Thymeleafwww.thymeleaf.org/documentation.html![](https://pic2.zhimg.com/v2-1bc377d57494a8dfffd6265d2cb9f1b5_ipico.jpg)
1. Thymeleaf 概述
1.1. Thymeleaf 是什么
Thymeleaf是一个模板引擎,主要用于编写动态页面。
1.2. Thymeleaf的作用
--问题:动态页面技术已经有JSP,为什么还要用Thymeleaf?
主要原因包括以下几点:
1. 使用模块引擎来编写动态页面,让开发人员无法在页面上编写 Java 代码,使得java代码和前端代码绝对的分离。
2. SpringBoot默认整合Thymeleaf,不需要任何配置直接整合成功,打jar包发布不需要做任何配置。
3. Thymeleaf相对于其他的模板引擎(如:Freemaker、velocity),有强大的工具支持。
4. 相对于Jsp页面,执行效率高。
总结:所有JSP可以使用的地方,Thymeleaf都可以使用,并根据Thymeleaf的优势,可以得出结论:Thymeleaf的作用就是取代JSP。
2. Thymeleaf 入门配置
--需求:配置 SpringBoot 整合 Thymeleaf 框架。
2.1. 配置步骤说明
第一步:创建一个 SpringBoot 项目。
第二步:编写一个 index.html 页面。
第三步:编写一个 Controller,设置参数跳转到页面。
第四步:测试页面显示结果。
2.2. 配置步骤
第一步:创建一个 SpringBoot 项目
--使用Spring Initialer创建Springboot项目。
![](https://pic2.zhimg.com/80/v2-6a687c28c26b54565ae5a6347e23fbb5_720w.webp)
注意:IDEA不支持Artifact(项目名)混合大小写,否则会报错。
--选择模块
![](https://pic2.zhimg.com/80/v2-7a73e119d499397e6dce269948d5b9dd_720w.webp)
第二步:index.html 页面
在resources/templates目录创建一个index.html页面。
注意,必须加上命名空间xmlns:th="http://www.thymeleaf.org/,否则Thymeleaf的自定义标签没有提示。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 使用th:text属性输出 -->
<div th:text="${message}" ></div>
</body>
</html>
第三步:编写跳转页面的 Controller
@Controller
public class PageController {
@GetMapping("/index")
public String showPage(Model model) {
model.addAttribute("message", "HelloWorld");
return "index";
}
}
第四步:测试页面显示结果
启动项目,执行查看结果
![](https://pic3.zhimg.com/80/v2-83a90512c86cbf18768d51ba3d828056_720w.webp)
2.3. 疑难问题
--问题:为什么thymeleaf页面放在templates文件夹里面,并且后缀要是.html呢?
SpringBoot框架会将内置支持的功能组件放在spring-boot-autoconfigure-2.2.1.RELEASE.jar 包下,而 Thymeleaf 框架就是内置支持的。所以在这个包里面可以找对应的自动配置代码,如图:
![](https://pic4.zhimg.com/80/v2-a1dda243455401fc3d5f56b4fbd4e00b_720w.webp)
如果找默认的属性配置应该找XxxxProperties类,如图所示,Thymeleaf模板的前后缀如下:
![](https://pic4.zhimg.com/80/v2-f7b8cd467356fb3bf27dd43301d4ea7f_720w.webp)
所以Thymeleaf的页面存放在templates文件夹中,并且页面的后缀为.html。
--问题:项目结构中还有一个static文件夹,是用来放什么的呢?
用来存放静态资源(css、js、image等等),SpringBoot将通用的Web模块的参数放在Web分包,具体资源配置信息放置在ResourceProperties配置类中。
![](https://pic3.zhimg.com/80/v2-7e461c4b34715d67ca5a27ba4e068bde_720w.webp)
因此静态资源默认路径为:
![](https://pic3.zhimg.com/80/v2-0e05b4463d02cff6b949e4aa8f06710a_720w.webp)
3.Thymeleaf 语法说明
既然SpringBoot默认集成Thymeleaf,以及Thymeleaf相对于JSP的多个优势,那么学习Thymeleaf是大势所趋,回想起当初我们学习JSP的时候,也是通过作用域对象、基础语法、标签库等等语法学习JSP,那么Thymeleaf同样的可以从语法进行学习。
3.1. 表达式
3.1.1. 表达式一览表
![](https://pic2.zhimg.com/80/v2-23dfc3cab29610643a2a7d40e352a9dd_720w.webp)
注意事项:Thymeleaf 表达式只能放置标签的 Thymeleaf 的自定义属性里面(如div标签中的th:text属性)。如果要放在非Thymeleaf 的自定义属性里面,那么需要使用内联表达式包起来。
内联表达式的意思是:在内嵌表达式的基础上嵌入基本表达式(变量、选择变量、消息等等)
3.1.2. 变量表达式
变量表达式的作用是:从web作用域里面取到对应的值,作用域包括 request、session、application。
后台代码
@GetMapping("/index")
public String showPage(HttpServletRequest request, HttpSession session) {
User user1 = new User(1L, "zhangsan", "333333");
request.setAttribute("user1", user1);
User user2 = new User(2L, "lisi", "444444");
session.setAttribute("user2", user2);
User user3 = new User(3L, "wangwu", "555555");
ServletContext application = request.getServletContext();
application.setAttribute("user3", user3);
return "index";
}
页面代码
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
request: <br/>
<div>
编号: <label th:text="${user1.id}"></label><br/>
用户名:<label th:text="${user1.username}"></label> <br/>
密码:<label th:text="${user1.password}"></label><br/>
</div>
session:<br/>
<div>
编号: <label th:text="${session.user2.id}"></label><br/>
用户名:<label th:text="${session.user2.username}"></label> <br/>
密码:<label th:text="${session.user2.password}"></label><br/>
</div>
application:<br/>
<div>
编号:<label th:text="${application.user3.id}"></label><br/>
用户名:<label th:text="${application.user3.username}"></label><br/>
密码:<label th:text="${application.user3.password}"></label><br/>
</div>
</body>
</html>
测试结果
![](https://pic2.zhimg.com/80/v2-0f748443d690d3e99ee1c9610eacb671_720w.webp)
3.1.3. 选择变量表达式
--问题:使用变量表达式来取request、session、application作用域上的属性时,可以发现,我们需要重复编写user1、session.user2和application.use3三次,如果user对象的属性有十几个怎么办?显然写十几次相同的代码不是我们想要解决方案。针对这种问题,Thymeleaf提供了选择变量表达式来解决。
request: <br/>
<div>
编号: <label th:text="${user1.id}"></label><br/>
用户名:<label th:text="${user1.username}"></label> <br/>
密码:<label th:text="${user1.password}"></label><br/>
</div>
session:<br/>
<div>
编号: <label th:text="${session.user2.id}"></label><br/>
用户名:<label th:text="${session.user2.username}"></label> <br/>
密码:<label th:text="${session.user2.password}"></label><br/>
</div>
等用于:
request: <br/>
<div th:object="${user1}">
编号: <label th:text="*{id}"></label><br/>
用户名:<label th:text="*{username}"></label> <br/>
密码:<label th:text="*{password}"></label><br/>
</div>
session:<br/>
<div th:object="${session.user2}">
编号: <label th:text="*{id}"></label><br/>
用户名:<label th:text="*{username}"></label> <br/>
密码:<label th:text="*{password}"></label><br/>
</div>
3.1.4. 消息表达式
3.1.4.1.说明
消息表达式的作用,就是用于对国际化功能的支持。所谓的国际化功能就是指,根据浏览器的编码,返回对应编码的内容的支持。
3.1.4.2.配置步骤
第一步:编写国际化支持配置文件
国际化配置文件名称命名规范:
默认名:xxx.properties
指定国家编码的名称:xxx_语言编码_国家编号.properties
--示例:
![](https://pic4.zhimg.com/80/v2-3d0bbb481ba93cb0d38a0c9965e634db_720w.webp)
## 默认声明:message.properties
home.welcome=HelloWorld
————————————————————————
## 中文支持声明:message_brick_CN.properties
home.welcome=你好世界
第二步:配置 SpringBoot 配置文件 application.properties
注意:配置的besename就是国际化文件名字名,不需要写语言国家编号以及后缀。
## 配置国际化支持
spring.messages.basename=message
第三步:Thymeleaf 对国际化的支持,消息表达式
标签消息表达式取值:<span th:text="#{home.welcome}"></span><br />
内嵌消息表达式取值:[[#{home.welcome}]]
3.1.5. 链接表达式
链接表达式的作用:用来指定的跳转的链接。
3.1.6. 作用域对象的获取
作用域对象包括:request,session,application。
获得方式就是在变量表达式里面使用${#request}、${#session}、${#servletContext}。
获取请求URL:<span th:text="${#request.getRequestURL()}"></span><br />
获取会话超时时间:<span th:text="${#session.getMaxInactiveInterval()}"></span><br />
获取服务器信息:<span th:text="${#servletContext.getServerInfo()}"></span>
![](https://pic3.zhimg.com/80/v2-6fc067e135758b494e2f0f6eae619f12_720w.webp)
3.1.7. 作用域内容对象的空值处理
当获取一个作用域中不存在的对象属性,那么会返回一个null,但是有些情况下还通过点运算符获取对象属性,那么这是SpringBoot会报异常。有些情况下,就是根据某个对象是否为null来执行相应的操作。
--需求:获取session作用域中的user对象,如果不为null就输出Id,如果为null,就输出空字符串,而不是报异常。
--分析:可以在调用对象或者方法的点(.)前面,使用问号(?)来判断null。如下面示例:
编号:<span th:text="${session?.user?.id}"></span>
3.2. 标签与属性
--问题:通过前面的案例,可以发现似乎所有HTML5标签的属性都有一个对应的Thymeleaf属性,到底是不是这样的呢?
因为Thymeleaf的表达式是写在自定义的属性里面的。如果HTML5原来的属性没有 对应的Thymeleaf属性,就会导致有某些属性无法按Thymeleaf的理念设值。因此可以得出:所有的HTML5标签的所有属性都有一个自定义的Thymeleaf属性对应。 如input标签的type、value属性对应的Thymeleaf属性就是th:type、th:value。<input type="text" th:type="" value="张三" th:value="" />
总结:Thymeleaf属性只有当Thymeleaf模板引擎启动的情况下,才会生效,即取代对应的HTML5属性,相反,Thymeleaf属性仅仅只是一个无用的自定义属性,因为浏览器内核不认识,因此使用Thymeleaf模板引擎可以使得前端代码和后端代码分离,当出现显示问题时,可以立即定位问题所在(是前端页面还是后台返回数据有错),这也是Thymeleaf相对于JSP的一个优势。
3.3. 判断
Thymeleaf支持四种判断:th:if/th:unless、逻辑运算符(and、or、not)、三目运算符、switch。
第一种:if & unless
<!-- 如果条件为真,执行标签内的内容 -->
<div th:if="${false}">
天天18
</div>
<!-- 如果添加为假,执行标签内的内容 -->
<div th:unless="${false}">
别做梦
</div>
![](https://pic1.zhimg.com/80/v2-9a209609f41bc6388e8dd3d2ef35a078_720w.webp)
第二种:and、or、not
<div th:if="${true or false}">
真的18岁
</div>
<div th:if="${not false}">
真的别做梦
</div>
![](https://pic4.zhimg.com/80/v2-a42fb08dae6459ae1e396f8d7ed704c3_720w.webp)
第三种:三目运算符
<span th:text="true ? '今年不是18岁' : '总算清醒了'"></span>
![](https://pic1.zhimg.com/80/v2-b42a0f6a3caf6439f204c53672614128_720w.webp)
第四种:switch
<div th:switch="${21}">
<div th:case="16">我今年16岁</div>
<div th:case="17">我今年17岁</div>
<div th:case="18">我今年18岁</div>
<div th:case="*">我年年18岁</div>
</div>
![](https://pic4.zhimg.com/80/v2-568df99ccc9e06a4caf3b76cdfa14013_720w.webp)
注意:这里演示的案例,都是写死的值,在开发中,应该是读取作用域对象中的值。
3.4. 循环
Thymeleaf使用th:each来实现循环遍历。
页面代码
<h3>需求:输出用户信息</h3>
<table border="1" cellspacing="0">
<tr>
<th>编号</th>
<th>姓名</th>
<th>密码</th>
</tr>
<tr th:each="user, iterStat:${users}">
<td th:text="${user.id}"></td>
<td th:text="${user.username}"></td>
<td th:text="${user.password}"></td>
</tr>
</table>
<h3>需求:输出用户信息,声明状态对象</h3>
<table border="1" cellspacing="0">
<tr>
<td>当前迭代索引</td>
<td>当前迭代序号</td>
<td>编号</td>
<td>姓名</td>
<td>密码</td>
</tr>
<tr th:each="user, iter:${users}">
<td th:text="${iter.index}"></td>
<td th:text="${iter.count}"></td>
<td th:text="${user.id}"></td>
<td th:text="${user.username}"></td>
<td th:text="${user.password}"></td>
</tr>
</table>
后台代码
@GetMapping("/index")
public String showPage(Model model) {
ArrayList<User> users = new ArrayList<>();
users.add(new User(1L, "zhangsan", "333333"));
users.add(new User(2L, "lisi", "444444"));
users.add(new User(3L, "wangwu", "555555"));
model.addAttribute("users", users);
return "index";
}
测试结果
![](https://pic2.zhimg.com/80/v2-84835538996f95055d7a185f817323a9_720w.webp)