如何使用Thymeleaf给web项目中的网页渲染显示动态数据?
编译软件: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的准备知识
- 4.1 物理视图
- 4.2 逻辑视图
- 五. 如何编写第一个Thymeleaf的程序?
- 六.Thymeleaf的基本语法
- 6.1 th名称空间
- 6.2 修改标签的文本值(双标签)
- 6.3 修改标签的属性值(单标签和双标签)
- 6.4 解析URL地址
- 6.5 获得域对象中的数据
- 6.5.1 获取应用域对象中的数据
- 6.5.2 获取会话域对象中的数据(Httpsession session)
- 6.5.3 获取请求域对象中的数据(HttpservletRequest request)
- 6.6 获得请求参数
- 6.6.1 根据一个参数名获取一个参数值
- 6.6.2 根据一个参数名获取多个参数值
- 6.7 内置对象
- 6.7.1 基本内置对象
- 6.7.2 公共内置对象
- 6.8 OGNL( 对象-图导航语言)
- 6.8.1 简单对象
- 6.8.2 稍微复杂的对象
- 6.8.3 list集合(简单集合)
- 6.8.4 复杂集合(list集合存储对象)
- 6.8.5 复杂集合(map集合存储对象)
- 6.9 分支与迭代
- 6.9.1 分支,控制元素的是否显示
- 6.9.1.1 th:if 和 th:unless
- 6.9.1.2 th:switch和th:case
- 6.9.2 迭代(遍历循环)
- 6.9.2.1 简单数组迭代
- 6.9.2.2 复杂数组迭代
- 6.10 Thymeleaf包含其他模板文件
- 6.10.1 应用场景
- 6.10.2 操作步骤
- ①给公共的代码片段起个名字
- ②在其他页面根据名字引用
- a. th:replace
- b. th:insert
- c. th:include
- 6.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的准备知识
4.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
对此,路径的开头部分我们称之为视图前缀,路径的结尾部分我们称之为视图后缀
4.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;@Overridepublic 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的基本语法
6.1 th名称空间
Thymeleaf所有的表达式都是通过属性的方式添加,th:表达式内容
添加的位置
:html标签的属性上
xmlns:th="http://www.thymeleaf.org"
6.2 修改标签的文本值(双标签)
语法:
th:text=“新值”
示例代码如下:
<h2 th:text="${msg}">放服务器传过来的msg数据</h2>
从请求域中获取key为msg的value值写入标签体中,原有的标签体内容会被覆盖
6.3 修改标签的属性值(单标签和双标签)
语法:
th:属性名=“新值”
示例代码如下::
<input type="text"value="这是原始值"th:value="${msg}">
6.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,然后再呈现在浏览器中供客户观看
6.5 获得域对象中的数据
6.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对象的别名叫什么。
6.5.2 获取会话域对象中的数据(Httpsession session)
语法:
${session.会话域中的key值}
6.5.3 获取请求域对象中的数据(HttpservletRequest request)
语法:
${请求域中的key}
ps:详细应用在上述的章节内容已有展示,故不作涉及
6.6 获得请求参数
语法:
${param.请求参数的key值)
6.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>
6.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>
6.7 内置对象
释义:
可以直接使用的对象
6.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>
.....
6.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>
6.8 OGNL( 对象-图导航语言)
对象-图的概念:
从根对象触发,通过特定的语法,逐层访问对象的各种属性。
简而言之:
就是将复杂的对象或者集合放在域对象内,Thymeleaf去获取这些数据在网页渲染
6.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>
6.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() {}@Overridepublic 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() {}@Overridepublic 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>
6.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>
6.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集合就通过下标获得到元素,如果元素是对象的话,还是回到上一句
6.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>
6.9 分支与迭代
6.9.1 分支,控制元素的是否显示
6.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>
6.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>
6.9.2 迭代(遍历循环)
语法:
th:each=“obj,status:后台请求域中数据的key”
6.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>
6.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>
6.10 Thymeleaf包含其他模板文件
6.10.1 应用场景
网页内公共代码片段的提取
公共代码片段是什么?
以腾讯视频 pc端为例,无论用户点击了什么频道,网站左侧的红框部分总是在那里,不会改变
6.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的标签内
6.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.测试代码
相关文章:

如何使用Thymeleaf给web项目中的网页渲染显示动态数据?
编译软件:IntelliJ IDEA 2019.2.4 x64 操作系统:win10 x64 位 家庭版 服务器软件:apache-tomcat-8.5.27 目录一. 什么是Thymeleaf?二. MVC2.1 为什么需要MVC?2.2 MVC是什么?2.3 MVC和三层架构之间的关系及工…...
01 | 电机常用语
1 电机常用术语 1.1 原点 原点是指步进电机在驱动直线运动机构时的起始点。 1.2 点动 点动是电动机控制方式中的一种。 点动由于在这一控制回路中没有自保,也没有并接其它的自动装置,只是按下控制回路的启动按钮,主回路才通电,松开启动按钮,主回路就没电了。最典型的是…...
Leetcode.2601 质数减法运算
题目链接 Leetcode.2601 质数减法运算 Rating : 1779 题目描述 给你一个下标从 0 开始的整数数组 nums,数组长度为 n 。 你可以执行无限次下述运算: 选择一个之前未选过的下标 i ,并选择一个 严格小于 nums[i]的质数 ppp &…...

DP7416国产192K数字音频接收芯片兼容替代CS8416
目录192K 数字音频应用DP7416简介芯片特性192K 数字音频应用 采样率192khz,能将192,000hz以下的频率都录下来,而且对声波每秒连续采样192,000次。在回放的时候,这192,000个采样点按顺序播放,从而还原原来的声音。 过采样技术除…...

