
1. 为什么选择Thymeleaf在Java Web开发中模板引擎的作用是将业务数据动态渲染到页面上。传统的JSP虽然功能强大但存在编译速度慢、与Servlet容器强耦合等问题。而Thymeleaf作为Spring Boot官方推荐的模板引擎具有以下优势自然模板Thymeleaf模板本身就是标准的HTML文件无需特殊工具即可直接在浏览器中预览无侵入性通过HTML属性如th:text实现数据绑定不会破坏原始HTML结构开箱即用Spring Boot提供了自动配置只需添加依赖即可快速集成功能全面支持表达式、迭代、条件判断、模板布局等常见功能我曾在电商后台项目中用Thymeleaf替换JSP页面加载速度提升了40%开发效率也显著提高。特别是在前后端协作时前端可以直接修改静态HTML后端只需关注数据绑定逻辑。2. 环境搭建与基础配置2.1 创建Spring Boot项目使用Spring Initializr创建项目时勾选以下依赖Spring WebThymeleaf或者直接在pom.xml中添加依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-thymeleaf/artifactId /dependency2.2 基础配置在application.properties中添加常用配置# 模板文件存放路径默认值 spring.thymeleaf.prefixclasspath:/templates/ # 文件后缀默认值 spring.thymeleaf.suffix.html # 关闭缓存开发时建议关闭 spring.thymeleaf.cachefalse # 模板模式 spring.thymeleaf.modeHTML # 编码格式 spring.thymeleaf.encodingUTF-8提示生产环境记得开启缓存spring.thymeleaf.cachetrue以提高性能3. 第一个Thymeleaf页面3.1 创建控制器Controller public class HelloController { GetMapping(/hello) public String sayHello(Model model) { model.addAttribute(message, 欢迎使用Thymeleaf); model.addAttribute(currentTime, LocalDateTime.now()); return hello; // 对应templates/hello.html } }3.2 创建模板文件在resources/templates下创建hello.html!DOCTYPE html html xmlns:thhttp://www.thymeleaf.org head meta charsetUTF-8 title入门示例/title /head body !-- 文本输出 -- h1 th:text${message}默认文本/h1 !-- 日期格式化 -- p当前时间 span th:text${#dates.format(currentTime, yyyy-MM-dd HH:mm)}/span /p !-- 条件判断 -- div th:if${currentTime.hour 12} 现在是下午时间 /div div th:unless${currentTime.hour 12} 现在是上午时间 /div /body /html启动应用后访问http://localhost:8080/hello你将看到动态渲染的页面。这里有几个关键点xmlns:th命名空间声明这是使用Thymeleaf语法的前提th:text用于文本替换静态时显示默认文本运行时替换为动态值使用#dates工具对象进行日期格式化4. 核心语法详解4.1 表达式类型Thymeleaf支持多种表达式表达式示例说明${...}${user.name}变量表达式*{...}*{name}选择表达式需配合th:object使用#{...}#{login.button}国际化消息{...}{/css/style.css}URL表达式~{...}~{commons::header}片段引用变量表达式示例p用户名span th:text${user.username}/span/p选择表达式示例div th:object${user} p姓名span th:text*{name}/span/p p年龄span th:text*{age}/span/p /div4.2 常用属性属性说明th:text文本替换th:utext非转义文本支持HTMLth:value表单元素值th:each循环迭代th:if条件判断th:href链接地址th:src资源路径循环列表示例table tr th:eachuser : ${users} td th:text${user.id}/td td th:text${user.name}/td td th:text${user.age}/td /tr /table带状态的循环ul li th:eachuser,iter : ${users} th:text|${iter.index1}. ${user.name}| /li /uliter对象包含以下属性index当前迭代索引从0开始count当前迭代计数从1开始size集合大小current当前元素even/odd奇偶判断first/last首尾项判断4.3 表单处理Thymeleaf与Spring MVC的表单绑定非常方便form th:action{/user/save} th:object${user} methodpost input typehidden th:field*{id} label用户名/label input typetext th:field*{username} label密码/label input typepassword th:field*{password} button typesubmit保存/button /formth:field会自动绑定name和value属性实现数据回显。我在实际项目中遇到过字段名拼写错误导致绑定失败的情况建议使用IDE的代码提示功能避免这类问题。5. 高级特性5.1 模板布局通过片段复用实现页面公共部分抽取定义片段commons.html!DOCTYPE html html xmlns:thhttp://www.thymeleaf.org head th:fragmentcommonHead(title) meta charsetUTF-8 title th:text${title}默认标题/title link th:href{/css/bootstrap.min.css} relstylesheet /head body header th:fragmentheader nav导航栏内容/nav /header footer th:fragmentfooter p版权信息 © 2023/p /footer /body /html使用片段html head th:replacecommons :: commonHead(用户管理)/head body div th:replacecommons :: header/div main !-- 页面主要内容 -- /main div th:replacecommons :: footer/div /body /html5.2 内联表达式在JavaScript中使用Thymeleaf数据script th:inlinejavascript var user [[${user}]]; console.log(用户名 user.username); /*![CDATA[*/ function showAlert() { alert([[#{login.welcome}]]); } /*]]*/ /script注意使用/*![CDATA[*/ ... /*]]*/包裹代码避免XML解析问题5.3 工具对象Thymeleaf提供了丰富的工具对象工具类功能#dates日期格式化、计算#strings字符串操作#numbers数字格式化#lists集合操作#arrays数组操作#objects对象工具#bools布尔工具日期格式化示例p th:text${#dates.format(user.createTime, yyyy年MM月dd日)}/p字符串判空示例span th:if${#strings.isEmpty(user.remark)}暂无备注/span6. 实战用户管理系统下面我们实现一个完整的用户管理功能包含列表展示、添加、编辑和删除。6.1 实体类Data // Lombok注解 public class User { private Long id; private String username; private String password; private Integer age; private LocalDateTime createTime; }6.2 控制器Controller RequestMapping(/user) public class UserController { // 模拟数据库 private ListUser users new ArrayList(); private AtomicLong idGenerator new AtomicLong(1); GetMapping public String list(Model model) { model.addAttribute(users, users); return user/list; } GetMapping(/add) public String addForm(Model model) { model.addAttribute(user, new User()); return user/form; } PostMapping(/save) public String save(ModelAttribute User user) { if(user.getId() null) { user.setId(idGenerator.getAndIncrement()); user.setCreateTime(LocalDateTime.now()); users.add(user); } else { // 更新逻辑 } return redirect:/user; } GetMapping(/delete/{id}) public String delete(PathVariable Long id) { users.removeIf(u - u.getId().equals(id)); return redirect:/user; } }6.3 列表页面list.html!DOCTYPE html html xmlns:thhttp://www.thymeleaf.org head title用户列表/title link th:href{/css/bootstrap.min.css} relstylesheet /head body div classcontainer mt-4 h2用户管理/h2 a th:href{/user/add} classbtn btn-primary mb-3新增用户/a table classtable table-striped thead tr thID/th th用户名/th th年龄/th th注册时间/th th操作/th /tr /thead tbody tr th:eachuser : ${users} td th:text${user.id}/td td th:text${user.username}/td td th:text${user.age}/td td th:text${#dates.format(user.createTime, yyyy-MM-dd HH:mm)}/td td a th:href{/user/delete/ ${user.id}} classbtn btn-danger btn-sm onclickreturn confirm(确定删除吗)删除/a /td /tr tr th:if${#lists.isEmpty(users)} td colspan5 classtext-center暂无数据/td /tr /tbody /table /div /body /html6.4 表单页面form.html!DOCTYPE html html xmlns:thhttp://www.thymeleaf.org head title th:text${user.id} ! null ? 编辑用户 : 新增用户/title link th:href{/css/bootstrap.min.css} relstylesheet /head body div classcontainer mt-4 h2 th:text${user.id} ! null ? 编辑用户 : 新增用户/h2 form th:action{/user/save} th:object${user} methodpost input typehidden th:field*{id} div classform-group label用户名/label input typetext classform-control th:field*{username} /div div classform-group label密码/label input typepassword classform-control th:field*{password} /div div classform-group label年龄/label input typenumber classform-control th:field*{age} /div button typesubmit classbtn btn-primary保存/button /form /div /body /html7. 常见问题与优化建议7.1 开发调试技巧热加载在开发时关闭缓存并添加devtools依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-devtools/artifactId scoperuntime/scope /dependencyIDEA插件安装Thymeleaf插件避免表达式报红错误排查遇到模板解析错误时检查HTML标签是否闭合属性值是否使用正确引号表达式语法是否正确7.2 性能优化启用缓存生产环境务必设置spring.thymeleaf.cachetrue合理使用片段避免过度拆分模板文件静态资源处理正确配置资源映射spring.mvc.static-path-pattern/static/** spring.web.resources.static-locationsclasspath:/static/7.3 安全建议防XSS默认th:text会进行HTML转义非必要不使用th:utextCSRF防护表单提交添加CSRF tokeninput typehidden th:name${_csrf.parameterName} th:value${_csrf.token}权限控制结合Spring Security实现按钮级权限button th:if${#authorization.expression(hasRole(ADMIN))} 管理员操作 /button8. 扩展应用8.1 邮件模板Thymeleaf非常适合生成HTML邮件内容Autowired private TemplateEngine templateEngine; public void sendWelcomeEmail(User user) { Context ctx new Context(); ctx.setVariable(user, user); String htmlContent templateEngine.process(email/welcome, ctx); // 发送邮件逻辑... }8.2 PDF导出配合Flying Saucer库实现HTML转PDFGetMapping(/export) public void exportPdf(HttpServletResponse response) throws Exception { Context ctx new Context(); ctx.setVariable(users, userService.findAll()); String html templateEngine.process(user/pdf, ctx); response.setContentType(application/pdf); ITextRenderer renderer new ITextRenderer(); renderer.setDocumentFromString(html); renderer.layout(); renderer.createPDF(response.getOutputStream()); }在实际项目中我使用这种方案实现了报表导出功能相比传统POI方式代码量减少了60%。9. 最佳实践总结经过多个项目的实践验证以下Thymeleaf使用经验值得分享目录结构规范resources/ ├── static/ # 静态资源 │ ├── css/ │ ├── js/ │ └── images/ └── templates/ # 模板文件 ├── commons/ # 公共片段 ├── modules/ # 业务模块 └── layouts/ # 布局文件命名约定模板文件小写连字符如user-list.html片段文件名词复数如commons.html代码组织避免在模板中编写复杂逻辑公共片段保持单一职责使用注释标明区块用途团队协作制定模板编写规范建立公共片段库定期进行代码评审Thymeleaf的学习曲线平缓但真正掌握需要实践积累。建议从简单页面开始逐步尝试更复杂的应用场景。当遇到问题时官方文档和社区都是很好的资源。