在Java中,模板引擎可以帮助生成文本输出。常见的模板引擎包括FreeMarker、Velocity和Thymeleaf等
Thymeleaf是一个适用于Web和独立环境的现代服务器端Java模板引擎。
Thymeleaf 和 JSP比较:
Thymeleaf目前所作的工作和JSP有相似之处,Thymeleaf和JSP都是属于服务端渲染技术,Thymeleaf比JSP功能强大许多。
Thymeleaf就是SpringBoot 官方推荐使用的模板引擎。
搭建thymeleaf环境:
1、创建一个 SpringBoot 项目
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.14</version>
<scope>provided</scope>
</dependency>
2、编写跳转页面的 Controller
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private Integer id;
private String name;
private Integer age;
private Date birthday;
}
@Controller
public class IndexController {
@RequestMapping("/index")
public String index(Model model) {
model.addAttribute("message", "HelloWorld");
Student student = new Student(1, "李四", 23, new Date());
model.addAttribute("student", student);
Student student1 = new Student(1, "张三1", 23, new Date());
Student student2 = new Student(2, "张三2", 23, new Date());
Student student3 = new Student(3, "张三3", 23, new Date());
List<Student> list = new ArrayList<>();
list.add(student1);
list.add(student2);
list.add(student3);
model.addAttribute("list", list);
return "index";
}
}
3、index.html 页面
在resources/templates目录创建一个index.html页面。
注意,必须加上命名空间xmlns:th="Thymeleaf",否则Thymeleaf的自定义标签没有提示。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--使用th:text输出-->
<div th:text="${message}"></div>
<input type="text" th:id="${student.id}" th:name="${student.name}" th:value="${student.name}"/>
<!--循环-->
<table border="1">
<tr>
<td>编号</td>
<td>姓名</td>
<td>年龄</td>
<td>生日</td>
</tr>
<tr th:each="student:${list}">
<td th:text="${student.id}">1</td>
<td th:text="${student.name}">张三</td>
<td th:text="${student.age}">23</td>
<td th:text="${#dates.format(student.birthday, 'yyyy-MM-dd')}">1990-12-13</td>
</tr>
</table>
<!--取出集合中某一个-->
<div th:text="${list[0].name}"></div>
</body>
</html>
疑难问题
问题:为什么thymeleaf页面放在templates文件夹里面,并且后缀要是.html呢?
SpringBoot框架会将内置支持的功能组件放在spring-boot-autoconfigure-3.2.5.jar 包下,而 Thymeleaf 框架就是内置支持的。
所以在这个包里面可以找对应的自动配置代码,如图:
如果找默认的属性配置应该找XxxxProperties类,如图所示,Thymeleaf模板的前后缀如下:
所以Thymeleaf的页面存放在templates文件夹中,并且页面的后缀为.html。
常用标签:
- 数学运算
二元操作:+, - , * , / , %
一元操作: - (负)
- 逻辑运算
一元 : and or
二元 : !,not
- 比较运算(为避免转义尴尬,可以使用括号中的英文进行比较运算!)
比较:> , < , >= ,
等于:== , != ( eq , ne )
- 简单表达式
变量表达式: ${...}
选择变量表达式: *{...}
消息表达式: #{...}
URL 表达式: @{...}
代码段表达式: ~{...}
<body>
<!-- 使用th:text属性输出 -->
<div th:text="${message}" ></div>
<input type="text" th:id="${student.id}" th:name="${student.name}" th:value="${student.name}"><br/>
<!--循环-->
<table border="1">
<tr>
<td>编号</td>
<td>姓名</td>
<td>年龄</td>
<td>生日</td>
</tr>
<tr th:each="student:${list}">
<td th:text="${student.id}">1</td>
<td th:text="${student.name}">张三</td>
<td th:text="${student.age}">23</td>
<td th:text="${#dates.format(student.birthday, 'yyyy-MM-dd')}">1990-12-13</td>
</tr>
</table>
<!-- springmvc 保存了一个 model 对象: list -->
<!-- 获取所有 list -->
<p th:text="${list}"></p>
<!-- 获取 list 的第一个元素 -->
<p th:text="${list[0]}"></p>
<!-- 获取第一个 student 对象的 name 属性 -->
<p th:text="${list[0].name}"></p>
<!-- 也可以用 ['name'] 来获取第一个 student 对象的 name 属性 -->
<p th:text="${list[0]['name']}"></p>
<!-- 甚至可以调用方法! -->
<p th:text="${list[0].getName()}"></p>
<p th:text="${list[0]['name'].substring(0, 1)}"></p>
<!--判断
Thymeleaf支持四种判断:th:if/th:unless、逻辑运算符(and、or、not)、三目运算符、switch。-->
<!--第一种:if & unless-->
<!-- 如果条件为真,执行标签内的内容 -->
<div th:if="${false}">
天天18
</div>
<div th:if="${list[0].name eq '张三1'}">
张三1
</div>
<div th:if="${list[0].name == '张三1'}">
张三1
</div>
<!-- 如果条件为假,执行标签内的内容 -->
<div th:unless="${false}">
unless
</div>
<!--第二种:and、or、not-->
<div th:if="${true or false}">
真的18岁
</div>
<div th:if="${not false}">
真的别做梦
</div>
<!--第三种:三目运算符-->
<span th:text="true ? '今年不是18岁' : '总算清醒了'"></span><br/>
<span th:text="${student.age eq 23} ? '今年是23' : '不是23'"></span>
<span th:text="${student.age eq 23 ? '今年23' : '不是23'}"></span>
<!--第四种:switch-->
<div th:switch="${student.age}">
<div th:case="16">我今年16岁</div>
<div th:case="17">我今年17岁</div>
<div th:case="18">我今年18岁</div>
<div th:case="20">我今年20岁</div>
<div th:case="23">我今年23岁</div>
<div th:case="*">我年年18岁</div>
</div>
</body>
域对象
变量表达式的作用是:从web作用域里面取到对应的值,作用域包括 request、session、application。
@RequestMapping("/data")
public String data(HttpServletRequest request, HttpSession session) {
Student student1 = new Student(1, "张三1", 23 , new Date());
request.setAttribute("student1", student1);
Student student2 = new Student(2, "张三2", 23, new Date());
session.setAttribute("student2", student2);
Student student3 = new Student(3, "张三3", 23, new Date());
ServletContext application = request.getServletContext();
application.setAttribute("student3", student3);
return "data";
}
<body>
request:
<div>
编号:<span th:text="${student1.id}"></span><br>
姓名:<span th:text="${student1.name}"></span><br>
年龄:<span th:text="${student1.age}"></span><br>
</div>
session:
<div>
编号:<span th:text="${session.student2.id}"></span><br>
姓名:<span th:text="${session.student2.name}"></span><br>
年龄:<span th:text="${session.student2.age}"></span><br>
</div>
application:
<div>
编号:<span th:text="${application.student3.id}"></span><br>
姓名:<span th:text="${application.student3.name}"></span><br>
年龄:<span th:text="${application.student3.age}"></span><br>
</div>
</body>
选择变量表达式
问题:取request、session、application作用域上的属性时,可以发现,我们需要重复编写student1、session.student2和application.student3三次,
如果student对象的属性有十几个怎么办?显然写十几次相同的代码不是我们想要解决方案。
针对这种问题,Thymeleaf提供了选择变量表达式来解决。
request: <br/>
<div th:object="${student1}">
编号: <p th:text="*{id}"></p><br/>
姓名:<p th:text="*{name}"></p> <br/>
年龄:<p th:text="*{age}"></p><br/>
</div>
session:<br/>
<div th:object="${session.student2}">
编号: <p th:text="*{id}"></p><br/>
姓名:<p th:text="*{name}"></p> <br/>
年龄:<p th:text="*{age}"></p><br/>
</div>
作用域内容对象的空值处理
当获取一个作用域中不存在的对象属性,那么会返回一个null,但是有些情况下还通过点运算符获取对象属性,那么这是SpringBoot会报异常。有些情况下,就是根据某个对象是否为null来执行相应的操作。
--需求:获取session作用域中的user对象,如果不为null就输出name,如果为null,就输出空字符串,而不是报异常。
--分析:可以在调用对象或者方法的点(.)前面,使用问号(?)来判断null
编号:
内置工具对象:# 符号直接使用
除了基本对象, thymeleaf 还提供了一组工具对象,其实和java中对应的方法大同小异。
@RequestMapping(value = "/util")
public String set(Model model) {
Set<String> names = new HashSet<String>() ;
List<Integer> ids = new ArrayList<Integer>() ;
for (int i = 0 ; i < 5 ; i ++) {
names.add("boot-" + i) ;
ids.add(i) ;
}
model.addAttribute("names", names) ;
model.addAttribute("ids", ids) ;
model.addAttribute("mydate", new Date()) ;
return "util" ;
}
<body>
<p th:text="${#dates.format(mydate,'yyyy-MM-dd')}"/>
<p th:text="${#dates.format(mydate,'yyyy-MM-dd HH:mm:ss.SSS')}"/>
<hr/>
<p th:text="${#strings.replace('www.baidu.cn','.','$')}"/>
<p th:text="${#strings.toUpperCase('www.baidu.cn')}"/>
<p th:text="${#strings.trim('www.baidu.cn')}"/>
<hr/>
<p th:text="${#sets.contains(names,'boot-0')}"/>
<p th:text="${#sets.contains(names,'boot-9')}"/>
<p th:text="${#sets.size(names)}"/>
<hr/>
<p th:text="${#lists.contains(ids,0)}"/>
</body>
Link URL
链接 URL 表达式语法是 @{...}
反斜杠 ”/“ 开头,代表static目录下的静态资源文件
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" th:href="@{/bootstrap-3.3.7-dist/css/bootstrap.css}">
<script type="text/javascript" th:src="@{/jquery-2.1.4.js}"></script>
<script type="text/javascript" th:src="@{/mylayer.js}"></script>
</head>
<body>
<a class="btn btn-primary" href="/">返回首页</a> <br/>
<a class="btn btn-primary" href="#" th:href="@{/}">返回首页</a> <br/>
<a href="/student/search">访问StudentController下面的search方法</a> <br/>
<a href="#" th:href="@{/student/search}">访问StudentController下面的search方法</a><br/>
<!-- 会生成 url: http://localhost:8888/student/search?id=2&name=zhangsan -->
<a href="#" th:href="@{/student/search(id=${student.id},name=${student.name})}">访问UrlController下面的demo方法带参数</a>
</body>
</html>
@Controller
@RequestMapping("/student")
public class StudentController {
@RequestMapping("/search")
public String search(Integer id, String name) {
System.out.println("StudentController.search");
System.out.println("id: " + id);
System.out.println("name: " + name);
return "index";
}
}
如何引入另一个html页面:
header.html:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:fragment="common_resource">
<link rel="stylesheet" th:href="@{/bootstrap-3.3.7-dist/css/bootstrap.css}">
<script type="text/javascript" th:src="@{/jquery-2.1.4.js}"></script>
<script type="text/javascript" th:src="@{/mylayer.js}"></script>
</div>
</body>
</html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--<link rel="stylesheet" th:href="@{/bootstrap-3.3.7-dist/css/bootstrap.css}">
<script type="text/javascript" th:src="@{/jquery-2.1.4.js}"></script>
<script type="text/javascript" th:src="@{/mylayer.js}"></script>-->
<div th:replace="header::common_resource"></div>
</head>