一、Thymeleaf模版简介
官方文档:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#appendix-a-expression-basic-objects
中文文档:
https://www.e-learn.cn/thymeleaf/thymeleaf-instroduce
SpringBoot提供了大量的模版引擎,包括FreeMarker、Groovy、Thymeleaf、Velcoity和Mustache,SpringBoot中推荐使用Thymeleaf作为模版引擎,因为Thymeleaf提供了完美的SpringMVC支持。
Thymeleaf是一个java类库,它是一个xml/xthml/html5的模版引擎,可以作为MVC的Web应用的View层。
- 通过xmlns:th=”http://www.thymeleaf.org”命名空间,将页面转换为动态试图,需要进行动态处理的元素使用“th:”作为前缀。
- 通过th:text=”${person.name}”访问model中的属性。
- 通过th:each=”person:${people}”来做循环迭代。
- 通过th:if=”${not #lists.isEmpty(people)}”来判断people是否为空。
5 .通过th:src=”@{jquery-3.3.1.min.js}”来访问Web中的静态资源。 - 通过th:inline=”javascript”来添加script标签,这样在JavaScript代码中即可访问model中的属性值。
- 通过“[[${}]]”格式来获得实际值。
在传统的SpringMVC中,若我们需要集成一个模版引擎的话,需要定义ViewResolver。而Thymeleaf提供了一个SpringTemplateEngine的类,用来驱动SpringMVC下使用Thymeleaf模版引擎。而在SpringBoot中对Thymeleaf进行了自动配置,可以在application中以spring.thymeleaf开发来进行配置,不配置的情况下模版的默认目录是templates。
在src/main/resource/static中放入需要引入的静态资源:Bootstrap和jQuery。根据默认的原则在src/main/resource/templates下创建index.html文件。
二、SpringBoot整合Thymeleaf
- Maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
静态资源
SpringBoot默认的几个静态页面的目录:
/static、/public、/resources 、/META-INF/resources配置Thymeleaf,在application.properties下配置
#thymelea模板配置
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.servlet.content-type=text/html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.cache
是否开启模板缓存,默认true
spring.thymeleaf.check-template-location
是否检查模板路径是否存在,默认true
spring.thymeleaf.content-type
指定Content-Type,默认为: text/html
spring.thymeleaf.enabled
是否允许MVC使用Thymeleaf,默认为: true
spring.thymeleaf.encoding
指定模板的编码,默认为: UTF-8
spring.thymeleaf.excluded-view-names
指定不使用模板的视图名称,多个以逗号分隔.
spring.thymeleaf.mode
**指定模板的模式,具体查看StandardTemplateModeHandlers,默认为: HTML5
spring.thymeleaf.mode = LEGACYHTML5
spring.thymeleaf.mode的默认值是HTML5,其实是一个很严格的检查,改为LEGACYHTML5可以得到一个可能更友好亲切的格式要求。
**
spring.thymeleaf.prefix
指定模板的前缀,默认为:classpath:/templates/
spring.thymeleaf.suffix
指定模板的后缀,默认为:.html
spring.thymeleaf.template-resolver-order
指定模板的解析顺序,默认为第一个.
spring.thymeleaf.view-names
指定使用模板的视图名,多个以逗号分隔.
- 编写Controller
@Controller
public class IndexController {
@GetMapping("/index")
public ModelAndView test(ModelAndView mv) {
//视图文件名
mv.setViewName("index");
mv.addObject("name","欢迎使用Thymeleaf!");
return mv;
}
}
- 编写html
在src/main/resources/templates目录下创建:index.html
<!--引入命名空间-->
<html xmlns:th="http://www.thymeleaf.org">
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>thymeleaf示例</title>
</head>
<body>
<h1>Hello thymeleaf</h1>
<h2 th:text="'名称:'+${name}">默认值</h2>
</body>
</html>
文本需要th:text属性来设置。我们可以在文本元素中添加默认值,这样当Thymeleaf引擎处理失败的时候页面会显示默认值。${...}是变量表达式,将括号中的变量替换为其值。
三、基础语法
th属性:
常用th属性解读
html有的属性,Thymeleaf基本都有,而常用的属性大概有七八个。其中th属性执行的优先级从1~8,数字越低优先级越高。
1)th:text :设置当前元素的文本内容,相同功能的还有th:utext,两者的区别在于前者不会转义html标签,后者会。优先级不高:order=7
2)th:value:设置当前元素的value值,类似修改指定属性的还有th:src,th:href。优先级不高:order=6
3)th:each:遍历循环元素,和th:text或th:value一起使用。注意该属性修饰的标签位置,详细往后看。优先级很高:order=2
4)th:if:条件判断,类似的还有th:unless,th:switch,th:case。优先级较高:order=3
5)th:insert:代码块引入,类似的还有th:replace,th:include,三者的区别较大,若使用不恰当会破坏html结构,常用于公共代码块提取的场景。优先级最高:order=1
6)th:fragment:定义代码块,方便被th:insert引用。优先级最低:order=8
7)th:object:声明变量,一般和*{}一起配合使用,达到偷懒的效果。优先级一般:order=4
8)th:attr:修改任意属性,实际开发中用的较少,因为有丰富的其他th属性帮忙,类似的还有th:attrappend,th:attrprepend。优先级一般:order=5
- 变量表达式 {}" 获取对象属性 。例如:
<form id="userForm">
<input id="id" name="id" th:value="${user.id}"/>
<input id="username" name="username" th:value="${user.username}"/>
<input id="password" name="password" th:value="${user.password}"/>
</form>
<div th:text="hello"></div>
<div th:text="${user.username}"></div>
- 选择变量表达式 {}
使用方法:首先通过th:object 获取对象,然后使用th:xx = "{}"获取对象属性。
这种简写风格极为清爽,推荐大家在实际项目中使用。 例如:
<form id="userForm" th:object="${user}">
<input id="id" name="id" th:value="{id}"/>
<input id="username" name="username" th:value="{username}"/>
<input id="password" name="password" th:value="*{password}"/>
</form> - 链接表达式 @{}
使用方法:通过链接表达式@{}直接拿到应用路径,然后拼接静态资源路径。例如:
<script th:src="@{/webjars/jquery/jquery.js}"></script>
<link th:href="@{/webjars/bootstrap/css/bootstrap.css}" rel="stylesheet" type="text/css">
- 片段表达式 ~{}
Thymeleaf 3.0 引入了一个新的片段表达式。形如:~{commons::footer}。
该特性十分有用(比如解决定义通用的header和footer的问题)
base.html
片段表达式是Thymeleaf的特色之一,细粒度可以达到标签级别,这是JSP无法做到的。
片段表达式拥有三种语法:
~{ viewName } 表示引入完整页面
~{ viewName ::selector} 表示在指定页面寻找片段 其中selector可为片段名、jquery选择器等
~{ ::selector} 表示在当前页寻找
使用方法:首先通过th:fragment定制片段 ,然后通过th:replace 填写片段路径和片段名。例如:
<!-- /views/common/head.html-->
<head th:fragment="static">
<script th:src="@{/webjars/jquery/3.3.1/jquery.js}"></script>
</head>
<!-- /views/your.html -->
<div th:replace="~{common/head::static}"></div>
在实际使用中,我们往往使用更简洁的表达,去掉表达式外壳直接填写片段名。例如:
<!-- your.html -->
<div th:replace="common/head::static"></div>
值得注意的是,使用替换路径th:replace 开头请勿添加斜杠,避免部署运行的时候出现路径报错。(因为默认拼接的路径为spring.thymeleaf.prefix = classpath:/templates/)
支持两种语法结构
推荐:~{templatename::fragmentname}
支持:~{templatename::#id}
templatename:模版名,Thymeleaf会根据模版名解析完整路径:/resources/templates/templatename.html,要注意文件的路径。
fragmentname:片段名,Thymeleaf通过th:fragment声明定义代码块,即:th:fragment="fragmentname"
id:HTML的id选择器,使用时要在前面加上#号,不支持class选择器。
代码块表达式的使用
代码块表达式需要配合th属性(th:insert,th:replace,th:include)一起使用。
th:insert:将代码块片段整个插入到使用了th:insert的HTML标签中,
th:replace:将代码块片段整个替换使用了th:replace的HTML标签中,
th:include:将代码块片段包含的内容插入到使用了th:include的HTML标签中,
用一个官方例子来区分三者的不同,第三部分会通过实战再次用到该知识。
<!--th:fragment定义代码块标识-->
<footer th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</footer>
<!--三种不同的引入方式-->
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
<!--th:insert是在div中插入代码块,即多了一层div-->
<div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
</div>
<!--th:replace是将代码块代替当前div,其html结构和之前一致-->
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
<!--th:include是将代码块footer的内容插入到div中,即少了一层footer-->
<div>
© 2011 The Good Thymes Virtual Grocery
</div>
- 消息表达式
即通常的国际化属性:#{msg} 用于获取国际化语言翻译值。例如:
<title th:text="#{user.title}"></title>
- 其它表达式
在基础语法中,默认支持字符串连接、数学运算、布尔逻辑和三目运算等。例如:
<input name="name" th:value="${'I am '+(user.name!=null?user.name:'NoBody')}"/>
- 注释
Thymeleaf 注释:
1、<!--/* This code will be removed at Thymeleaf parsing time! */-->
2、<!--/*-->
<div>
you can see me only before Thymeleaf processes me!
</div>
<!--*/-->
3、<!--/*/
<div th:text="${...}">
...
</div>
/*/-->
四、迭代循环
想要遍历List集合很简单,配合th:each 即可快速完成迭代。例如遍历用户列表:
<div th:each="user:${userList}">
账号:<input th:value="${user.username}"/>
密码:<input th:value="${user.password}"/>
</div>
在集合的迭代过程还可以获取状态变量,只需在变量后面指定状态变量名即可,状态变量可用于获取集合的下标/序号、总数、是否为单数/偶数行、是否为第一个/最后一个。例如:
<div th:each="user,stat:${userList}" th:class="${stat.even}?'even':'odd'">
下标:<input th:value="${stat.index}"/>
序号:<input th:value="${stat.count}"/>
账号:<input th:value="${user.username}"/>
密码:<input th:value="${user.password}"/>
</div>
如果缺省状态变量名,则迭代器会默认帮我们生成以变量名开头的状态变量 xxStat, 例如:
<div th:each="user:${userList}" th:class="${userStat.even}?'even':'odd'">
下标:<input th:value="${userStat.index}"/>
序号:<input th:value="${userStat.count}"/>
账号:<input th:value="${user.username}"/>
密码:<input th:value="${user.password}"/>
</div>
th:remove
th:remove的值如下:
1.all:删除包含标签和所有的孩子。
2.body:不包含标记删除,但删除其所有的孩子。
3.tag:包含标记的删除,但不删除它的孩子。
4.all-but-first:删除所有包含标签的孩子,除了第一个。
5.none:什么也不做。这个值是有用的动态评估。
五、条件判断
条件判断通常用于动态页面的初始化,例如:
<div th:if="${userList}">
<div>的确存在..</div>
</div>
如果想取反则使用unless 例如:
<div th:unless="${userList}">
<div>不存在..</div>
</div>
六、日期格式化
使用默认的日期格式(toString方法) 并不是我们预期的格式:Mon Dec 03 23:16:50 CST 2018
<input type="text" th:value="${user.createTime}"/>
此时可以通过时间工具类#dates来对日期进行格式化:2018-12-03 23:16:50
<input type="text" th:value="${#dates.format(user.createTime,'yyyy-MM-dd HH:mm:ss')}"/>
七、内联写法
(1)为什么要使用内联写法?·答:因为 JS无法获取服务端返回的变量。
(2)如何使用内联表达式?答:标准格式为:[[${xx}]] ,可以读取服务端变量,也可以调用内置对象的方法。例如获取用户变量和应用路径:
<script th:inline="javascript">
var user = [[${user}]];`
var APP_PATH = [[${#request.getContextPath()}]];
var LANG_COUNTRY = [[${#locale.getLanguage()+'_'+#locale.getCountry()}]];
</script>
(3)标签引入的JS里面能使用内联表达式吗?答:不能!内联表达式仅在页面生效,因为Thymeleaf只负责解析一级视图,不能识别外部标签JS里面的表达式。
八、七大基础对象:
${#ctx} 上下文对象,可用于获取其它内置对象。
${#vars}: 上下文变量。
${#locale}:上下文区域设置。
${#request}: HttpServletRequest对象。
${#response}: HttpServletResponse对象。
${#session}: HttpSession对象。
${#servletContext}: ServletContext对象。
常用的工具类:
#strings:字符串工具类
#lists:List 工具类
#arrays:数组工具类
#sets:Set 工具类
#maps:常用Map方法。
#objects:一般对象类,通常用来判断非空
#bools:常用的布尔方法。
#execInfo:获取页面模板的处理信息。
#messages:在变量表达式中获取外部消息的方法,与使用#{...}语法获取的方法相同。
#uris:转义部分URL / URI的方法。
#conversions:用于执行已配置的转换服务的方法。
#dates:时间操作和时间格式化等。
#calendars:用于更复杂时间的格式化。
#numbers:格式化数字对象的方法。
#aggregates:在数组或集合上创建聚合的方法。
#ids:处理可能重复的id属性的方法。
九、常见问题
-
去掉IDE thymeleaf Html显示红色波浪线
打开IDE的file->setting->左上角搜索inspections,然后在右边的搜索栏输入thy,就会显示如下页面,将Expression variables validation的√去掉,然后点击确定。
- 日期格式处理
添加:
@Column
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date createtime;
显示:
//java代码:
@GetMapping("/index")
public String test(Model model) {
model.addAttribute("date",new Date());
//视图文件名
return "index";
}
//H5界面
<span th:text="${#dates.format(date, 'yyyy-MM-dd')}">2018-05-06</span>
或者
<span th:text="${#dates.format(date,'yyyy-MM-dd HH:mm:ss')}">2019-05-06 00:00:00</span>