虽然JSP为我们带来了便捷,但是其缺点也是显而易见的,那么有没有一种既能实现模板,又能兼顾前后端分离的模板引擎呢?
有的兄弟有的,就是Thymeleaf模板,是一个适用于Web和独立环境的现代化服务器端Java模板引擎。
我们这边先写一个Servlet和html来看看效果怎么样:
1 |
|
接着在resource文件夹中放入test.html:
1 |
|
这个时候我们运行页面就会发现竟然填进去了:

前端和后端还是分离状态,所以说这个模板更好用、更清晰。
语法基础
接着我们来了解Thymeleaf如何为普通的标签添加内容,比如我们示例中编写的:
1 | <div th:text="${title}"></div> |
这里我们用th:text来传入一个文本,title是这个属性名字,这里你不管传入什么都是字符串,并不能解析出代码,哪怕你传入的是Html语句。如果我们要传入html的话可以使用th:utext属性:
1 | <div th:utext="${title}"></div> |
并且我们传入的是一个引用,这个title本身就是一个字符串变量,我们当然也可以调用字符串的方法然后打印出来:
1 | <div th:text="${title.toLowerCase()}"></div> |
这样打印出来的都是小写的。
并且th:后面什么属性都能接,也就是说什么都可以替换。举个例子我们可以直接:
1 | <img width="700" th:src="${url}" th:alt="${alt}"> |
在Servlet中:
1 |
|
我们发现是可以运行出来图片的:👇

当然这个还能算数儿:
1 | <div th:text="${value % 2}"></div> |
还能判断:
1 | <div th:text="${value % 2 == 0 ? 'yyds' : 'lbwnb'}"></div> |
还能拼接:
1 | <div th:text="${name}+' 我是文本 '+${value}"></div> |
就像Java中的字符串拼接一样,这里要注意一下,字符串不能直接写,要添加单引号。
流程控制语法
if判断语句
首先我们来看if判断语句,如果if条件满足,则此标签留下,若if条件不满足,则此标签自动被移除:
1 | <div th:if="${eval}">我是判断条件标签</div> |
接着来写下Servlet:
1 |
|
判断规则如下:
- 如果值不是空的:
- 如果值是布尔值并且为
true。 - 如果值是一个数字,并且是非零
- 如果值是一个字符,并且是非零
- 如果值是一个字符串,而不是“错误”、“关闭”或“否”(这里都是英文,具体去看百里叶香的文档)
- 如果值不是布尔值、数字、字符或字符串。
- 如果值是布尔值并且为
- 如果值为空,th:if将计算为false
unless
其实就是!=的意思,if的反向效果。
多分支switch
我们接着来看多分支条件判断,我们可以使用th:switch属性来实现:
我们先来写一个html:
1 | <div th:switch="${eval}"> |
只不过没有default属性,但是我们可以使用th:case="*"来代替:
1 | <div th:case="*">我是Default</div> |
List遍历
它如何实现遍历,假如我们有一个存放书籍信息的List需要显示,那么如何快速生成一个列表呢?我们可以使用th:each来进行遍历操作:
1 | <ul> |
接着写Servlet:
1 |
|
我们来看下结果:

我们还可以获取当前循环的迭代状态,只需要在最后添加iterStat即可,从中可以获取很多信息,比如当前的顺序:
1 | <ul> |
状态变量在th:each属性中定义,并包含以下数据:
- 当前_迭代索引_,以0开头。这是
index属性。 - 当前_迭代索引_,以1开头。这是
count属性。 - 迭代变量中的元素总量。这是
size属性。 - 每个迭代的_迭代变量_。这是
current属性。 - 当前迭代是偶数还是奇数。这些是
even/odd布尔属性。 - 当前迭代是否是第一个迭代。这是
first布尔属性。 - 当前迭代是否是最后一个迭代。这是
last布尔属性。
模板布局
我们在看B站某些分P视频的时候,会发现标题和评论区都是没有变的,只有中间的视频变了,那么这是怎么做到的呢?
Thymeleaf就可以轻松实现这样的操作,我们只需要将不会改变的地方设定为模板布局,并在不同的页面中插入这些模板布局,就无需每个页面都去编写同样的内容了。现在我们来创建两个页面:
1 |
|
1 |
|
接着将模板引擎写成工具类的形式:
1 | public class ThymeleafUtil { |
1 |
|
现在就有两个Servlet分别对应两个页面了,但是这两个页面实际上是存在重复内容的,我们要做的就是将这些重复内容提取出来。
我们单独编写一个head.html来存放重复部分:
1 |
|
现在,我们就可以直接将页面中的内容快速替换:
1 | <div th:include="head.html::head-title"></div> |
我们可以使用th:insert和th:replace和th:include这三种方法来进行页面内容替换,那么th:insert和th:replace(和th:include,自3.0年以来不推荐)有什么区别?
th:insert最简单:它只会插入指定的片段作为标签的主体。th:replace实际上将标签直接替换为指定的片段。th:include和th:insert相似,但它没有插入片段,而是只插入此片段的内容。
当然还支持参数的传递,把模板当成一个类使用来传入参数:
1 | <div class="head" th:fragment="head-title(sub)"> |
现在直接在替换位置添加一个参数即可:
1 | <div th:include="head.html::head-title('这个是第1个页面的二级标题')"></div> |
说些什么吧!