【JavaWeb】Thymeleaf的简介与使用

Thmeleaf

请添加图片描述

MVC
为什么需要MVC

我们之前在书城项目第二阶段做登录的时候,曾经提出过优化登录失败后的处理

虽然说可以实现在登录失败之后跳转回到登录页面,并且展示失败信息,但是代码实在是太恶心了,根本没法维护,所以我们需要将视图展示抽取出来,单独作为一个View视图层

但是我们如果只使用HTML作为视图的话,它是无法展示动态数据的,所以我们对HTML的新的期待:既能够正常显示页面,又能在页面中包含动态数据部分。而动态数据单靠HTML本身是无法做到的,所以此时我们需要引入服务器端动态视图模板技术。

MVC概念

M:Model模型

V:View视图

C:Controller控制器

MVC是在表述层开发中运用的一种设计理念。主张把封装数据的『模型』显示用户界面的『视图』协调调度的控制器分开。

好处:

  • 进一步实现各个组件之间的解耦
  • 让各个组件可以单独维护
  • 将视图分离出来以后,我们后端工程师和前端工程师的对接更方便

Thymeleaf的简介

1 Thymeleaf的概念

Thymeleaf是一款用于渲染XML/XHTML/HTML5内容的模板引擎。类似JSP,Velocity,FreeMaker等, 它也可以轻易的与Spring MVC等Web框架进行集成作为Web应用的模板引擎。它的主要作用是在静态页面上渲染显示动态数据

2 Thymeleaf的优势
  • SpringBoot官方推荐使用的视图模板技术,和SpringBoot完美整合。

  • 不经过服务器运算仍然可以直接查看原始值,对前端工程师更友好。

DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Titletitle>
head>
<body><p th:text="${username}">Original Valuep>body>
html>
3 物理视图和逻辑视图
物理视图

在Servlet中,将请求转发到一个HTML页面文件时,使用的完整的转发路径就是物理视图。

/pages/user/login_success.html

如果我们把所有的HTML页面都放在某个统一的目录下,那么转发地址就会呈现出明显的规律:

/pages/user/login.html
/pages/user/login_success.html
/pages/user/regist.html
/pages/user/regist_success.html

……

路径的开头都是:/pages/user/

路径的结尾都是:.html

所以,路径开头的部分我们称之为视图前缀,路径结尾的部分我们称之为视图后缀。

逻辑视图

逻辑视图

物理视图=视图前缀+逻辑视图+视图后缀

上面的例子中:

视图前缀逻辑视图视图后缀物理视图
/pages/user/login.html/pages/user/login.html
/pages/user/login_success.html/pages/user/login_success.html
Thymeleaf的入门案例
配置上下文参数

物理视图=视图前缀+逻辑视图+视图后缀


<context-param><param-name>view-prefixparam-name><param-value>/WEB-INF/view/param-value>
context-param>
<context-param><param-name>view-suffixparam-name><param-value>.htmlparam-value>
context-param>

说明:param-value中设置的前缀、后缀的值不是必须叫这个名字,可以根据实际情况和需求进行修改。

为什么要放在WEB-INF目录下?

原因:WEB-INF目录不允许浏览器直接访问,所以我们的视图模板文件放在这个目录下,是一种保护。以免外界可以随意访问视图模板文件。

访问WEB-INF目录下的页面,都必须通过Servlet转发过来,简单说就是:不经过Servlet访问不了。

这样就方便我们在Servlet中检查当前用户是否有权限访问。

那放在WEB-INF目录下之后,重定向进不去怎么办?

重定向到Servlet,再通过Servlet转发到WEB-INF下。

创建Servlet基类

这个类大家直接复制粘贴即可,将来使用框架后,这些代码都将被取代。

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 {// 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);}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());}
}
入门案例代码
1 创建index.html文件
2 index.html编写超链接访问Servlet
<a href="/webday08/TestThymeleafServlet">初步测试Thymeleafa>
3 创建Servlet
<servlet><servlet-name>testThymeleafServletservlet-name><servlet-class>com.atguigu.servlet.TestThymeleafServletservlet-class>
servlet>
<servlet-mapping><servlet-name>testThymeleafServletservlet-name><url-pattern>/testThymeleafurl-pattern>
servlet-mapping>
5 修改Servlet让其继承ViewBaseServlet
6 在doPost()方法中跳转到Thymeleaf页面
package com.atguigu.servlet;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;/*** @author Leevi* 日期2021-05-13  09:15*/
public class TestThymeleafServlet extends ViewBaseServlet {@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doGet(request, response);}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setAttribute("username","奥巴马");//请求转发跳转到/WEB-INF/view/target.htmlprocessTemplate("target",request,response);}
}
7 Thymeleaf页面代码
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8"><title>目标页面title>head><body><h1 th:text="${username}">这里要显示一个动态的usernameh1>body>
html>