全球土壤湿度数据获取方法
土壤湿度亦称土壤含水率,表示土壤干湿程度的物理量。是土壤含水量的一种相对变量。通常用土壤含水量占干土重的百分数是示,亦称土壤质量湿度,如用土壤水分容积占土壤总容积的百分数表示,则称土壤容积湿度。通常说的土壤湿度&#…...

在proteus中仿真arduino实现矩阵键盘程序
矩阵键盘是可以解决我们端口缺乏的问题,当然,如果我们使用芯片来实现矩阵键盘的输入端口缺乏的问题将更加划算了,本文暂时不使用芯片来解决问题,而使用纯朴的8根线来实现矩阵键盘,目的是使初学者掌握原理。想了解使用芯…...

【ROS2指南-5】理解ROS2服务
目标:使用命令行工具了解 ROS 2 中的服务。 教程级别:初学者 时间: 10分钟 内容 背景 先决条件 任务 1 设置 2 ros2服务列表 3 ros2服务类型 4 ros2 服务查找 5 ros2界面展示 6 ros2 服务调用 概括 下一步 相关内容 背景 服务是 …...

探索Apache Hudi核心概念 (3) - Compaction
Compaction是MOR表的一项核心机制,Hudi利用Compaction将MOR表产生的Log File合并到新的Base File中。本文我们会通过Notebook介绍并演示Compaction的运行机制,帮助您理解其工作原理和相关配置。 1. 运行 Notebook 本文使用的Notebook是:《A…...

100Wqps异地多活,得物是怎么架构的?
说在前面 在40岁老架构师尼恩的数千读者群中,一直在指导大家简历和职业升级,前几天,指导了一个华为老伙伴的简历,小伙伴的优势在异地多活,但是在简历指导的过程中,尼恩发现: 异地多活的概念、异…...

35岁的测试工程师被公司强行辞退,感叹道:我以前就该好好努力了
曾经的高薪软件测试工程师,今年35岁了,被公司劝退了,外卖跑到凌晨,很累,但还是有一种想诉说的冲动。哪怕让大家觉得已经说得太多了,烦了,都成祥林嫂了,但是,我是真的想说…...

ASP.NET动态Web开发技术第5章
第5章数据验证一.预习笔记 1.验证控件概述: 2.RequiredFieldValidator(必填验证) 常用属性1:ControlToValidator:被验证的输入控件的ID 常用属性2:Text:验证失败时,验证控件显示的文本 常用…...

【数据结构与算法篇】时间复杂度与空间复杂度
目录 一、数据结构和算法 1.什么是数据结构? 2.什么是算法? 3.数据结构和算法的重要性 二、算法的时间复杂度和空间复杂度 1.算法效率 2.算法的复杂度 3.复杂度在校招中的考察 4.时间复杂度 5.空间复杂度 6.常见复杂度对比 7.复杂度的OJ练…...

HTTP API接口设计规范
1. 所有请求使用POST方法 使用post,相对于get的query string,可以支持复杂类型的请求参数。例如日常项目中碰到get请求参数为数组类型的情况。 便于对请求和响应统一做签名、加密、日志等处理 2. URL规则 URL中只能含有英文,使用英文单词或…...
数据一致性校验(pt-table-checksum)
介绍 pt-table-checksum 和 pt-table-sync 是 percona 公司发布的、检查 MySQL 主从数据库数据一致性校验的工具。pt-table-checksum 利用 MySQL 复制原理,在主库执行校验和计算,并对比主从库校验和,由此判断主从库数据是否一致。如果发现数…...

Talk预告 | 新加坡国立大学郑奘巍 AAAI‘23 杰出论文:大批量学习算法加速推荐系统训练
本期为TechBeat人工智能社区第486期线上Talk! 北京时间3月30日(周四)20:00,新加坡国立大学二年级博士生——郑奘巍的Talk将准时在TechBeat人工智能社区开播! 他与大家分享的主题是: “大批量学习算法加速推荐系统训练”,届时将分…...

肖 sir_就业课__004项目流程(H模型)
项目流程: 一、面试提问(h模型) 1、你说下你们公司测试流程? 2、给你一个需求你会怎么做? 3、你讲下你的工作? 4、谈谈你是如何去测试? 答案:h模型 要求第一人称来写 讲解简化文字流程&#x…...

snipaste 截图工具——可以使图片悬浮在任何软件上,方便对比
一、下载 官网下载地址:Snipaste Downloads (需要梯子) CSDN下载地址:https://download.csdn.net/download/weixin_43042683/87671809 1. 下载 压缩包后,免安装,直接解压后既可以使用。 2. 点击Snipaste.…...
Docker 快速部署Springboot项目
编写Dockerfile文件 # Docker image for springboot file run # VERSION 0.0.1 # Author: # 基础镜像使用java FROM openjdk:8 # 作者 MAINTAINER laihx # VOLUME 指定了临时文件目录为/tmp。 # 其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到…...

【LeetCode: 剑指 Offer II 112. 最长递增路径 | 递归 | DFS | 深度优先遍历 | 记忆化缓存表】
🍎作者简介:硕风和炜,CSDN-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享💎💎💎 🍎座右…...

hive 入门 一般用于正式环境 修改元数据(二)
安装配置可参考 https://blog.csdn.net/weixin_43205308/article/details/130020674 1、如果启动过derby,最小初始化过 在安装路径下删除 derby.log metastore_db rm -rf derby.log metastore_db此处省略安装mysql数据库 2、配置MySQL 登录mysql mysql -uroot …...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...

面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...