Thymeleaf模版
大约 18 分钟
Thymeleaf 简介
传统显示层输出
- 统的 WEB 开发中主要是依靠 JSP 实现了显示层的开发,这样一来为了便于 JSP 中的代码编写就需要大量的使用 EL、JSTL 并结合前端技术实现最终的页面展示。虽然最终可以实现良好的页面显示,但是代码会将前后端程序融合在一起,使得程序的可维护性非常的差。

Thymeleaf 实现结构
- 为了解决 JSP 代码过于臃肿的问题,在 SpringBoot 中默认引入了 Thymeleaf 模版程序,Thymeleaf 是个 XML、XHTML、HTML5 模板引擎,利用该模版程序可以直接在静态文件中编写动态程序代码,以实现控制层数据传递的内容输出,但是这样的输出往往都需要经过特定的处理转换才可以实现

Thymeleaf
- Thymeleaf 的主要目标在于提供一种可被浏览器正确显示的、格式良好的模板创建方式开发者可以通过它来创建经过验证的 XML 与 HTML 模板,相对于传统的逻辑程序代码,开发者只需将标签属性添加到模板中即可,而后这些标签属性就会在 DOM(文档对象模型)上执行预先制定好的逻辑,这样极大的简化了显示层的程序逻辑代码。
前后端分离
- 在传统项目开发中,由于所有的前台显示代码都需要结合动态处理完成,这样对于代码的开发与维护实在是过于困难了,正是因为这样才有了前后端分离设计,即:后端程序只负责处理服务端业务,而前端美工实现前台显示业务的控制

- 在实际开发中,使用 Thymeleaf 模版的项目大多都是在单容器环境下实现的项目开发而在前后端分离的项目设计之中,前后端可能会提供有各自的集群服务,但是只要后端服务返回 Rest 结构的数据即可实现响应,而在这样的项目中是不需要将页面交给 Thymeleaf 模版页面进行处理的,
Thymeleaf 编程起步

1、
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf', version: '2.4.4'
2、
project('microboot-thymeleaf') { // 子模块
dependencies { // 配置子模块依赖
compile(project(':microboot-common')) // 引入其他子模块
compile('org.springframework.boot:spring-boot-starter-thymeleaf') // 引入了Thymeleaf模版
}
}
project('microboot-common') { // 子模块
dependencies { // 配置子模块依赖
compile('org.springframework.boot:spring-boot-starter-web')// 引入SpringBoot依赖
}
}
3、
sourceSets { // 源代码目录配置
main { // main及相关子目录配置
java { srcDirs = ['src/main/java'] }
resources { srcDirs = ['src/main/resources', "src/main/view"] } // 追加一个新的源代码目录
}
test { // test及相关子目录配置
java { srcDirs = ['src/test/java'] }
resources { srcDirs = ['src/test/resources'] }
}
}
4、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<p th:text="'title = ' + ${title}"/>
<p th:text="'content = ' + ${content}"/>
<p th:text="${message}"/>
</body>
</html>
5、
package com.yootk.action;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller // 此时不是进行了Rest响应
@RequestMapping("/thymeleaf/*") // 设置父路径
public class ThymeleafAction {
@RequestMapping("view")
public ModelAndView view(String message) {
ModelAndView mav = new ModelAndView("message/message_show"); // 设置跳转路径
mav.addObject("message", message); // 用户发送的请求参数
mav.addObject("title", "沐言科技");// 由用户自定义传递的属性
mav.addObject("content", "www.yootk.com");// 由用户自定义传递的属性
return mav;
}
}
6、
package com.yootk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication // 一个注解解决所有的问题
public class StartSpringBootThymeleafApplication {
public static void main(String[] args) {
SpringApplication.run(StartSpringBootThymeleafApplication.class, args); // 运行SpringBoot程序
}
}
7、
localhost/message/show?message=爆可爱的小李老师
8、
package com.yootk.action;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller // 此时不是进行了Rest响应
@RequestMapping("/thymeleaf/*") // 设置父路径
public class ThymeleafAction {
// @RequestMapping("view")
// public ModelAndView view(String message) {
// ModelAndView mav = new ModelAndView("message/message_show"); // 设置跳转路径
// mav.addObject("message", message); // 用户发送的请求参数
// mav.addObject("title", "沐言科技");// 由用户自定义传递的属性
// mav.addObject("content", "www.yootk.com");// 由用户自定义传递的属性
// return mav;
// }
@RequestMapping("view")
public String view(String message, Model model) {
model.addAttribute("message", message); // 用户发送的请求参数
model.addAttribute("title", "沐言科技");// 由用户自定义传递的属性
model.addAttribute("content", "www.yootk.com");// 由用户自定义传递的属性
return "message/message_show";
}
}
9、
localhost/thymeleaf/view?message=爆可爱的小李老师
Thymeleaf 环境配置