Thymeleaf的基本语法

1 th名称空间
xmlns:th="http://www.thymeleaf.org"
2 表达式语法
修改标签文本值

代码示例:

<p th:text="标签体新值">标签体原始值p>
th:text作用
  • 不经过服务器解析,直接用浏览器打开HTML文件,看到的是『标签体原始值』
  • 经过服务器解析,Thymeleaf引擎根据th:text属性指定的『标签体新值』去替换『标签体原始值』
字面量和变量

『字面量』是一个经常会遇到的概念,我们可以对照『变量』来理解它的含义。

// a是变量,100是字面量
int a = 100;
System.out.println("a = " + a);
  • 变量:变量名字符串本身不是它的值,它指向的才是它的值
  • 字面量:它就是字面上的含义,我们从『字面』上看到的直接就是它的值

现在我们在th:text属性中使用的就是『字面量』,它不指代任何其他值。

修改指定属性值

代码示例:

<input type="text" name="username" th:value="文本框新值" value="文本框旧值" />

语法:任何HTML标签原有的属性,前面加上『th:』就都可以通过Thymeleaf来设定新值。

解析URL地址

代码示例:


<a th:href="@{/index.html}">访问index.htmla>

经过解析后得到:

/webday08/index.html

所以@{}的作用是在字符串前附加『上下文路径』

这个语法的好处是:实际开发过程中,项目在不同环境部署时,Web应用的名字有可能发生变化。所以上下文路径不能写死。而通过@{}动态获取上下文路径后,不管怎么变都不怕啦!

首页使用URL地址解析

如果我们直接访问index.html本身,那么index.html是不需要通过Servlet,当然也不经过模板引擎,所以index.html上的Thymeleaf的任何表达式都不会被解析。

解决办法:通过Servlet访问index.html,这样就可以让模板引擎渲染页面了:

进一步的好处:

通过上面的例子我们看到,所有和业务功能相关的请求都能够确保它们通过Servlet来处理,这样就方便我们统一对这些请求进行特定规则的限定。

给URL地址后面附加请求参数
3 域对象在Thymeleaf中的使用
回顾域对象

域对象是在服务器中有一定作用域范围的对象,在这个范围内的所有动态资源都能够共享域对象中保存的数据

回顾域对象的类型
1 请求域

在请求转发的场景下,我们可以借助HttpServletRequest对象内部给我们提供的存储空间,帮助我们携带数据,把数据发送给转发的目标资源。

请求域:HttpServletRequest对象内部给我们提供的存储空间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L7MPhBi2-1645832241874)(/images/img012.png)]

2 会话域

会话域的范围是一次会话(登录与登出为一次会话)

3 应用域(全局域)

应用域的范围是整个项目全局

在Thymeleaf中操作域对象

我们通常的做法是,在Servlet中将数据存储到域对象中,而在使用了Thymeleaf的前端页面中取出域对象中的数据并展示

操作请求域

Servlet中代码:

String requestAttrName = "helloRequestAttr";
String requestAttrValue = "helloRequestAttr-VALUE";request.setAttribute(requestAttrName, requestAttrValue);

Thymeleaf表达式:

<p th:text="${helloRequestAttr}">request field valuep>
操作会话域

Servlet中代码:

// ①通过request对象获取session对象
HttpSession session = request.getSession();// ②存入数据
session.setAttribute("helloSessionAttr", "helloSessionAttr-VALUE");

Thymeleaf表达式:

<p th:text="${session.helloSessionAttr}">这里显示会话域数据p>
操作应用域

Servlet中代码:

// ①通过调用父类的方法获取ServletContext对象
ServletContext servletContext = getServletContext();// ②存入数据
servletContext.setAttribute("helloAppAttr", "helloAppAttr-VALUE");

Thymeleaf表达式:

