什么是Thymeleaf?
Thymeleaf是适用于Web和独立环境的现代服务器端
Java模板引擎
。官网:Thymeleaf
什么是Java模板引擎?
模板引擎不是某一特定领域的技术,它是跨领域跨平台的概念。本文要讲的Java领域的模板引擎,Java模板引擎是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档(这个特定的文档可以称之为模板,模板中套用不同的数据展示不同的视图,从而实现动态交互),用于网站的模板引擎就会生成一个标准的HTML文档
简而言之,Java模板引擎本质就是一个特定的文档,当我们注入不同的数据,该文档会被解析成不同的HTML文档,从而展示不同的网页
较为常见的Java模板引擎有:JSP、Thymeleaf、FreeMaker、Velocity等模板引擎
Thymeleaf的特点:
Thymeleaf的优点:
动态交互。一个模板注入不同的数据,会展示不同的网页
动静分离。 Thymeleaf使用HTML通过一些特定标签语法代表其含义,但并未破坏HTML结构,即使无网络、不通过后端渲染也能在浏览器成功打开,大大方便界面的测试和修改(解决了JSP调试困难的弊端)
降低了项目的复杂性。Thymeleaf将前后端分离开来,让专业的人干专业的事,避免了JSP的前后端混写的缺点,大大提高了开发效率
易于使用。Thymeleaf模板引擎被主流的Springboot框架集成,Springboot官方做了很多默认配置,开发者只需编写对应html即可,大大减轻了上手难度和配置复杂度
Thymeleaf的作用:
t_book表:
Step1:创建Maven项目
目录结构:
Step2:导入依赖
<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.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>ThymeleafartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.16version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>4.0.1version>
<scope>providedscope>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13.2version>
dependency>
<dependency>
<groupId>org.attoparsergroupId>
<artifactId>attoparserartifactId>
<version>2.0.5.RELEASEversion>
dependency>
<dependency>
<groupId>org.javassistgroupId>
<artifactId>javassistartifactId>
<version>3.28.0-GAversion>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.30version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>1.7.25version>
dependency>
<dependency>
<groupId>ognlgroupId>
<artifactId>ognlartifactId>
<version>3.1.26version>
dependency>
<dependency>
<groupId>org.thymeleafgroupId>
<artifactId>thymeleafartifactId>
<version>3.0.12.RELEASEversion>
dependency>
<dependency>
<groupId>org.unbescapegroupId>
<artifactId>unbescapeartifactId>
<version>1.1.6.RELEASEversion>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<version>2.2version>
<configuration>
<port>8080port>
configuration>
plugin>
plugins>
build>
project>
Step3:编写web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<context-param>
<param-name>view-prefixparam-name>
<param-value>/html/param-value>
context-param>
<context-param>
<param-name>view-suffixparam-name>
<param-value>.htmlparam-value>
context-param>
web-app>
Step4:编写实体类
略……
Step5:编写组件
1)数据访问层……
2)业务逻辑层……
3)控制层
ViewBaseServlet
package com.hhxy.controller;
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;
/**
* @author ghp
* @date 2022/9/21
*/
public class ViewBaseServlet extends HttpServlet {
private TemplateEngine templateEngine;
/**
* 初始化方法
*/
@Override
public void init() throws ServletException {
// 1、获取ServletContext对象
ServletContext servletContext = this.getServletContext();
// 2、创建Thymeleaf解析器对象
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
// 3、给解析器对象设置参数
// 3.1 HTML是默认模式,明确设置是为了代码更容易理解
templateResolver.setTemplateMode(TemplateMode.HTML);
//3.2 设置前缀
String viewPrefix = servletContext.getInitParameter("view-prefix");
templateResolver.setPrefix(viewPrefix);
//3.3 设置后缀
String viewSuffix = servletContext.getInitParameter("view-suffix");
templateResolver.setSuffix(viewSuffix);
//3.4 设置缓存过期时间(毫秒)
templateResolver.setCacheTTLMs(60000L);
//3.5 设置是否缓存
templateResolver.setCacheable(true);
//3.6 设置服务器端编码方式
templateResolver.setCharacterEncoding("utf-8");
// 4、创建模板引擎对象
templateEngine = new TemplateEngine();
// 5、给模板引擎对象设置模板解析器
templateEngine.setTemplateResolver(templateResolver);
}
/**
* 处理模板
* @param templateName 模板的名字
*/
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());
}
}
IndexServlet
package com.hhxy.controller;
import com.hhxy.pojo.Book;
import com.hhxy.service.BookService;
import com.hhxy.service.imp.BookServiceImp;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
/**
* @author ghp
* @date 2022/9/21
*/
@WebServlet("/indexServlet")
public class IndexServlet extends ViewBaseServlet {
//1、获取BookService对象
private BookService bookService = new BookServiceImp();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//2、调用BookService对象的方法,获取数据
List<Book> books = bookService.selectAll();
//3、将数据保存到Session域对象中
HttpSession session = request.getSession();
session.setAttribute("books",books);
/*
thymeleaf会将 逻辑视图名称 对应到 物理视图名称
逻辑视图名称:index
物理视图名称:view-prefix(前缀) + 逻辑视图名称 + view-suffix(后缀)
真实的视图名称: /html/ index .html (看web.xml中的配置)
*/
super.processTemplate("index",request,response);
}
}
Step6:编写Thymeleaf
DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<html lang="en">
<head>
<meta charset="UTF-8">
<title>indextitle>
head>
<body>
<table border="1px" align="center">
<tr>
<td>书名td>
<td>书的单价td>
<td>书的库存td>
tr>
<tr th:if="${#lists.isEmpty(session.books)}">
<td colspan="4">对不起,库存为空!td>
tr>
<tr th:unless="${#lists.isEmpty(session.books)}" th:each="book : ${session.books}">
<td th:text="${book.getName()}">td>
<td th:text="${book.getPrice()}">td>
<td th:text="${book.getStock()}">td>
tr>
table>
body>
html>
Step7:测试
在使用Thymeleaf之前,我们首先要在页面的
html标签
中声明命名空间。<html xmlns:th="http://www.thymeleaf.org">
为什么要引入命名空间?
引入命名空间的目的是为了避免命名冲突,比如在Thymeleaf中我们是使用
$
符获取域对象中的值的,当我们页面中引入了JQuery后,在JQuery中使用$
是获取结点对象,这就会产生冲突导致页面无法正常展示。当然不声明Thymeleaf命名空间也是能够使用Thymeleaf的。
Thymeleaf 作为一种模板引擎,它拥有自己的语法规则。Thymeleaf 语法分为以下 2 类:
th:eache
:
status中,有count(获取循环的次数,从1开始)、first(判断是否为第一次循环)、index(获取循环的索引号,从0开始)、event(判断count是否为偶数)、last(判断是否是最后一次循环)、odd(判断count是否为奇数)、size(获取集合的长度)
<tr th:each="employee,status : ${employees}">
<td th:text="${status.count}">td>
tr>
拓展:
th:field
:获取域对象的属性值,后台不能用reques.setAttribute()来传值,可以用model.addAttribute()来传值;而这两种方式th:value都可以接收;在单选框中,当th:field中的属性值与value的值一样,单选框就会被选中
Thymeleaf 模板引擎支持多种表达式:
- 变量表达式:
${...}
- 选择变量表达式:
*{...}
- 链接表达式:
@{...}
- 国际化表达式:
#{...}
- 片段引用表达式:
~{...}
知识拓展:
变量表达式和国际化表达式都属于OGNL(Objects-Graph Navigation Language,对象导航图语言)是应用于Java中的一个开源的表达式语言
变量表达式(Variable Expressions):用于在模板中引用和显示变量的值。例如,
${variable}
表示引用名为variable
的变量
使用 ${}
包裹的表达式被称为变量表达式,该表达式具有以下功能:
获取对象的属性或方法
获取内置的基本对象并使用
获取内置的工具对象并使用
${对象.属性/方法名}
:获取对象的属性或方法
//获取对象的方法
${book.getName()}
${#内置的基本对象}
:获取内置的基本对象并使用
ctx
:上下文对象vars
:上下文变量locale
:上下文的语言环境request
:HttpServletRequest 对象(仅在 Web 应用中可用)response
:HttpServletResponse 对象(仅在 Web 应用中可用)session
:HttpSession 对象(仅在 Web 应用中可用)servletContext
:ServletContext 对象(仅在 Web 应用中可用)//获取Session域对象中存储的List集合对象
//方式一:
${#session.getAttribute('books')
//方式二:
${session.books}
${#内置的工具对象}
:获取内置的工具对象并使用
strings
:字符串工具对象,常用方法有:equals、equalsIgnoreCase、length、trim、toUpperCase、toLowerCase、indexOf、substring、replace、startsWith、endsWith,contains 和 containsIgnoreCase 等numbers
:数字工具对象,常用的方法有:formatDecimal 等bools
:布尔工具对象,常用的方法有:isTrue 和 isFalse 等arrays
:数组工具对象,常用的方法有:toArray、length、isEmpty、contains 和 containsAll 等lists/sets
:List/Set 集合工具对象,常用的方法有:toList、size、isEmpty、contains、containsAll 和 sort 等maps
:Map 集合工具对象,常用的方法有:size、isEmpty、containsKey 和 containsValue 等dates
:日期工具对象,常用的方法有:format、year、month、hour 和 createNow 等//使用内置工具对象 strings 的 equals 方法,来判断字符串与对象的某个属性是否相等
${#strings.equals('张三',name)}
选择表达式(Selection Expressions):用于从对象中选择属性或方法。例如,
*{user.name}
表示选择user
对象的name
属性。选择变量也可以称为星号表达式,表达式与变量表达式功能基本一致,只是在变量表达式的基础上增加了与
th:object
的配合使用。当使用th:object
存储一个对象后,我们可以在其后代中使用选择变量表达式*{...}
获取该对象中的属性,其中,*
即代表该对象
<div th:object="${session.user}" >
<p th:text="*{userName}">firstnamep>
div>
URL表达式(URL Expressions):用于生成动态URL链接。例如,
@{/path}
会生成相对于当前上下文路径的URL。
@{/xxx}
@{/xxx(k1=v1,k2=v2)}
链接表达式(Link Expressions):类似于URL表达式,用于生成页面内部的锚点链接。例如,
#fragmentId
会生成一个指向具有相应片段标识符的位置的链接。
链接表达式是用于生成页面内部的锚点链接(即片段标识符)。它们使用#
符号作为前缀,后跟片段标识符。例如,#fragmentId
会生成一个指向具有相应片段标识符的位置的链接。链接表达式主要用于在同一页面内部进行导航和定位。
DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Link and URL Expression Demotitle>
head>
<body>
<h1>Link and URL Expression Demoh1>
<p>Link Expression:p>
<a th:href="#section1">Go to Section 1a>
<a th:href="#section2">Go to Section 2a>
<p>URL Expression:p>
<a th:href="@{/path1}">Link to Path 1a>
<a th:href="@{/path2}">Link to Path 2a>
<section id="section1">
<h2>Section 1h2>
<p>This is section 1 content.p>
section>
<section id="section2">
<h2>Section 2h2>
<p>This is section 2 content.p>
section>
body>
html>
在上面的示例中,我们使用Thymeleaf的链接表达式和URL表达式创建了一些链接。
链接表达式使用#
符号,并通过th:href
属性生成到相应片段标识符的锚点链接。例如,Go to Section 1
会生成一个链接,点击后将滚动至具有section1
片段标识符的位置。
URL表达式使用@
符号,并通过th:href
属性生成动态的URL链接。例如,Link to Path 1
会生成相对于当前上下文路径的URL,点击后将导航到/path1
。
国际表达式使用的基本步骤:
messages_en.properties
(英语)、messages_zh_CN.properties
(中文)等。每个属性文件中包含了对应语言的键值对,用于表示不同语言下的文本信息。Locale
解析器:在 Spring MVC 中,需要配置 LocaleResolver
来解析用户的语言偏好,并将其应用到 Thymeleaf 视图中。常见的 LocaleResolver 有 CookieLocaleResolver
、SessionLocaleResolver
等,你可以根据需求选择合适的LocaleResolver。#{}
来包裹键名,Thymeleaf 会根据当前 Locale 自动寻找对应的属性值。例如,
表示从国际化资源文件中获取键为 “welcome.message” 的文本信息并显示在HTML中。Thymeleaf的片段引用表达式(Fragment Expression)是一种在模板中引用和渲染片段的方式。它允许将一个或多个片段从其他模板中提取出来并在当前模板中进行引用和渲染。
Thymeleaf的片段引用表达式使用~{}
包裹片段名称,并可以传递参数。以下是使用片段引用表达式的基本语法:
复制代码
其中,templateName
表示模板文件名,fragmentName
表示片段名称。通过::
符号来连接模板文件名和片段名称。在片段引用表达式中,还可以传递参数给被引用的片段。参数以键值对的形式传递,使用逗号分隔。
示例中的parameter1
和parameter2
是片段中定义的参数名称,value1
和value2
是要传递的实际值。
使用片段引用表达式可以将片段从其他模板中提取出来并插入到当前模板的指定位置。这有助于模块化开发和代码复用,可以将通用的部分抽离出来,减少重复代码的编写。
需要注意的是,被引用的片段必须在对应的模板文件中存在,并且在片段定义处使用th:fragment
属性进行标记。例如,在templateName.html
模板文件中定义一个片段:
html复制代码
然后在另一个模板中使用片段引用表达式来引用和渲染该片段:
html复制代码
通过使用Thymeleaf的片段引用表达式,我们可以方便地将模板中的特定部分提取出来并在其他模板中重复使用,提高了代码的可维护性和重用性。
参考文章:
- Thymeleaf教程(10分钟入门)
- 代码重工
- OGNL 表达式_MyBatis 入门教程
- ognl概念和原理详解
- cloudfavorites/favorites-web: 云收藏 Spring Boot 2.X 开源项目 (github.com):
渲染就是将Java对象中的数据显示到网页上的这个过程 ↩︎