1、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<h1>自定义的前缀</h1>
<p th:text="'title = ' + ${title}"/>
<p th:text="'content = ' + ${content}"/>
<p th:text="${message}"/>
</body>
</html>
2、
server:
port: 80
spring:
thymeleaf:
prefix: classpath:/muyan/ # 自定义前缀
suffix: .yootk # 自定义后缀
3、
localhost/thymeleaf/view?message=爆可爱的小李老师
整合静态资源
Thymeleaf 静态资源
- 在 WEB 开发中除了要进行动态页面的显示处理之外,也需要引入一些静态资源,例如:图片、样式文件、脚本等,在 Thymeleaf 中这些静态资源需要定义在 static 路径之中同时可以直接进行资源引入

1、
.message {
background: gray;
color: white;
font-size: 22px;
text-align: center;
}
2、
window.onload = function() {
console.log("沐言科技:www.yootk.com");
}
3、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<link rel="icon" type="image/x-icon" href="/images/favicon.ico"/>
<link rel="stylesheet" type="text/css" href="/css/style.css"/>
<script type="text/javascript" src="/js/message_index.js"></script>
</head>
<body>
<div><img src="/images/muyan_yootk.png"/></div>
<div class="message">沐言科技:www.yootk.com</div>
</body>
</html>
4、
http://localhost/message_index.html
路径访问支持
传统 WEB 定位
- 在传统的 JSP 代码开发中,一般会通过 request 内置对象所提供的方法实现当前请求资源的动态获取,会采用如下的代码完成:
<%
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ request.getContextPath()
%>
- 而后再使用“\<base\>”元素(<base href="<%=basePath%>"/>)进行引用才可以解决路径操作问题,而这样的操作代码形式在 Thymeleaf 中就可以极为简化的实现处理
路径定位
- 在进行 WEB 项目开发中,由于需要经常性的进行页面跳转,所以准确的实现资源定位是保证页面显示最重要的一环,那么此时最佳的做法就是采用绝对定位的方式设置资源的加载路径,此时就需要通过 HTML 所提供的“<base>”属性进行处理,并结合当前的访问协议、主机名称、端口号以及虚拟目录的名称实现动态配置,但是这些操作在 Thymeleaf 中彻底消失了,如果要想进行资源定位只需要采用“@{路径)”的形式即可

1、
package com.yootk.action;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller // 此时不是进行了Rest响应
@RequestMapping("/thymeleaf/*") // 设置父路径
public class ThymeleafAction {
@RequestMapping("path")
public String path() {
return "message/message_path"; // 跳转路径
}
}
2、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<link rel="icon" type="image/x-icon" th:href="@{/images/favicon.ico}"/>
<link rel="stylesheet" type="text/css" th:href="@{/css/style.css}"/>
<script type="text/javascript" th:src="@{/js/message_index.js}"></script>
</head>
<body>
<div><img th:src="@{/images/muyan_yootk.png}"></div>
<div class="message">沐言科技:<a th:href="@{https://www.yootk.com}">www.yootk.com</a></div>
</body>
</html>
3、
localhost/message/path
读取资源文件
范例:定义资源文件
- Thymeleaf 作为页面显示模版,在开发中也会存在有国际化的访问需要,所以在 Thyemeleaf 中也可以直接实现 SpringBoot 中的资源文件读取。如果要想进行资源读取那么首先应该在“src/main/resources”源代码目录中定义相应的资源文件,本次资源文件定义的 BaseName 为“i18n.Message
资源配置
- 本次配置了中文(zh_CN)以及英文(en_Us)两个语言资源文件,而要想让此资源文件生效,则需要在 application.yml 文件之中进行资源配置,这样 Thymeleaf 模版才可以通过指定的语法实现内容读取
动态 Locale 拦截配置
- 如果要想在项目中引入 LocaleChangelnterceptor 拦截器,则需要开发者创建一个专属的 WEB 配置类,该类可以实现“WebMvcConfigurer”配置接口,随后在该类中设置 Locale 切换的参数名称(此处名称设置为 lang),同时也需要配置在默认情况下的 Locale 实例,本次将默认的 Locale 设置为中文环境

