Thymeleaf
是一个跟 Velocity
、FreeMarker
类似的模板引擎,它可以完全替代 JSP
。相较与其他的模板引擎,它有如下三个极吸引人的特点
如果希望以 Jar
形式发布模块则尽量不要使用 JSP
相关知识,这是因为 JSP
在内嵌的 Servlet
容器上运行有一些问题 (内嵌 Tomcat
、 Jetty
不支持 Jar
形式运行 JSP
,Undertow
不支持 JSP
)。
Spring Boot
中推荐使用 Thymeleaf
作为模板引擎,因为 Thymeleaf
提供了完美的 Spring MVC
支持
Spring Boot
提供了大量模板引擎,包括:
主要增加 spring-boot-starter-thymeleaf
和 nekohtml
这两个依赖
spring-boot-starter-thymeleaf
:Thymeleaf
自动配置nekohtml
:允许使用非严格的 HTML 语法
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.2.RELEASEversion>
<relativePath/>
parent>
<groupId>com.zysheepgroupId>
<artifactId>spring-boot-thymeleafartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>spring-boot-thymeleafname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>net.sourceforge.nekohtmlgroupId>
<artifactId>nekohtmlartifactId>
<version>1.9.22version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
###ThymeLeaf配置
spring:
thymeleaf:
cache: false # 开发时关闭缓存,不然没法看到实时页面
#模板的模式,支持 HTML, XML TEXT JAVASCRIPT
mode: HTML5 # 用非严格的 HTML
#编码 可不用配置
encoding: UTF-8
#内容类别,可不用配置
servlet:
content-type: text/html
#Tomcat 服务
server:
port: 80
创建一个测试效果的 JavaBean
,简单封装一下即可
public class User implements Serializable {
private String username;
private Integer age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
创建一个 Controller
,造一些测试数据并设置跳转
@Controller
public class MainController {
@RequestMapping(value = {"/","thymeleaf/index"},method = RequestMethod.GET)
public String index(Model model){
User user = new User();
user.setUsername("zysheep");
user.setAge(20);
model.addAttribute("user",user);
return "index";
}
}
在 templates
目录下创建 index.html
文件,代码如下:
DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<html >
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<span th:text="${user.username}">小明span>
body>
html>
修改 html
标签用于引入 thymeleaf
引擎,这样才可以在其他标签里使用 th:*
语法,声明如下:
DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
启动成功后,访问:http://localhost/thymeleaf/index 即可看到效果
HTML代码:
DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>th:texttitle>
head>
<body>
<span th:text="${user.username}">小明span>
body>
html>
Java代码:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private String username;
private Integer age;
}
@Controller
public class ThyymeleafController {
/**
* @param Model model
* @return String
* @author Administrator
* @throws
* @date 2020/3/18 10:59
*/
@GetMapping("/")
public String index(Model model){
User user = new User();
user.setUsername("伽罗");
user.setAge(21);
model.addAttribute("user",user);
return "th-text";
}
}
使用"th:text"
是对内容的原样输出,使用“th:utext”
可以进行html标签输出。
Java代码:
@RequestMapping("/eat")
public ModelAndView eat() {
ModelAndView modelAndView = new ModelAndView("/cat");
modelAndView.addObject("data", "老王是吃货");
return modelAndView;
}
HTML代码:
<h4 th:text="'th:text '+${data}">h4>
<h4 th:utext="'th:utext '+${data}">h4>
th:if为满足条件的业务处理,th:unless正好相反,是除去的意思。
<span th:if="${age > 18}">
成年
span>
<span th:unless="${age > 18}">
未成年
span>
<div th:switch="${age}">
<span th:case="18">18岁span>
<span th:case="19">19岁span>
<spa th:case="*">其他spa>
div>
注意 :默认选项使用th:case=“*” 指定。
<div th:each="name,item:${names}">
<span th:text="${item.count}"></span>
<span th:text="${name}"></span>
</div>
@RequestMapping("/")
public ModelAndView index() {
ArrayList<String> names = new ArrayList<>();
names.add("java");
names.add("golang");
names.add("nodejs");
ModelAndView modelAndView = new ModelAndView("/index");
modelAndView.addObject("names",names);
return modelAndView;
}
其中item
为每行的详细值,key
值如下:
footer.html页面代码:
DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
head>
<body>
<div th:fragment="copyright">
© 著作权归 老王 所有
div>
<div th:fragment="about">
关于
div>
<div th:fragment="links">
CCTV
div>
body>
html>
声明了两个代码片段,copyright
和about
。
cat.html
页面代码:
DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
head>
<body>
<div th:replace="footer :: copyright">div>
<div th:insert="footer :: about">div>
<div th:include="footer :: links">div>
body>
html>
其中第一个div引用了footer.html 的 copyright 代码片段,第二个div引用了 footer.html 的 about 代码片段。
双冒号的理解: 其中使用“::”双冒号来完成对页面片段的引用,有点像php里面的语法,使用双冒号来表示对类的静态属性和方法进行直接引用。
总结: 可以很清晰的看出th:insert
、th:replace
、th:include
之间的区别,在于是否保留自己的主标签,th:include
在3.0之后已经不推荐使用了,可以使用th:replace
标签替代。
使用fragment
我们是可以在html
代码中传参的,比如我们定义了一个top.html
其中有一个“欢迎XXX”的提示,而这个人名XXX就是需要动态传递的,这样我们可以最大程度的完成代码的复用,这个时候就是一个很好的使用场景,我们需要这样做。
页面main.html代码:
DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
>
<head>
<meta charset="UTF-8">
head>
<body>
<div th:replace="footer :: webcome('老王')">div>
body>
html>
页面top.html
DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
>
<head>
<meta charset="UTF-8">
head>
<body>
<div th:fragment="webcome(about)">
<span th:text="'欢迎:'+${about}">span>
div>
body>
html>
页面代码:
DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
>
<head>
<meta charset="UTF-8">
head>
<body>
<div th:with="sum=4-2">
<span th:text="${sum}">span>
div>
body>
html>
页面输出结果:2
th:remove
用于html代码的删除,th:remove
值有五个:
all
删除本段所有代码body
删除主标签内的所有元素tag
删除主标签,保留主标签所有的元素all-but-first
保留主标签和第一个元素,其他全部删除none
不删除任何标签th:style 定义样式
th:onclick 点击事件
th:href 赋值属性href
th:value 赋值属性value
th:src 赋值src
th:action 赋值属性action
th:id 赋值属性id
th:attr 定义多个属性
th:object 定义一个对象
th:field 表单字段绑定。
th:href 定义超链接。
th:id div 标签中的ID 声明,类似HTML 标签中的归属性。
th:if 条件判断语句。
th:include 布局标签,替换内容到引入文件。
变量表达式的使用,我们前面的代码已经见到了,``是我们平常开发中最常用的表达式,用于把后台Java类的动态数据,映射到页面,例如:
Java代码:
public ModelAndView index() {
ModelAndView modelAndView = new ModelAndView("/cat");
modelAndView.addObject("data", "hello world!");
return modelAndView;
}
HTML代码:
DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
head>
<body>
<span th:text="${data}">span>
body>
html>
选择表达式相当于选择了一个对象,在使用的时候不在需要这个对象的前缀,直接使用属性的key进行内容展示,代码如下:
<div th:object="${user}">
<span th:text="${user.username}">span>
<span th:text="*{age}">span>
<span th:text="${#dates.format(user.createTime, 'yyyy-MM-dd HH:mm:ss')}">span>
div>
最终效果:
伽罗 21 2020-03-18 14:09:22
总结 : *{age} = ${user.age}只是省去了“user.”前缀,效果都是一样的。
用于转换url
,代码如下:
<a th:href="@{/footer(id=666,name=laowang)}">链接a>
最终呈现的效果:
<a href="/footer?id=666&name=laowang">链接a>
链接表达式,可以传递参数,用逗号分隔。服务器根相对路径:@{~/path/to/something}
ex:
后台带过来的request域中图片的值在页面中展示
@PostMapping("/uploadFile")
public String uploadFile(@RequestPart("file") MultipartFile file,Model model) throws IOException {
String upload = FileUploadUtils.upload(file);
log.info("上传路径:{}",upload);
model.addAttribute("uploadUrl",upload);
return "img";
}
html
<img th:src="@{http://localhost:8080{uploadUrl}(uploadUrl=${uploadUrl})}"/>
文本操作分为两个:文本拼加、文本替换
文本拼加 :
<span th:text="'我叫'+${name}">span>
文本替换 : 文本替换的语法:|内容${tag}|
<span th:text="|我叫${name},是一名开发工程师。|">span>
<tr th:class="${row.even}? 'even' : 'odd'">
<p th:text="${val}">...p>
结果:
<p>1234567890p>
<p>1,234,567,890p>
虽然标准的标签几乎可以满足所有的业务场景,但某些情况我们更喜欢直接写入HTML文本,例如:
<p>Hello, [[${name}]]p>
嵌入文本有两种写法“[[…]]”和“[(…)]”,分别的作用就像th:text 和 th:utext 一样,例如:
<p>
[[${name}]]
p>
<p>
[(${name})]
p>
#ctx: 操作当前上下文.
#vars: 操作上下文变量.
#request: (仅适用于Web项目) HttpServletRequest对象.
#response: (仅适用于Web项目) HttpServletResponse 对象.
#session: (仅适用于Web项目) HttpSession 对象.
#servletContext: (仅适用于Web项目) ServletContext 对象.
#execInfo: 操作模板的工具类,包含了一些模板信息,比如:${#execInfo.templateName} .
#uris: url处理的工具
#conversions: methods for executing the configured conversion service (if any).
#dates: 方法来源于 java.util.Date 对象,用于处理时间,比如:格式化.
#calendars: 类似于 #dates, 但是来自于 java.util.Calendar 对象.
#numbers: 用于格式化数字.
#strings: methods for String objects: contains, startsWith, prepending/appending, etc.
#objects: 普通的object对象方法.
#bools: 判断bool类型的工具.
#arrays: 数组操作工具.
#lists: 列表操作数据.
#sets: Set操作工具.
#maps: Map操作工具.
#aggregates: 操作数组或集合的工具.
#dates 日期函数。
#lists 列表函数。
#arrays 数组函数。
#strings 字符串函数。
#numbers 幸生字函捷生。
#ca lendars 日历函数。
#objects 对象函数。
#bools 逻辑函数。
Spring Boot
在Thymeleaf
结构模块很好提供了静态资源的引用方法
th:[href | src]@{资源在static下的目录}, 如:@{lib/jquery.js},不用填写默认的static文件夹
DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>xxxtitle>
<link rel="stylesheet" type="text/css" th:href="@{css/ws.css}"/>
head>
<body>
<script th:src="@{lib/sockjs.min.js}">script>
<script th:src="@{lib/stomp.min.js}">script>
<script th:src="@{lib/jquery.js}">script>
<script th:src="@{js/ws.js}">script>
body>
html>
使用原始的相对路径的话,则为 href=“…/static/css/ws.css”, src=“…/static/lib/jquery.js” 注意:使用Thymeleaf的引用方法,只有运行项目才有效。普通打开HTML无法解析。
在script标签中通过th:inline="javascript"
来声明这是要特殊处理的js脚本,使用嵌入文本标签获取值
<script th:inline="javascript">
const value = [[${project.customerId}]];
$('#customerId').find("option[value="+value+"]").attr("selected",true);
</script>