<p th:text="${application.helloAppAttr}">这里显示应用域数据p>
4 获取请求参数
获取请求参数的语法
${param.参数名}
根据一个参数名获取一个参数值

页面代码:

<p th:text="${param.username}">这里替换为请求参数的值p>
根据一个参数名获取多个参数值

页面代码:

<p th:text="${param.team}">这里替换为请求参数的值p>

如果想要精确获取某一个值,可以使用数组下标。页面代码:

<p th:text="${param.team[0]}">这里替换为请求参数的值p>
<p th:text="${param.team[1]}">这里替换为请求参数的值p>
OGNL
OGNL的概念

OGNL:Object-Graph Navigation Language对象-图 导航语言

对象图的概念

从根对象触发,通过特定的语法,逐层访问对象的各种属性。

OGNL语法
1 起点

在Thymeleaf环境下,${}中的表达式可以从下列元素开始:

  • 访问属性域的起点
    • 请求域属性名
    • session
    • application
  • param
  • 内置对象
    • request
    • session
    • lists
    • strings
2 属性访问语法
  • 访问对象属性:使用getXxx()、setXxx()方法定义的属性
    • 对象.属性名
  • 访问List集合或数组
    • 集合或数组[下标]
  • 访问Map集合
    • Map集合.key
    • Map集合[‘key’]
分支与迭代
分支
if和unless

让标记了th:if、th:unless的标签根据条件决定是否显示。

示例的实体类:

package com.atguigu.bean;/*** 包名:com.atguigu.bean** @author Leevi* 日期2021-05-13  10:58*/
public class Teacher {private String teacherName;public Teacher() {}public Teacher(String teacherName) {this.teacherName = teacherName;}public String getTeacherName() {return teacherName;}public void setTeacherName(String teacherName) {this.teacherName = teacherName;}
}

示例的Servlet代码:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 1.创建ArrayList对象并填充List<Employee> employeeList = new ArrayList<>();employeeList.add(new Employee(1, "tom", 500.00));employeeList.add(new Employee(2, "jerry", 600.00));employeeList.add(new Employee(3, "harry", 700.00));// 2.将集合数据存入请求域request.setAttribute("employeeList", employeeList);// 3.调用父类方法渲染视图super.processTemplate("list", request, response);
}

示例的HTML代码:

<table><tr><th>员工编号th><th>员工姓名th><th>员工工资th>tr><tr th:if="${#lists.isEmpty(employeeList)}"><td colspan="3">抱歉!没有查询到你搜索的数据!td>tr><tr th:if="${not #lists.isEmpty(employeeList)}"><td colspan="3">有数据!td>tr><tr th:unless="${#lists.isEmpty(employeeList)}"><td colspan="3">有数据!td>tr>
table>

if配合not关键词和unless配合原表达式效果是一样的,看自己的喜好。

switch
<h3>测试switchh3>
<div th:switch="${user.memberLevel}"><p th:case="level-1">银牌会员p><p th:case="level-2">金牌会员p><p th:case="level-3">白金会员p><p th:case="level-4">钻石会员p>
div>
2.7.2 迭代

<table border="1" cellspacing="0" width="500"><tr><th>编号th><th>姓名th>tr><tbody th:if="${#lists.isEmpty(teacherList)}"><tr><td colspan="2">教师的集合是空的!!!td>tr>tbody><tbody th:unless="${#lists.isEmpty(teacherList)}"><tr th:each="teacher,status : ${teacherList}"><td th:text="${status.count}">这里显示编号td><td th:text="${teacher.teacherName}">这里显示老师的名字td>tr>tbody>
table>
Thymeleaf包含其他模板文件
创建页面的公共代码片段

使用th:fragment来给这个片段命名:

<div th:fragment="header"><p>被抽取出来的头部内容p>
div>
在需要的页面中进行包含
语法效果特点
th:insert把目标的代码片段整个插入到当前标签内部它会保留页面自身的标签
th:replace用目标的代码替换当前标签它不会保留页面自身的标签
th:include把目标的代码片段去除最外层标签,然后再插入到当前标签内部它会去掉片段外层标记,同时保留页面自身标记

页面代码举例:


<div id="badBoy" th:insert="segment :: header">div标签的原始内容
div><div id="worseBoy" th:replace="segment :: header">div标签的原始内容
div><div id="worstBoy" th:include="segment :: header">div标签的原始内容
div>


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部