1、
yootk.message = 李兴华高薪就业编程训练营
yootk.url = edu.yootk.com
yootk.welcome = 欢迎“{}”光临本站点!
2、
yootk.message = 沐言科技(MuYan Technology)
yootk.url = www.yootk.com
yootk.welcome = 欢迎“{0}”访问沐言科技官方站点!
3、
yootk.message = MuYan Technology
yootk.url = www.yootk.com
yootk.welcome = Welcome“{0}” Access Site!
4、
server:
port: 80
spring:
messages:
basename: i18n/Message
5、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<link rel="icon" type="image/x-icon" th:href="@{/images/favicon.ico}"/>
<link rel="stylesheet" type="text/css" th:href="@{/css/style.css}"/>
<script type="text/javascript" th:src="@{/js/message_index.js}"></script>
</head>
<body>
<h2 th:text="'【资源】message = ' + #{yootk.message}"/>
<h2 th:text="'【资源】url = ' + #{yootk.url}"/>
<h2 th:text="'【资源】welcome = ' + #{yootk.welcome('李兴华')}"/>
</body>
</html>
6、
package com.yootk.action;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller // 此时不是进行了Rest响应
@RequestMapping("/thymeleaf/*") // 设置父路径
public class ThymeleafAction {
@RequestMapping("i18n")
public String path() {
return "message/message_i18n"; // 跳转路径
}
}
7、
localhost/thymeleaf/i18n
8、
package com.yootk.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import java.util.Locale;
@Configuration
public class ThymeleafConfig implements WebMvcConfigurer { // 进行WEB配置
public LocaleResolver localeResolver() {
SessionLocaleResolver slr = new SessionLocaleResolver(); // 进行当前Session对应的Locale配置
slr.setDefaultLocale(Locale.SIMPLIFIED_CHINESE); // 设置默认的解析器
return slr;
}
public LocaleChangeInterceptor localeChangeInterceptor() { // 修改Locale实例的拦截器
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang"); // 根据lang的参数来设置不同的Locale实例
return lci;
}
@Override
public void addInterceptors(InterceptorRegistry registry) { // 通过拦截器来进行Locale处理
registry.addInterceptor(localeChangeInterceptor()); // 添加拦截器
}
}
9、
http://localhost/message/i18n?lang=zh_CN
http://localhost/message/i18n?lang=en_US
环境对象支持

1、
package com.yootk.action;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller // 此时不是进行了Rest响应
@RequestMapping("/thymeleaf/*") // 设置父路径
public class ThymeleafAction {
@RequestMapping("attribute")
public String attribute(HttpServletRequest request, HttpServletResponse response) {
// 考虑到讲解问题,本次将设置重名的属性,但是属性的范围不同
request.setAttribute("message", "【REQUEST】沐言科技:www.yootk.com");
request.getSession().setAttribute("message", "【SESSION】沐言科技:www.yootk.com");
request.getServletContext().setAttribute("message", "【APPLICATION】沐言科技:www.yootk.com");
return "message/message_attribute"; // 跳转路径
}
}
2、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<link rel="icon" type="image/x-icon" th:href="@{/images/favicon.ico}"/>
<link rel="stylesheet" type="text/css" th:href="@{/css/style.css}"/>
</head>
<body>
<div th:text="'{REQUEST属性}message = ' + ${message}"/>
<div th:text="'{SESSION属性}message = ' + ${session.message}"/>
<div th:text="'{APPLICATION属性}message = ' + ${application.message}"/>
</body>
</html>
3、
localhost/thymeleaf/attribute
4、3.1被废弃
<div th:text="'【request内置对象】远程主机:' + ${#httpServletRequest.getRemoteAddr()}"/>
<div th:text="'【request内置对象】message属性:' + ${#httpServletRequest.getAttribute('message')}"/>
<div th:text="'【session内置对象】SessionID:' + ${#httpSession.getId()}"/>
<div th:text="'【application内置对象】虚拟服务名称:' + ${#httpServletRequest.getServletContext().getVirtualServerName()}"/>
对象输出
Thymeleaf 输出对象属性
- 在控制层进行业务处理时,会将数据处理的结果以对象的形式传递到模版页面,而后模版页面就需要根据所传入的对象实现相应属性的获取

