一、Thymeleaf 的概念
Thymeleaf 是一款用于渲染 XML/XHTML/HTML5
内容,适用于 Web 和独立环境的现代服务器端的
Java 模板引擎
它与 JSP,Velocity,FreeMaker 等模板引擎类似,
也可以轻易地与 Spring MVC 等 Web 框架集成。
与其它模板引擎相比,Thymeleaf 最大的特点是,
即使不启动 Web 应用,也可以直接在浏览器中打
开并正确显示模板页面 。
模板引擎:
是为了使用户界面与业务数据分离而产生的,它
可以生成特定格式的文档,用于网站的模板引擎
就会生成一个标准的 html 文档。
Thymeleaf 支持 HTML 原型,其文件后缀为“.html”,
因此它可以直接被浏览器打开,此时浏览器会忽略
未定义的 Thymeleaf 标签属性,展示 thymeleaf 模
板的静态页面效果;当通过 Web 应用程序访问时,
Thymeleaf 会动态地替换掉静态内容,使页面动态
显示
二、Thymeleaf 的特点
Thymeleaf 模板引擎具有以下特点:
动静结合:Thymeleaf 既可以直接使用浏览器打开,
查看页面的静态效果,也可以通过 Web
应用程序进行访问,查看动态页面效果。
开箱即用:Thymeleaf 提供了 Spring 标准方言以及
一个与 SpringMVC 完美集成的可选模块,
可以快速的实现表单绑定、属性编辑器、
国际化等功能。
多方言支持:它提供了 Thymeleaf 标准和 Spring 标
准两种方言,可以直接套用模板实现
JSTL、 OGNL 表达式;必要时,开发人
员也可以扩展和创建自定义的方言。
与 SpringBoot 完美整合:SpringBoot 为 Thymeleaf 提
供了的默认配置,并且还为 Thymeleaf 设
置了视图解析器,因此 Thymeleaf 可以与
Spring Boot 完美整合。
三、Thymeleaf 语法
在使用 Thymeleaf 之前,首先要在页面的 html 标签中
声明名称空间
<html xmlns:th="http://www.thymeleaf.org">
此步骤可避免编辑器出现 html 验证错误,但这一步并
非必须进行的,即使我们不声明该命名空间,也不影
响 Thymeleaf 的使用
Thymeleaf 语法分为:
① 标准表达式语法
② th 属性
1. 标准表达式语法
① 变量表达式:${...}
② 选择变量表达式:*{...}
③ 链接表达式:@{...}
④ 国际化表达式:#{...}
⑤ 片段引用表达式:~{...}
(1) 变量表达式
${...}
该表达式具有以下功能:
① 获取对象的属性和方法
② 使用内置的基本对象
③ 使用内置的工具对象
1) 获取对象的属性和方法
例如:获取 person 对象的 lastName 属性
${person.lastName}
2) 使用内置的基本对象
Thymeleaf 中常用的内置基本对象如下:
#ctx :上下文对象
#vars :上下文变量
#locale:上下文的语言环境
以下4个仅在 Web 应用中可用:
#request:HttpServletRequest 对象
#response:HttpServletResponse 对象
#session:HttpSession 对象
#servletContext:ServletContext 对象
例如,我们通过以下 2 种形式,都可以获取到
session 对象中的 map 属性:
${#session.getAttribute('map')}
${session.map}
3) 使用内置的工具对象
strings:字符串工具对象,常用方法有:
equals、equalsIgnoreCase、length、trim、
toUpperCase、toLowerCase、indexOf、
substring、replace、startsWith、endsWith,
contains 和 containsIgnoreCase 等;
numbers:数字工具对象,常用的方法有:
formatDecimal 等;
bools:布尔工具对象,常用的方法有:
isTrue 和 isFalse 等;
arrays:数组工具对象,常用的方法有:
toArray、length、isEmpty、contains 和
containsAll 等;
lists/sets:List/Set 集合工具对象,常用的方
法有:toList、size、isEmpty、contains、
containsAll 和 sort 等;
maps:Map 集合工具对象,常用的方法有:
size、isEmpty、containsKey 和 containsValue
等;
dates:日期工具对象,常用的方法有:format、
year、month、hour 和 createNow 等。
例如,我们可以使用 strings 的 equals 方法,来判
断字符串与对象的某个属性是否相等
${#strings.equals('编程帮',name)}
(2) 选择变量表达式
*{...}
当使用 th:object 存储一个对象后,我们可以在
其后代中使用选择变量表达式 *{...} 获取该对象
中的属性,其中,“*” 即代表该对象
<div th:object="${session.user}" >
<p th:text="*{fisrtName}">firstname</p>
</div>
th:object 用于存储一个临时变量,该变量只在该标
签及其后代中有效
(3) 链接表达式
@{...}
不管是静态资源的引用,还是 form 表单的请求,凡是
链接都可以用链接表达式
无参请求:@{/xxx}
有参请求:@{/xxx(k1=v1,k2=v2)}
例如使用链接表达式引入 css 样式表:
<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">
(4) 国际化表达式
#{...}
消息表达式一般用于国际化的场景:
th:text="#{msg}"
(5) 片段引用表达式
~{...}
用于在模板页面中引用其他的模板片段
两种语法结构如下:
推荐:~{templatename::fragmentname}
支持:~{templatename::#id}
templatename:模版名,Thymeleaf 会根据模版名解析完整路径:/resources/templates/templatename.html,要注意文件的路径。
fragmentname:片段名,Thymeleaf 通过 th:fragment 声明定义代码块,即:th:fragment="fragmentname"
id:HTML 的 id 选择器,使用时要在前面加上 # 号,不支持 class 选择器。
2. th 属性
属性 | 描述 | 示例 |
th:id | 替换 HTML 的 id 属性 | <input id="html-id" th:id="thymeleaf-id" /> |
th:text | 文本替换,转义特殊字符 | <h1 th:text="hello,bianchengbang" >hello</h1> |
th:utext | 文本替换,不转义特殊字符 | <div th:utext="'<h1>你好</h1>'" >欢迎你</div> |
th:object | 在父标签选择对象,子标签使用 *{…} 选择表达式选取值。 没有选择对象,那子标签使用选择表达式和 ${…} 变量表达式是一样的效果。 同时即使选择了对象,子标签仍然可以使用变量表达式。 | <div th:object="${session.user}" > <p th:text="*{fisrtName}"> firstname </p> </div> |
th:value | 替换 value 属性 | <input th:value = "${user.name}" /> |
th:with | 局部变量赋值运算 | <div th:with="isEvens = ${prodStat.count}%2 == 0" th:text="${isEvens}"></div> |
th:style | 设置样式 | <div th:style="'color:#F00; font-weight:bold'">百度 www.baidu.com</div> |
th:onclick | 点击事件 | <td th:onclick = "'getInfo()'"></td> |
th:each | 遍历,支持 Iterable、Map、数组等 | <table> <tr th:each="m:${session.map}"> <td th:text="${m.getKey()}"></td> <td th:text ="${m.getValue()}"></td> </tr> </table> |
th:if | 根据条件判断是否需要展示此标签 | <a th:if ="${userId == collect.userId}"> |
th:unless | 和 th:if 判断相反,满足条件时不显示 | <div th:unless="${m.getKey()=='name'}" ></div> |
th:switch | 与 Java 的 switch case语句类似 通常与 th:case 配合使用,根据不同的条件展示不同的内容 | <div th:switch="${name}"> <span th:case="a">编程帮</span> <span th:case="b"> www.baidu.com</span> </div> |
th:fragment | 模板布局,类似 JSP 的 tag,用来定义一段被引用或包含的模板片段 | <footer th:fragment="footer">插入的内容</footer> |
th:insert | 布局标签; 将使用 th:fragment 属性指定的模板片段(包含标签)插入到当前标签中 | <div th:insert="commons/bar::footer"></div> |
th:replace | 布局标签; 使用 th:fragment 属性指定的模板片段(包含标签)替换当前整个标签 | <div th:replace="commons/bar::footer"></div> |
th:selected | select 选择框选中 | <select> <option>---</option> <option th:selected="${name=='a'}"> 百度 </option> <option th:selected ="${name=='b'}"> www.baidu.com </option> </select> |
th:src | 替换 HTML 中的 src 属性 | <img th:src="@{/asserts/img/bootstrap-solid.svg}" src="asserts/img/bootstrap-solid.svg" /> |
th:inline | 内联属性; 该属性有 text、none、javascript 三种取值, 在 <script> 标签中使用时,js 代码中可以获取到后台传递页面的对象 | <script type="text/javascript" th:inline="javascript"> var name = /*[[${name}]]*/ 'baidu'; alert(name) </script> |
th:action | 替换表单提交地址 | <form th:action="@{/user/login}" th:method="post"></form> |
三、 Thymeleaf 公共页面抽取
1. 抽取公共页面
将公共页面片段抽取出来,存放到一个独立
的页面中,并使用 Thymeleaf 提供的
th:fragment 属性为这些抽取出来的公共页面
片段命名
例如:将公共页面片段抽取出来,存放在
commons.html 中
<div th:fragment="fragment-name" id="fragment-id">
<span>公共页面片段</span>
</div>
2. 引用公共页面
可以使用以下 3 个属性引用:
th:insert:将代码块片段整个插入到使用了
th:insert 属性的 HTML 标签中;
th:replace:将代码块片段整个替换使用了
th:replace 属性的 HTML 标签中;
th:include:将代码块片段包含的内容插入
到使用了 th:include 属性的 HTML
标签中
使用以上 3 个属性引入页面片段,都可以通过
以下 2 种方式实现:
~{templatename::selector}:模板名::选择器
~{templatename::fragmentname}:模板名::片段名
通常情况下,~{} 可以省略,其行内写法为 [[~{...}]]
或 [(~{...})],其中 [[~{...}]] 会转义特殊字符,
[(~{...})] 则不会转义特殊字符。
(1) 在页面 fragment.html 中引入 commons.html 中声明
的页面片段
<!--th:insert 片段名引入-->
<div th:insert="commons::fragment-name"></div>
<!--th:insert id 选择器引入-->
<div th:insert="commons::#fragment-id"></div>
------------------------------------------------
<!--th:replace 片段名引入-->
<div th:replace="commons::fragment-name"></div>
<!--th:replace id 选择器引入-->
<div th:replace="commons::#fragment-id"></div>
------------------------------------------------
<!--th:include 片段名引入-->
<div th:include="commons::fragment-name"></div>
<!--th:include id 选择器引入-->
<div th:include="commons::#fragment-id"></div>
(2) 启动 Spring Boot,使用浏览器访问 fragment.html
<!--th:insert 片段名引入-->
<div>
<div id="fragment-id">
<span>公共页面片段</span>
</div>
</div>
<!--th:insert id 选择器引入-->
<div>
<div id="fragment-id">
<span>公共页面片段</span>
</div>
</div>
------------------------------------------------
<!--th:replace 片段名引入-->
<div id="fragment-id">
<span>公共页面片段</span>
</div>
<!--th:replace id 选择器引入-->
<div id="fragment-id">
<span>公共页面片段</span>
</div>
------------------------------------------------
<!--th:include 片段名引入-->
<div>
<span>公共页面片段</span>
</div>
<!--th:include id 选择器引入-->
<div>
<span>公共页面片段</span>
</div>
3. 传递参数
(1) 传入参数
引用公共页面片段时,我们可以通过以下 2 种方式,
将参数传入到被引用的页面片段中:
① 模板名::选择器名或片段名(参数1=参数值1,参数2
=参数值2)
② 模板名::选择器名或片段名(参数值1,参数值2)
注:
若传入参数较少时,一般采用第二种方式,直接
将参数值传入页面片段中;
若参数较多时,建议使用第一种方式,明确指定
参数名和参数值
<!--th:insert 片段名引入-->
<div th:insert="commons::fragment-name(var1='insert-name',var2='insert-name2')"></div>
<!--th:insert id 选择器引入-->
<div th:insert="commons::#fragment-id(var1='insert-id',var2='insert-id2')"></div>
------------------------------------------------
<!--th:replace 片段名引入-->
<div th:replace="commons::fragment-name(var1='replace-name',var2='replace-name2')"></div>
<!--th:replace id 选择器引入-->
<div th:replace="commons::#fragment-id(var1='replace-id',var2='replace-id2')"></div>
------------------------------------------------
<!--th:include 片段名引入-->
<div th:include="commons::fragment-name(var1='include-name',var2='include-name2')"></div>
<!--th:include id 选择器引入-->
<div th:include="commons::#fragment-id(var1='include-id',var2='include-id2')"></div>
(2) 使用参数
在声明页面片段时,我们可以在片段中声明并
使用这些参数,例如:
<!--使用 var1 和 var2 声明传入的参数,并在该片段中直接使用这些参数 -->
<div th:fragment="fragment-name(var1,var2)" id="fragment-id">
<p th:text="'参数1:'+${var1} + '-------------------参数2:' + ${var2}">...</p>
</div>
四、Springboot 整合
1. 加入依赖
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
</parent>
<dependencies>
<!--web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--thymeleaf配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
2. 创建 html
在 resources 中创建 templates 目录,在 templates
目录创建 demo1.html,代码如下:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Thymeleaf的入门</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<!--输出hello数据-->
<p th:text="${hello}"></p>
</body>
</html>
3. 修改 application.yml 配置
在 resources 中创建 application.yml,并设置
thymeleaf 的缓存设置,设置为 false
默认加缓存的,用于测试:修改后不需要重启
spring:
thymeleaf:
cache: false
在这里,其实还有一些默认配置,比如
视图前缀:classpath:/templates/
视图后缀:.html
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties
部分源码如下:
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean cache = true; //是否启用模板缓存
4. 控制层
创建 controller 用于测试后台 设置数据到 model 中
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/test")
public class TestController {
/***
* 访问/test/hello 跳转到demo1页面
* @param model
* @return
*/
@RequestMapping("/hello")
public String hello(Model model){
model.addAttribute("hello","hello welcome");
return "demo1";
}
}
5. 测试
创建启动类 ThymeleafApplication
,代码如下:
@SpringBootApplication
public class ThymeleafApplication {
public static void main(String[] args) {
SpringApplication.run(ThymeleafApplication.class,args);
}
}