什么是模板引擎?
模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的html文档。从字面上理解模板引擎,最重要的就是模板二字,这个意思就是做好一个模板后套入对应位置的数据,最终以html的格式展示出来,这就是模板引擎的作用。
thymeleaf是一个可以完全替代jsp的模板引擎,thymeleaf 在有网络和无网络的环境下皆可运行:
并且随着市场使用的验证Thymeleaf也达到的它的目标和大家对他的期望,在实际开发有着广泛的应用。Thymeleaf作为被Springboot官方推荐的模板引擎,一定有很多过人和不寻同之处:
动静分离: Thymeleaf选用html作为模板页,这是任何一款其他模板引擎做不到的!Thymeleaf使用html通过一些特定标签语法代表其含义,但并未破坏html结构,即使无网络、不通过后端渲染也能在浏览器成功打开,大大方便界面的测试和修改。
开箱即用: Thymeleaf提供标准和Spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、改JSTL、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
Springboot官方大力推荐和支持,Springboot官方做了很多默认配置,开发者只需编写对应html即可,大大减轻了上手难度和配置复杂度。
首先,打开你的IDEA创建新项目,选择Spring Initializr方式创建Springboot项目 ,然后点击next。具体如下图所示。

点击next之后,我们进行next 填写好Group(一般com或者com.xxx)和Aritifact(一般项目名)创建。其他地方没有特殊情况不需要修改,具体如下图:

IDEA的编译器做的很友好,可以直接选择热门的依赖而不需要去进行寻找,我们勾选其中Web 模块的Spring web依赖以及Template 模块的Thymeleaf依赖。finish 即可:

当然,如果你创建项目时没有勾选依赖也不要紧,在pom.xml中添加以下依赖:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
就这样,程序创建完毕,依赖也成功添加,你就可以在此基础上正式开始你的个性化操作。
pom.xml
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.4.RELEASEversion>
<relativePath/>
parent>
<properties>
<java.version>1.8java.version>
<commons.io.version>2.5commons.io.version>
<commons.fileupload.version>1.3.3commons.fileupload.version>
<jsoup.version>1.11.3jsoup.version>
<poi.version>3.17poi.version>
<pagehelper.boot.version>1.2.5pagehelper.boot.version>
<fastjson.version>1.2.47fastjson.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>${fastjson.version}version>
dependency>
<dependency>
<groupId>org.yamlgroupId>
<artifactId>snakeyamlartifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<fork>truefork>
configuration>
plugin>
plugins>
build>
application.yml配置文件,yml文件要有yml解析器;
项目配置的视图默认是放在资源文件的templates目录下;
而视图解析器默认前缀:/templates/,后缀:.html。
# 开发环境配置
server:
# 服务端口
port: 8080
servlet:
# 项目contextPath
context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# tomcat最大线程数,默认为200
max-threads: 800
# Tomcat启动初始化的线程数,默认值25
min-spare-threads: 30
# Spring配置
spring:
# 模板引擎
thymeleaf:
mode: HTML
encoding: utf-8
# 禁用缓存
cache: false
# 资源信息
messages:
# 国际化资源文件路径
basename: i18n/messages
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
# 服务模块
devtools:
restart:
# 热部署开关
enabled: true
在编写Controller和Thymeleaf之前,先让你看一下最终项目的目录结构,有个初略的印象和概念:

在其中:
项目基于Springboot框架,且选了Spring web(Springmvc)作为mvc框架,其中Thymeleaf就是v(view)视图层,我们需要在controller中指定Thymeleaf页面的url,然后再Model中绑定数据。
我们在com.Thymeleaf文件下创建controller文件夹,在其中创建urlController.java的controller文件,文件内容(代码)为:
package com.Thymeleaf.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class urlController {
@GetMapping("index")//页面的url地址
public String getindex(Model model)//对应函数
{
model.addAttribute("name","bigsai");
return "index";//与templates中index.html对应
}
}
上述代码就是一个完整的controller。部分含义如下:
咱们在项目的resources目录下的templates文件夹下面创建一个叫index.html的文件,咱们在这个html文件中的标签修改为这样在Thymeleaf中就可以使用Thymeleaf的语法和规范啦。
对于第一个Thymelaf程序,你只需将index.html文件改成这样即可:
DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>titletitle>
head>
<body>
hello 第一个Thymeleaf程序
<div th:text="${name}">name是bigsai(我是离线数据)div>
body>
html>
你可能会对感到陌生,这个标签中的th:text="${name}"就是Thymeleaf取值的一个语法,这个值从后台渲染而来(前面controller中在Model中存地值),如果没网络(直接打开html文件)的时候静态数据为:name是bigsai(我是离线数据)。而如果通过网络访问那么内容将是前面在controller的Model中储存的bigsai。
这样写好之后咱们执行这个Springboot程序。通过网络访问http://localhost:8080/index