1、
package com.yootk.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Date;
@Data // 自动生成结构
@AllArgsConstructor // 全参构造
public class Member {
private String mid;
private String name;
private Integer age;
private Double salary;
private Date birthday;
}
2、
package com.yootk.action;
import com.yootk.vo.Member;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
@Controller // 此时不是进行了Rest响应
@RequestMapping("/thymeleaf/*") // 设置父路径
public class ThymeleafAction {
@RequestMapping("show")
public String show(Model model) throws Exception {
Member member = new Member("yootk", "李兴华", 16, 888.66,
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse("1997-07-15 21:10:32"));
model.addAttribute("member", member);
return "member/member_show"; // 跳转路径
}
}
3、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<div th:text="'【Member对象属性】mid:' + ${member.mid}"/>
<div th:text="'【Member对象属性】name:' + ${member.name}"/>
<div th:text="'【Member对象属性】age:' + ${member.age}"/>
<div th:text="'【Member对象属性】salary:' + ${member.salary}"/>
<div th:text="'【Member对象属性】birthday:' + ${member.birthday}"/>
</body>
</html>
4、
http://localhost/member/show
5、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<div th:text="'【Member对象属性】mid:' + ${member.mid}"/>
<div th:text="'【Member对象属性】name:' + ${member.name}"/>
<div th:text="'【Member对象属性】age:' + ${member.age}"/>
<div th:text="'【Member对象属性】salary:' + ${member.salary}"/>
<div th:text="'【Member对象属性】birthday:' + ${member.birthday}"/>
<hr/>
<div th:text="'【Thymeleaf格式化】格式化金钱数字,salary = ' + ${#numbers.formatCurrency(member.salary)}"/>
<div th:text="'【Thymeleaf格式化】格式化日期时间,birthday = ' + ${#dates.format(member.birthday, 'yyyy-MM-dd HH:mm:ss')}"/>
</body>
</html>
6、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<div th:object="${member}">
<div th:text="'【Member对象属性】mid:' + *{mid}"/>
<div th:text="'【Member对象属性】name:' + *{name}"/>
<div th:text="'【Member对象属性】age:' + *{age}"/>
<div th:text="'【Member对象属性】salary:' + *{salary}"/>
<div th:text="'【Member对象属性】birthday:' + *{birthday}"/>
<hr/>
<div th:text="'【Thymeleaf格式化】格式化金钱数字,salary = ' + *{#numbers.formatCurrency(salary)}"/>
<div th:text="'【Thymeleaf格式化】格式化日期时间,birthday = ' + *{#dates.format(birthday, 'yyyy-MM-dd HH:mm:ss')}"/>
</div>
</body>
</html>
页面逻辑处理
页面逻辑
- 页面显示时往往需要对一个甚至多个数据项的内容进行关系判断(>或 gt、<或 lt、>=或 ge、<=或 le、==或 eg、!=或 ne),这样就需要通过逻辑运算符的形式连接这些判断表达式在 Thyemeleaf 模版语法中提供了基本的逻辑运算符:与运算(and)、或运算(or)
1、
package com.yootk.action;
import com.yootk.vo.Member;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.text.SimpleDateFormat;
@Controller // 此时不是进行了Rest响应
@RequestMapping("/thymeleaf/*") // 设置父路径
public class ThymeleafAction {
@RequestMapping("show")
public String show(Model model) throws Exception {
Member member = new Member("yootk", "李兴华", 16, 888.66,
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse("1997-07-15 21:10:32"));
model.addAttribute("member", member);
return "member/member_show"; // 跳转路径
}
}
2、
localhost/thymeleaf/show
3、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<div th:object="${member}">
<div th:if="*{age lt 18}"> <!-- 小于判断 -->
年轻人,需要踏踏实实的学习一门技术,才能够获得你想要的未来!
</div>
<div th:unless="*{age le 18}"> <!-- 大于等于判断 -->
你已经是一个成年人了,需要担负起生活与家庭的重任,加油!
</div>
<!-- 只要是程序的逻辑几乎就都会存在有所谓的与、或、非的概念 -->
<div th:if="*{mid eq 'yootk' and salary gt 800}">
欢迎“<span th:text="*{name}"/>”光临访问,恭喜你有了人生的第一笔收入,金额“<span th:text="${#numbers.formatCurrency(member.salary)}"/>”
</div>
</div>
</body>
</html>
4、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<div th:object="${member}">
<div th:text="*{mid == 'yootk' ? '沐言科技' : '李兴华高薪就业编程训练营'}">
</div>
</body>
</html>
5、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<div th:object="${member}">
<div th:text="*{mid ?: '沐言科技'}">
</div>
</body>
</html>
6、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<body>
<div th:object="${member}">
<div th:switch="*{mid}">
<span th:case="muyan">欢迎“李兴华高薪就业编程训练营“</span>
<span th:case="yootk">欢迎访问沐言科技首页</span>
<span th:case="*">请认真学习《SpringBoot就业编程实战》,宗旨:白漂到底,自我拯救</span>
</div>
</div>
</body>
</html>
数据迭代处理
数据迭代
- 动态列表显示是 JavaWEB 开发中较为常见的一项功能,开发者可以通过控制器传递 List 或 Map 集合到显示层,而后通过 Thyemeleaf 提供的“th:each”语法实现迭代内容获取
1、
package com.yootk.action;
import com.yootk.vo.Member;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
@Controller // 此时不是进行了Rest响应
@RequestMapping("/member/*") // 设置父路径
public class MemberAction {
@RequestMapping("list")
public String list(Model model) throws Exception {
List<Member> memberList = new ArrayList<>();
for (int x = 0; x < 10; x++) {
Member member = new Member("yootk - " + x, "李兴华", 16 + x, 888.66 + x * 100,
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse("1997-07-15 21:10:32"));
memberList.add(member); // 将对象保存在集合之中
}
model.addAttribute("memberList", memberList);
return "member/member_list"; // 跳转路径
}
}
2、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<link rel="icon" type="image/x-icon" th:href="@{/images/favicon.ico}"/>
<link rel="stylesheet" type="text/css" th:href="@{/bootstrap/css/bootstrap.css}"/>
<script type="text/javascript" th:src="@{/bootstrap/js/bootstrap.js}"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<table class="table table-hover table-striped">
<tr>
<td width="10%" class="text-center">No.</td>
<td width="15%" class="text-center">编号</td>
<td width="15%" class="text-center">姓名</td>
<td width="10%" class="text-center">年龄</td>
<td width="15%" class="text-center">月薪</td>
<td width="20%" class="text-center">生日</td>
</tr>
<tr th:each="member, memberStat : ${memberList}">
<td class="text-center" th:text="${memberStat.index + 1}"/>
<td class="text-center" th:text="${member.mid}"/>
<td class="text-center" th:text="${member.name}"/>
<td class="text-center" th:text="${member.age}"/>
<td class="text-center" th:text="${#numbers.formatCurrency(member.salary)}"/>
<td class="text-center" th:text="${#dates.format(member.birthday, 'yyyy-MM-dd')}"/>
</tr>
</table>
</div>
</div>
</div>
</body>
</html>
3、
localhost/member/list
4、
package com.yootk.action;
import com.yootk.vo.Member;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller // 此时不是进行了Rest响应
@RequestMapping("/member/*") // 设置父路径
public class MemberAction {
@RequestMapping("map")
public String map(Model model) throws Exception {
Map<String, Member> memberMap = new HashMap<>();
for (int x = 0; x < 10; x++) {
Member member = new Member("yootk - " + x, "李兴华", 16 + x, 888.66 + x * 100,
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse("1997-07-15 21:10:32"));
memberMap.put("muyan - " + x, member); // 将对象保存在集合之中
}
model.addAttribute("memberMap", memberMap);
return "member/member_map"; // 跳转路径
}
@RequestMapping("list")
public String list(Model model) throws Exception {
List<Member> memberList = new ArrayList<>();
for (int x = 0; x < 10; x++) {
Member member = new Member("yootk - " + x, "李兴华", 16 + x, 888.66 + x * 100,
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse("1997-07-15 21:10:32"));
memberList.add(member); // 将对象保存在集合之中
}
model.addAttribute("memberList", memberList);
return "member/member_list"; // 跳转路径
}
}
5、
localhost/member/map
6、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<link rel="icon" type="image/x-icon" th:href="@{/images/favicon.ico}"/>
<link rel="stylesheet" type="text/css" th:href="@{/bootstrap/css/bootstrap.css}"/>
<script type="text/javascript" th:src="@{/bootstrap/js/bootstrap.js}"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<table class="table table-hover table-striped">
<tr>
<td width="10%" class="text-center">No.</td>
<td width="15%" class="text-center">KEY</td>
<td width="15%" class="text-center">编号</td>
<td width="15%" class="text-center">姓名</td>
<td width="10%" class="text-center">年龄</td>
<td width="15%" class="text-center">月薪</td>
<td width="20%" class="text-center">生日</td>
</tr>
<tr th:each="memberEntry, memberStat : ${memberMap}">
<td class="text-center" th:text="${memberStat.index + 1}"/>
<td class="text-center" th:text="${memberEntry.key}"/>
<td class="text-center" th:text="${memberEntry.value.mid}"/>
<td class="text-center" th:text="${memberEntry.value.name}"/>
<td class="text-center" th:text="${memberEntry.value.age}"/>
<td class="text-center" th:text="${#numbers.formatCurrency(memberEntry.value.salary)}"/>
<td class="text-center" th:text="${#dates.format(memberEntry.value.birthday, 'yyyy-MM-dd')}"/>
</tr>
</table>
</div>
</div>
</div>
</body>
</html>
页面包含指令
页面包含
- 为了提高程序页面的可复用性,往往需要将一个完整的页面拆分为若干个不同的子页面而后再需要的时候通过包含语句将代码合并为一个整体进行输出,如图 6-14 所示。在 Thymeleaf 模版中提供有页面的包含处理,并且提供有如下的两类实现语法:
- th:replace:使用标签进行替换,原始的宿主标签还在,但是包含标签不会出现;
- th:include:进行包含,原始的宿主标签消失,而保留包含的标签。

