本文目录导读:

- 项目结构
- Maven依赖 (pom.xml)
- 配置文件 (application.yml)
- 主类 (ThymeleafApplication.java)
- 模型类
- Service层
- Controller层
- Thymeleaf模板
我来为您提供一个完整的Spring Boot整合Thymeleaf的详细案例。
项目结构
spring-boot-thymeleaf-demo/
├── src/main/java/com/example/thymeleaf/
│ ├── ThymeleafApplication.java
│ ├── controller/
│ │ ├── UserController.java
│ │ └── PageController.java
│ ├── model/
│ │ ├── User.java
│ │ └── Product.java
│ └── service/
│ └── UserService.java
├── src/main/resources/
│ ├── static/
│ │ ├── css/
│ │ │ └── style.css
│ │ └── js/
│ │ └── main.js
│ ├── templates/
│ │ ├── index.html
│ │ ├── user/
│ │ │ ├── list.html
│ │ │ └── detail.html
│ │ └── fragments/
│ │ ├── header.html
│ │ └── footer.html
│ └── application.yml
└── pom.xml
Maven依赖 (pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.14</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>spring-boot-thymeleaf-demo</artifactId>
<version>1.0.0</version>
<name>spring-boot-thymeleaf-demo</name>
<description>Spring Boot整合Thymeleaf示例</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Thymeleaf extras(可选,用于更高级功能) -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
<!-- Lombok(可选,用于简化代码) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Boot DevTools(开发时热部署) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置文件 (application.yml)
spring:
application:
name: spring-boot-thymeleaf-demo
thymeleaf:
# 模板缓存(开发环境设置为false)
cache: false
# 模板编码
encoding: UTF-8
# 模板模式
mode: HTML
# 模板前缀
prefix: classpath:/templates/
# 模板后缀
suffix: .html
# 检查模板是否存在
check-template: true
# 检查模板位置
check-template-location: true
# 是否启用模板引擎
enabled: true
server:
port: 8080
主类 (ThymeleafApplication.java)
package com.example.thymeleaf;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ThymeleafApplication {
public static void main(String[] args) {
SpringApplication.run(ThymeleafApplication.class, args);
}
}
模型类
User.java
package com.example.thymeleaf.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
private String name;
private String email;
private Integer age;
private String role;
private Boolean active;
private LocalDateTime createdAt;
private List<String> hobbies;
public User(Long id, String name, String email, Integer age, String role, Boolean active) {
this.id = id;
this.name = name;
this.email = email;
this.age = age;
this.role = role;
this.active = active;
this.createdAt = LocalDateTime.now();
this.hobbies = Arrays.asList("读书", "运动", "编程");
}
}
Product.java
package com.example.thymeleaf.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
private Long id;
private String name;
private BigDecimal price;
private Integer stock;
private String category;
}
Service层
UserService.java
package com.example.thymeleaf.service;
import com.example.thymeleaf.model.User;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
public class UserService {
private List<User> users = new ArrayList<>();
@PostConstruct
public void init() {
User user1 = new User(1L, "张三", "zhangsan@example.com", 25, "管理员", true);
user1.setCreatedAt(LocalDateTime.now().minusDays(10));
user1.setHobbies(Arrays.asList("编程", "阅读", "游泳"));
User user2 = new User(2L, "李四", "lisi@example.com", 30, "用户", true);
user2.setCreatedAt(LocalDateTime.now().minusDays(5));
user2.setHobbies(Arrays.asList("旅游", "摄影"));
User user3 = new User(3L, "王五", "wangwu@example.com", 28, "用户", false);
user3.setCreatedAt(LocalDateTime.now().minusDays(15));
user3.setHobbies(Arrays.asList("游戏", "电影", "美食"));
User user4 = new User(4L, "赵六", "zhaoliu@example.com", 35, "用户", true);
user4.setCreatedAt(LocalDateTime.now().minusDays(1));
user4.setHobbies(Arrays.asList("音乐", "舞蹈"));
users.addAll(Arrays.asList(user1, user2, user3, user4));
}
public List<User> getAllUsers() {
return users;
}
public Optional<User> getUserById(Long id) {
return users.stream()
.filter(user -> user.getId().equals(id))
.findFirst();
}
public List<User> searchUsers(String keyword) {
if (keyword == null || keyword.isEmpty()) {
return users;
}
return users.stream()
.filter(user -> user.getName().contains(keyword) ||
user.getEmail().contains(keyword))
.collect(Collectors.toList());
}
public void addUser(User user) {
user.setId((long) (users.size() + 1));
user.setCreatedAt(LocalDateTime.now());
users.add(user);
}
}
Controller层
PageController.java
package com.example.thymeleaf.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
public class PageController {
@GetMapping("/")
public String index(Model model) {
model.addAttribute("title", "Spring Boot Thymeleaf 示例");
model.addAttribute("message", "欢迎使用 Thymeleaf 模板引擎");
model.addAttribute("currentYear", java.time.Year.now().getValue());
return "index";
}
@GetMapping("/fragments")
public String fragments(Model model) {
model.addAttribute("title", "Thymeleaf 片段示例");
return "fragments-demo";
}
@GetMapping("/expressions")
public String expressions(Model model) {
// 字符串
model.addAttribute("str1", "Hello");
model.addAttribute("str2", "Thymeleaf");
// 数字
model.addAttribute("num1", 100);
model.addAttribute("num2", 20);
// 条件
model.addAttribute("age", 25);
model.addAttribute("isAdmin", true);
// 空值测试
model.addAttribute("nullValue", null);
model.addAttribute("emptyString", "");
// 列表
List<String> fruits = Arrays.asList("苹果", "香蕉", "橙子", "葡萄");
model.addAttribute("fruits", fruits);
// Map
Map<String, String> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
model.addAttribute("map", map);
return "expressions";
}
}
UserController.java
package com.example.thymeleaf.controller;
import com.example.thymeleaf.model.User;
import com.example.thymeleaf.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
@Controller
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public String list(@RequestParam(required = false) String keyword, Model model) {
model.addAttribute("users", userService.searchUsers(keyword));
model.addAttribute("keyword", keyword);
model.addAttribute("totalUsers", userService.getAllUsers().size());
model.addAttribute("activeUsers", userService.getAllUsers().stream()
.filter(User::getActive).count());
return "user/list";
}
@GetMapping("/{id}")
public String detail(@PathVariable Long id, Model model) {
userService.getUserById(id).ifPresent(user ->
model.addAttribute("user", user));
return "user/detail";
}
@GetMapping("/add")
public String addForm(Model model) {
model.addAttribute("user", new User());
return "user/add";
}
@PostMapping("/add")
public String addUser(@ModelAttribute User user) {
userService.addUser(user);
return "redirect:/users";
}
@GetMapping("/conditional")
public String conditionalDemo(Model model) {
List<User> users = userService.getAllUsers();
model.addAttribute("users", users);
// 单个用户对象用于条件判断
model.addAttribute("adminUser", users.stream()
.findFirst().orElse(null));
return "user/conditional";
}
@GetMapping("/iteration")
public String iterationDemo(Model model) {
model.addAttribute("users", userService.getAllUsers());
return "user/iteration";
}
}
Thymeleaf模板
templates/index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">th:text="${title}">首页</title>
<link rel="stylesheet" th:href="@{/css/style.css}">
</head>
<body>
<div th:replace="~{fragments/header :: header}"></div>
<main class="container">
<h1 th:text="${title}">Thymeleaf标题</h1>
<p th:text="${message}">消息内容</p>
<div class="card">
<h2>Thymeleaf 功能列表</h2>
<ul>
<li><a th:href="@{/expressions}">表达式示例</a></li>
<li><a th:href="@{/users}">用户列表(迭代与条件判断)</a></li>
<li><a th:href="@{/fragments}">片段引用示例</a></li>
<li><a th:href="@{/users/conditional}">条件判断示例</a></li>
<li><a th:href="@{/users/iteration}">循环遍历示例</a></li>
<li><a th:href="@{/users/add}">添加用户(表单处理)</a></li>
</ul>
</div>
<footer>
<p>© <span th:text="${currentYear}">年份</span> Spring Boot Thymeleaf Demo</p>
</footer>
</main>
<div th:replace="~{fragments/footer :: footer}"></div>
</body>
</html>
templates/user/list.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">用户列表</title>
<link rel="stylesheet" th:href="@{/css/style.css}">
</head>
<body>
<div th:replace="~{fragments/header :: header}"></div>
<main class="container">
<h1>用户列表</h1>
<!-- 统计信息 -->
<div class="stats">
<div class="stat-item">
<span>总用户数:</span>
<strong th:text="${totalUsers}">0</strong>
</div>
<div class="stat-item">
<span>活跃用户:</span>
<strong th:text="${activeUsers}">0</strong>
</div>
</div>
<!-- 搜索表单 -->
<form th:action="@{/users}" method="get" class="search-form">
<input type="text" name="keyword" th:value="${keyword}" placeholder="搜索用户名或邮箱...">
<button type="submit">搜索</button>
<a th:href="@{/users}" th:if="${keyword}">清除搜索</a>
</form>
<!-- 用户表格 -->
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>邮箱</th>
<th>年龄</th>
<th>角色</th>
<th>状态</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!-- 空数据判断 -->
<tr th:if="${#lists.isEmpty(users)}">
<td colspan="8" class="text-center">没有找到用户</td>
</tr>
<tr th:each="user, stat : ${users}" th:class="${stat.odd} ? 'odd' : 'even'">
<td th:text="${user.id}">1</td>
<td>
<a th:href="@{/users/{id}(id=${user.id})}"
th:text="${user.name}">姓名</a>
</td>
<td th:text="${user.email}">邮箱</td>
<td th:text="${user.age}">年龄</td>
<td>
<span th:if="${user.role == '管理员'}" class="badge badge-warning"
th:text="${user.role}">角色</span>
<span th:unless="${user.role == '管理员'}" class="badge badge-info"
th:text="${user.role}">角色</span>
</td>
<td>
<span th:if="${user.active}" class="status-active">● 活跃</span>
<span th:unless="${user.active}" class="status-inactive">○ 禁用</span>
</td>
<td th:text="${#temporals.format(user.createdAt, 'yyyy-MM-dd HH:mm')}">创建时间</td>
<td>
<a th:href="@{/users/{id}(id=${user.id})}" class="btn btn-small">详情</a>
</td>
</tr>
</tbody>
</table>
</main>
<div th:replace="~{fragments/footer :: footer}"></div>
</body>
</html>
templates/user/detail.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">用户详情 - <span th:text="${user.name}">姓名</span></title>
<link rel="stylesheet" th:href="@{/css/style.css}">
</head>
<body>
<div th:replace="~{fragments/header :: header}"></div>
<main class="container">
<h1>用户详情</h1>
<div th:if="${user}" class="user-detail">
<h2 th:text="${user.name}">姓名</h2>
<div class="detail-grid">
<div class="detail-item">
<label>ID:</label>
<span th:text="${user.id}">1</span>
</div>
<div class="detail-item">
<label>邮箱:</label>
<span th:text="${user.email}">email@example.com</span>
</div>
<div class="detail-item">
<label>年龄:</label>
<span th:text="${user.age}">25</span>
</div>
<div class="detail-item">
<label>角色:</label>
<span th:text="${user.role}">用户</span>
</div>
<div class="detail-item">
<label>状态:</label>
<span th:if="${user.active}" class="status-active">活跃</span>
<span th:unless="${user.active}" class="status-inactive">禁用</span>
</div>
<div class="detail-item">
<label>创建时间:</label>
<span th:text="${#temporals.format(user.createdAt, 'yyyy-MM-dd HH:mm')}">时间</span>
</div>
</div>
<!-- 爱好列表 -->
<div>
<h3>个人爱好</h3>
<ul>
<li th:each="hobby : ${user.hobbies}" th:text="${hobby}">爱好</li>
</ul>
</div>
<div class="actions">
<a th:href="@{/users}" class="btn">返回列表</a>
<a th:href="@{/users/add}" class="btn btn-primary">添加用户</a>
</div>
</div>
<div th:if="${user == null}" class="alert">
未找到该用户
</div>
</main>
<div th:replace="~{fragments/footer :: footer}"></div>
</body>
</html>
templates/user/add.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">添加用户</title>
<link rel="stylesheet" th:href="@{/css/style.css}">
</head>
<body>
<div th:replace="~{fragments/header :: header}"></div>
<main class="container">
<h1>添加用户</h1>
<form th:action="@{/users/add}" th:object="${user}" method="post" class="form">
<div class="form-group">
<label>姓名:</label>
<input type="text" th:field="*{name}" required>
</div>
<div class="form-group">
<label>邮箱:</label>
<input type="email" th:field="*{email}" required>
</div>
<div class="form-group">
<label>年龄:</label>
<input type="number" th:field="*{age}" min="1" max="120" required>
</div>
<div class="form-group">
<label>角色:</label>
<select th:field="*{role}">
<option value="用户">用户</option>
<option value="管理员">管理员</option>
<option value="审计员">审计员</option>
</select>
</div>
<div class="form-group">
<label>状态:</label>
<input type="checkbox" th:field="*{active}">
<span>启用</span>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">保存</button>
<a th:href="@{/users}" class="btn">取消</a>
</div>
</form>
</main>
<div th:replace="~{fragments/footer :: footer}"></div>
</body>
</html>
templates/fragments/header.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">Header</title>
</head>
<body>
<header th:fragment="header" class="header">
<nav class="nav">
<div class="nav-brand">
<a th:href="@{/}">
<span class="brand-icon">🚀</span>
Spring Boot Demo
</a>
</div>
<div class="nav-links">
<a th:href="@{/}" th:classappend="${currentPage == 'home'} ? 'active'">首页</a>
<a th:href="@{/users}" th:classappend="${currentPage == 'users'} ? 'active'">用户管理</a>
<a th:href="@{/expressions}">表达式</a>
<a th:href="@{/fragments}">片段</a>
</div>
</nav>
<div th:if="${#authorization == null}" class="navbar-user">
<span>欢迎访问</span>
</div>
</header>
</body>
</html>
templates/fragments/footer.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">Footer</title>
</head>
<body>
<footer th:fragment="footer" class="footer">
<div class="container">
<p>© <span th:text="${#temporals.year(#temporals.createNow())}">年份</span>
Spring Boot Thymeleaf Demo. All rights reserved.</p>
</div>
</footer>
</body>
</html>
templates/expressions.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">表达式示例</title>
<link rel="stylesheet" th:href="@{/css/style.css}">
</head>
<body>
<div th:replace="~{fragments/header :: header}"></div>
<main class="container">
<h1>Thymeleaf 表达式示例</h1>
<!-- 变量表达式 -->
<div class="card">
<h2>变量表达式 ${...}</h2>
<p>字符串1:<span th:text="${str1}">str1</span></p>
<p>字符串2:<span th:text="${str2}">str2</span></p>
<p>数字1:<span th:text="${num1}">100</span></p>
<p>数字2:<span th:text="${num2}">20</span></p>
</div>
<!-- 选择表达式 -->
<div class="card">
<h2>选择表达式 *{...} 结合 th:object</h2>
<div th:object="${user != null} ? ${user} : null">
<!-- 这里使用 *{} 访问 user 的属性 -->
<p>名称:<span th:text="*{name}">名称</span></p>
</div>
<div th:with="user=${users != null && !#lists.isEmpty(users)} ? ${users[0]} : null"
th:object="${user}">
<p>名称(通过object):<span th:text="*{name}">名称</span></p>
</div>
</div>
<!-- URL表达式 -->
<div class="card">
<h2>URL表达式 @{...}</h2>
<ul>
<li><a th:href="@{/}">首页</a></li>
<li><a th:href="@{/users}">用户列表</a></li>
<li><a th:href="@{/users/{id}(id=1)}">用户详情</a></li>
<li><a th:href="@{/users/page(p=0,s=10)}">带参数链接</a></li>
</ul>
</div>
<!-- 条件判断 -->
<div class="card">
<h2>条件运算</h2>
<p>三目运算:<span th:text="${age >= 18} ? '成年人' : '未成年人'">判断结果</span></p>
<p>空安全运算符 (?:):<span th:text="${nullValue ?: '默认值'}">默认值</span></p>
<p>判断空字符串:<span th:if="${#strings.isEmpty(emptyString)}">空字符串</span></p>
</div>
<!-- 内联表达式 -->
<div class="card">
<h2>内联表达式</h2>
<p th:inline="text">你好,[[${str1}]] [[${str2}]]!</p>
<p th:inline="css">[[${str1}]]</p>
</div>
<!-- 运算示例 -->
<div class="card">
<h2>数学运算</h2>
<p>加法:<span th:text="${num1} + ${num2}">结果</span></p>
<p>减法:<span th:text="${num1} - ${num2}">结果</span></p>
<p>乘法:<span th:text="${num1} * ${num2}">结果</span></p>
<p>除法:<span th:text="${num1} / ${num2}">结果</span></p>
<p>取模:<span th:text="${num1} % ${num2}">结果</span></p>
</div>
<!-- 列表操作 -->
<div class="card">
<h2>集合操作</h2>
<ul>
<li th:each="fruit, stat : ${fruits}"
th:with="fruitInfo=${fruit}">
<span th:text="${fruit}">水果</span>
<span th:text="'(' + ${stat.index} + ')'" th:if="${stat.first}">(第一个)</span>
<span th:text="'(' + ${stat.count} + ')'" th:unless="${stat.first}">(其他)</span>
</li>
</ul>
</div>
</main>
<div th:replace="~{fragments/footer :: footer}"></div>
</body>
</html>
templates/user/conditional.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">条件判断示例</title>
<link rel="stylesheet" th:href="@{/css/style.css}">
</head>
<body>
<div th:replace="~{fragments/header :: header}"></div>
<main class="container">
<h1>Thymeleaf 条件判断示例</h1>
<!-- 基本条件判断 -->
<div class="card">
<h2>基本 if/unless</h2>
<div th:if="${adminUser != null}">
<p>管理员信息:<span th:text="${adminUser.name}">名称</span></p>
</div>
<div th:unless="${adminUser == null}">
<p>当前有管理员用户</p>
</div>
</div>
<!-- switch-case -->
<div class="card">
<h2>switch-case 示例</h2>
<div th:switch="${adminUser.role}">
<p th:case="'管理员'" th:text="'角色:' + ${adminUser.role}">管理员</p>
<p th:case="'用户'" th:text="'角色:' + ${adminUser.role}">用户</p>
<p th:case="*" th:text="'未知角色:' + ${adminUser.role}">其他角色</p>
</div>
</div>
<!-- 列表条件判断 -->
<div class="card">
<h2>结合循环的条件判断</h2>
<table class="table">
<thead>
<tr>
<th>姓名</th>
<th>角色</th>
<th>状态</th>
<th>年龄判断</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${users}">
<td th:text="${user.name}">姓名</td>
<td>
<span th:switch="${user.role}">
<span th:case="'管理员'" class="badge badge-danger" th:text="${user.role}">管理员</span>
<span th:case="'用户'" class="badge badge-info" th:text="${user.role}">用户</span>
<span th:case="*" th:text="${user.role}">其他</span>
</span>
</td>
<td>
<span th:if="${user.active}" class="text-success">✅ 激活</span>
<span th:if="${!user.active}" class="text-danger">❌ 禁止</span>
</td>
<td>
<span th:if="${user.age >= 30}" th:text="'30岁以上的用户'">>=30</span>
<span th:if="${user.age >= 25 && user.age < 30}" th:text="'25-29岁'">25-29</span>
<span th:if="${user.age < 25}" th:text="'25岁以下'"><25</span>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 空值判断 -->
<div class="card">
<h2>空值判断</h2>
<p th:if="${#lists.isEmpty(users)}">用户列表为空</p>
<p th:if="${!#lists.isEmpty(users)}">用户列表不为空</p>
</div>
</main>
<div th:replace="~{fragments/footer :: footer}"></div>
</body>
</html>
templates/user/iteration.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">循环遍历示例</title>
<link rel="stylesheet" th:href="@{/css/style.css}">
</head>
<body>
<div th:replace="~{fragments/header :: header}"></div>
<main class="container">
<h1>Thymeleaf 循环遍历示例</h1>
<!-- 基本循环 -->
<div class="card">
<h2>基本循环遍历</h2>
<h3>用户列表:</h3>
<ul>
<li th:each="user : ${users}"
th:text="${user.name} + ' - ' + ${user.email}">
用户信息
</li>
</ul>
</div>
<!-- 带状态的循环 -->
<div class="card">
<h2>带循环状态的遍历</h2>
<ul>
<li th:each="user, stat : ${users}">
<div class="user-item">
<span class="index" th:text="'#' + ${stat.index}">索引</span>
<span th:text="${user.name}">姓名</span>
<span class="badge"
th:if="${stat.first}"
th:text="'(第一个)'">第一个</span>
<span class="badge"
th:if="${stat.last}"
th:text="'(最后一个)'">最后一个</span>
<span class="badge badge-odd"
th:if="${stat.odd}"
th:text="'(奇数')">奇数</span>
<span class="badge badge-even"
th:if="${stat.even}"
th:text="'(偶数)'">偶数</span>
<span th:text="'大小:' + ${stat.size}">大小</span>
</div>
</li>
</ul>
</div>
<!-- 循环属性访问 -->
<div class="card">
<h2>搭配条件和状态的操作</h2>
<table class="table">
<thead>
<tr>
<th>#</th>
<th>姓名</th>
<th>角色</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr th:each="user, rowStat : ${users}"
th:class="${rowStat.odd} ? 'row-odd' : 'row-even'">
<td th:text="${rowStat.count}">序号</td>
<td th:text="${user.name}">姓名</td>
<td>
<span th:text="${user.role}">角色</span>
<span th:if="${user.role == '管理员'}" class="badge">⭐ 管理员</span>
</td>
<td>
<span th:text="${user.active ? '活跃' : '禁止'}">状态</span>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 嵌套循环 -->
<div class="card">
<h2>嵌套循环示例</h2>
<div th:each="user : ${users}">
<strong th:text="${user.name} + ' 的爱好:'">爱好</strong>
<ul>
<li th:each="hobby : ${user.hobbies}" th:text="${hobby}">爱好</li>
</ul>
<hr