Thymeleaf入门教程
liuian 2024-12-11 15:45 67 浏览
1. Thymeleaf 简介
Thymeleaf 是新一代 Java 模板引擎,与 Velocity、FreeMarker 等传统 Java 模板引擎不同,Thymeleaf 支持 HTML 原型,其文件后缀为“.html”,因此它可以直接被浏览器打开,此时浏览器会忽略未定义的 Thymeleaf 标签属性,展示 thymeleaf 模板的静态页面效果;当通过 Web 应用程序访问时,Thymeleaf 会动态地替换掉静态内容,使页面动态显示。
html<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--th:text 为 Thymeleaf 属性,用于在展示文本-->
<h1 th:text="欢迎您来到Thymeleaf">欢迎您访问静态页面 HTML</h1>
</body>
</html>
当直接使用浏览器打开时,浏览器展示结果如下。
欢迎您访问静态页面HTML
当通过 Web 应用程序访问时,浏览器展示结果如下。
欢迎您来到Thymeleaf
Thymeleaf 的特点:
- 动静结合:Thymeleaf 既可以直接使用浏览器打开,查看页面的静态效果,也可以通过 Web 应用程序进行访问,查看动态页面效果。
- 开箱即用:Thymeleaf 提供了 Spring 标准方言以及一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
- 多方言支持:它提供了 Thymeleaf 标准和 Spring 标准两种方言,可以直接套用模板实现 JSTL、 OGNL 表达式;必要时,开发人员也可以扩展和创建自定义的方言。
- 与 SpringBoot 完美整合:SpringBoot 为 Thymeleaf 提供了的默认配置,并且还为 Thymeleaf 设置了视图解析器,因此 Thymeleaf 可以与 Spring Boot 完美整合。
2. Thymeleaf 语法规则
在使用 Thymeleaf 之前,首先要在页面的 html 标签中声明名称空间,示例代码如下。
htmlxmlns:th="http://www.thymeleaf.org"
在 html 标签中声明此名称空间,可避免编辑器出现 html 验证错误,但这一步并非必须进行的,即使我们不声明该命名空间,也不影响 Thymeleaf 的使用。
2.1 标准表达式语法
2.1.1 变量表达式
使用${}包裹的表达式被称为变量表达式,该表达式具有以下功能:
- 获取对象的属性和方法 使用变量表达式可以获取对象的属性和方法,例如,获取 person 对象的 lastName 属性,表达式形式如下:
- html
- ${person.lastName}
- 使用内置的基本对象 使用变量表达式还可以使用内置基本对象,获取内置对象的属性,调用内置对象的方法。 Thymeleaf 中常用的内置基本对象如下: 例如,我们通过以下 2 种形式,都可以获取到 session 对象中的 map 属性:
- html
- ${#session.getAttribute('map')} ${session.map}
- 使用内置的工具对象
- 例如,我们可以使用内置工具对象 strings 的 equals 方法,来判断字符串与对象的某个属性是否相等,代码如下。
- html
- ${#strings.equals('编程帮',name)}
2.1.2 选择变量表达式
选择变量表达式与变量表达式功能基本一致,只是在变量表达式的基础上增加了与 th:object 的配合使用。当使用 th:object 存储一个对象后,我们可以在其后代中使用选择变量表达式(*{...})获取该对象中的属性,其中,“*”即代表该对象。
html<div th:object="${session.user}" >
<p th:text="*{fisrtName}">firstname</p>
</div>
th:object 用于存储一个临时变量,该变量只在该标签及其后代中有效,在后面的内容“th 属性”中我详细介绍。
2.1.3 链接表达式
不管是静态资源的引用,还是 form 表单的请求,凡是链接都可以用链接表达式 (@{...})。
链接表达式的形式结构如下:
- 无参请求:@{/xxx}
- 有参请求:@{/xxx(k1=v1,k2=v2)}
例如使用链接表达式引入 css 样式表,代码如下。
html<link href="asserts/css/signin.css" th:href="@{/asserts/css/signin.css}" rel="stylesheet">
2.1.4 国际化表达式
消息表达式一般用于国际化的场景。结构如下。
htmlth:text="#{msg}"
注意:此处了解即可,我们会在后面的章节中详细介绍。
2.1.5 片段引用表达式
片段引用表达式用于在模板页面中引用其他的模板片段,该表达式支持以下 2 中语法结构:
- 推荐:~{templatename::fragmentname}
- 支持:~{templatename::#id}
以上语法结构说明如下:
- templatename:模版名,Thymeleaf 会根据模版名解析完整路径:/resources/templates/templatename.html,要注意文件的路径。
- fragmentname:片段名,Thymeleaf 通过 th:fragment 声明定义代码块,即:th:fragment="fragmentname"
- id:HTML 的 id 选择器,使用时要在前面加上 # 号,不支持 class 选择器。
2.2 th 属性
Thymeleaf 还提供了大量的 th 属性,这些属性可以直接在 HTML 标签中使用,其中常用 th 属性及其示例如下表。
属性 | 描述 | 示例 |
th:id | 替换 HTML 的 id 属性 | <input id="html-id" th:id="thymeleaf-id" /> |
th:text | 文本替换,转义特殊字符 | <h1 th:text="hello,bianchengbang" >hello</h1> |
th:untext | 文本替换,文本替换,不转义特殊字符 | <div th:utext="'<h1>欢迎来到编程帮!</h1>'" >欢迎你</div> |
th:object | 在父标签选择对象,子标签使用 *{…} 选择表达式选取值。没有选择对象,那子标签使用选择表达式和 ${…} 变量表达式是一样的效果。同时即使选择了对象,子标签仍然可以使用变量表达式。 | <div th:object="${session.user}" > <p th:text="*{fisrtName}">firstname</p> </div> |
th:value | 替换 value 属性 | <input th:value = "${user.name}" /> |
th:with | 局部变量赋值运算 | <div th:with="isEvens = ${prodStat.count}%2 == 0" th:text="${isEvens}"></div> |
th:style | 设置样式 | <div th:style="'color:#F00; font-weight:bold'">编程帮 www.biancheng.net</div> |
th:onclick | 点击事件 | <td th:onclick = "'getInfo()'"></td> |
th:each | 遍历,支持 Iterable、Map、数组等。 | <table> <tr th:each="m:${session.map}"> <td th:text="${m.getKey()}"></td> <td th:text="${m.getValue()}"></td> </tr></table> |
th:if | 根据条件判断是否需要展示此标签 | <a th:if ="${userId == collect.userId}"> |
th:unless | 和 th:if 判断相反,满足条件时不显示 | <div th:unless="${m.getKey()=='name'}" ></div> |
th:switch | 与 Java 的 switch case语句类似通常与 th:case 配合使用,根据不同的条件展示不同的内容 | <div th:switch="${name}"> <span th:case="a">编程帮</span> <span th:case="b">www.biancheng.net</span></div> |
th:fragment | 模板布局,类似 JSP 的 tag,用来定义一段被引用或包含的模板片段 | <footer th:fragment="footer">插入的内容</footer> |
th:insert | 布局标签;将使用 th:fragment 属性指定的模板片段(包含标签)插入到当前标签中 | <div th:insert="commons/bar::footer"></div> |
th:replace | 布局标签;使用 th:fragment 属性指定的模板片段(包含标签)替换当前整个标签 | <div th:replace="commons/bar::footer"></div> |
th:selected | select 选择框选中 | <select> <option>---</option> <option th:selected="${name=='a'}"> 编程帮 </option> <option th:selected="${name=='b'}"> www.biancheng.net </option></select> |
th:src | 替换 HTML 中的 src 属性 | <img th:src="@{/asserts/img/bootstrap-solid.svg}" src="asserts/img/bootstrap-solid.svg" /> |
th:inline | 内联属性;该属性有 text、none、javascript 三种取值,在 <script> 标签中使用时,js 代码中可以获取到后台传递页面的对象。 | <script type="text/javascript" th:inline="javascript"> var name = /*[[${name}]]*/ ianchengbang'; alert(name)</script> |
th:action | 替换表单提交地址 | <form th:action="@{/user/login}" th:method="post"></form> |
3. Thymeleaf 公共页面抽取
在 Web 项目中,通常会存在一些公共页面片段(重复代码),例如头部导航栏、侧边菜单栏和公共的 js css 等。我们一般会把这些公共页面片段抽取出来,存放在一个独立的页面中,然后再由其他页面根据需要进行引用,这样可以消除代码重复,使页面更加简洁。
3.1 抽取公共页面
Thymeleaf 作为一种优雅且高度可维护的模板引擎,同样支持公共页面的抽取和引用。我们可以将公共页面片段抽取出来,存放到一个独立的页面中,并使用 Thymeleaf 提供的 th:fragment 属性为这些抽取出来的公共页面片段命名。 示例 1 将公共页面片段抽取出来,存放在 commons.html 中,代码如下。
html<div th:fragment="fragment-name" id="fragment-id">
<span>公共页面片段</span>
</div>
3.2 引用公共页面
在 Thymeleaf 中,我们可以使用以下 3 个属性,将公共页面片段引入到当前页面中。
- th:insert:将代码块片段整个插入到使用了 th:insert 属性的 HTML 标签中;
- th:replace:将代码块片段整个替换使用了 th:replace 属性的 HTML 标签中;
- th:include:将代码块片段包含的内容插入到使用了 th:include 属性的 HTML 标签中。
使用上 3 个属性引入页面片段,都可以通过以下 2 种方式实现。
- ~{templatename::selector}:模板名::选择器
- ~{templatename::fragmentname}:模板名::片段名
通常情况下,
{} 可以省略,其行内写法为 [[{...}]] 或 [({...})],其中 [[{...}]] 会转义特殊字符,[(~{...})] 则不会转义特殊字符。
示例 2
- 在页面 fragment.html 中引入 commons.html 中声明的页面片段,可以通过以下方式实现。
html<!--th:insert 片段名引入-->
<div th:insert="commons::fragment-name"></div>
<!--th:insert id 选择器引入-->
<div th:insert="commons::#fragment-id"></div>
------------------------------------------------
<!--th:replace 片段名引入-->
<div th:replace="commons::fragment-name"></div>
<!--th:replace id 选择器引入-->
<div th:replace="commons::#fragment-id"></div>
------------------------------------------------
<!--th:include 片段名引入-->
<div th:include="commons::fragment-name"></div>
<!--th:include id 选择器引入-->
<div th:include="commons::#fragment-id"></div>
- 启动 Spring Boot,使用浏览器访问 fragment.html,查看源码,结果如下。
html<!--th:insert 片段名引入-->
<div>
<div id="fragment-id">
<span>公共页面片段</span>
</div>
</div>
<!--th:insert id 选择器引入-->
<div>
<div id="fragment-id">
<span>公共页面片段</span>
</div>
</div>
------------------------------------------------
<!--th:replace 片段名引入-->
<div id="fragment-id">
<span>公共页面片段</span>
</div>
<!--th:replace id 选择器引入-->
<div id="fragment-id">
<span>公共页面片段</span>
</div>
------------------------------------------------
<!--th:include 片段名引入-->
<div>
<span>公共页面片段</span>
</div>
<!--th:include id 选择器引入-->
<div>
<span>公共页面片段</span>
</div>
3.3 传递参数
Thymeleaf 在抽取和引入公共页面片段时,还可以进行参数传递,大致步骤如下: 1.传入参数; 2.使用参数。
3.3.1 传入参数
引用公共页面片段时,我们可以通过以下 2 种方式,将参数传入到被引用的页面片段中: 模板名::选择器名或片段名(参数1=参数值1,参数2=参数值2) 模板名::选择器名或片段名(参数值1,参数值2)
注:若传入参数较少时,一般采用第二种方式,直接将参数值传入页面片段中; 若参数较多时,建议使用第一种方式,明确指定参数名和参数值,。
示例代码如下:
java<!--th:insert 片段名引入-->
<div th:insert="commons::fragment-name(var1='insert-name',var2='insert-name2')"></div>
<!--th:insert id 选择器引入-->
<div th:insert="commons::#fragment-id(var1='insert-id',var2='insert-id2')"></div>
------------------------------------------------
<!--th:replace 片段名引入-->
<div th:replace="commons::fragment-name(var1='replace-name',var2='replace-name2')"></div>
<!--th:replace id 选择器引入-->
<div th:replace="commons::#fragment-id(var1='replace-id',var2='replace-id2')"></div>
------------------------------------------------
<!--th:include 片段名引入-->
<div th:include="commons::fragment-name(var1='include-name',var2='include-name2')"></div>
<!--th:include id 选择器引入-->
<div th:include="commons::#fragment-id(var1='include-id',var2='include-id2')"></div>
3.3.2 使用参数
在声明页面片段时,我们可以在片段中声明并使用这些参数,例如:
java<!--使用 var1 和 var2 声明传入的参数,并在该片段中直接使用这些参数 -->
<div th:fragment="fragment-name(var1,var2)" id="fragment-id">
<p th:text="'参数1:'+${var1} + '-------------------参数2:' + ${var2}">...</p>
</div>
启动 Spring Boot,使用浏览器访问 fragment.html,结果如下图。
相关推荐
- eino v0.4.5版本深度解析:接口类型处理优化与错误机制全面升级
-
近日,eino框架发布了v0.4.5版本,该版本在错误处理、类型安全、流处理机制以及代理配置注释等方面进行了多项优化与修复。本次更新共包含6个提交,涉及10个文件的修改,由2位贡献者共同完成。本文将详...
- SpringBoot异常处理_springboot异常注解
-
在SpringBoot中,异常处理是构建健壮、可维护Web应用的关键部分。良好的异常处理机制可以统一返回格式、提升用户体验、便于调试和监控。以下是SpringBoot中处理异常的完整指...
- Jenkins运维之路(Jenkins流水线改造Day02-1-容器项目)
-
这回对线上容器服务器的流水线进行了一定的改造来满足目前线上的需求,还是会将所有的自动化脚本都放置到代码库中统一管理,我感觉一章不一定写的完,所以先给标题加了个-1,话不多说开干1.本次流水线的流程设计...
- 告别宕机!零基础搭建服务器监控告警系统!小白也能学会!
-
前言本文将带你从零开始,一步步搭建一个完整的服务器指标监控与邮件告警系统,使用的技术栈均为业界主流、稳定可靠的开源工具:Prometheus:云原生时代的监控王者,擅长指标采集与告警规则定义Node_...
- httprunner实战接口测试笔记,拿走不谢
-
每天进步一点点,关注我们哦,每天分享测试技术文章本文章出自【码同学软件测试】码同学公众号:自动化软件测试码同学抖音号:小码哥聊软件测试01开始安装跟创建项目pipinstallhttprunne...
- 基于JMeter的性能压测平台实现_jmeter压测方案
-
这篇文章已经是两年前写的,短短两年时间,JMeter开源应用技术的发展已经是翻天覆地,最初由github开源项目zyanycall/stressTestPlatform形成的这款测试工具也开始慢...
- 12K+ Star!新一代的开源持续测试工具!
-
大家好,我是Java陈序员。在企业软件研发的持续交付流程中,测试环节往往是影响效率的关键瓶颈,用例管理混乱、接口调试复杂、团队协作不畅、与DevOps流程脱节等问题都能影响软件交付。今天,给大家...
- Spring Boot3 中分库分表之后如何合并查询
-
在当今互联网应用飞速发展的时代,数据量呈爆发式增长。对于互联网软件开发人员而言,如何高效管理和查询海量数据成为了一项关键挑战。分库分表技术应运而生,它能有效缓解单库单表数据量过大带来的性能瓶颈。而在...
- 离线在docker镜像方式部署ragflow0.17.2
-
经常项目上会出现不能连外网的情况,要怎么使用ragflow镜像部署呢,这里提供详细的步骤。1、下载基础镜像根据docker-compose-base.yml及docker-compose.yml中的i...
- 看,教你手写一个最简单的SpringBoot Starter
-
何为Starter?想必大家都使用过SpringBoot,在SpringBoot项目中,使用最多的无非就是各种各样的Starter了。那何为Starter呢?你可以理解为一个可拔插式...
- 《群星stellaris》军事基地跳出怎么办?解决方法一览
-
《群星stellaris》军事基地跳出情况有些小伙伴出现过这种情况,究竟该怎么解决呢?玩家“gmjdadk”分享的自己的解决方法,看看能不能解决。我用英文原版、德语、法语和俄语四个版本对比了一下,结果...
- 数据开发工具dbt手拉手教程-03.定义数据源模型
-
本章节介绍在dbt项目中,如何定义数据源模型。定义并引入数据源通过Extract和Load方式加载到仓库中的数据,可以使用dbt中的sources组件进行定义和描述。通过在dbt中将这些数据集(表)声...
- docker compose 常用命令手册_docker-compose init
-
以下是DockerCompose常用命令手册,按生命周期管理、服务运维、构建配置、扩缩容、调试工具分类,附带参数解析、示例和关键说明,覆盖多容器编排核心场景:一、生命周期管理(核心命令...
- RagFlow与DeepSeek R1本地知识库搭建详细步骤及代码实现
-
一、环境准备硬件要求独立显卡(建议NVIDIAGPU,8GB显存以上)内存16GB以上,推荐32GB(处理大规模文档时更高效)SSD硬盘(加速文档解析与检索)软件安装bash#必装组件Docker...
- Docker Compose 配置更新指南_docker-compose配置
-
高效管理容器配置变更的最佳实践方法重启范围保留数据卷适用场景docker-composeup-d变更的服务常规配置更新--force-recreate指定/所有服务强制重建down→up流程...
- 一周热门
-
-
【验证码逆向专栏】vaptcha 手势验证码逆向分析
-
Python实现人事自动打卡,再也不会被批评
-
Psutil + Flask + Pyecharts + Bootstrap 开发动态可视化系统监控
-
一个解决支持HTML/CSS/JS网页转PDF(高质量)的终极解决方案
-
再见Swagger UI 国人开源了一款超好用的 API 文档生成框架,真香
-
网页转成pdf文件的经验分享 网页转成pdf文件的经验分享怎么弄
-
C++ std::vector 简介
-
飞牛OS入门安装遇到问题,如何解决?
-
系统C盘清理:微信PC端文件清理,扩大C盘可用空间步骤
-
10款高性能NAS丨双十一必看,轻松搞定虚拟机、Docker、软路由
-
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)