1、
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<foot th:fragment="companyHeader(title, url)"> <!-- 自定义的原始包含页面中的标签元素 -->
<img th:src="@{/images/logo.png}" style="height: 30px;"/>
<strong>
<span th:text="${title}"/>(<span th:text="${url}"/>)
</strong>
</foot>
2、
package com.yootk.action;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller // 此时不是进行了Rest响应
@RequestMapping("/thymeleaf/*") // 设置父路径
public class ThymeleafAction {
@RequestMapping("include")
public String include() throws Exception {
return "message/message_include"; // 跳转路径
}
}
3、
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<foot th:fragment="companyHeader"> <!-- 自定义的原始包含页面中的标签元素 -->
<img th:src="@{/images/logo.png}" style="height: 30px;"/>
<strong>
<span th:text="${title}"/>(<span th:text="${url}"/>)
</strong>
</foot>
4、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<link rel="icon" type="image/x-icon" th:href="@{/images/favicon.ico}"/>
<link rel="stylesheet" type="text/css" th:href="@{/css/style.css}"/>
<script type="text/javascript" th:src="@{/js/message_index.js}"></script>
</head>
<body>
<div th:replace="@{/commons/header} :: companyHeader('沐言科技', 'www.yootk.com')"/>
<hr>
<div th:include="@{/commons/footer} :: companyHeader" th:with="title=李兴华高薪就业编程训练营, url=edu.yootk.com"/>
</body>
</html>
页面数据处理

