SpringBoo-Thymeleaf
SpringBoo-Thymeleaf简介
SpringBoot并不推荐使用JSP,它推荐我们使用模板引擎Thymeleaf,它与Velocity、Freemark类似,可以完全取代JSP。
特点:
- 动静结合:Thymeleaf在有网络和无网络的环境下皆可运行,它可以直接查看页面的动态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持html原型,然后在html标签里增加了额外的属性来达到模板+数据的展示方式。浏览器解释html时会忽略未定义的标签属性,所以Thymeleaf的模板可以静态本地运行,当返回数据到页面时,Thymeleaf标签会动态地替换掉静态内容,使页面动态显示。
- 开箱即用:它提供了标准和Spring标准两种方言,可以直接套用模板实现JSTL、OGNL表达式效果,避免每天套模板、改JSTL、改标签的困扰,同时开发人员可以扩展和创建自定义的方言。(简单的说,和JSP的写法是基本一致的。)
- 多方言支持:Thymeleaf提供Spring标准方言和SpringMVC完美继承的可选模板,可以快速的实现表单绑定、属性编辑器、国际化等功能。
- 与SpringBoot完美整合:与SpringBoot完美整合、SpringBoot提供了Thymeleaf的默认配置,并且为Thymeleaf设置了视图解析器,我们可以像以前那样操作JSP一样来操作Thymeleaf。
Thymeleaf基本使用
添加启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
创建模板文件夹
SpringBoot会自动为Thymeleaf注册一个视图解析器ThymeleafViewResolver,还配置了模板文件(html)的位置,与jsp类似的前缀+视图名+后缀风格。
在ThymeleafProperties类的源码中我们可以看出,其默认的前缀如下
public static final String DEFAULT_PREFIX = "classpath:/templates/";
默认的后缀如下
public static final String DEFAULT_SUFFIX = ".html";
即:在resources下创建templates文件夹,将模板文件放在其目录下,后缀为html即可
创建Controller类测试
配置好模板文件的文件夹后,我们只需要创建非REST风格的Controller类,将其返回值设置为String,返回值为模板文件夹下的模板文件名即可通过该接口找到模板文件。
Thymeleaf的常用操作
如果需要将值返回值至该模板文件中,可以使用Model ,在Controller的方法中使用AddAttribute方法将数据添加至域对象中。
在html中我们可以通过th表达式来取出域对象的值。需要先在html页面中加入如下头信息。
<html lang="en" xmlns:th="http://www.thymeleaf.org">
案例:使用th表达式取出Model中值
package cn.rayfoo.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author 张瑞丰
* @description
* @date 2019/11/25
*/
@Controller
@RequestMapping("/thy")
@Slf4j
public class ThymeleafController {
@RequestMapping("/hello")
public String hello(Model model){
model.addAttribute("title","rayfoo.cn");
return "hello";
}
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${title}">Hello world</h1>
</body>
</html>
案例中h1标题显示的即为rayfoo.cn
Thymeleaf表达式
引入头信息
使用Thymeleaf表达式一定要记得引入头信息!!!
<html lang="en" xmlns:th="http://www.thymeleaf.org">
关闭Thymeleaf缓存
Thymeleaf内部提供了缓存的机制,为的是提高访问性能,但是这个缓存不利于我们的开发和测试,在项目开发阶段,我们可以将Thymeleaf的缓存关闭,关闭方法如下:
spring:
thymeleaf:
cache: false
mode: HTML5
encoding: utf-8spring:
获取变量值
Thymeleaf表达式最基础的应用,就是获取后台传递的值,格式如下。
<h1 th:text="${title}">Hello world</h1>
在标签中,直接使用th:test=""的形式即可获取后台model中存储的指定key的值,其用法和EL表达式几乎一致。
获取对象中的属性
如果后台传递给前台的是一个对象,也可以使用Thymeleaf来获取其中的属性。
方法1:使用th:text标签,通过连缀方式获取
方法2:使用th:object标签,在其子标签中通过th:text="*{}"取出其属性
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${title}">Hello world</h1>
<hr>
<p th:text="${person.id}"></p>
<p th:text="${person.name}"></p>
<p th:text="${person.age}"></p>
<hr>
<div th:object="${person}">
<p th:text="*{id}"></p>
<p th:text="*{name}"></p>
<p th:text="*{age}"></p>
</div>
</body>
</html>
资源地址和超链接地址
在前端页面中,我们经常会用到href和src,这类超链接和路径地址也可以使用Thymeleaf表达式来获取。主要分为如下三种形式。
-
绝对路径:绝对路径说白了就是直接写一个字面常量,代替元素的src或者href
<a href="" th:href="@{https://www.baidu.com}"></a>
-
上下文相关路径:即相对路径,使用此种路径的形式,会将“/”作为当前项目的资源文件的路径亦或是接口名,例如如下案例中,将static下的静态资源指定为图片的src。也可在“/”前加上“”,“”代表服务器的目录。
<img src="" th:src="@{/haibao.png}" alt=""> <img src="" th:src="@{~/haibao.png}" alt=""> <a href="" th:href="@{/hello}">携带参数</a>
-
携带参数
如果我们跳转到一个url,需要携带一些参数,例如:"http://localhost:8080/test?id=10"的形式,Thymeleaf同样提供了完善的解决方案。
<a href="" th:href="@{/hello(id=10,name='giao')}">携带参数</a>
字面值
在Thymeleaf中,还可以直接显示字面值,不过这个功能一般不会单独使用,一般用在在获取的变量前加上说明。字面值一般在${}中加单引号,如果后面要加上遍历,以"+"链接即可。
例如:
<h1 th:text="${'姓名'+person.name}"></h1>
还可以直接书写数字、布尔值等数据
<h1 th:text="${10}"></h1>
<h1 th:text="${true}"></h1>
一般我们都会把字面值写在外部,在${}中取域对象的内容。
例如:
<h1 th:text="'姓名'+${person.name}"></h1>
如果大量使用拼接,可以使用“|”声明内部使用了连接,可以省略“+”
<h1 th:text="|'姓名'${person.name}|"></h1>
运算符
-
Thymeleaf中支持常用的算数运算符(+、-、*、/、%)等
-
还支持比较运算符(>、<、==、>=、<=)等,但是我们不能在html中直接使用>、<。要使用如下代替。
运算符 html中使用格式 > gt < lt >= ge <= le 例如:
<h1 th:text="1 gt 2"></h1>
上述代码会在前端页面中显示一个false字面值。
-
除此之外还支持三元运算符?:
<h1 th:text="1 gt 2 ? '真' : '假'"></h1>
上述代码会输出一个‘假’的字面值。
-
默认表达式
前面的值为空,就显示默认值,否则就显示本身
例如:
<h1 th:text="'aa'?: '我是空值'"></h1> <h1 th:text="null?: '我是空值'"></h1> <h1 th:text="person.name?: '我是空值'"></h1>
第一行会显示aa,第二行会显示‘我是空值’。第三行如果name为空显示‘我是空值’,否则显示name的值。
其实这个表达式就是对三元表达式的简化,即th:text="person.name!=null?: person.name'我是空值'"。
内联与局部变量
在标签内部或者html页面中,也可以直接获取域对象中的值,通过如下两种方法:
[[${person.name}]]
[(${person.name})]
其中,[[]]为原样输出,[()]为带格式输出(如果字符串中包含html语义,可以解析其语义)。
局部变量,如下例先获取heros集合,从中取出一个元素hero,其作用域就是其子标签,不能在div之外调用。
<div th:with="hero = ${heros[0]}">
<p th:text="${hero.username}"></p>
<p th:text="${hero.phone}"></p>
<p th:text="${hero.email}"></p>
</div>
判断
Thymeleaf中也可以进行判断
th:if="${布尔表达式}"当表达式为true显示
<h1 th:if="${hero.id==1}">奥利给!</h1>
th:unless="${布尔表达式}" 当表达式为false显示
<h1 th:unless="${hero.id==1}">奥利给!</h1>
th:switch="${值}"类似于java中的switch语句,它结合th:cast="'值'"来使用,可以跟多个case,如果指定defalut可以在case中指定一个*即可。如果是字符串类型的值切记在case中加上''
<div th:switch="${heros[0].id}">
<p th:case="1">这是编号1</p>
<p th:case="2">这是编号2</p>
<p th:case="3">这是编号3</p>
<p th:case="4">这是编号4</p>
<p th:case="*"></p>
</div>
迭代
迭代就如它的字面意思,用于迭代展示后台传递的数据,它是为了取代JSP中的c:foreach,在Thymeleaf中迭代的语法是th:each="item:${list}"。其不仅支持简单的展示每个迭代元素,还stat关键字进行支持各种判断。
<div>
<p th:each="item:${heros}">
<span th:text="${item.username}"></span>
<span th:text="${item.email}"></span>
</p>
</div>
上面是一个简单的案例,其中会产生heros.size个p标签,而非只是产生内部的span。
下面我们结合stat关键字做一些复杂的数据展示:
<div>
<p th:each="item,stat:${heros}">
<span th:text="${item.username}"></span>
<span th:text="${item.email}"></span>
<span th:text="${stat.index}"></span><!--当前元素的下标-->
<span th:text="${stat.count}"></span><!--当前元素的位置-->
<span th:text="${stat.size}"></span><!--总元素个数-->
<span th:text="${stat.first}"></span><!--是否为第一个元素-布尔值-->
<span th:text="${stat.last}"></span><!--是否为第末尾元素-布尔值-->
<span th:text="${stat.even}"></span><!--是否为偶数元素-布尔值-->
<span th:text="${stat.odd}"></span><!--是否为奇数元素-布尔值-->
<span th:text="${stat.current}"></span><!--当前对象-->
</p>
</div>
鲁班 12341241@qq.com 0 1 10 true false false true Hero(id=1, username=鲁班, profession=射手, phone=13499887733, email=12341241@qq.com)
李白 libai@163.com 1 2 10 false false true false Hero(id=2, username=李白, profession=刺客, phone=18977665521, email=libai@163.com)
阿轲 aike@qq.com 2 3 10 false false false true Hero(id=3, username=阿轲, profession=刺客, phone=18977665997, email=aike@qq.com)
德玛 demaxiya.126.com6 3 4 10 false false true false Hero(id=4, username=德玛, profession=肉盾, phone=13700997665, email=demaxiya.126.com6)
亚索 yasuo@qq.com 4 5 10 false false false true Hero(id=5, username=亚索, profession=战士, phone=13586878987, email=yasuo@qq.com)
奶妈 nama@qq.com 5 6 10 false false true false Hero(id=6, username=奶妈, profession=辅助, phone=13398909089, email=nama@qq.com)
剑圣 jiansheng@163.com 6 7 10 false false false true Hero(id=7, username=剑圣, profession=刺客, phone=13398909088, email=jiansheng@163.com)
盖伦 gailun@126.com 7 8 10 false false true false Hero(id=8, username=盖伦, profession=肉盾, phone=15923242231, email=gailun@126.com)
锤石 8888@163.com 8 9 10 false false false true Hero(id=9, username=锤石, profession=辅助, phone=13398908900, email=8888@163.com)
阿木 13398908928@qq.com 9 10 10 false true true false Hero(id=10, username=阿木, profession=辅助, phone=13398908928, email=13398908928@qq.com)
内置对象
JSP中存在九大内置对象,Thymeleaf中同样提供了一些内置对象。
Thymeleaf通过#加域对象名称的方式获取域对象。以下是常用的域对象。
${#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属性的方法。
示例:
${#strings.abbreviate(str,10)} str截取0-10位,后面的全部用…这个点代替,注意,最小是3位
${#strings.toUpperCase(name)}
判断是不是为空:null:
<span th:if="${name} != null">不为空</span>
<span th:if="${name1} == null">为空</span>
判断是不是为空字符串: “”
<span th:if="${#strings.isEmpty(name1)}">空的</span>
判断是否相同:
<span th:if="${name} eq 'jack'">相同于jack,</span>
<span th:if="${name} eq 'ywj'">相同于ywj,</span>
<span th:if="${name} ne 'jack'">不相同于jack,</span>
不存在设置默认值:
<span th:text="${name2} ?: '默认值'"></span>
是否包含(分大小写):
<span th:if="${#strings.contains(name,'ez')}">包ez</span>
<span th:if="${#strings.contains(name,'y')}">包j</span>
是否包含(不分大小写)
<spanth:if="${#strings.containsIgnoreCase(name,'y')}">包</span>
${#strings.startsWith(name,'o')}
${#strings.endsWith(name, 'o')}
${#strings.indexOf(name,frag)}// 下标
${#strings.substring(name,3,5)}// 截取
${#strings.substringAfter(name,prefix)}// 从 prefix之后的一位开始截取到最后,比如 (ywj,y) = wj, 如果是(abccdefg,c) = cdefg//里面有2个c,取的是第一个c
${#strings.substringBefore(name,suffix)}// 同上,不过是往前截取
${#strings.replace(name,'las','ler')}// 替换
${#strings.prepend(str,prefix)}// 拼字字符串在str前面
${#strings.append(str,suffix)}// 和上面相反,接在后面
${#strings.toUpperCase(name)}
${#strings.toLowerCase(name)}
${#strings.trim(str)}
${#strings.length(str)}
${#strings.abbreviate(str,10)}// str截取0-10位,后面的全部用…这个点代替,注意,最小是3位
片段引入
如果要把头部和尾部都封装为一个单独的页面在其他页面中多次引用,可以使用Thymeleaf提供的片段引入的功能。
使用insert引入:将公共标签的片段插入到指定页面
-
创建一个新的Thymeleaf页面
-
在该页面中写好头部和尾部(也可以是任何需要封装的内容)代码
-
在公共页面(例如base.html)中声明片段(th:fragment="片段名称")
-
回到需要引入的页面,创建一个div,在div中使用th:insert="~{需要引入的页面的名称::片段名称}" ,或者使用th:insert="~{需要引入的页面的名称::#片段id名称}",如果使用id引入可以不指定fragment
-
此时该div中就会引入base.html中的代码片段
下面是base.html中的代码:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <nav th:fragment="header"> <h1>这里是头部</h1> </nav> <footer id="footer"> <h1>这里是尾部</h1> </footer> </body> </html>
下面是引入的代码:
<div th:insert="~{base::header}"></div><!--通过fragment引入--> <div th:replace="~{base::#footer}"></div><!--通过id引入-->
还可以使用以下两种方式,操作方法与上述方法一致,替换为th:xx即可。
使用replace引入:将公共的标签替换为指定标签,与上述区别就是第4步的div标签将不存在,直接替换为base代码段中的标签。
使用include 引入:将公共标签的内容,添加到标签中,区别就是base中代码片段中加th:fragment的标签将不存在,使用4中的div标签作为父标签。
页面传值
引入页面的同时还可以给引入页面传递一些值,用于一些判断,因为使用的不多在这里就不过提。
Js模板
在Thymeleaf中使用th:inline="JavaScript "可以使用域对象中的数据,使用方式如下:
<script th:inline="javascript">
var username = /*[[${title}]]*/"giao";
console.log(username);
</script>
上述代码中,如果域对象中有值,则显示域对象中的值,没有值则显示字符串常量。