编译软件:IntelliJ IDEA 2019.2.4 x64
操作系统:win10 x64 位 家庭版
服务器软件:apache-tomcat-8.5.27
目录
- 一. 什么是Thymeleaf?
- 二. MVC
- 2.1 为什么需要MVC?
- 2.2 MVC是什么?
- 2.3 MVC和三层架构之间的关系及工作流程
- 三. Thymeleaf的工作原理
- 四. Thymeleaf的优势
- 五. Thymeleaf的准备知识
- 5.1 物理视图
- 5.2 逻辑视图
- 六. 如何编写第一个Thymeleaf的程序?
- 七.Thymeleaf的基本语法
- 7.1 th名称空间
- 7.2 修改标签的文本值(双标签)
- 7.3 修改标签的属性值(单标签和双标签)
- 7.4 解析URL地址
- 7.5 获得域对象中的数据
- 7.5.1 获取应用域对象中的数据
- 7.5.2 获取会话域对象中的数据(Httpsession session)
- 7.5.3 获取请求域对象中的数据(HttpservletRequest request)
- 7.6 获得请求参数
- 7.6.1 根据一个参数名获取一个参数值
- 7.6.2 根据一个参数名获取多个参数值
- 7.7 内置对象
- 7.7.1 基本内置对象
- 7.7.2 公共内置对象
- 7.8 OGNL( 对象-图导航语言)
- 7.8.1 简单对象
- 7.8.2 稍微复杂的对象
- 7.8.3 list集合(简单集合)
- 7.8.4 复杂集合(list集合存储对象)
- 7.8.5 复杂集合(map集合存储对象)
- 7.9 分支与迭代
- 7.9.1 分支,控制元素的是否显示
- 7.9.1.1 th:if 和 th:unless
- 7.9.1.2 th:switch和th:case
- 7.9.2 迭代(遍历循环)
- 7.9.2.1 简单数组迭代
- 7.9.2.2 复杂数组迭代
- 7.10 Thymeleaf包含其他模板文件
- 7.10.1 应用场景
- 7.10.2 操作步骤
- ①给公共的代码片段起个名字
- ②在其他页面根据名字引用
- a. th:replace
- b. th:insert
- c. th:include
- 7.10.3 综合案例
一. 什么是Thymeleaf?
Thymeleaf是一种用于Java web应用程序的服务器端模板引擎,可以将HTML、XML、JavaScript等静态文件与动态数据(如表单数据、数据库中的数据等)结合起来,在服务器端生成动态的Web页面。
简而言之,它的主要作用就是在静态页面上渲染显示动态数据
Thymeleaf的设计目标是使Web开发变得更加自然和可维护。相比于其他模板引擎,Thymeleaf提供了更好的语法支持和功能,例如标记优雅降级、敏捷布局、动态URL、等,因此它被广泛地应用于Spring框架的开发中。
二. MVC
2.1 为什么需要MVC?
- 提高代码的可维护性:MVC模式将应用程序分成三个互不干扰的部分,使代码更加清晰简洁,易于阅读和
- 支持程序的可扩展性和可重用性:MVC模式使得开发人员在修改应用程序时更加轻松自如,只需要修改特定的代码库即可,而不会影响到其他部门的代码。这种思路与基于组件或者服务的方法相似。
- 提升用户体验:MVC模式开发出来的应用程序中,UI
界面(视图)负责直接呈现数据给用户。同时,视图也不包含任何关于业务领域或者实体(模型)的信息。控制器分离了模型和视图,对用户请求进行处理并起到转发作用,使得界面更加优秀、交互式、快速响应让用户体验更好。
2.2 MVC是什么?
MVC,英文全称为Model-View-Controller(模型-视图-控制器),它是一种常用于软件工程中的设计模式
Model模型
: javaBean(User/Book等类)
View视图
: html+服务器的动态数据
什么叫服务器的动态数据?如下图所示
Controller控制器
: 在web阶段可以暂时将Servlet视为控制器
2.3 MVC和三层架构之间的关系及工作流程
MVC的架构关系及相应的工作流程图解如下所示:
工作流程:
当浏览器向服务器发起请求时,请求被Servlet(控制器)所接收,Servlet会根据请求的内容调用Service(业务逻辑层)去处理相应的业务需求,Service会根据业务需要,会调用DAO层去处理数据,DAO层连接数据库获取相应的数据,然后回传数据给Service,Service根据数据处理好业务需求,将结果回传给Servlet,Servlet将结果传给Thymeleaf,让它渲染页面,从而生成的view对象响应给浏览器。
三. Thymeleaf的工作原理
原理:
从上节中的MVC架构工作流程图中可知,当Servlet接收到service(业务层)给的结果的时候,首先是到视图层(Thymeleaf),将动态数据和HTML进行拼接,从而产生一个View对象(视图),将view对象展示在浏览器上(用户看到的就是有动态数据的网页)
四. Thymeleaf的优势
- SpringBoot官方推荐使用的视图模板技术,和SpringBoot完美整合
- 不经过服务器运算仍然可以直接查看原始值,对前端工程师更友好
五. Thymeleaf的准备知识
5.1 物理视图
释义:
在Servlet中,将请求转发到一个HTML页面文件时,使用的完整的转发路径就是物理视图。
如下图所示:
上述图中所有的HTML页面都放在统一的目录(/WEB-INF/pages下),转发地址已经呈现出一种明显的规律。
将上面所有的物理视图抽取出来
/WEB-INF/pages/a.html
/WEB-INF/pages/abc.html
/WEB-INF/pages/admin.html
…
/WEB-INF/pages/index.html
/WEB-INF/pages/root.html
路径的开头都是
:/WEB-INF/pages/
路径的结尾都是
:.html
对此,路径的开头部分我们称之为视图前缀,路径的结尾部分我们称之为视图后缀
5.2 逻辑视图
物理视图:视图前缀+逻辑视图+视图后缀
逻辑视图
:控制页面跳转的位置
例如:物理视图/WEB-INF/pages/a.html ,/WEB-INF/pages/ 是视图前缀,.html是视图后缀,中间的部分a是逻辑视图,即在servlet中页面跳转的代码语句中要写的跳转位置
六. 如何编写第一个Thymeleaf的程序?
程序需求:
在index.html中访问HelloServlet,由HelloServlet传给Thymeleaf,使其将请求域中的数据(这是给服务器的数据)渲染至admin.html,响应给浏览器
步骤:
①导入Thymeleaf的jar包(共8个)
ps:和导入Beanutils的jar包步骤一致,请自行参阅我的这篇博客Servlet 之超详解【2023年最新版】 第九节的内容。
②在web.xml中配置全局初始化参数
<!--thymeleaf的前缀和后缀-->
<context-param>
<param-name>view-prefix</param-name>
<param-value>/pages/</param-value>
</context-param>
<context-param>
<param-name>view-suffix</param-name>
<param-value>.html</param-value>
</context-param>
③创建Thymeleaf的模板类ViewBaseServlet(直接复制下面的代码,粘贴到自己的项目下ViewBaseServlet中即可),该类是 HttpServlet 的子类,专门处理 Web 应用程序中视图页面的呈现。在后期使用框架时,该类会被取代。
代码演示如下:
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ViewBaseServlet extends HttpServlet {
private TemplateEngine templateEngine;
@Override
public void init() throws ServletException {//对servlet初始化的(对象创建后立刻初始化)
// 1.获取ServletContext对象
ServletContext servletContext = this.getServletContext();
// 2.创建Thymeleaf解析器对象
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
// 3.给解析器对象设置参数
// ①HTML是默认模式,明确设置是为了代码更容易理解
templateResolver.setTemplateMode(TemplateMode.HTML);
// ②设置前缀
String viewPrefix = servletContext.getInitParameter("view-prefix");
templateResolver.setPrefix(viewPrefix);
// ③设置后缀
String viewSuffix = servletContext.getInitParameter("view-suffix");
templateResolver.setSuffix(viewSuffix);
// ④设置缓存过期时间(毫秒)
templateResolver.setCacheTTLMs(60000L);
// ⑤设置是否缓存
templateResolver.setCacheable(true);
// ⑥设置服务器端编码方式
templateResolver.setCharacterEncoding("utf-8");
// 4.创建模板引擎对象
templateEngine = new TemplateEngine();
// 5.给模板引擎对象设置模板解析器
templateEngine.setTemplateResolver(templateResolver);
}
//就是Thymeleaf要进行渲染的方法,后期如果要进行页面的渲染的话,需要调用此方法
protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
// 1.设置响应体内容类型和字符集
resp.setContentType("text/html;charset=UTF-8");
// 2.创建WebContext对象
WebContext webContext = new WebContext(req, resp, getServletContext());
// 3.处理模板数据
templateEngine.process(templateName, webContext, resp.getWriter());
}
}
注意:ViewBaseServlet类里的
上述红框中的两个名称要和web.xml中全局初始化参数里设置的前缀名和后缀名保持一致,如下图所示
代码演示如下:
④创建HelloServlet(计划用HelloServlet传给thymeleaf去渲染网页,响应给客户端),并在web.xml中设置它的访问路径(/hello)
<!-- 设置访问HelloServlet的路径 /hello -->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>Servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
⑤创建index.html,在其中设置访问HelloServlet的超链接(计划访问后台的HelloServlet)
代码演示如下:
<a href="hello">点击访问HelloServlet</a>
⑥HelloServlet(要通过Thymeleafi进行页面的渲染,需要继承ViewBaseServlet)
代码演示如下:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloServlet extends ViewBaseServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("访问到了HelloServlet类中的doGet方法");
//这里假设业务已经处理好了,HelloServlet已经拿到了业务层传过来的结果
System.out.println("HelloServlet已经拿到了业务层的处理结果....");
//给响应(跳转至admin.html,并且msg的数据展示在网页上)
String msg="这是给服务器的数据";
//HelloServlet发送给Themeleaf,让它对页面进行渲染
//设置请求域中的共享数据
request.setAttribute("msg",msg);
this.processTemplate("admin",request,response);//Themeleaf的原理也是转发
}
}
⑦admin.html中需要写thymealf的渲染表达式
代码演示如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>admin页面</h1>
<h2 th:text="${msg}">这是服务器传过来的msg</h2>
</body>
</html>
注意:
要想使用thymealf的渲染表达式,就必须满足下面的两点要求
a.需要在html标签内设置th这个名称空间
示例代码如下:
<html lang="en"xmlns:th="http://www.thymeleaf.org">
b.在一个标签内通过添加属性的方式,让thymeleaf对该标签的标签体内容进行渲染(覆盖)
示例代码如下:
<h2 th:text="${msg}">放服务器传过来的msg数据</h2>
其中 $(msg},是从请求域内获得key值为msg的value值
七.Thymeleaf的基本语法
7.1 th名称空间
Thymeleaf所有的表达式都是通过属性的方式添加,th:表达式内容
添加的位置
:html标签的属性上
xmlns:th="http://www.thymeleaf.org"
7.2 修改标签的文本值(双标签)
语法:
th:text=“新值”
示例代码如下:
<h2 th:text="${msg}">放服务器传过来的msg数据</h2>
从请求域中获取key为msg的value值写入标签体中,原有的标签体内容会被覆盖
7.3 修改标签的属性值(单标签和双标签)
语法:
th:属性名=“新值”
示例代码如下::
<input type="text"value="这是原始值"th:value="${msg}">
7.4 解析URL地址
目的:
拿到urI中的上下文路径
语法:
@{/)
用途:
a.用在base标签上
示例代码如下:
<base href="" th:href="@{/}">
b.作为请求的路径
示例代码如下:
//写法一:
<a href="root?id=101&name=jack">Rootservlet01</a>
//写法二:
<a th:href="@{/root(id=101,name='jack',age=20)}">RootServlet02</a>
注意
这里存在一个问题,在以下两个html网页中,均设了使用thymeleaf去动态的获取上下文路径,使其可以被服务器将上下文路径渲染进base标签里。index网页中故意写错base标签中的href属性值(/day07_Thymeleaf_war_exploded123/),希望原来的错误href属性值可以被渲染为正确的路径(/day07_Thymeleaf_war_exploded/)
代码如下所示:
//index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<base href="/day07_Thymeleaf_war_exploded123/" th:href="@{/}">
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="hello">访问HelloServlet</a>
</body>
</html>
//admin.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<!-- 使用Themeleaf动态获取上下文路径 -->
<base href="" th:href="@{/}">
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>admin页面</h1>
<h2 th:text="${msg}">这是服务器传过来的msg</h2>
输入: <input type="text" value="这是原始值" th:value="${msg}"><br>
<a href=-""th:href="${msg}">a标签</a><br/>
上下文路径:<h2 th:text="@{/}"></h2>
<!-- 传递参数 -->
<a href="root?id=101&name=jack">Rootservlet01</a>
<a th:href="@{/root(id=101,name='jack',age=20)}">RootServlet02</a>
</body>
</html>
代码运行后测试结果显示渲染失败
原因分析:
index.html中的base标签写入的是错误的项目路径,即无法从正确的项目路径去访问HelloServlet,自然也就不会别Thymeleaf所渲染
结论:
如果你的网页想使用thymeleaf的渲染表达式的话,就必须经过Servlet然后在经过Thymeleaf进行渲染才可以,在实际开发中项目内所有的网页都需要thymeleaf渲染(都需要过Servlet在过Thymeleaf模板引擎)
解决方案:
让index.html去过一遍servlet,将index.html移动至本地动态web项目下web/pages里,这样它可以Thymeleaf所识别,新增一个ToindexServlet,并同时在web-xml中设置访问ToindexServlet的路径
代码演示如下:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ToindexServlet extends ViewBaseServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processTemplate("index",request,response);
}
}
在浏览器地址栏里键入 “http://localhost:8080/day07_Thymeleaf_war_exploded/index”,以get形式访问ToindexServlet,调用其doGet方法对index.html进行渲染
附注:
在上述代码不变的前提下,你在web.xml中修改访问ToindexServlet的路径为"/index.abc" or “/index.html” 。这种写法在web.xml中没有语法问题,但是你在浏览器网址栏输入
http://localhost:8080/day07_Thymeleaf_war_exploded/index.html
时才可以访问到index.html,看似是在项目路径下直接找的index.html,实则不然,这是项目路径下键入访问ToindexServlet的路径,由它再过Thymeleaf渲染Index.html,然后再呈现在浏览器中供客户观看
7.5 获得域对象中的数据
7.5.1 获取应用域对象中的数据
语法:
ServletContext application(一般取别名为application)
${appliaction.应用域中的key值)
示例代码如下:
//在HelloServlet中设置应用域的数据
ServletContext application = request.getServletContext();
application.setAttribute("applicationMsg","这是应用域中的applicationMsg数据");
//在admin.html中设置
<!-- 从应用域中获取applicationMsg给admin渲染 -->
<p th:text="${application.applicationMsg}"></p>
注意:
${appliaction.应用域中的key值)中的application和ServletContext对象的别名没有丝毫关系,它是写死的,无论ServletContext对象的别名叫什么。
7.5.2 获取会话域对象中的数据(Httpsession session)
语法:
${session.会话域中的key值}
7.5.3 获取请求域对象中的数据(HttpservletRequest request)
语法:
${请求域中的key}
ps:详细应用在上述的章节内容已有展示,故不作涉及
7.6 获得请求参数
语法:
${param.请求参数的key值)
7.6.1 根据一个参数名获取一个参数值
案例:根据在index.html里访问adminServlet的超链接添加i请求参数,由adminServlet传给thymeleaf渲染admin.html并响应给客户端,admin.html可以获取请求参数并显示
示例代码如下:
//在index.html中访问adminServlet的超链接中添加请求参数
<a href="admin?id=101&name=jack">访问adminServlet</a>
//在adminServlet中获取请求参数并让thymeleaf渲染admin.html,响应给浏览器
String id = request.getParameter("id");
System.out.println("id="+id);
String name = request.getParameter("name");
System.out.println("name="+name);
//调用Thymeleaf渲染admin.html并响应给客户端
this.processTemplate("admin",request,response);
<!-- admin.html获取请求参数 -->
获取请求参数:
<p th:text="${param.id}"></p>
<p th:text="${param.name}"></p>
7.6.2 根据一个参数名获取多个参数值
案例:根据在index.html里访问adminServlet的超链接添加i请求参数(同一个参数有多个残数值),由adminServlet传给thymeleaf渲染admin.html并响应给客户端,admin.html获取请求参数并显示
示例代码如下:
//在index.html中访问adminServlet的超链接中添加请求参数(同一个参数名有多个参数值)
<a href="admin?hobbys=basketball&hobbys=run&hobbys=rap">访问adminServlet</a>
//在adminServlet中获取一个参数名获取多个参数值,让thymeleaf渲染admin.html,响应给浏览器看
String[] hobbys = request.getParameterValues("hobbys");
System.out.println(Arrays.toString(hobbys));
<!-- 在admin.html中获取一个参数名获取多个参数值 --->
<p th:text="${param.hobbys}"></p>
<!-- 获取参数hobbys第一个参数值 -->
<p th:text="${param.hobbys[0]}"></p>
<!-- 获取参数hobbys第二个参数值 -->
<p th:text="${param.hobbys[1]}"></p>
<!-- 获取参数hobbys第三个参数值 -->
<p th:text="${param.hobbys[2]}"></p>
7.7 内置对象
释义:
可以直接使用的对象
7.7.1 基本内置对象
常用基本内置对象:
#request
:就是Servlet中的HttpServletRequest对象
#response
: 就是Servlet中的HttpServletResponse对象
#session
:就是Servlet中的Httpsession对象
#servletContext
: 就是Servlet中的ServletContext对象
案例:获取基本内置对象request的主机名
代码示例如下:
<!-- 获取基本内置对象request的主机名 -->
<p th:text="${#request.getServerName()}"></p>
<!-- 获取request的上下文路径 -->
<p th:text="${#request.getContextPath()}"></p>
.....
7.7.2 公共内置对象
#strings
:提供了很多对字符串操作的方法
#arrays
:提供了操作数组的常用方法
#lists
:提供了操作List集合的捞用方法
#sets
:提供了操作set集合的常用方法
#maps
:提供了操作Map集合的常用方法
案例:演示#strings,#arrays,#lists等部分常用公共内置对象的部分常用方法
//在请求域中添加一个数据(数组)
String[] names={"java","python","lua"};
request.setAttribute("names",names);
//在请求域中添加一个数据(list集合)
List<String> list=new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
request.setAttribute("list",list);
//调用Thymeleaf渲染root.html并响应给客户端
this.processTemplate("root",request,response);
<!--Arrays中的方法:-->
<p>Arrays中的方法:</p>
<p th:text="${#arrays.length(names)}"></p>
<p th:text="${#arrays.contains(names,'java')}"></p>
<!--List中的方法:-->
<p>list中的方法:</p>
<p th:text="${#lists.size(list)}"></p>
<p th:text="${#lists.isEmpty(list)}"></p>
7.8 OGNL( 对象-图导航语言)
对象-图的概念:
从根对象触发,通过特定的语法,逐层访问对象的各种属性。
简而言之:
就是将复杂的对象或者集合放在域对象内,Thymeleaf去获取这些数据在网页渲染
7.8.1 简单对象
案例:请求域内共享简单对象employee,rootServlet调用Thymeleaf渲染root.html并响应给客户端,root.html要显示动态数据(请求域内的简单对象employee)
代码示例如下:
//在rootServle中创建一个employee对象
Employee employee=new Employee(101,"张三",0,7800.0);
//请求域内共享一个简单对象
request.setAttribute("emp",employee);
//调用Thymeleaf渲染root.html并响应给客户端
this.processTemplate("root",request,response);
<p>简单对象:</p>
//emp整个对象
<p th:text="${emp}"></p>
//拿到对象emp内getId方法的返回值,下同
<p th:text="${emp.id}"></p>
<p th:text="${emp,name}"></p>
<p th:text="${emp.gender}"></p>
<p th:text="${emp.salary}"></p>
<p th:text="${emp.value}"></p>
7.8.2 稍微复杂的对象
案例:创建一个Employee002类,但是Employee02类中将一个Computer类作为自己的成员属性,在请求域内共享Employee002类的对象emp02,rootServlet调用Thymeleaf渲染root.html并响应给客户端,root.html要显示动态数据(请求域内的稍微复杂的对象emp02)
代码演示如下:
//创建Employee02类
public class Employee02 {
private Integer id;
private String name;
private Integer gender; //0 男 1 女
private Double salary;
private Computer computer;//对象关联
public Employee02(Integer id, String name, Integer gender, Double salary, Computer computer) {
this.id = id;
this.name = name;
this.gender = gender;
this.salary = salary;
this.computer = computer;
}
public Employee02() {
}
@Override
public String toString() {
return "Employee02{" +
"id=" + id +
", name='" + name + '\'' +
", gender=" + gender +
", salary=" + salary +
", computer=" + computer +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public Computer getComputer() {
return computer;
}
public void setComputer(Computer computer) {
this.computer = computer;
}
}
//创建Computer类
public class Computer {
private Integer id;
private String brand;
private double price;
public Computer() {
}
@Override
public String toString() {
return "Computer{" +
"id=" + id +
", brand='" + brand + '\'' +
", price=" + price +
'}';
}
public Computer(Integer id, String brand, double price) {
this.id = id;
this.brand = brand;
this.price = price;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
//在rootServle中创建一个employee02对象,渲染root.html后响应给客户端
Employee02 employee02=new Employee02(102,"熊二",1,34567d,new Computer(1,"联想",5000.0)
//请求域内共享一个稍微复杂的对象
request.setAttribute("emp02",employee02);
//调用Thymeleaf渲染root.html页面,响应给客户端
this.processTemplate("root",request,response);
//root.html获取请求域内emp02的相关属性
复杂对象:
<div th:text="${emp02}"></div>
<div th:text="${emp02.id}"></div>
<div th:text="${emp02.name}"></div>
<div th:text="${emp02.salary}"></div>
Kdiv th:text="${emp02.computer}"></div>
//调用的是emp02的电脑对象的getId()的返回值,下同
<div th:text="{emp02.computer.id}"></div>
<div th:text="$emp02.computer.brand}"></div>
<div th:text="$empe2.computer.price}"></div>
7.8.3 list集合(简单集合)
案例:在请求域内共享list集合,rootServlet调用Thymeleaf渲染root.html网页并响应给客户端,root.html要显示动态数据(请求域内的list集合)
代码演示如下:
//请求域内共享一个list集合
List<String> strs=new ArrayList<>();
strs.add("法外狂徒张三");
strs.add("法外狂徒李四");
strs.add("法外狂徒王五");
request.setAttribute("strs",strs);
//调用Thymeleaf渲染root.html并响应给客户端
this.processTemplate("root",request,response);
<p>list集合</p>
<p th:text="${strs}"></p>
//从请求域中获取list集合strs中下标为0的元素(第0+1个元素),下同
<p th:text="${strs[0]}"></p>
<p th:text="${strs[1]}"></p>
<p th:text="${strs[2]}"></p>
7.8.4 复杂集合(list集合存储对象)
案例:在请求域内共享复杂集合,集合内放三个Employee类的对象,rootServlet调用Thymeleaf渲染root.html,在root.html中要显示动态数据(请求域内的复杂集合)
代码示例如下:
//请求域内共享复杂集合
List<Employee> emps=new ArrayList<>();
emps.add(new Employee(101,"法外狂徒张三",0,500000.0));
emps.add(new Employee(102,"法外狂徒李四",1,68787.0));
emps.add(new Employee(103,"法外狂徒王五",1,198687.0));
request.setAttribute("emps",emps);
//调用Thymeleaf渲染root.html并响应给客户端
this.processTemplate("root",request,response);
<p>复杂集合</p>
<p th:text="${emps}"></p>
//获取集合中第一个对象的toString()的返回值
<p th:text="${emps[0]}"></p>
//获取集合中第一个对象的getId()的返回值
<p th:text="${emps[0].id}"></p>
//获取集合中第一个对象的getName()的返回值
<p th:text="${emps[0].name}"></p>
总结:
遇到对象就通过.属性名的方式去获取属性值(原理是调用get方法)
遇到Lst集合就通过下标获得到元素,如果元素是对象的话,还是回到上一句
7.8.5 复杂集合(map集合存储对象)
遇到Map集合就通过.key值的方式获得value值,如果value值是对象的话,遇到对象就通过.属性名的方式去获取属性值(原理是调用get方法)
案例:请求域内共享map集合,rootServlet调用Thymeleaf渲染root.html后响应给客户端,root.html要显示动态数据(请求域内的map集合)
代码示例如下:
//请求域内共享map集合
Map<String,Employee> map=new HashMap<>();
map.put("emp01",new Employee(101,"法外狂徒张三",0,500000.0));
map.put("emp02",new Employee(102,"法外狂徒李四",1,68787.0));
map.put("emp03",new Employee(103,"法外狂徒王五",1,198687.0));
request.setAttribute("map",map);
//调用Thymeleaf渲染root.html并响应给客户端
this.processTemplate("root",request,response);
<p>map集合</p>
<p th:text="${map}"></p>
//获取请求域内map集合的key值为emp01的value值
<p th:text="${map.emp01}"></p>
//获取请求域内map集合的key值为emp01的value值(对象)的getId()的返回值,下同
<p th:text="${map.emp01.id}"></p>
<p th:text="${map.emp02.name}"></p>
7.9 分支与迭代
7.9.1 分支,控制元素的是否显示
7.9.1.1 th:if 和 th:unless
语法:
th:if=""
: 值如果是true,元素就显示,值如果是false,就不显示
th:unless=""
: 和if反过来即可
案例:请求域内共享msg数据,调用Thymeleaf渲染页面并呼应给客户端,页面内使用h:if
或th:unless等渲染表达式去判断msg数据的长度
代码示例如下:
//在请求域中共享msg数据
request.setAttribute("msg","这是msg数据");
this.processTemplate("toif",request,response);
<p>th:if/unless</p>
<p th:text="${msg}"></p>
<p th:if="${#strings.length(msg)>5}">msg的数据长度大于5就显示</p>
<p th:if="${#strings.length(msg)<=5}">msg的数据长度小于或等于5就显示(1)</p>
<p th:unless="${#strings.length(msg)>5}">msg的数据长度小于或等于5就显示(2)</p>
<p th:unless="${not (#strings.length(msg)<=5)}">msg的数据长度小于或等于5就显示(3)</p>
7.9.1.2 th:switch和th:case
语法:
th:switch=“” (看switch中的数据和哪个case相同,有相同的就显示哪个)
th:case=“”
案例:请求域内共享msg数据,调用Thymeleaf渲染页面并呼应给客户端,页面内使用渲染表达式th:switch和th:case去判断msg数据的长度并显示结果
代码示例如下:
request.setAttribute("msg","这是msg");
this.processTemplate("toif",request,response);
<div th:switch="${#strings.length(msg)}">
<p th:case="1">长度为1</p>
<p th:case="2">长度为2</p>
<p th:case="3">长度为3</p>
<p th:case="4">长度为4</p>
<p th:case="5">长度为5</p>
</div>
7.9.2 迭代(遍历循环)
语法:
th:each=“obj,status:后台请求域中数据的key”
7.9.2.1 简单数组迭代
案例:请求域内共享一个list集合,调用thymeleaf渲染页面并响应给客户端,页面使用渲染表达式th:each去遍历请求域内list集合,在无序列表中显示
代码示例如下:
//请求域内共享一个list集合
List<String> strs=new ArrayList<>();
strs.add("法外狂徒张三");
strs.add("法外狂徒李四");
strs.add("法外狂徒王五");
request.setAttribute("strs",strs);
//迭代从请求域获得的list集合strs,并在无序列表中显示
<ul>
<li th:each="str,status :${strs}" th:text="${str}"></li>
7.9.2.2 复杂数组迭代
案例:请求域内共享一个list集合(装三个Employee类的对象),调用thymeleaf渲染页面并响应给客户端,页面使用渲染表达式th:each去遍历请求域内的list集合,在表格中显示
//请求域内共享复杂集合
List<Employee> emps=new ArrayList<>();
emps.add(new Employee(101,"法外狂徒张三",0,500000.0));
emps.add(new Employee(102,"法外狂徒李四",1,68787.0));
emps.add(new Employee(103,"法外狂徒王五",1,198687.0));
request.setAttribute("emps",emps);
<table border="1" width="300px">
<tr>
<td>序号</td>
<th>编号</th>
<th>姓名</th>
<th>性别</th>
<th>工资</th>
</tr>
<tr th:each="emp,status :${emps}">
<!-- status.index是从0开始的 -->
<td th:text="${status.index+1}"></td>
<td th:text="${emp.id}"></td>
<td th:text="${emp.name}"></td>
<!--
<td th:if="${emp.gender==0}" th:text="男"></td>
<td th:if="${emp.gender==1}" th:text="女"></td>
-->
<td th:text="${emp.gender==0?'男':'女'}"></td>
<td th:text="${emp.salary}"></td>
</tr>
</table>
7.10 Thymeleaf包含其他模板文件
7.10.1 应用场景
网页内公共代码片段的提取
公共代码片段是什么?
以腾讯视频 pc端为例,无论用户点击了什么频道,网站左侧的红框部分总是在那里,不会改变
7.10.2 操作步骤
①给公共的代码片段起个名字
使用th:fragment来给这个片段命名:
样例代码如下:
<div th:fragment="abc"id="header">公共头部信息</div>
我给上述公共的代码片段命名为abc
②在其他页面根据名字引用
有三种写法,但实现的最终效果都相同
a. th:replace
效果
:将引入标签整体替换目标标签
特点
:它不会保留页面自身的标签
样例代码如下:
<div th:replace="base::abc"id="ahcden "></div>
它使用了 th:replace 属性来替换当前标签,其值为 base::abc 表示使用名为 abc 的模板作为替换内容。其中 base 是模板的前缀或命名空间,通常与模板所在的文件夹或包名相关联。此外,这个标签也有一个 id 属性,其值为 “ahcden”。
用通俗的话来讲,找存放公共代码片段的页面(base.html),在页面里找名称为abc的公共代码片段,将公共代码片段所在的标签替换使用th:replace的标签
b. th:insert
效果
:将引入标签插入到目标标签内
特点
:它会保留页面自身的标签
样例代码如下:
<div th:insert="base::abc"id="aheader"></div>
找存放公共代码片段的页面(base.html),在页面里找名称为abc的公共代码片段,将公共代码片段所在的标签引入到使用th:replace的标签内
c. th:include
效果
: 将引入标签内容插入到目标标签内
特点
:它会去掉片段外层标记,同时保留页面自身标记
样例代码如下:
<div th:include="base::abc"id="aheader"></div>
找存放公共代码片段的页面(base.html),在页面里找名称为abc的公共代码片段,将公共代码片段所在的标签,去掉外层的标签,将内容引入到使用th:replace的标签内
7.10.3 综合案例
案例需求:创建四个html(a,b,c,abc),其中abc.html放前三个html都要用到的公共代码片段,剩余三个html的内容自定义。三个html均需在首页(index.html)通过超链接访问对应的servlet,再由各自对应的servlet穿给thymeleaf渲染对应的html文件,最后响应给客户端
1.创建三个html(a,b和c)对应的servlet(AServlet,BServlet和CServlet),并在web-xml中设置对应Servlet的访问路径
代码演示如下:
//在web-xml中设置对应Servlet的访问路径
<!-- 设置访问AServlet的路径 /a -->
<servlet>
<servlet-name>AServlet</servlet-name>
<servlet-class>Servlet.AServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AServlet</servlet-name>
<url-pattern>/a</url-pattern>
</servlet-mapping>
<!-- 设置访问BServlet的路径 /b -->
<servlet>
<servlet-name>BServlet</servlet-name>
<servlet-class>Servlet.BServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BServlet</servlet-name>
<url-pattern>/b</url-pattern>
</servlet-mapping>
<!-- 设置访问CServlet的路径 /c -->
<servlet>
<servlet-name>CServlet</servlet-name>
<servlet-class>Servlet.CServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CServlet</servlet-name>
<url-pattern>/c</url-pattern>
</servlet-mapping>
//创建a.html对应的AServlet
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AServlet extends ViewBaseServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processTemplate("a",request,response);
}
}
//创建b.html对应的BServlet
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class BServlet extends ViewBaseServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processTemplate("b",request,response);
}
}
//创建c.html对应的CServlet
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CServlet extends ViewBaseServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processTemplate("c",request,response);
}
}
2.在首页(index.html)中设立访问AServlet,BServlet,CServlet的超链接,并创建abc,a,b和c.html
//在index.html中设立访问AServlet,BServlet,CServlet的超链接
<a href="a">访问AServlet</a><br>
<a href="b">访问BServlet</a><br>
<a href="c">访问CServlet</a>
//创建abc.html,它存放的是a,b和c.html都要用的公共代码片段
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="@{/}">
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:fragment="base" id="header">公共头部信息</div>
</body>
</html>
//创建a.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="@{/}">
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:include="abc::base" id="aheader"></div>
<h1>a</h1>
</body>
</html>
//创建b.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="@{/}">
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:include="abc::base" id="bheader"></div>
<h1>b</h1>
</body>
</html>
//创建c.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="@{/}">
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div th:include="abc::base" id="cheader"></div>
<h1>c</h1>
</body>
</html>
3.测试代码