Spring Boot + Thymeleaf 框架详解与案例实战
Spring Boot 和 Thymeleaf 是 Java Web 开发中常用的组合,Spring Boot 提供了快速构建应用的框架,而 Thymeleaf 是一个现代化的模板引擎,适合与 Spring Boot 集成用于渲染动态 HTML 页面。本文将详细介绍 Spring Boot + Thymeleaf 的核心概念,并通过一个完整的案例展示如何使用它们开发 Web 应用。
一、Spring Boot 简介
Spring Boot 是基于 Spring 框架的快速开发工具,旨在简化 Spring 应用的初始搭建和开发过程。它的核心特性包括:
- 自动配置:根据依赖自动配置 Spring 应用。
- 嵌入式服务器:内置 Tomcat、Jetty 或 Undertow,无需单独部署。
- 生产就绪功能:如指标、健康检查、外部化配置等。
- 无代码生成和 XML 配置:通过注解和约定优于配置的方式开发。
二、Thymeleaf 简介
Thymeleaf 是一个用于 Web 和独立环境的现代服务器端 Java 模板引擎,能够处理 HTML、XML、JavaScript、CSS 甚至纯文本。它的主要特点包括:
- 自然模板:模板文件可以直接用浏览器打开,无需启动应用。
- 与 Spring 集成:支持 Spring MVC 的
Model
和@ModelAttribute
。 - 国际化支持:内置国际化功能。
- 表达式语言:支持条件判断、循环、变量操作等。
三、Spring Boot + Thymeleaf 集成步骤
3.1 创建 Spring Boot 项目
使用 Spring Initializr 生成项目:
- Project:Maven Project
- Language:Java
- Spring Boot:最新稳定版(如 3.1.x)
- Dependencies:
- Spring Web
- Thymeleaf
生成项目后,解压并导入到 IDE(如 IntelliJ IDEA 或 Eclipse)。
3.2 项目结构
src/ | |
├── main/ | |
│ ├── java/com/example/demo/ | |
│ │ ├── controller/ # 控制器层 | |
│ │ ├── model/ # 数据模型 | |
│ │ └── DemoApplication.java # 主启动类 | |
│ └── resources/ | |
│ ├── static/ # 静态资源(CSS、JS、图片) | |
│ ├── templates/ # Thymeleaf 模板文件(HTML) | |
│ └── application.properties # 配置文件 |
3.3 配置 Thymeleaf
在 application.properties
中配置 Thymeleaf(可选,默认配置已足够):
properties
# Thymeleaf 配置 | |
spring.thymeleaf.cache=false # 开发时关闭缓存,修改模板后立即生效 | |
spring.thymeleaf.prefix=classpath:/templates/ # 模板文件路径 | |
spring.thymeleaf.suffix=.html # 模板文件后缀 |
四、案例:用户信息管理系统
4.1 需求说明
开发一个简单的用户信息管理系统,支持:
- 显示用户列表。
- 添加新用户。
- 删除用户。
4.2 实现步骤
4.2.1 创建数据模型
在 model/User.java
中定义用户类:
java
package com.example.demo.model; | |
public class User { | |
private Long id; | |
private String name; | |
private String email; | |
// 构造方法、Getter 和 Setter | |
public User() {} | |
public User(Long id, String name, String email) { | |
this.id = id; | |
this.name = name; | |
this.email = email; | |
} | |
public Long getId() { | |
return id; | |
} | |
public void setId(Long id) { | |
this.id = id; | |
} | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public String getEmail() { | |
return email; | |
} | |
public void setEmail(String email) { | |
this.email = email; | |
} | |
} |
4.2.2 创建控制器
在 controller/UserController.java
中定义控制器:
java
package com.example.demo.controller; | |
import com.example.demo.model.User; | |
import org.springframework.stereotype.Controller; | |
import org.springframework.ui.Model; | |
import org.springframework.web.bind.annotation.*; | |
import java.util.ArrayList; | |
import java.util.List; | |
@Controller | |
@RequestMapping("/users") | |
public class UserController { | |
// 模拟数据库 | |
private List<User> users = new ArrayList<>(); | |
{ | |
users.add(new User(1L, "Alice", "alice@example.com")); | |
users.add(new User(2L, "Bob", "bob@example.com")); | |
} | |
// 显示用户列表 | |
@GetMapping | |
public String listUsers(Model model) { | |
model.addAttribute("users", users); | |
return "user/list"; // 对应 templates/user/list.html | |
} | |
// 显示添加用户表单 | |
@GetMapping("/new") | |
public String showAddUserForm(Model model) { | |
model.addAttribute("user", new User()); | |
return "user/form"; // 对应 templates/user/form.html | |
} | |
// 处理添加用户请求 | |
@PostMapping | |
public String addUser(@ModelAttribute User user) { | |
// 模拟生成 ID | |
long nextId = users.stream().mapToLong(User::getId).max().orElse(0L) + 1; | |
user.setId(nextId); | |
users.add(user); | |
return "redirect:/users"; // 重定向到用户列表 | |
} | |
// 删除用户 | |
@GetMapping("/delete/{id}") | |
public String deleteUser(@PathVariable Long id) { | |
users.removeIf(user -> user.getId().equals(id)); | |
return "redirect:/users"; | |
} | |
} |
4.2.3 创建 Thymeleaf 模板
用户列表页面 (templates/user/list.html
)
html
<!DOCTYPE html> | |
<html xmlns:th="http://www.thymeleaf.org"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>用户列表</title> | |
<link rel="stylesheet" th:href="@{/css/style.css}"> | |
</head> | |
<body> | |
<h1>用户列表</h1> | |
<a th:href="@{/users/new}" class="btn">添加用户</a> | |
<table> | |
<thead> | |
<tr> | |
<th>ID</th> | |
<th>姓名</th> | |
<th>邮箱</th> | |
<th>操作</th> | |
</tr> | |
</thead> | |
<tbody> | |
<tr th:each="user : ${users}"> | |
<td th:text="${user.id}"></td> | |
<td th:text="${user.name}"></td> | |
<td th:text="${user.email}"></td> | |
<td> | |
<a th:href="@{/users/delete/{id}(id=${user.id})}" class="btn btn-danger">删除</a> | |
</td> | |
</tr> | |
</tbody> | |
</table> | |
</body> | |
</html> |
用户表单页面 (templates/user/form.html
)
html
<!DOCTYPE html> | |
<html xmlns:th="http://www.thymeleaf.org"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>添加用户</title> | |
<link rel="stylesheet" th:href="@{/css/style.css}"> | |
</head> | |
<body> | |
<h1>添加用户</h1> | |
<form th:action="@{/users}" th:object="${user}" method="post"> | |
<div> | |
<label for="name">姓名:</label> | |
<input type="text" id="name" th:field="*{name}" required> | |
</div> | |
<div> | |
<label for="email">邮箱:</label> | |
<input type="email" id="email" th:field="*{email}" required> | |
</div> | |
<button type="submit">提交</button> | |
<a th:href="@{/users}" class="btn">取消</a> | |
</form> | |
</body> | |
</html> |
静态资源 (static/css/style.css
)
css
body { | |
font-family: Arial, sans-serif; | |
margin: 20px; | |
} | |
table { | |
width: 100%; | |
border-collapse: collapse; | |
margin-top: 20px; | |
} | |
table, th, td { | |
border: 1px solid #ddd; | |
} | |
th, td { | |
padding: 8px; | |
text-align: left; | |
} | |
th { | |
background-color: #f2f2f2; | |
} | |
.btn { | |
display: inline-block; | |
padding: 8px 16px; | |
background-color: #4CAF50; | |
color: white; | |
text-decoration: none; | |
border-radius: 4px; | |
margin-right: 10px; | |
} | |
.btn-danger { | |
background-color: #f44336; | |
} |
4.2.4 启动应用
运行 DemoApplication.java
:
java
package com.example.demo; | |
import org.springframework.boot.SpringApplication; | |
import org.springframework.boot.autoconfigure.SpringBootApplication; | |
@SpringBootApplication | |
public class DemoApplication { | |
public static void main(String[] args) { | |
SpringApplication.run(DemoApplication.class, args); | |
} | |
} |
4.2.5 访问应用
启动后,访问以下 URL:
- 用户列表:
http://localhost:8080/users
- 添加用户:
http://localhost:8080/users/new
五、Thymeleaf 常用语法
5.1 变量表达式 ${...}
用于访问 Model 中的属性:
html
<p th:text="${user.name}"></p> |
5.2 选择表达式 *{...}
用于访问当前上下文对象的属性(通常与 th:object
配合使用):
html
<form th:object="${user}"> | |
<input type="text" th:field="*{name}"> | |
</form> |
5.3 链接表达式 @{...}
用于生成 URL:
html
<a th:href="@{/users}">用户列表</a> | |
<a th:href="@{/users/delete/{id}(id=${user.id})}">删除</a> |
5.4 条件判断 th:if
和 th:unless
html
<div th:if="${user.active}">活跃用户</div> | |
<div th:unless="${user.active}">非活跃用户</div> |
5.5 循环 th:each
html
<ul> | |
<li th:each="item : ${items}" th:text="${item}"></li> | |
</ul> |
5.6 片段引用 th:replace
和 th:insert
将公共部分(如页眉、页脚)提取到单独的模板中:
html
<!-- 公共模板 templates/layout/header.html --> | |
<div th:fragment="header"> | |
<h1>网站标题</h1> | |
</div> | |
<!-- 引用公共模板 --> | |
<div th:replace="layout/header :: header"></div> |
六、总结
6.1 Spring Boot + Thymeleaf 的优势
- 快速开发:Spring Boot 的自动配置和 Thymeleaf 的自然模板特性减少了开发时间。
- 前后端分离:Thymeleaf 模板可以直接在浏览器中预览,适合前后端协作。
- 易于维护:清晰的模板结构和强大的表达式语言使代码易于维护。
6.2 适用场景
- 传统 Web 应用开发。
- 需要快速搭建的原型或小型项目。
- 需要前后端协作的团队。
6.3 扩展建议
- 集成 Spring Security:实现用户认证和授权。
- 使用 Thymeleaf 布局:通过
th:fragment
和th:replace
实现页面复用。 - 前后端分离:如果需要更复杂的前端交互,可以结合 Vue.js 或 React.js,Thymeleaf 仅用于渲染初始页面。
七、完整代码示例
你可以在 GitHub 上创建一个仓库,将上述代码上传,方便后续参考和扩展。
通过本文的介绍和案例,你已经掌握了 Spring Boot + Thymeleaf 的基本用法。如果需要进一步深入,可以参考以下资源:
如果有任何问题或需要进一步的帮助,欢迎在评论区留言!