引入css
<link rel="stylesheet" th:href="@{index.css}">
引入JavaScript
<script type="text/javascript" th:src="@{index.js}">script>
超链接
<a th:href="@{index.html}">超链接a>
创建这么一个对象
public class user {
private String name;
private int age;
private String detail;
public user(String name, int age, String detail) {
this.name = name;
this.age = age;
this.detail = detail;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
}
在Model中添一些数据
@GetMapping("index")//页面的url地址
public String getindex(Model model)//对应函数
{
user user1=new user("bigsai",22,"一个幽默且热爱java的社会青年");
List<String>userList=new ArrayList<>();
userList.add("zhang san 66");
userList.add("li si 66");
userList.add("wang wu 66");
Map<String ,String>map=new HashMap<>();
map.put("place","博学谷");
map.put("feeling","very well");
//数据添加到model中
model.addAttribute("name","bigsai");//普通字符串
model.addAttribute("user",user1);//储存javabean
model.addAttribute("userlist",userList);//储存List
model.addAttribute("map",map);//储存Map
return "index";//与templates中index.html对应
}
取普通字符串
如果在controller中的Model直接存储某字符串,我们可以直接${对象名}进行取值。完整代码如下:
<h2>普通字符串h2>
<table border="0">
<tr>
<td th:text="'我的名字是:'+${name}">td>
tr>
table>
运行结果为:

取JavaBean对象
取JavaBean对象也很容易,因为JavaBean自身有一些其他属性,所以咱们就可以使用${对象名.对象属性}或者${对象名['对象属性']}来取值,这和JavaScript语法是不是很相似呢!除此之外,如果该JavaBean如果写了get方法,咱们也可以通过get方法取值例如${对象.get方法名}完整代码如下:
<h2>JavaBean对象h2>
<table bgcolor="#ffe4c4" border="1">
<tr>
<td>介绍td>
<td th:text="${user.name}">td>
tr>
<tr>
<td>年龄td>
<td th:text="${user['age']}">td>
tr>
<tr>
<td>介绍td>
<td th:text="${user.getDetail()}">td>
tr>
table>
运行结果为:

取List集合(each):
因为List集合是个有序列表,里面内容可能不止一个,你需要遍历List对其中对象取值,而遍历需要用到标签:th:each,具体使用为,其中item就相当于遍历每一次的对象名,在下面的作用域可以直接使用,而userlist就是你在Model中储存的List的名称。完整的代码为:
<h2>List取值h2>
<table bgcolor="#ffe4c4" border="1">
<tr th:each="item:${userlist}">
<td th:text="${item}">td>
tr>
table>
运行结果为:

直接取Map
很多时候我们不存JavaBean而是将一些值放入Map中,再将Map存在Model中,我们就需要对Map取值,对于Map取值你可以${Map名['key']}来进行取值。也可以通过${Map名.key}取值,当然你也可以使用${map.get('key')}(java语法)来取值,完整代码如下:
<h2>Map取值h2>
<table bgcolor="#8fbc8f" border="1">
<tr>
<td>place:td>
<td th:text="${map.get('place')}">td>
tr>
<tr>
<td>feeling:td>
<td th:text="${map['feeling']}">td>
tr>
table>
运行结果为:

遍历Map
如果说你想遍历Map获取它的key和value那也是可以的,这里就要使用和List相似的遍历方法,使用th:each="item:${Map名}"进行遍历,在下面只需使用item.key和item.value即可获得值。完整代码如下:
<h2>Map遍历h2>
<table bgcolor="#ffe4c4" border="1">
<tr th:each="item:${map}">
<td th:text="${item.key}">td>
<td th:text="${item.value}">td>
tr>
table>

虽然Springboot官方对Thymeleaf做了很多默认配置,但咱们引入Thymeleaf的jar包依赖后很可能根据自己特定需求进行更细化的配置,例如页面缓存、字体格式设置等等。
Springboot官方提供的配置内容有以下:
# THYMELEAF (ThymeleafAutoConfiguration)
spring.thymeleaf.cache=true # Whether to enable template caching.
spring.thymeleaf.check-template=true # Whether to check that the template exists before rendering it.
spring.thymeleaf.check-template-location=true # Whether to check that the templates location exists.
spring.thymeleaf.enabled=true # Whether to enable Thymeleaf view resolution for Web frameworks.
spring.thymeleaf.enable-spring-el-compiler=false # Enable the SpringEL compiler in SpringEL expressions.
spring.thymeleaf.encoding=UTF-8 # Template files encoding.
spring.thymeleaf.excluded-view-names= # Comma-separated list of view names (patterns allowed) that should be excluded from resolution.
spring.thymeleaf.mode=HTML # Template mode to be applied to templates. See also Thymeleaf's TemplateMode enum.
spring.thymeleaf.prefix=classpath:/templates/ # Prefix that gets prepended to view names when building a URL.
spring.thymeleaf.reactive.chunked-mode-view-names= # Comma-separated list of view names (patterns allowed) that should be the only ones executed in CHUNKED mode when a max chunk size is set.
spring.thymeleaf.reactive.full-mode-view-names= # Comma-separated list of view names (patterns allowed) that should be executed in FULL mode even if a max chunk size is set.
spring.thymeleaf.reactive.max-chunk-size=0 # Maximum size of data buffers used for writing to the response, in bytes.
spring.thymeleaf.reactive.media-types= # Media types supported by the view technology.
spring.thymeleaf.servlet.content-type=text/html # Content-Type value written to HTTP responses.
spring.thymeleaf.suffix=.html # Suffix that gets appended to view names when building a URL.
spring.thymeleaf.template-resolver-order= # Order of the template resolver in the chain.
spring.thymeleaf.view-names= # Comma-separated list of view names (patterns allowed) that can be resolved.
上面的配置有些我们可能不常使用,因为Springboot官方做了默认配置大部分能够满足我们的使用需求,但如果你的项目有特殊需求也需要妥善使用这些配置。
比如spring.thymeleaf.cache=false是否允许页面缓存的配置,我们在开发时候要确保页面是最新的所以需要禁用缓存;而在上线运营时可能页面不常改动为了减少服务端压力以及提升客户端响应速度会允许页面缓存的使用。
再比如在开发虽然我们大部分使用UTF-8多一些,我们可以使用spring.thymeleaf.encoding=UTF-8来确定页面的编码,但如果你的项目是GBK编码就需要将它改成GBK。
另外Springboot默认模板引擎文件是放在templates目录下:spring.thymeleaf.prefix=classpath:/templates/,如果你有需求将模板引擎也可修改配置,将templates改为自己需要的目录。同理其他的配置如果需要自定义化也可参照上面配置进行修改。
咱们上面知道Thymeleaf通过特殊的标签来寻找属于Thymeleaf的部分,并渲染该部分内容,而除了上面展示过的th:text之外还有很多常用标签,并且Thymeleaf也主要通过标签来识别替换对应位置内容,Thymeleaf标签有很多很多,功能也很丰富,这里列举一些比较常用的标签如下:
首先,创建HTML页面,在html页面中
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<input id="sex" type="text" th:value="${sex}"/>
<p th:text="${sex}">p>
<p><span th:text="${sex}">span>p>
<a><span th:text="${msg}">span>a>
<span th:text="${sex}">span>
<span><span th:text="${msg}">span>span>
<textarea id="remark" class="form-control" th:text="${remark}">textarea>
<textarea id="remark" class="form-control">[[*{remark}]]textarea>
<a th:href="@{'/news/newdetails/'+${news.newsId}}">测试a>
<div th:style="'background-image:url('+@{/img/common/bg6.jpg}+')'">
//TODO 代码块
div>
| 语法 | 名称 | 描述 | 作用 |
|---|---|---|---|
| ${…} | Variable Expressions | 变量表达式 | 取出上下文的值 |
| *{…} | Selection Variable Expressions | 选择变量表达式 | 取出选择的对象的属性值 |
| #{…} | Message Expressions | 消息表达式 | 使文字消息国际化 |
| @{…} | Link URL Expressions | 链接表达式 | 用于表示各种超链接地址 |
| ~{…} | Fragment Expressions | 片段表达式 | 引用一段公共的代码片段 |
@GetMapping("/standard-expression-syntax/variables")
public String variables(ModelMap model, HttpSession session) {
model.put("now", new Date());
model.put("message", "Welcome to BeiJing!");
session.setAttribute("user", new User("fanlychie", "男", 24));
... ...
}
通过变量表达式${}取出上下文环境中的message变量:
<p th:text="${message}">p>
它相当于:
ctx.getVariable("message");
变量表达式${}是面向整个上下文的,而选择变量表达式*{}的上下文是父标签(th:object)所选择的对象:
<div th:object="${session.user}">
<p th:text="*{name}">p>
<p th:text="*{sex}">p>
<p th:text="*{age}">p>
div>
它相当于:
<div>
<p th:text="${session.user.name}">p>
<p th:text="${session.user.sex}">p>
<p th:text="${session.user.age}">p>
div>
如果对象没有被选择,那么,
*{}和${}表达式所达到的效果是完全相同的:
<p th:text="*{session.user.name}">p>
<p th:text="${session.user.name}">p>
文本外部化是从模板文件中提取模板代码的片段,以便可以将它们保存在单独的文件(通常是.properties文件)中,文本的外部化片段通常称为“消息”。通俗易懂的来说#{…}语法就是用来读取配置文件中数据的。在Thymeleaf你可以使用#{…}语法获取消息,具体实例代码如下:
首先在templates目录下建立home.properties中写入以下内容:
bigsai.nane=bigsai
bigsai.age=22
province=Jiang Su
在application.properties中加入以下内容:
spring.messages.basename=templates/home
这样我们就可以在Thymeleaf中读取配置的文件了,完整代码如下:
<h2>消息表达h2>
<table bgcolor="#ffe4c4" border="1">
<tr>
<td>nametd>
<td th:text="#{bigsai.name}">td>
tr>
<tr>
<td>年龄td>
<td th:text="#{bigsai.age}">td>
tr>
<tr>
<td>provincetd>
<td th:text="#{province}">td>
tr>
table>
运行结果为:

链接表达式@{}是专门用来处理 URL 链接地址的。
绝对地址示例:
<p th:text="@{https://fanlychie.github.io}">p>
页面相对地址示例:
<p th:text="@{commons/base.html}">p>
上下文相对地址(相对于当前的服务)示例:
<p th:text="@{/css/mian.css}">p>
服务器相对地址(相对于部署在同一个服务器中的不同服务)示例:
<p th:text="@{~/image/upload}">p>
参数使用示例:
<p th:text="@{/css/mian.css(v=1.0)}">p>
<p th:text="@{/user/order(username=${session.user.name})}">p>
<p th:text="@{/user/order(username=${session.user.name},status='PAIED')}">p>
<p th:text="@{/user/{username}/info(username=${session.user.name})}">p>
片段表达式~{}可以用来引用一段公共的 HTML 代码片段。
| 语法 | 描述 |
|---|---|
| ~{templatename} | 引用整个模板文件的代码片段 |
| ~{templatename :: selector} | selector可以是th:frament指定的名称或其他选择器。如类选择器、ID选择器等 |
| ~{::selector} | 相当于~{this::selector},表示引用当前模板定义的代码片段 |
在 Thymeleaf 模板文件中,你可以使用th:fragment属性来定义一段公共的代码片段,然后你可以通过使用th:insert、th:replace、th:include(Thymeleaf 3.0 开始不再推荐使用,本文也将不再介绍它)属性来将这些公共的代码片段引入到模板文件中来。
src/main/resources/templates/base.html,通过th:fragment属性定义一段公共的代码片段:
<html xmlns:th="http://www.thymeleaf.org">
<footer th:fragment="footer1">
<p >All Rights Reservedp>
footer>
<footer th:fragment="footer2(start,now)">
<p th:text="|${start} - ${now} All Rights Reserved|">p>
footer>
html>
在test里面写上
<div class="showing">
<div th:replace="include::footer1" >div>
<div th:replace="include::footer2(2015,2018)" >div>
div>
效果
All Rights Reserved
2015-2018 All Rights Reserved
src/main/resources/templates/index.html,通过th:insert属性引用一段公共的代码片段:
<div th:insert="~{base :: footerFragment}">div>
其中,~{}是可选的,我们可以去掉这层的包裹:
<div th:insert="base :: footerFragment">div>
若 index.html 与 base.html 不在同级目录,如 templates/commons/base.html:
<div th:insert="~{commons/base :: footerFragment}">div>
使用th:fragment属性定义代码片段时,你还可以声明一组参数:
<div th:fragment="crumbs(parent, child)">
<i th:text="${parent}">i> <i th:text="${child}">i>
div>
<div th:insert="::crumbs('用户中心', '我的订单')">div>
此外,我们还可以通过类选择器、ID选择器等来引用公共的代码片段:
<div th:insert="~{base :: #footer}">div>
除了th:insert属性th:replace也可以用来引用公共的代码片段。不同的是,th:insert是直接将代码片段插入到标签体内,而th:replace则是用代码片段直接替换标签体内容。
<div th:insert="~{base :: footerFragment}">div>
<div th:replace="~{base :: footerFragment}">div>
[[]]相当于th:text,对含有 HTML 标签的内容自动进行字符转义。
<p>The message is : [[${htmlContent}]]p>
[()]相当于th:utext,对含有 HTML 标签的内容不进行字符转义。
<p>The message is : [(${htmlContent})]p>
我们已经了解到,使用[[]]和[()]语法可以直接在 HTML 文本中使用标准表达式,如果想要使用更多高级的功能,需要使用th:inline属性来激活,它的取值如下:
| 值 | 描述 |
|---|---|
| none | 禁止内联表达式,可以原样输出[[]]和[()]字符串 |
| text | 文本内联,可以使用th:each等高级语法 |
| css | 样式内联,如 : < style th:inline=“css”> |
| javascript | 脚本内联,如:< style th:inline=“javascript”> |
none
<p th:inline="none">[[1, 2], [3, 4]]p>
text
<p th:inline="text">
[# th:each="city : ${cities}"]
[(${city.name})]
[/]
p>
css
<style th:inline="css">
body {
background-color:[[${bgColor}]];
}
style>
javascript
<script th:inline="javascript">
var user = [[${user}]];
alert("用户名:" + user.name);
script>
Thymeleaf内置对象的语法${# }内部必须以 # 开头
字符串拼接
<p th:text="'Welcome to ' + ${location} + '!'">p>
字面值替换
<p th:text="|Welcome to ${location}!|">p>
字符串内置对象使用
判断字符串是否为空
<span th:text="${#strings.isEmpty(str)}">span>
判断字符串str中是否包含str1
<span th:text="${#strings.contains(str, str1)}">span>
获取字符串str的长度
<span th:text="${#strings.length(str)}">span>
判断字符串str是否以str1开始,以str2结尾
<span th:text="${#strings.startsWith(str,str1)}">span>
<span th:text="${#strings.endsWith(str,str2)}">span>
字符串str截取,从start开始,到end结束
<span th:text="${#strings.substring(str,start)}">span>
<span th:text="${#strings.substring(str,start,end)}">span>
字符串大小写转换
<span th:text="${#strings.toUpperCase(str)}">span>
<span th:text="${#strings.toLowerCase(str)}">span>
支持+(加)、-(减)、*(乘)、/(除)、%(模)运算:
<p th:text="4 + 2">p>
<p th:text="4 - 2">p>
<p th:text="4 * 2">p>
<p th:text="4 / 2">p>
<p th:text="4 % 2">p>
<p th:text="${pagination.page + 1}">p>
<p th:text="${pagination.page} + 1">p>
支持and(且)、or(或)、!(非)、not(非)运算:
<p th:text="${user.online and user.vip}">p>
<p th:text="${user.online or user.vip}">p>
<p th:text="${!user.online}">p>
<p th:text="${not user.online}">p>
支持<(lt)、>(gt)、<=(le)、>=(ge)、==(eq)、!=(ne):
<p th:text="${user.age < 60}">p>
<p th:text="${user.age <= 60}">p>
<p th:text="${user.age > 18}">p>
<p th:text="${user.age >= 18}">p>
<p th:text="${user.age == 18}">p>
<p th:text="${user.age != 18}">p>
<span th:text="${sex eq 0} ? '男' : '女'">性别span>
三元运算符:(if) ? (then) : (else)
<span th:text="${sex eq 0} ? '男' : '女'">性别span>
二元运算符:(value) ?: (defaultValue)。
其中,value非空(null)即真,条件为真时输出value,否则输出defaultValue。假设token = null,user.email = fanlychie@gmail.com
<p th:text="${token} ?: '你还没有登录,请先登录'">p>
<p th:text="${user.email} ?: '你还没有绑定邮箱'">p>
当模板运行在服务器端时,Thymeleaf 会解析th:*属性的具体值替换标签体的内容。无操作符(_)则允许你使用原型标签体的内容作为默认值:
<p th:text="${token} ?: _">你还没有登录,请先登录p>
if判断
<p>
<span th:if="${sex==1}">
男
span>
<span th:if="${sex==0}">
女
span>
p>
if 取反,可以用unless
<th:block th:unless="${null != newsList}">
//TODO 代码块
th:block>
for循环
遍历(迭代)的语法th:each=“自定义的元素变量名称 : ${集合变量名称}”:
<div>
<spn>你所在城市:spn>
<select name="mycity">
<option th:each="city : ${cities}" th:text="${city.name}">option>
select>
div>
属性th:each提供了一个用于跟踪迭代的状态变量,它包含以下几个属性:
| 语法 | 描述 | 描述 |
|---|---|---|
| index | int | 当前迭代的索引,从0开始 |
| count | int | 当前迭代的计数,从1开始 |
| size | int | 集合中元素的总个数 |
| current | int | 当前的元素对象 |
| even | boolean | 当前迭代的计数是否是偶数 |
| odd | boolean | 当前迭代的计数是否是奇数 |
| first | boolean | 当前元素是否是集合的第一个元素 |
| last | boolean | 当前元素是否是集合的最后一个元素 |
迭代遍历,a代表每个集合中便利到的对象,s代表对象的状态,:之后是要遍历的集合。
状态变量的使用语法:th:each="自定义的元素变量名称, 自定义的状态变量名称 : ${集合变量名称}":
<div>
<spn>所在城市:spn>
<select name="mycity">
<option th:each="city, status : ${cities}" th:text="${city.name}" th:item-index="${status.count}">option>
select>
div>
<div th:each="a,s : ${list}">
<span th:text="${a}">span>,
<span th:text="${#strings.concat('index--',s.index)}">span>,
<span th:text="${#strings.concat('count--',s.count)}">span>,
<span th:text="${#strings.concat('first--',s.first)}">span>,
<span th:text="${#strings.concat('last--',s.last)}">span>,
<span th:text="${#strings.concat('current--',s.current)}">span>,
<span th:text="${#strings.concat('odd--',s.odd)}">span>,
<span th:text="${#strings.concat('size--',s.size)}">span>,
div>
不管什么时候,Thymeleaf 始终会为每个th:each创建一个状态变量,默认的状态变量名称就是自定义的元素变量名称后面加Stat字符串组成:
<div>
<spn>所在城市:spn>
<select name="mycity">
<option th:each="city : ${cities}" th:text="${city.name}" th:item-index="${cityStat.count}">option>
select>
div>
已知数组下标取值
<span th:text="*{newsList[0].title}">span>
switch case用法
<p>
<div th:switch="${sex}">
<span th:case="1">男span>
<span th:case="0">女span>
div>
p>
| 对象 | 描述 |
|---|---|
| #ctx | 上下文对象 |
| #vars | 同#ctx,表示上下文变量 |
| #locale | 上下文本地化(特定的地理区域)变量,可参考java.util.Locale |
| #request | HttpServletReques对象,可参考javax.servlet.http.HttpServletRequest |
| #response | HttpServletResponse对象,可参考javax.servlet.http.HttpServletResponse |
| #session | HttpSession对象,可参考javax.servlet.http.HttpSession |
| #servletContext | ServletContext对象,可参考javax.servlet.ServletContext |
<p th:text="${#ctx.getLocale()}">p>
<p th:text="${#ctx.getVariable('message')}">p>
<p th:text="${#ctx.containsVariable('message')}">p>
<p th:text="${#vars.getLocale()}">p>
<p th:text="${#vars.getVariable('message')}">p>
<p th:text="${#vars.containsVariable('message')}">p>
<p th:text="${#locale}">p>
<p th:text="${#locale.country}">p>
<p th:text="${#locale.displayCountry}">p>
<p th:text="${#locale.language}">p>
<p th:text="${#locale.displayLanguage}">p>
<p th:text="${#locale.displayName}">p>
<p th:text="${#request.protocol}">p>
<p th:text="${#request.scheme}">p>
<p th:text="${#request.serverName}">p>
<p th:text="${#request.serverPort}">p>
<p th:text="${#request.method}">p>
<p th:text="${#request.requestURI}">p>
<p th:text="${#request.requestURL}">p>
<p th:text="${#request.servletPath}">p>
<p th:text="${#request.parameterNames}">p>
<p th:text="${#request.parameterMap}">p>
<p th:text="${#request.queryString}">p>
注意,请求地址的 URL 参数直接通过#request.x是取不出来的,需要使用param.x语法来取出。如,URL:/standard-expression-syntax/variables?q=expression,取出 q 参数的正确姿势:
<p th:text="${param.q}">p>
<p th:text="${#response.status}">p>
<p th:text="${#response.bufferSize}">p>
<p th:text="${#response.characterEncoding}">p>
<p th:text="${#response.contentType}">p>
<p th:text="${#session.id}">p>
<p th:text="${#session.lastAccessedTime}">p>
<p th:text="${#session.getAttribute('user').name}">p>
注意,放到会话里面的对象直接通过#session.x是取不出来的,需要使用session.x语法来取出。如,取出会话里面的 user 对象的正确姿势:
<p th:text="${session.user.name}">p>
| 对象 | 描述 |
|---|---|
| #messages | 消息工具类,与#{…}作用相同 |
| #uris | 地址相关工具类 |
| #conversions | 对象转换工具类 |
| #dates | 日期时间工具类 |
| #calendars | 日历工具类 |
| #numbers | 数字工具类 |
| #strings | 字符串工具类 |
| #objects | 对象工具类 |
| #bools | 布尔工具类 |
| #arrays | 数组工具类 |
| #lists | List工具类 |
| #sets | Set工具类 |
| #maps | Map工具类 |
<p th:text="${#strings.isEmpty(message)}">p>
<p th:text="${#dates.format(now, 'yyyy-MM-dd HH:mm:ss')}">p>
所谓字面值,首先它不是一个变量,它是一个具体的确切的值,通常这些值是比较简单的,例如:18、'welcome’等,它们没有名称,以至于我们只能用值来称呼它们,因此我们称其为字面值。
文字字面值是用单引号引起来的任何字符内容,如果字符内容里面含有单引号,则需要进行转义:
<p th:text="'Welcome to BeiJing!'">p>
<p th:text="'\'Welcome to BeiJing!\''">p>
<p th:text="2017">p>
<p th:text="2017 + 1">p>
<p th:text="1 > 2">p>
<p th:text="1 > 2 ? '是' : '否'">p>
<p th:text="${user == null}">p>
字面令牌(Literal Tokens)的内容只能含有(不能含有空格、特殊符号等):
实际上,数字、布尔和空字面值都是字面令牌的特殊情况。字面令牌能够用来对标准表达式语法进行简化,我们可以将包裹它的内容的单引号去掉:
<p th:text="Welcome to BeiJing!">p>
它等效于:
<p th:text="'Welcome to BeiJing!'">p>
首先介绍两个最基础的th:*属th:text和th:utext,它们都是用于处理文本消息内容。
在标签体中展示表达式评估结果的文本内容:
<p th:text="${message}">p>
使用外部化的文本内容:
<p th:text="${message}">Welcome to BeiJing!p>
当它作为静态文件直接运行时,浏览器会自动忽略它不能识别的th:text属性,而显示
标签体的文本内容Welcome to BeiJing!
当它作为模板文件运行在服务器端时,th:text属性的具体值将会替换
标签体的文本内容。
属性th:utext与th:text的区别在于:
假设:message = "Welcome to BeiJing!"。
使用th:text属性:
<p th:text="${message}">p>
th:text效果:Welcome to BeiJing!
使用th:utext属性:
<p th:utext="${message}">p>
th:utext效果:Welcome to BeiJing!
在 Thymeleaf 模板文件中,你可以使用th:(或者使用th:attr属性)来设置任意的 HTML5 标签属性的值。不仅如此,你还可以th:-*来同时为多个不同的标签属性设置相同的一个值,甚至你可以使用th:attrappend和th:attrprepend来追加新的值到现有的标签属性值中。
这种方式是不被推荐的,了解一下就行。下面是用th:attr="href=…"来设置标签href属性的值:
<a th:attr="href=@{https://www.google.com.hk}">谷歌一下你就知道a>
显然th:attr="href=@{http://www.baidu.com}"不够简洁,我们更推荐下面的这种语法:
<a th:href="@{https://www.google.com.hk}">谷歌一下你就知道a>
其中th:*中的*可以是 HTML5 支持的任意属性名称,甚至这些属性名称可以是自定义的:
<div th:item-id="${user.id}">Welcome to BeiJing!div>
如果想要同时为标签的多个不同属性设置相同的一个值,可以使用th:*-*的语法:
<img src="logo.png" th:alt-title="LOGO图片">
它相当于:
<img src="logo.png" th:alt="LOGO图片" th:title="LOGO图片">
th:attrappend和th:attrprepend可以将表达式的结果分别追加到指定的属性值之后和之前。
<button class="btn" th:attrappend="class=${outOfStock} ? ' enable' : ' disable'">购买button>
<button class="btn" th:attrprepend="class=${outOfStock} ? 'enable ' : 'disable '">购买button>
另外,还有两个常用的具体附加属性th:classappend="..."和th:styleappend=""。
它们分别用来代替th:attrappend="class=..."和th:attrappend="style=..."。
<button class="btn" th:classappend="${outOfStock} ? ' enable' : ' disable'">购买button>
在 HTML 中有些属性是布尔属性,布尔属性是指没有值的属性,如readonly、checked、selected等。它们若存在那就意味着值为 true。
<input type="checkbox" name="rememberme" checked /> 记住我
<input type="radio" name="sex" value="male" checked> 男
<input type="radio" name="sex" value="female"> 女
<input type="text" name="appId" value="J123654" readonly>
<select>
<option selected>北京option>
<option>上海option>
<option>广州option>
<option>深圳option>
select>
Thymeleaf 也允许我们通过th:*(这里的*表示任意的布尔属性) 来选择是否使用这些布尔属性。
<input type="checkbox" name="rememberme" th:checked="${rememberme}" /> 记住我
正如你所见,如果表达式的结果为true,则自动勾选复选框,若为false,则不会自动勾选。
格式化日期
<p th:text="${#dates.format(myDate)}">p>
<p th:text="${#dates.format(myDate, 'yyyy-MM-dd')}">p>
<p th:text="${#dates.format(myDate, 'yyyy-MM-dd HH:mm:ss')}">p>
获取年月日
<p th:text="${#dates.createNow()}">p>
<p th:text="${#dates.year(date)}">p>
<p th:text="${#dates.month(date)}">p>
<p th:text="${#dates.day(date)}">p>
/*
* 根据year,month,day创建日期(java.util.Date)对象,比如 ${#dates.create('2008','08','08')}
*/
${#dates.create(year,month,day)}
${#dates.create(year,month,day,hour,minute)}
${#dates.create(year,month,day,hour,minute,second)}
${#dates.create(year,month,day,hour,minute,second,millisecond)}
/*
* 创建当前日期创建一个日期(java.util.Date)对象(时间设置为00:00)
*/
${#dates.createToday()}
${#dates.createTodayForTimeZone()}
/*
* 从其组件创建日历(java.util.Calendar)对象
*/
${#calendars.create(year,month,day)}
${#calendars.create(year,month,day,hour,minute)}
${#calendars.create(year,month,day,hour,minute,second)}
${#calendars.create(year,month,day,hour,minute,second,millisecond)}
${#calendars.createForTimeZone(year,month,day,timeZone)}
${#calendars.createForTimeZone(year,month,day,hour,minute,timeZone)}
${#calendars.createForTimeZone(year,month,day,hour,minute,second,timeZone)}
${#calendars.createForTimeZone(year,month,day,hour,minute,second,millisecond,timeZone)}
/*
* 为当前日期和时间创建一个日历(java.util.Calendar)对象
*/
${#calendars.createNow()}
${#calendars.createNowForTimeZone()}
/*
* 为当前日期创建日历(java.util.Calendar)对象(时间设置为00:00)
*/
${#calendars.createToday()}
${#calendars.createTodayForTimeZone()}
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<p th:text="${#strings.toUpperCase(myStr)}">p>
<p th:text="${#strings.indexOf(myStr,'ll')}">p>
<p th:text="${#strings.substring(myStr, 2, 5)}">p>
<p th:text="${#strings.concat(myStr, 'Java')}">p>
<p th:text="${#strings.length(myStr)}">p>
<p th:text="${#strings.length('happy')}">p>
<p th:text="${#strings.contains(myStr, 'hello')}">p>
body>
html>
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<p th:text="${#lists.size(myList)}">p>
<p th:text="${#lists.contains(myList, 1)}">p>
<p th:text="${#lists.isEmpty(myList)}">p>
<p th:text="${#lists.sort(myList)}">p>
body>
html>
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<p th:text="${#numbers.formatCurrency(myNumber)}">p>
<p th:text="${#numbers.formatDecimal(myNumber, 4, 1)}">p>
body>
html>
<p th:text="${#bools.isTrue(obj)}">p>
<p th:text="${#bools.isFalse(cond)}">p>
通过加问号来判断前面的值是否为空,防止报错
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<p th:text="${data?.name}">p>
body>
html>
package com.xdu.studyspringboot.controller;
import com.xdu.studyspringboot.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
public class ThymeleafController {
@RequestMapping("/utilObject")
public String testUtilObject(HttpServletRequest request){
request.setAttribute("data", new User(1, "Tom", 22));
return "test";
}
}
下面介绍常见的两种注释:
语法:,注释的代码块会在文件源代码中显示出来。
单行注释
多行注释
语法:,注释的代码块会在引擎解析的时候抹去。
单行注释
多行注释
<div th:switch="${user.role}">
<p th:case="admin">管理员p>
<p th:case="user">普通用户p>
div>