1、
package com.yootk.action;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Map;
import java.util.Set;
@Controller // 此时不是进行了Rest响应
@RequestMapping("/thymeleaf/*") // 设置父路径
public class ThymeleafAction {
@RequestMapping("handle")
public String handle(Model model) throws Exception {
model.addAttribute("message", "www.YOOTK.com");
model.addAttribute("language", Set.of("Java", "Python", "GoLang"));
model.addAttribute("infos", Map.of("yootk", "yootk.com", "edu", "edu.yootk.com"));
return "message/message_handle"; // 跳转路径
}
}
2、
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"> <!-- 引入命名空间 -->
<head>
<title>Thymeleaf模版渲染</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<link rel="icon" type="image/x-icon" th:href="@{/images/favicon.ico}"/>
<link rel="stylesheet" type="text/css" th:href="@{/css/style.css}"/>
</head>
<p>
<!-- 此时直接实现了一个字符串常量的替换,该常量是在模版页面之中进行定义的 -->
<p th:text="${'字符串替换:' + #strings.replace('沐言优拓(www.yootk.com)', '沐言优拓', '沐言科技')}"/>
<!-- 针对于传递过来的message属性进行内容的替换处理 -->
<p th:text="${'字符串替换:' + #strings.replace(message, 'YOOTK.com', 'yootk.com')}"/>
<p th:text="${'字符串转大写:' + #strings.toUpperCase(message)}"/>
<p th:text="${'字符串截取:' + #strings.substring(message, 4)}"/>
<p th:if="${#sets.contains(language, 'Java')}"> ”Java“是当今重要的软件编程语言!</p>
<p th:if="${#maps.containsKey(infos, 'yootk')}">
可以发现KEY为“yootk”的信息,对应的内容为:<span th:text="${infos.edu}">
</p>
</body>
</html>
3、
http://localhost/thymeleaf/handle
demo
