Spring Boot 中Thymeleaf
一、快速入门
官网:https://www.thymeleaf.org/
可下载文档学习。
二、为什么选择Thymeleaf
我们知道Spring MVC本身是支持多种视图技术。视图技术不推荐使用 JSP,官方推荐使用一些第三方的模板引擎:Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP 。相较于其他的模板引擎,特点:
动静结合:
Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。
开箱即用:
它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、改jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
多方言支持:
Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
与SpringBoot完美整合
SpringBoot提供了Thymeleaf的默认配置,并且为Thymeleaf设置了视图解析器,我们可以像以前操作jsp一样来操作Thymeleaf。代码几乎没有任何区别,就是在模板语法上有区别。
本质上,它们跟Spring MVC继承时,是提供了Spring MVC的 ViewResolver
组件的自定义实现。
比如:Thymeleaf 的实现是 ThymeleafViewResolver
与解析JSP的InternalViewResolver
类似.
在spring boot下的导入方式,如下图所示。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
三、快速了解一下启动器做了啥?
1. XxxProperties : 能找到对应的配置项的支持。
Thymeleaf也会根据前缀和后缀来确定模板文件的位置:
默认前缀:classpath:/templates/
默认后缀:.html
2. XxxAutoConfiguration : 就是自动配置的逻辑。
知道它自动配置了什么,将来我可以直接使用。
当不满足我的需求时,如何替换默认配置。
四、Thymeleaf的语法
(一)编写html模板,渲染模型中的数据把html 的名称空间,改成:xmlns:th=“http://www.thymeleaf.org” 会有语法提示,如下图官方文档:
基本表达式:
(二)url
Thymeleaf对于URL的处理是通过语法@{…}来处理的。Thymeleaf支持绝对路径URL:
(三)片段
th:fragment 布局标签,定义一个代码片段,方便其它地方引用
< th:insert >是将内容插入到所属标签的内部作为子标签。
< th:replace >是将内容直接替换所在的标签。
< th:block > 是虚拟标签,不会影响网页结构。
<!--
片段引用的特殊指令:
th:insert 将内容插入到所属标签的内部作为子标签
th:replace 将内容直接替换所在的标签
<th:block> 这个标签是虚拟的标签,不会影响网页结构
-->
<th:block th:insert="~{commons/fragment::pageHeader}"/>
(四) 判断条件 文本替换
使用 th:if、th:text
(五)迭代
使用 th:each 标签
lstat称作状态变量,属性有:
index:当前迭代对象的index(从0开始计算)
count: 当前迭代对象的index(从1开始计算)
size:被迭代对象的大小
current:当前迭代变量
even/odd:布尔值,当前循环是否是偶数/奇数(从0开始计算)
first:布尔值,当前循环是否是第一个
last:布尔值,当前循环是否是最后一个
也可配合 th:object 和 * {} 表达式,可以简写 ${}
<!--
关于遍历,重复哪个标签,就往那个标签上写指令
th:each 的值:
格式1: 项 : ${集合}
格式2: 项,状态变量 : ${集合}
关于状态变量,还要默认的规则:
如果没有定义,其实它也生成了, 项+'Stat'
配合 th:object 和 *{} 表达式,可以简写 ${}
-->
<ul>
<li th:each="f : ${user.friends}" th:object="${f}">
<div>
<span th:text="${f.name}">姓名</span>
<span th:text="*{lastTime}">时间</span>
</div>
</li>
</ul>
(六)内置对象
(七)工具
(八)常用th标签汇总
(1) th:action:
定义后台控制器路径,类似<form>标签的action属性。
例如:
<form th:action="@{/login}">...</form>
(2) th:each:
对象遍历,功能类似jsp中的<c:forEach>标签。用于遍历展示或者遍历录入。
例如:
<form th:action="@{/addStudent}" th:object="${stuReqBean}" method="POST">
<div th:each="stuIter,rowStat:${stuReqBean.students}">
<input type="text" value="" th:field="*{students[__${rowStat.index}__].firstName}"></input>
<input type="text" value="" th:field="*{students[__${rowStat.index}__].school}"></input>
</div>
</form>
//后台代码
@RequestMapping(value = "/addStudent", method = RequestMethod.POST)
public String addStudent(@ModelAttribute(value = "stuReqBean")
StudentRequestBean stuReqBean,ModelMap model) {...}
(3) th:field:
常用于表单字段绑定。通常与th:object一起使用。 属性绑定、集合绑定。
例如:
<form th:action="@{/login}" th:object="${loginBean}">
<input type="text" value="" th:field="*{username}"></input>
<input type="text" value="" th:field="*{user[0].username}"></input>
</form>
(4) th:href:
定义超链接,类似<a>标签的href 属性。value形式为@{/logout}
例如:
<a th:href="@{/logout}"></a>
(5) th:id:
div id声明,类似html标签中的id属性。
例如:
<div th:id = "stu+(${rowStat.index}+1)"></div>
(6) th:if:
条件判断。如果为否则标签不显示,例如:
例如:
<div th:if="${rowStat.index} == 0">... do something ...</div>
(7) th:include&;th:fragment:
声明定义该属性的div为模板片段,常用与头文件、页尾文件的引入。常与th:include,th:replace一起使用。
声明模板片段/WEBINF/templates/footer. html :
<div th: fragment=" copy" >
© 2011 The Good Thymes Virtual Grocery
</div>
引入模板片段:
<div th: include=" /templates/footer : : copy" ></div>
<div th: replace=" /templates/footer : : copy" ></div>
(8) th:object:
用于表单数据对象绑定,将表单绑定到后台controller的一个JavaBean参数。常与th:field一起使用进行表单数据绑定。
public class LoginBean implements Serializable{...}
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(@ModelAttribute(value = "loginBean") LoginBean loginBean,ModelMap model) {...}
<form th:action="@{/login}" th:object="${loginBean}">...</form>
(9) th:src:
用于外部资源引入,类似于<script>标签的src属性,常与@{}一起使用。
例如:
<script th:src="@{/resources/js/jquery/jquery.json-2.4.min.js}"
(10) th:text:
文本显示。
例如:
<td th:text="${username}" ></td>
(11) th:value:
用于标签复制,类似<option>标签的value属性。
例如:
<option th:value="Adult">Adult</option>
<input type="hidden" th:value="${msg}" />
(12) th:inline:
定义js脚本可以使用变量。
例如:
<script th:inline="javascript">
//提交表单
function form_submit() {
var data={
userId:[[${userId}]], //js引用后端传来的值
role:[[${role}]],
password:$("#password").val(),
}
$.post("xx",data,function (mes) {
...xxx...
})
(12) th:remove:
用于移除标签。
例如:
<a th:remove="${status}!=0?all:none" >未提交</a>
(13) th: style:
用于修改标签style。
例如:
<span th:style="'display:' + @{(${sitrue} ? 'none' : 'inline-block')} + ''">
(14) th: onclick:
用于修改点击事件。
例如:
<button th:οnclick="'getCollect()'"></button>
3. 标准表达式
(1) 字面
文本文字:放在 单引号 里面,可以是任意字符,如:'one text','Another one!',...
<span th:text="'working web application'">template file
数字文字:0,34,3.0,12.3,...
<span th:text="2020">1492
布尔文字:true,false
<div th:if="${user.isAdmin()} == false">
空字面: null
<div th:if="${variable.something} == null">
(2) 文字操作:
字符串连接: +
例如:
<span th:text="'Welcome to our application, ' + ${user.name} + '!'">
文字替代: |The name is ${name}|
例如:
<span th:text="|Welcome to our application, ${user.name}!|">
(3) 算术运算:
二元运算符:+,-,*,/,%
例如:
<span th:text="1+1">1+1
(4) 布尔运算:
二元运算符:and,or
布尔否定(一元运算符): !,not
例如:
<span th:if="${!#lists.isEmpty(list)} and ${#lists.isEmpty(list)}" >and
<span th:if="${!#lists.isEmpty(list)} or ${#lists.isEmpty(list)}" >or
<span th:if="${!#lists.isEmpty(list)}">not
(5) 比较和相等:
比较:>,<,>=,<=(gt,lt,ge,le)
相等判断:==,!=(eq,ne)
例如:
<ol>
<li>>(gt):<span th:text="1+1" th:if="${#lists.size(list)} > 1">大于>else</li>
<li>小于lt:<span th:if="${#lists.size(list)} lt 1">小于else</li>
<li>>=(ge):<span th:if="${#lists.size(list)} >= 1">大于等于>=else</li>
<li>小于等于(le):<span th:if="${#lists.size(list)} le 1">小于等于else</li>
<li>!(not):<span th:if="${!#lists.isEmpty(list)}">!(not)else</li>
<li>==(eq):<span th:text="'Execution mode is ' + ( (${execMode} == 'dev')? 'Development' : 'Production')">等于==</li>
<li>!=(ne/neq):size:<span th:text="${#lists.size(list)}"th:if="${#lists.size(list)} != 1"></li>
</ol>
(6) 条件运算符:
IF-THEN: (if) ? (then)
<span th:class="${title1} ? 'green'">样例
IF-THEN-ELSE: (if) ? (then) : (else)
<span th:class="${title} ? 'green' :' red'">样例一
默认: (value) ?: (defaultvalue)
<span th:text="*{age}?: '(no age specified)'">20
五、Thymeleaf关闭模板缓存
添加devtools(热部署)依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
在application.properties配置文件关闭
# 开发阶段关闭thymeleaf的模板缓存
spring.thymeleaf.cache=false
在application.yml配置文件关闭
# 开发阶段关闭thymeleaf的模板缓存
spring:
thymeleaf:
cache: false
SpringBoot 配置devtools实现热部署
spring为开发者提供了一个名为spring-boot-devtools的模块来使Spring Boot应用支持热部署,提高开发者的开发效率,无需手动重启Spring Boot应用。
原理:
深层原理是使用了两个ClassLoader,一个Classloader加载那些不会改变的类(第三方Jar包),另一个ClassLoader加载会更改的类,称为restart ClassLoader,这样在有代码更改的时候,原来的restart ClassLoader 被丢弃,重新创建一个restart ClassLoader,由于需要加载的类相比较少,所以实现了较快的重启时间。
说明:
说明:
(1) devtools可以实现页面热部署(即页面修改后会立即生效,这个可以直接在application.properties文件中配置spring.thymeleaf.cache=false来实现),
实现类文件热部署(类文件修改后不会立即生效),实现对属性文件的热部署。
即devtools会监听classpath下的文件变动,并且会立即重启应用(发生在保存时机),注意:因为其采用的虚拟机机制,该项重启是很快的
(2)配置了后在修改java文件后也就支持了热启动,不过这种方式是属于项目重启(速度比较快的项目重启),会清空session中的值,也就是如果有用户登陆的话,项目重启后需要重新登陆。
默认情况下,/META-INF/maven,/META-INF/resources,/resources,/static,/templates,/public这些文件夹下的文件修改不会使应用重启,但是会重新加载(devtools内嵌了一个LiveReload server,当资源发生改变时,浏览器刷新)。
配置:
在application.properties中配置spring.devtools.restart.enabled=false,此时restart类加载器还会初始化,但不会监视文件更新。
在SprintApplication.run之前调用System.setProperty(“spring.devtools.restart.enabled”, “false”);可以完全关闭重启支持,配置内容:
#热部署生效
spring.devtools.restart.enabled: true
#设置重启的目录
#spring.devtools.restart.additional-paths: src/main/java
#classpath目录下的WEB-INF文件夹内容修改不重启
spring.devtools.restart.exclude: WEB-INF/**
IDEA配置
当我们修改了Java类后,IDEA默认是不自动编译的,而spring-boot-devtools又是监测classpath下的文件发生变化才会重启应用,所以需要设置IDEA的自动编译:
(1)File-Settings-Compiler-Build Project automatically
(2)ctrl + shift + alt + /,选择Registry,勾上 Compiler autoMake allow when app running
测试:
修改类–>保存:应用会重启
修改配置文件–>保存:应用会重启
修改页面–>保存:应用不会重启,但会重新加载,页面会刷新(原理是将spring.thymeleaf.cache设为false)