文章目录
Thymeleaf
官网
开发传统Java WEB工程时,我们可以使用JSP页面模板语言,但是在SpringBoot中已经不推荐使用了。SpringBoot支持如下页面模板语言
Thymeleaf
FreeMarker
Velocity
Groovy
JSP
上面并没有列举所有SpringBoot支持的页面模板技术。其中Thymeleaf是SpringBoot官方所推荐使用的,下面来谈谈Thymeleaf一些常用的语法规则。
Thymeleaf模板既能用于web环境下,也能用于非web环境下,在非web环境下,它能直接显示模板上的静态数据,在web环境下,它能像JSP一样从后台接收数据并替换掉模板上的静态数据;
Thymeleaf 它是基于HTML的,以HTML标签为载体,Thymeleaf 要寄托在HTML的标签下实现对数据的展示;
thymeleaf是另外的一种模板技术,它本身并不属于springboot,springboot只是很好地集成这种模板技术,作为前端页面的数据展示;
springboot中的集成
添加Thymeleaf依赖
要想使用Thhymeleaf,首先要在pom.xml文件中单独添加Thymeleaf依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
Thymeleaf 在 SpringBoot 中的配置大全:
#spring.thymeleaf.cache = true #启用模板缓存。
#spring.thymeleaf.check-template = true #在呈现模板之前检查模板是否存在。
#spring.thymeleaf.check-template-location = true #检查模板位置是否存在。
#spring.thymeleaf.content-type = text/html #Content-Type值。
#spring.thymeleaf.enabled = true #启用MVC Thymeleaf视图解析。
#spring.thymeleaf.encoding = UTF-8 #模板编码。
#spring.thymeleaf.excluded-view-names = #应该从解决方案中排除的视图名称的逗号分隔列表。
#spring.thymeleaf.mode = HTML5 #应用于模板的模板模式。另请参见StandardTemplateModeHandlers。
#spring.thymeleaf.prefix = classpath:/templates/ #在构建URL时预先查看名称的前缀。
#spring.thymeleaf.suffix = .html #构建URL时附加到查看名称的后缀。
#spring.thymeleaf.template-resolver-order = #链中模板解析器的顺序。
#spring.thymeleaf.view-names = #可以解析的视图名称的逗号分隔列表。
#开发阶段,建议关闭thymeleaf的缓存
spring.thymeleaf.cache=false
#使用遗留的html5以去掉对html标签的校验
spring.thymeleaf.mode=LEGACYHTML5
在使用springboot的过程中,如果使用thymeleaf作为模板文件,则要求HTML格式必须为严格的html5格式,必须有结束标签,否则会报错;
如果不想对标签进行严格的验证,使用spring.thymeleaf.mode=LEGACYHTML5去掉验证,去掉该验证,则需要引入如下依赖,否则会报错:
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<dependency>
<groupId>org.unbescape</groupId>
<artifactId>unbescape</artifactId>
<version>1.1.5.RELEASE</version>
</dependency>
NekoHTML是一个Java语言的 HTML扫描器和标签补全器 ,这个解析器能够扫描HTML文件并“修正”HTML文档中的常见错误。
NekoHTML能增补缺失的父元素、自动用结束标签关闭相应的元素,修复不匹配的内嵌元素标签等;
注意: springboot默认已经配置了springMvc视图解析器
springboot中的应用
HTML页面的元素中加入以下属性:
<html xmlns:th="http://www.thymeleaf.org">
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Spring boot集成 Thymeleaf</title>
</head>
<body>
<p th:text="${data}">Spring boot集成 Thymeleaf</p>
</body>
</html>
html写入位置
Spring Boot默认存放模板页面的路径在src/main/resources/templates或者src/main/view/templates,这个无论是使用什么模板语言都一样,当然默认路径是可以自定义的,不过一般不推荐这样做。另外Thymeleaf默认的页面文件后缀是.html。
所以在springboot自动生成的项目中有resources/templates这个文件夹,我们一般用这个.因为springboot底层已经做好的视图的映射 templates文件夹表示html的根路径
在controller中的操作
thymeleaf变量表达式
引入连接
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<base th:href="${#request.getContextPath()}+'/'">
<link rel="shortcut icon" th:href="@{/personstyle/images/ico/favicon.ico}">
<link rel="stylesheet" type="text/css" th:href="@{/css/font-awesome.min.css}">
<link rel="stylesheet" type="text/css" th:href="@{/css/iconfont.css}">
<link rel="stylesheet" type="text/css" th:href="@{/jquery-easyui/themes/black/easyui.css}">
<link rel="stylesheet" type="text/css" th:href="@{/jquery-easyui/themes/icon.css}">
<!-- 本项目公用顶层样式 勿删 -->
<link rel="stylesheet" th:href="@{/personstyle/css/base.css}">
<!-- 自定义css -->
<link rel="stylesheet" th:href="@{/personstyle/css/all_style.css}">
<script type="text/javascript" charset="UTF-8" th:src="@{/jquery-easyui/jquery.min.js}"></script>
<script type="text/javascript" charset="UTF-8" th:src="@{/jquery-easyui/jquery.easyui.min.js}"></script>
<script type="text/javascript" charset="UTF-8" th:src="@{/jquery-easyui/locale/easyui-lang-zh_CN.js}"></script>
<script type="text/javascript" charset="UTF-8" th:src="@{/personstyle/js/echarts.min.js}"></script>
<script type="text/javascript" charset="UTF-8" th:src="@{/personstyle/js/common.js}"></script>
<script type="text/javascript" charset="UTF-8" th:src="@{/personstyle/js/flv.js}"></script>
<script type="text/javascript" charset="UTF-8" th:src="@{/personstyle/js/VideoControl.js}"></script>
<title>监控报警</title>
</head>
base
<base th:href="${#request.getContextPath()}+'/'">
在js中显示
var userId = [[${userId}]];
数据的展示全部寄托在html标签中
thymeleaf所有的数据表达式均是html每个标签元素中,依靠标签来展示数据,不能单独使用.
这是与JSTL不一样的地方
标准变量表达式
语法${}
<span th:text="${user.nick}">默认数据</span>
<span th:text="${user.phone}">默认数据</span>
<span th:text="${user.email}">默认数据</span>
<span th:text="${user.address}">默认数据</span>
th:text="" 是Thymeleaf的一个属性,用于文本的显示;
如果${}能获取到数据则展示thymeleaf中的数据 否则展示默认数据
选择变量表达式
语法:*{…}
选择变量表达式,也叫星号变量表达式,使用 th:object 属性来绑定对象.
比如:页面接收一个user实体类
<div th:object="${user}" >
<p>nick: <span th:text="*{nick}">张</span></p>
<p>phone: <span th:text="*{phone}" >三</span></p>
<p>email: <span th:text="*{email}" >北京</span></p>
<p>address: <span th:text="*{address}" >北京</span></p>
</div>
选择表达式首先使用th:object来邦定后台传来的User对象,然后使用 * 来代表这个对象,后面 {} 中的值是此对象中的属性;
选择变量表达式 *{…} 是另一种类似于变量表达式 ${…} 表示变量的方法;
选择变量表达式在执行时是在选择的对象上求解,而${…}是在上下文的变量Model上求解;
上面的代码等价于:
<div>
<p>nick: <span th:text="${user.nick}">张</span></p>
<p>phone: <span th:text="${user.phone}" >三</span></p>
<p>email: <span th:text="${user.email}" >北京</span></p>
<p>address: <span th:text="${user.address}" >北京</span></p>
</div>
标准变量表达式和选择变量表达式可以混合一起使用比较灵活,比如:
<div th:object="${user}" >
<p>nick: <span th:text="*{nick}">张</span></p>
<p>phone: <span th:text="${user.phone}" >三</span></p>
<p>email: <span th:text="${user.email}" >北京</span></p>
<p>address: <span th:text="*{address}" >北京</span></p>
</div>
也可以不使用 th:object 进行对象的选择,而直接使用 *{…} 获取数据,比如:
<div>
<p>nick: <span th:text="*{user.nick}">张</span></p>
<p>phone: <span th:text="*{user.phone}" >三</span></p>
<p>email: <span th:text="*{user.email}" >北京</span></p>
<p>address: <span th:text="*{user.address}" >北京</span></p>
</div>
URL表达式
语法:@{…}
URL表达式可用于
1、绝对URL,比如:
<a href="info.html" th:href="@{'http://localhost:8080/boot/user/info?id='+${user.id}}">查看</a>
2、相对URL,相对于页面,比如:
<a href="info.html" th:href="@{'user/info?id='+${user.id}}">查看</a>
3、相对URL,相对于项目上下文,比如:
<a href="info.html" th:href="@{'/user/info?id='+${user.id}}">查看</a> (项目的上下文名会被自动添加)
Thymeleaf常见属性展示
th:action
定义后台控制器的路径,类似标签的action属性,比如:
<form id="login" th:action="@{/login}">......</form>
th:each(重点)
这个属性非常常用,比如从后台传来一个对象集合那么就可以使用此属性遍历输出,它与JSTL中的<c: forEach>类似,此属性既可以循环遍历集合,也可以循环遍历数组及Map,比如:
<tr th:each="user, interStat : ${userlist}">
<td th:text="${interStat.index}"></td>
<td th:text="${user.id}"></td>
<td th:text="${user.nick}"></td>
<td th:text="${user.phone}"></td>
<td th:text="${user.email}"></td>
<td th:text="${user.address}"></td>
</tr>
th:each=“user, iterStat : ${userlist}” 中的
u
s
e
r
L
i
s
t
是
后
台
传
来
的
K
e
y
,
u
s
e
r
是
{userList} 是后台传来的Key, user是
userList是后台传来的Key,user是{userList} 中的一个数据,
iterStat 是 ${userList} 循环体的信息,
其中user及iterStat自己可以随便写;
interStat是循环体的信息,通过该变量可以获取如下信息:
index、size、count、even、odd、first、last,其含义如下:
index: 当前迭代对象的index(从0开始计算)
count: 当前迭代对象的个数(从1开始计算)
size: 被迭代对象的大小
current: 当前迭代变量
even/odd: 布尔值,当前循环是否是偶数/奇数(从0开始计算)
first: 布尔值,当前循环是否是第一个
last: 布尔值,当前循环是否是最后一个
注意:循环体信息interStat也可以不定义,则默认采用迭代变量加上Stat后缀,即userStat
Map类型的循环:
<div th:each="myMapVal : ${myMap}">
<span th:text="${myMapVal.key}"></span>
<span th:text="${myMapVal.value}"></span>
<br/>
</div>
m y M a p V a l . k e y 是 获 取 m a p 中 的 k e y , {myMapVal.key} 是获取map中的key, myMapVal.key是获取map中的key,{myMapVal.value} 是获取map中的value;
数组类型的循环:
<div th:each="myArrayVal : ${myArray}">
<div th:text="${myArrayVal}"></div>
</div>
th:href
定义超链接,比如:
<a class="login" th:href="@{/login}">登录</a>
th:id
类似html标签中的id属性,比如:
<span th:id="${hello}">aaa</span>
th:if
条件判断,比如后台传来一个变量,判断该变量的值,1为男,2为女:
<span th:if="${sex} == 1" >
男:<input type="radio" name="se" th:value="男" />
</span>
<span th:if="${sex} == 2">
女:<input type="radio" name="se" th:value="女" />
</span>
th:unless
th:unless是th:if的一个相反操作,上面的例子可以改写为:
<span th:unless="${sex} == 1" >
女:<input type="radio" name="se" th:value="女" />
</span>
<span th:unless="${sex} == 2">
男:<input type="radio" name="se" th:value="男" />
</span>
th:switch/th:case
switch,case判断语句,比如:
<div th:switch="${sex}">
<p th:case="1">性别:男</p>
<p th:case="2">性别:女</p>
<p th:case="*">性别:未知</p>
</div>
一旦某个case判断值为true,剩余的case则都当做false,“*”表示默认的case,前面的case都不匹配时候,执行默认的case;
th:object
用于数据对象绑定
通常用于选择变量表达式(星号表达式)
th:src
用于外部资源引入,比如
<script th:src="@{/static/js/jquery-2.4.min.js}"></script>
<img th:src="@{/static/image/logo.png}"/>
th:text 和th:utext
th:utext和th:text的区别是:th:text会对<和>进行转义,而th:utext不会转义。
<input type="text" id="realName" name="reaName" th:text="${realName}">
th:value
类似html标签中的value属性,能对某元素的value属性进行赋值,比如:
<input type="hidden" id="userId" name="userId" th:value="${userId}">
th:attr
该属性也是用于给HTML中某元素的某属性赋值,但该方式写法不够优雅,比如上面的例子可以写成如下形式:
<input type="hidden" id="userId" name="userId" th:attr="value=${userId}" >
Thymeleaf字面量
文本字面量
用单引号’…'包围的字符串为文本字面量,比如:
<a th:href="@{'api/getUser?id=' + ${user.id}}">修改</a>
数字字面量
<p>今年是<span th:text="2017">1949</span>年</p>
<p>20年后, 将是<span th:text="2017 + 20">1969</span>年</p>
boolean字面量
true和false
<p th:if="${isFlag} == false">
false在花括号外面,解析识别由Thymleaf自身完成
</p>
<p th:if="${isFlag == true}">
false写在花括号里面,解析识别由SpringEL完成
</p>
null字面量
<p th:if="${userlist == null}">
userlist为空
</p>
<p th:if="${userlist != null}">
userlist不为空
</p>
Thymeleaf 字符串拼接
一种是字面量拼接:
<a href="#" th:text="'第'+${sex}+'页 ,共'+${sex}+'页'"></a>
另一种更优雅的方式,使用“|”减少了字符串的拼接:
<a href="#" th:text="|第${sex}页,共${sex}页|"></a>
Thymeleaf 三元运算判断
<span th:text="${sex eq '1'} ? '男' : '女'">未知</span>
Thymeleaf 运算和关系判断
算术运算:+ , - , * , / , %
关系比较: > , < , >= , <= ( gt , lt , ge , le )
相等判断:== , != ( eq , ne )
Thymaleaf 表达式基本对象
1、模板引擎提供了一组内置的对象,这些内置的对象可以直接在模板中使用,这些对象由#号开始引用:
2、官方手册:http://t.cn/RHsbZpk
#ctx:上下文对象
#vars:上下文变量
#locale: 上下文语言环境.
#httpServletRequest: (仅在web上下文)相当于HttpServletRequest 对象,这是2.x版本,若是3.x版本使用 #request;
#httpSession: (仅在web上下文)相当于HttpSession 对象,这是2.x版本,若是3.x版本使用#session; 需要在后台controller中设置了session
Thymaleaf 表达式功能对象
1、模板引擎提供的一组功能性内置对象,可以在模板中直接使用这些对象提供的功能方法:
2、工作中常使用的数据类型,如集合,时间,数值,可以使用thymeleaf的提供的功能性对象来解析他们;
3、内置功能对象前都需要加#号,内置对象一般都以s结尾;
日期格式化
#dates: java.util.Date对象的实用方法,<span th:text="${#dates.format(curDate, 'yyyy-MM-dd HH:mm:ss')}"></span>
#calendars: 和dates类似, 但是 java.util.Calendar 对象;
#numbers: 格式化数字对象的实用方法;
#strings: 字符串对象的实用方法: contains, startsWith, prepending/appending等;
#objects: 对objects操作的实用方法;
#bools: 对布尔值求值的实用方法;
#arrays: 数组的实用方法;
#lists: list的实用方法,比如
#sets: set的实用方法;
#maps: map的实用方法;
#aggregates: 对数组或集合创建聚合的实用方法;
操作内置对象
虽然在这种模版开发框架里面是不提倡使用内置对象的,但是很多情况下依然需要使用内置对象进行处理,所以下面来看下如何在页面中使用JSP内置对象。
1在控制器里面增加一个方法,这个方法将采用内置对象的形式传递属性。
@RequestMapping(value = "/inner", method = RequestMethod.GET)
public String inner(HttpServletRequest request, Model model) {
request.setAttribute("requestMessage", "springboot-request");
request.getSession().setAttribute("sessionMessage", "springboot-session");
request.getServletContext().setAttribute("applicationMessage",
"springboot-application");
model.addAttribute("url", "www.baidu.cn");
request.setAttribute("url2",
"<span style='color:red'>www.baidu.cn</span>");
return "show_inner";
}
2在页面之中如果要想访问不同属性范围中的内容,则可以采用如下的做法完成:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>SpringBoot模版渲染</title>
<script type="text/javascript" th:src="@{/js/main.js}"></script>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<p th:text="${#httpServletRequest.getRemoteAddr()}"/>
<p th:text="${#httpServletRequest.getAttribute('requestMessage')}"/>
<p th:text="${#httpSession.getId()}"/>
<p th:text="${#httpServletRequest.getServletContext().getRealPath('/')}"/>
<hr/>
<p th:text="'requestMessage = ' + ${requestMessage}"/>
<p th:text="'sessionMessage = ' + ${session.sessionMessage}"/>
<p th:text="'applicationMessage = ' + ${application.applicationMessage}"/>
</body>
</html>
thymeleaf 考虑到了实际的开发情况,因为 request 传递属性是最为常用的,但是 session 也有可能使用,例如:用户登录之后需要显示用户 id,那么就一定要使用到 session,所以现在必须增加属性范围的形式后才能够正常使用。在 thymeleaf 里面也支持有 JSP 内置对象的获取操作,不过一般很少这样使用。
逻辑处理
所有的页面模版都存在各种基础逻辑处理,例如:判断、循环处理操作。在 Thymeleaf 之中对于逻辑可以使用如下的一些运算符来完成,例如:and、or、关系比较(>、<、>=、<=、==、!=、lt、gt、le、ge、eq、ne)。
通过控制器传递一些属性内容到页面之中:
<span th:if="${member.age lt 18}">
未成年人!
</span>
<span th:if="${member.name eq '啊三'}">
欢迎小三来访问!
</span>
不满足条件的判断
<span th:unless="${member.age gt 18}">
你还不满18岁,不能够看电影!
</span>
通过swith进行分支判断
<span th:switch="${member.uid}">
<p th:case="100">uid为101的员工来了</p>
<p th:case="99">uid为102的员工来了</p>
<p th:case="*">没有匹配成功的数据!</p>
</span>
数据遍历
在实际开发过程中常常需要对数据进行遍历展示,一般会将数据封装成list或map传递到页面进行遍历操作。
1定义控制器类,向页面传递List数据和Map数据
@Controller
public class UserController {
@RequestMapping(value = "/user/map", method = RequestMethod.GET)
public String map(Model model) {
Map<String,User> allMembers = new HashMap<String,User>();
for (int x = 0; x < 10; x++) {
User vo = new User();
vo.setUid(101L + x);
vo.setName("赵四 - " + x);
vo.setAge(9);
vo.setSalary(99999.99);
vo.setBirthday(new Date());
allMembers.put("mldn-" + x, vo);
}
model.addAttribute("allUsers", allMembers);
return "user_map";
}
@RequestMapping(value = "/user/list", method = RequestMethod.GET)
public String list(Model model) {
List<User> allMembers = new ArrayList<User>();
for (int x = 0; x < 10; x++) {
User vo = new User();
vo.setUid(101L + x);
vo.setName("赵四 - " + x);
vo.setAge(9);
vo.setSalary(99999.99);
vo.setBirthday(new Date());
allMembers.add(vo) ;
}
model.addAttribute("allUsers", allMembers);
return "user_list";
}
}
2list类型数据遍历
<body>
<table>
<tr><td>No.</td><td>UID</td><td>姓名</td><td>年龄</td><td>偶数</td><td>奇数</td></tr>
<tr th:each="user,memberStat:${allUsers}">
<td th:text="${memberStat.index + 1}"/>
<td th:text="${user.uid}"/>
<td th:text="${user.name}"/>
<td th:text="${user.age}"/>
<td th:text="${memberStat.even}"/>
<td th:text="${memberStat.odd}"/>
</tr>
</table>
</body>
3map类型数据遍历
<body>
<table>
<tr><td>No.</td><td>KEY</td><td>UID</td><td>姓名</td><td>年龄</td><td>偶数</td><td>奇数</td></tr>
<tr th:each="memberEntry,memberStat:${allUsers}">
<td th:text="${memberStat.index + 1}"/>
<td th:text="${memberEntry.key}"/>
<td th:text="${memberEntry.value.uid}"/>
<td th:text="${memberEntry.value.name}"/>
<td th:text="${memberEntry.value.age}"/>
<td th:text="${memberStat.even}"/>
<td th:text="${memberStat.odd}"/>
</tr>
</table>
</body>
页面引入
我们常常需要在一个页面当中引入另一个页面,例如,公用的导航栏以及页脚页面。thymeleaf中提供了两种方式进行页面引入。
th:replace
th:include
1新建需要被引入的页面文件,路径为"src/main/view/templates/commons/footer.html"
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<footer th:fragment="companyInfo">
<p>设为首页 ©2018 SpringBoot 使用<span th:text="${projectName}"/>前必读
意见反馈 京ICP证030173号 </p>
</footer>
可以看到页面当中还存在一个变量projectName,这个变量的值可以在引入页面中通过th:with="projectName=百度"传过来。
<div th:include="@{/commons/footer} :: companyInfo" th:with="projectName=百度"/>
thymeleaf:字符串Strings常见的使用方法
==判断是不是为空:null: ==
<span th:if="${name} != null">不为空</span>
<span th:if="${name1} == null">为空</span>
==判断是不是为空字符串: “” ==
<span th:if="${#strings.isEmpty(name1)}">空的</span> //为空
<img th:if="${not #strings.isEmpty(path)}" th:src="${path}" class="layui-nav-img">//不为空弄个
==判断是否相同: ==
<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>
是否包含(不分大小写)
<span th:if="${#strings.containsIgnoreCase(name,'y')}">包j</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位