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 语法<?xml version="1.0" encoding="UTF-8"?> <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.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.zysheep</groupId> <artifactId>spring-boot-thymeleaf</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-boot-thymeleaf</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>net.sourceforge.nekohtml</groupId> <artifactId>nekohtml</artifactId> <version>1.9.22</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </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>Title</title> </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:text</title> </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", "<span style='color:red'>老王是吃货</span>"); 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}
文本操作分为两个:文本拼加、文本替换
文本拼加 :
<span th:text="'我叫'+${name}"></span>
文本替换 : 文本替换的语法:|内容${tag}|
<span th:text="|我叫${name},是一名开发工程师。|"></span>
<tr th:class="${row.even}? 'even' : 'odd'">
<p th:text="${val}">...</p>
结果:
<p>1234567890</p> <p>1,234,567,890</p>
虽然标准的标签几乎可以满足所有的业务场景,但某些情况我们更喜欢直接写入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文件夹
templates
目录下的ws.html
可以这样引用static
下的资源文件<!DOCTYPE html> <html lang="en" xmlns:th="https://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>xxx</title> <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无法解析。