Thymeleaf 基础概念 什么是 Thymeleaf?
Thymeleaf 是一个现代服务器端 Java 模板引擎,适用于 Web 和独立环境,能够处理 HTML、XML、JavaScript、CSS 甚至纯文本。
其主要目标是提供一种优雅且高度可维护的模板创建方式。
Thymeleaf 的核心特性包括: 自然模板 :Thymeleaf 的模板可以直接在浏览器中预览,未定义的 Thymeleaf 标签会被忽略,这使得设计师和开发人员可以共同使用同一份模板文件。
多种模板模式 :支持 HTML、XML、TEXT、JAVASCRIPT、CSS 和 RAW 六种不同的模板模式。
可扩展性 :Thymeleaf 是一个高度可扩展的模板引擎框架,允许定义和自定义模板处理方式。
Thymeleaf 的主要特点 自然模板 :Thymeleaf 模板可以直接在浏览器中预览,即使未处理的模板也能作为设计原型使用。
丰富的标签语言 :提供多种标签和表达式语法,简化模板开发。
与 Spring Boot 的无缝集成 :Thymeleaf 提供了与 Spring Boot 和 Spring MVC 的完美集成,简化了表单绑定、属性编辑器、国际化等功能的实现。
支持多种模板模式 :能够处理 HTML、XML、JavaScript、CSS 和纯文本等多种格式的模板。
Thymeleaf 标签系统详解 基本标签语法 Thymeleaf 的标签语法基于 HTML 标签属性的形式,使用
th:
前缀表示 Thymeleaf 特定的属性。
基本语法形式包括: HTML 命名空间声明 : 在 HTML 文档中声明 Thymeleaf 的命名空间,这是使用 Thymeleaf 标签的前提条件:
表达式语法 :Thymeleaf 支持多种表达式类型,包括变量表达式、消息表达式、链接 URL 表达式和片段表达式。
标准标签 :Thymeleaf 提供了一系列标准标签,用于处理各种常见的模板需求。
主要标签详解 1. 内容设置标签
th:text
:用于设置标签的文本内容。
默认文本
th:utext
:与
th:text
类似,但不会对 HTML 特殊字符进行转义。
Welcome to our fantastic grocery store!
th:attr
:设置任意 HTML 属性的值。
2. 条件标签
th:if
:根据条件显示或隐藏内容。
管理员专用功能
th:unless
:与
th:if
相反,当条件为假时显示内容。
普通用户功能
th:switch和th:case
:实现多条件分支。
管理员
普通用户
其他用户
3. 迭代标签
th:each
:用于集合的迭代,生成重复的 HTML 结构。
产品名称
价格
th:each状态变量
:在迭代过程中可以获取当前索引、奇偶性等信息。
产品名称
价格
4. 表单标签
th:action
:设置表单提交的 URL。
th:method
:设置表单提交的方法。
th:field
:与 Spring Boot 集成时,用于绑定表单字段到模型对象的属性。
5. URL 标签
th:href
:设置超链接的 URL。
用户资料
th:src
:设置图像、脚本等资源的 URL。
6. 片段标签
th:fragment
:定义可重用的模板片段。
用户名
电子邮件
th:include
:包含另一个模板片段,但保留片段内的 HTML 结构。
th:replace
:用另一个模板片段替换当前元素的内容。
th:insert
:将另一个模板片段插入到当前元素中。
特殊标签
th:block
:用于包装一组元素,不生成实际的 HTML 元素。
产品名称
产品描述
th:remove
:移除整个元素及其内容。
这段内容将被移除
th:show
和
th:hide
:根据条件显示或隐藏内容(通过 CSS 控制)。
显示的内容
隐藏的内容
Thymeleaf 表达式语法 Thymeleaf 的表达式语法是 Thymeleaf 功能的核心,它允许在模板中动态地引用数据、执行计算和操作。
Thymeleaf 支持多种类型的表达式,每种表达式都有其特定的用途和语法。
变量表达式 变量表达式用于访问模型数据或上下文变量的值。
它们是 Thymeleaf 表达式中最基础也是最常用的一种。
语法 :
${...}
示例 :
默认文本
高级用法 : 访问对象属性:
${user.name}
调用方法:
${user.toString()}
访问集合元素:
${products[0].name}
访问 Map 元素:
${userMap[user.id].name}
表达式对象 :Thymeleaf 提供了一些内置对象,可以用于表达式中:
#ctx
:上下文对象
#vars
:上下文变量
#locale
:当前语言环境
#request
:HttpServletRequest 对象(仅在 Web 上下文中可用)
#response
:HttpServletResponse 对象(仅在 Web 上下文中可用)
#session
:HttpSession 对象(仅在 Web 上下文中可用)
#servletContext
:ServletContext 对象(仅在 Web 上下文中可用) 选择变量表达式 选择变量表达式用于在选定的对象上执行表达式,类似于在 OGNL 或 SpringEL 中使用
@
符号。
语法 :
*{...}
示例 :
姓名: John
邮箱: john@example.com
消息表达式 消息表达式用于国际化,允许模板根据用户的语言环境显示相应的文本。
语法 :
#{...}
示例 :
Welcome
带参数的消息 :
Welcome, John
链接 URL 表达式 链接 URL 表达式用于生成应用程序中的 URL,可以处理各种类型的 URL,并自动处理上下文路径和会话 ID。
语法 :
@{...}
示例 :
Example
Profile
User List
User Detail
片段表达式 片段表达式用于引用和重用模板片段,可以提高模板的复用性和可维护性。
语法 :
~{...}
示例 :
用户名
电子邮件
文本操作 Thymeleaf 提供了一些文本操作功能,允许在模板中执行字符串连接和替换。
字符串连接 :
+
html 复制
Hello, World!
文本替换 :
|
Welcome, John!
算术运算 Thymeleaf 支持基本的算术运算,可以在表达式中执行简单的数学计算。
运算符 : 加法:
+
减法:
-
乘法:
*
除法:
/
取模:
%
示例 :
100
布尔运算 Thymeleaf 支持布尔运算,允许在模板中执行条件判断。
运算符 : 与:
and
或
&&
或:
or
或
||
非:
!
或
not
示例 :
比较运算 Thymeleaf 支持比较运算,允许在模板中比较两个值。
运算符 : 等于:
==
或
eq
不等于:
!=
或
neq
或
ne
大于:
>
或
gt
小于:
<
或
lt
大于等于:
>=
或
ge
小于等于:
<=
或
le
示例 :
条件表达式 Thymeleaf 支持条件表达式,允许在模板中根据条件选择不同的值。
语法 : 如果-那么:
(condition) ? (then)
如果-那么-否则:
(condition) ? (then) : (else)
默认表达式(Elvis 运算符):
(value) ?: (defaultvalue)
示例 :
否
未指定用户名
无操作令牌 无操作令牌用于指示 Thymeleaf 不执行任何操作,通常用于保留原型文本。
符号 :
_
示例 :
未指定用户名
数据转换和格式化 Thymeleaf 提供了数据转换和格式化功能,允许在模板中以特定的格式显示数据。
语法 :
{...}
(注意:这里是双花括号) 示例 :
2023-10-01
RMB 1,000.00
Thymeleaf 与 Spring Boot 集成 Thymeleaf 与 Spring Boot 的集成非常简单,通过添加适当的依赖和配置,可以快速实现模板渲染和数据绑定。
快速集成步骤 添加依赖 : 在 Spring Boot 项目中,只需添加
spring-boot-starter-thymeleaf
依赖即可。
org.springframework.boot
spring-boot-starter-thymeleaf
配置模板引擎 : Spring Boot 会自动配置 Thymeleaf 模板引擎,但可以根据需要自定义配置。
spring:
thymeleaf:
cache: false # 开发环境建议关闭缓存
mode: HTML5
encoding: UTF-8
suffix: .html
prefix:classpath:/templates/
创建控制器 : 创建控制器方法来处理请求并返回模板视图。
@Controller
public class HomeController {
@GetMapping("/")
public String index(Model model) {
model.addAttribute("message", "Hello, Thymeleaf!");
return "index";
}
}
创建模板 : 在
src/main/resources/templates/
目录下创建 HTML 模板文件。
Index
默认消息
与 Spring MVC 集成 Thymeleaf 与 Spring MVC 的集成非常紧密,提供了许多便利功能,如表单绑定、属性编辑器等。
表单绑定 : 使用
th:object
和
th:field
实现模型对象与表单字段的绑定。
错误消息显示 : 使用
th:errors
显示验证错误信息。
用户名错误
选项列表 : 使用
th:each
创建下拉列表。
与 Spring Data 集成 Thymeleaf 可以与 Spring Data 集成,简化数据展示和操作。
分页支持 : 使用 Thymeleaf 的标准标签显示分页信息。
集合迭代 : 使用
th:each
迭代集合数据。
用户名
电子邮件
自定义方言 Thymeleaf 允许创建自定义方言,扩展其功能。
创建处理器 : 实现
IProcessor
接口创建自定义处理器。
public class MyProcessor implements IProcessor {
@Override
public void process(IProcessingContext context) {
// 处理逻辑
}
}
注册方言 : 在 Spring Boot 配置中注册自定义方言。
@Configuration
public class ThymeleafConfig {
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.addDialect(new MyDialect());
return engine;
}
}
常见配置选项 模板缓存 : 可以开启或关闭模板缓存,开发环境建议关闭。
spring:
thymeleaf:
cache: false
模板路径 : 可以配置模板文件的路径。
spring:
thymeleaf:
prefix: classpath:/templates/
模板后缀 : 可以配置模板文件的后缀。
spring:
thymeleaf:
suffix: .html
模板模式 : 可以配置模板的模式,如 HTML5、XHTML 等。
spring:
thymeleaf:
mode: HTML5
字符编码 : 可以配置模板的字符编码。
spring:
thymeleaf:
encoding: UTF-8
Thymeleaf 模板布局 模板布局是 Thymeleaf 的一个重要特性,它允许将模板分解为多个可重用的部分,提高模板的复用性和可维护性。
基本布局概念 片段 : 定义可重用的模板片段,供其他模板引用。
网站标题
布局继承 : 使用布局继承创建模板层次结构,子模板可以继承父模板的结构。
默认标题
关于我们
关于我们
公司简介
布局标签 Thymeleaf 提供了几个布局相关的标签,用于控制模板的结构和内容。
th:replace
: 用另一个模板片段替换当前元素的内容。
th:include
: 包含另一个模板片段,保留片段内的 HTML 结构。
th:insert
: 将另一个模板片段插入到当前元素中。
th:with
: 定义局部变量,供后续表达式使用。
总价: 100 元
布局示例 以下是一个完整的布局示例,展示了如何使用 Thymeleaf 的布局功能创建一个灵活且易于维护的模板系统。
片段文件 (fragments.html) :
网站标题
© 2023 网站名称. All rights reserved.
用户列表
用户名
电子邮件
用户名
电子邮件
默认布局 (default.html) :
默认标题
用户列表页面 (userList.html) :
用户列表
布局最佳实践 分离关注点 : 将不同的功能模块分离到不同的片段中,如页眉、页脚、导航等。
使用参数化片段 : 定义可以接收参数的片段,增强复用性。
${text}
创建布局层次结构 : 创建多个层次的布局,如基础布局、通用布局、特定页面布局等。
使用条件包含 : 根据条件决定是否包含某些片段。
管理静态资源 : 使用 Thymeleaf 的链接标签管理静态资源,如 CSS、JavaScript 等。
Thymeleaf 表单处理 表单处理是 Web 应用程序中的重要功能,Thymeleaf 提供了强大的表单支持,简化了表单的创建和处理。
基本表单创建 Thymeleaf 提供了多种方式创建表单,可以根据需求选择合适的方式。
简单表单 : 创建一个简单的表单,用于收集用户输入。
使用 Spring Data Binding : 与 Spring Data Binding 集成,简化表单处理。
表单验证 Thymeleaf 提供了多种方式处理表单验证,确保用户输入的合法性。
服务器端验证 : 使用 Spring 的验证框架进行服务器端验证。
@Controller
public class FormController {
@PostMapping("/submit")
public String submit(@Valid User user, BindingResult result, Model model) {
if (result.hasErrors()) {
return "form";
}
// 处理成功提交
return "success";
}
}
显示验证错误 : 使用 Thymeleaf 的错误标签显示验证错误。
用户名错误
电子邮件错误
客户端验证 : 使用 HTML5 的客户端验证功能进行初步验证。
复杂表单结构 Thymeleaf 支持创建各种复杂的表单结构,满足不同的业务需求。
选项列表 : 创建下拉列表、单选按钮组和复选框组。
文件上传 : 处理文件上传功能。
动态表单 : 使用 JavaScript 动态添加或移除表单字段。
表单国际化 Thymeleaf 支持表单的国际化,允许根据用户的语言环境显示相应的表单标签和错误消息。
国际化表单标签 : 使用消息表达式显示国际化的表单标签。
国际化错误消息 : 使用消息表达式显示国际化的错误消息。
用户名不能为空
Username cannot be empty
国际化日期和数字格式 : 使用 Thymeleaf 的数据转换功能显示国际化的日期和数字格式。
10/10/2023
Thymeleaf 高级用法 Thymeleaf 提供了许多高级功能,可以进一步提升模板的灵活性和可维护性。
自定义处理器 Thymeleaf 允许创建自定义处理器,扩展其功能以满足特定需求。
创建自定义处理器 : 实现
IProcessor
接口创建自定义处理器。
public class MyProcessor implements IProcessor {
@Override
public void process(IProcessingContext context) {
// 处理逻辑
}
}
注册自定义处理器 : 在 Spring Boot 配置中注册自定义处理器。
@Configuration
public class ThymeleafConfig {
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.addProcessor(new MyProcessor());
return engine;
}
}
使用自定义处理器 : 在模板中使用自定义处理器。
自定义处理器
内联 内联是 Thymeleaf 的一个高级功能,允许在模板中嵌入和处理其他类型的文本,如 JavaScript 和 CSS。
文本内联 : 在模板中嵌入和处理文本。
Hello, World!
JavaScript 内联 : 在 JavaScript 代码中嵌入和处理 Thymeleaf 表达式。
CSS 内联 : 在 CSS 代码中嵌入和处理 Thymeleaf 表达式。
预处理 : 在模板处理之前执行预处理表达式。
Welcome, John
文本模板模式 文本模板模式允许 Thymeleaf 处理非 HTML 类型的文本,如纯文本、CSV、XML 等。
文本模板 : 创建和处理纯文本模板。
Dear [[${name}]],
Thank you for your order.
Your order number is [[${orderNumber}]].
Best regards,
The Store Team
CSV 模板 : 创建和处理 CSV 文件。
name,email,phone
[[${users->*{name,email,phone}->#strings.csv}]](#strings.csv)
XML 模板 : 创建和处理 XML 文件。
Book Title
Author Name
100
模板缓存 Thymeleaf 提供了模板缓存功能,可以提高模板处理的性能。
启用缓存 : 在配置中启用模板缓存。
spring:
thymeleaf:
cache: true
缓存控制 : 使用缓存控制标签控制模板的缓存行为。
缓存清除 : 在模板更改后清除缓存,确保最新的模板被使用。
@Autowired
private TemplateEngine templateEngine;
public void clearCache() {
templateEngine.clearCache();
}
解耦模板逻辑 解耦模板逻辑是 Thymeleaf 的一个高级功能,允许将模板的逻辑部分与内容部分分离。
基本用法 : 使用
th:ref
标签引用外部的模板逻辑。
动态引用 : 根据条件动态引用不同的模板逻辑。
性能优化 : 解耦模板逻辑可以提高模板处理的性能,特别是在大型应用程序中。
@Configuration
public class ThymeleafConfig {
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setDecoupledLogicEnabled(true);
return engine;
}
}
Thymeleaf 最佳实践 在使用 Thymeleaf 时,遵循一些最佳实践可以提高模板的质量和可维护性。
模板结构 合理的模板结构可以提高模板的可维护性和复用性。
模块化设计 : 将模板分解为多个模块,每个模块负责特定的功能。
templates/
fragments/ # 片段模板
header.html
footer.html
navigation.html
layouts/ # 布局模板
default.html
admin.html
pages/ # 页面模板
home.html
about.html
contact.html
层次结构 : 创建模板的层次结构,从基础布局到具体页面。
- 基础布局 (base.html)
- 通用布局 (general.html)
- 具体页面 (home.html, about.html, contact.html)
命名规范 : 使用一致的命名规范,便于识别和管理模板。
- 前缀:page_, fragment_, layout_
- 后缀:.html, .fragment.html, .layout.html
表达式使用 合理的表达式使用可以提高模板的可读性和性能。
避免复杂的表达式 : 尽量避免在模板中使用复杂的表达式,将复杂的逻辑放在控制器或服务层。
管理功能
管理功能
使用局部变量 : 使用
th:with
定义局部变量,简化复杂的表达式。
管理功能
优先使用标准方言 : 优先使用 Thymeleaf 的标准方言,除非有特殊需求。
默认消息
[[${message}]]
性能优化 合理的性能优化可以提高应用程序的响应速度和用户体验。
启用模板缓存 : 在生产环境中启用模板缓存,提高模板处理的性能。
spring:
thymeleaf:
cache: true
减少模板处理开销 : 减少模板处理的开销,提高性能。
使用静态资源优化 : 使用静态资源优化技术,如 CDN、压缩、缓存等。
国际化支持 国际化支持是现代 Web 应用程序的重要功能,Thymeleaf 提供了良好的支持。
消息资源文件 : 使用消息资源文件存储国际化的文本。
messages_en.properties
messages_zh.properties
消息表达式 : 使用消息表达式在模板中引用国际化的文本。
Page Title
语言切换 : 实现语言切换功能,允许用户选择不同的语言。
错误处理 合理的错误处理可以提高应用程序的稳定性和用户体验。
错误页面 : 创建自定义的错误页面,提供友好的错误信息。
Error
An error has occurred.
日志记录 : 实现日志记录功能,帮助排查和解决错误。
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public String handleException(Exception e, Model model) {
log.error("An error has occurred.", e);
model.addAttribute("error", e.getMessage());
return "error";
}
}
验证错误 : 使用 Thymeleaf 的错误标签显示验证错误。
用户名错误
Thymeleaf 实战案例 案例一:用户注册表单 以下是一个用户注册表单的完整示例,展示了如何使用 Thymeleaf 创建和处理表单。
控制器 :
@Controller
public class RegistrationController {
@GetMapping("/register")
public String showRegistrationForm(Model model) {
model.addAttribute("user", new User());
return "register";
}
@PostMapping("/register")
public String registerUser(@Valid User user, BindingResult result, Model model) {
if (result.hasErrors()) {
return "register";
}
// 处理用户注册逻辑
return "redirect:/success";
}
}
模板 (register.html) :
用户注册
用户注册
用户模型 :
public class User {
private String username;
private String email;
private String password;
private String confirmPassword;
// Getters and setters
}
验证配置 :
@Configuration
public class ValidationConfig {
@Bean
public Validator validator() {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setValidationMessageSource(messageSource());
return bean;
}
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("messages");
messageSource.setUseCodeAsDefaultMessage(true);
return messageSource;
}
}
消息资源文件 (messages.properties) :
user.username.empty=用户名不能为空
user.email.empty=电子邮件不能为空
user.password.empty=密码不能为空
user.confirmPassword.mismatch=两次输入的密码不一致
案例二:产品列表页面 以下是一个产品列表页面的完整示例,展示了如何使用 Thymeleaf 显示和操作数据。
控制器 :
@Controller
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/products")
public String listProducts(Model model) {
List products = productService.findAll();
model.addAttribute("products", products);
return "products";
}
@PostMapping("/products")
public String searchProducts(@RequestParam("keyword") String keyword, Model model) {
List products = productService.searchByKeyword(keyword);
model.addAttribute("products", products);
return "products";
}
}
模板 (products.html) :
产品列表
产品列表
产品名称
价格
库存
操作
产品名称
价格
库存状态
详情
加入购物车
没有找到相关产品。
产品模型 :
public class Product {
private Long id;
private String name;
private Double price;
private Integer stock;
// Getters and setters
}
产品服务 :
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public List findAll() {
return productRepository.findAll();
}
public List searchByKeyword(String keyword) {
return productRepository.findByKeyword(keyword);
}
}
产品仓库 :
@Repository
public interface ProductRepository extends JpaRepository {
@Query("SELECT p FROM Product p WHERE p.name LIKE %:keyword% OR p.description LIKE %:keyword%")
List findByKeyword(@Param("keyword") String keyword);
}
案例三:博客文章管理 以下是一个博客文章管理页面的完整示例,展示了如何使用 Thymeleaf 创建复杂的管理界面。
控制器 :
@Controller
@RequestMapping("/admin/blogs")
public class BlogController {
@Autowired
private BlogService blogService;
@GetMapping
public String listBlogs(Model model) {
List blogs = blogService.findAll();
model.addAttribute("blogs", blogs);
return "admin/blogs/list";
}
@GetMapping("/{id}")
public String viewBlog(@PathVariable("id") Long id, Model model) {
Blog blog = blogService.findById(id);
model.addAttribute("blog", blog);
return "admin/blogs/view";
}
@GetMapping("/new")
public String newBlog(Model model) {
model.addAttribute("blog", new Blog());
return "admin/blogs/form";
}
@PostMapping
public String saveBlog(@Valid Blog blog, BindingResult result, Model model) {
if (result.hasErrors()) {
return "admin/blogs/form";
}
blogService.save(blog);
return "redirect:/admin/blogs";
}
@GetMapping("/{id}/edit")
public String editBlog(@PathVariable("id") Long id, Model model) {
Blog blog = blogService.findById(id);
model.addAttribute("blog", blog);
return "admin/blogs/form";
}
@PostMapping("/{id}")
public String updateBlog(@PathVariable("id") Long id, @Valid Blog blog, BindingResult result, Model model) {
if (result.hasErrors()) {
return "admin/blogs/form";
}
blog.setId(id);
blogService.save(blog);
return "redirect:/admin/blogs";
}
@PostMapping("/{id}/delete")
public String deleteBlog(@PathVariable("id") Long id) {
blogService.delete(id);
return "redirect:/admin/blogs";
}
}
列表模板 (list.html) :
博客列表
博客列表
新建博客
标题
作者
创建时间
操作
博客标题
作者
创建时间
查看
编辑
表单模板 (form.html) :
博客表单
博客表单
查看模板 (view.html) :
博客详情
博客标题
博客内容
分类: 分类
博客模型 :
public class Blog {
private Long id;
private String title;
private String author;
private String content;
private Category category;
private Date createdAt;
// Getters and setters
}
分类模型 :
public class Category {
private Long id;
private String name;
// Getters and setters
}
博客服务 :
@Service
public class BlogService {
@Autowired
private BlogRepository blogRepository;
public List findAll() {
return blogRepository.findAll();
}
public Blog findById(Long id) {
return blogRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Blog not found"));
}
public void save(Blog blog) {
blogRepository.save(blog);
}
public void delete(Long id) {
Blog blog = findById(id);
blogRepository.delete(blog);
}
}
博客仓库 :
@Repository
public interface BlogRepository extends JpaRepository {
}
