文章目录
14.1 官方文档
14.1.1 在线文档
14.1.2 离线文档
- usingthymeleaf.pdf
14.2 基本介绍
● Thymeleaf 是什么
- Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,可完全替代 JSP
- Thymeleaf 是一个 java 类库,他是一个 xml/xhtml/html5 的模板引擎,可以作为 mvc 的 web 应用的 view 层
● Thymeleaf 的优点
- 实现 JSTL、 OGNL 表达式效果, 语法相似,java 程序员上手快
- Thymeleaf 模版页面无需服务器渲染,也可以被浏览器运行,页面简洁
- SpringBoot 支持 FreeMarker、Thymeleaf、veocity
● Thymeleaf 的缺点
- Thymeleaf:Thymeleaf is a modern server-side Java template engine for both web and standalone environments
- 缺点:并不是一个高性能的引擎,适用于单体应用
- 说明:如果要做一个高并发的应用,选择前后端分离更好,但是作为 SpringBoot 推荐的模板引擎,还是要学习 Thymeleaf 使用
- 后面还要学 Vue + ElementPlus + Axios + SpringBoot 前后端分离
14.3 Thymeleaf 机制说明
-
Thymeleaf 是服务器渲染技术,页面数据是在服务端进行渲染的
-
比如:manage.html 中一段 thymeleaf 代码,是在用户请求该页面时,有 thymeleaf 模板引擎完成处理的 (在服务端完成) ,并将结果页面返回
-
因此使用了 Thymeleaf ,并不是前后端分离
14.4 Thymeleaf 语法
14.4.1 表达式
- 表达式一览
表达式名字 | 语法 | 用途 |
---|---|---|
变量取值 | ${...} | 获取请求域、session 域、对象等值 |
选择变量 | *{...} | 获取上下文对象值 |
消息 | #{...} | 获取国际化等值 |
链接 | @{...} | 生成链接 |
片段表达式 | ~{...} | jsp:include 作用,引入公共页面片段 |
- 字面量
- 文本值:‘xjs’ ,‘hello’ …
- 数字:10,7,36.8
- 布尔值:true,false
- 空值:null
- 变量:name,age,… 变量不能有空格
- 文本操作
- 文本操作
- 字符串拼接:+
- 变量替换:
age= ${age}
14.4.2 运算符
-
数学运算
运算符:+ ,- ,* ,/ ,%
-
布尔运算
运算符:and ,or
一元运算: ! ,not -
比较运算
比较:> ,< ,>= ,<= ( gt ,lt ,ge ,le )
等式:== ,!= ( eq ,ne ) -
条件运算
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
14.4.3 th 属性
html 有的属性,Thymeleaf 基本都有,而常用的属性大概有七八个,其中 th 属性执行的优先级从 1~8,数字越低优先级越高
th:text
:设置当前元素的文本内容,相同功能的还有th:utext
,两者的区别在于前者不会转义 html 标签,后者会。优先级不高:order=7th:value
:设置当前元素的 value 值,类似修改指定属性的还有th:src
,th:href
。优先级不高:order=6th:each
:遍历循环元素,和th:text
或th:value
一起使用。注意该属性修饰的标签位置,详细往后看。优先级很高:order=2th:if
:条件判断,类似的还有th:unless
,th:switch
,th:case
。优先级较高:order=3th:insert
:代码块引入,类似的还有th:replace
,th:include
,三者的区别较大,若使用不恰当会破坏 html 结构,常用于公共代码块提取的场景。优先级最高:order=1th:fragment
:定义代码块,方便被 th:insert 引用。优先级最低:order=8th:object
:声明变量,一般和*{}
一起配合使用,达到偷懒的效果。优先级一般:order=4th:attr
:修改任意属性,实际开发中用的较少,因为有丰富的其他 th 属性帮忙,类似的还有th:attrappend
,th:attrprepend
。优先级一般:order=5
14.4.4 迭代
<tr th:each="prod : ${prods}">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
</tr>
14.4.5 条件运算
<a href="comments.html"
th:href="@{/product/comments(prodId=${prod.id})}"
th:if="${not #lists.isEmpty(prod.comments)}">view</a>
<div th:switch="${user.role}">
<p th:case="'admin'">User is an administrator</p>
<p th:case="#{roles.manager}">User is a manager</p>
<p th:case="*">User is some other thing</p>
</div>
14.4.6 使用 Thymeleaf -th 属性需要注意点
-
若要使用 Thymeleaf 语法,首先要声明名称空间:
xmlns:th="http://www.thymeleaf.org"
-
明确各种标签的使用
● 设置文本内容
th:text
● 设置 input 的值th:value
● 循环输出th:each
● 条件判断th:if
● 插入代码块th:insert
● 定义代码块th:fragment
● 声明变量th:object
-
th:each
的用法需要格外注意,打个比方:如果你要循环一个 div 中的 p 标签,则th:each
属性必须放在 p 标签上。若你将th:each
属性放在 div 上,则循环的是将整个 div -
变量表达式中提供了很多的内置方法,该内置方法是用#开头,请不要与
#{}
消息表达式弄混
14.5 Thymeleaf 综合案例
14.5.1 需求说明
- 说明:使用 SpringBoot + Thymeleaf 完成简单的用户登录-列表功能
14.5.2 思路分析
- 说明:使用 SpringBoot + Thymeleaf 完成简单的用户登录
- 思路分析/图解
14.5.3 代码实现
- 创建项目,项目名使用 springboot-usersys,使用灵活创建项目的方式
- 说明一下,要支持 Thymeleaf,需要加入 thymeleaf-starter,在 pom.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
<groupId>com.xjs</groupId>
<artifactId>springboot-usersys</artifactId>
<version>1.0-SNAPSHOT</version>
<!--导入springboot父工程-规定写法-->
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.5.3</version>
</parent>
<dependencies>
<!--导入web项目场景启动器: 会自动导入和web开发相关的所有依赖[库/jar]-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<!--引入 Thymeleaf-start
1. 会进行默认配置
2. 程序员按照规则开发即可
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
</project>
- 引入 starter-Thymeleaf ,项目会自动完成配置,程序员按照规则开发即可
- 创建 adminLogin.html 和 manage.html 和静态图片到指定目录,从准备好的拷贝即可,注意 将 html 文件放到 templates/ 目录下,该目录,不能直接访问
----- adminLogin.html -----
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body bgcolor="#CED3FE">
<img src="images/1.GIF"/>
<hr/>
<div style="text-align: center">
<h1>用户登陆</h1>
<form action="#" method="post">
<label style="color: red"></label><br/>
用户名:<input type="text" style="width:150px" name="name"/><br/><br/>
密 码 :<input type="password" style="width:150px" name="password"/><br/><br/>
<input type="submit" value="登录"/>
<input type="reset" value="重新填写"/>
</form>
</div>
<hr/>
<!--<img src="images/logo.png"/>-->
</body>
</html>
----- manage.html -----
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>管理后台</title>
</head>
<body bgcolor="#CED3FE">
<img src="images/1.GIF"/>
<a href='#'>返回管理界面</a> <a href='#'>安全退出</a> 欢迎您:XXX
<hr/>
<div style="text-align: center">
<h1>管理雇员~</h1>
<table border="1px" cellspacing="0" bordercolor="green" style="width:800px;margin:
auto">
<tr bgcolor="pink">
<td>id</td>
<td>name</td>
<td>pwd</td>
<td>email</td>
<td>age</td>
</tr>
<tr bgcolor="#ffc0cb" th:each="user:${users}">
<td th:text="${user.id}">a</td>
<td th:text="${user.name}">b</td>
<td th:text="${user.password}">c</td>
<td th:text="${user.age}">d</td>
<td th:text="${user.email}">e</td>
</tr>
</table>
<br/>
</div>
<hr/>
<!--<img src="images/logo.png"/>-->
</body>
</html>
- 创建 D:\xjs_springboot\springboot-usersys\src\main\java\com\xjs\springboot\bean\Admin.java
package com.xjs.springboot.bean;
import lombok.Data;
/**
* @Author: 谢家升
* @Version: 1.0
*/
@Data
public class Admin {
private String name;
private String password;
}
- 创建 D:\xjs_springboot\springboot-usersys\src\main\java\com\xjs\springboot\bean\User.java
package com.xjs.springboot.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author: 谢家升
* @Version: 1.0
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
private String password;
private Integer age;
private String email;
}
- 创建 D:\xjs_springboot\springboot-usersys\src\main\java\com\xjs\springboot\controller\IndexController.java ,默认进入登录页面
package com.xjs.springboot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import sun.awt.SunHints;
/**
* @Author: 谢家升
* @Version: 1.0
*/
@Controller
public class IndexController {
//编写方法,转发到登录页面
@GetMapping({"/", "/login"})
public String login() {
/**
* 解读:
* 1. 因为我们引入了 spring-boot-starter-thymeleaf
* 2. 这里就会直接使用视图解析到 thymeleaf 下的模板文件 adminLogin.html
*/
return "adminLogin";
}
}
- 创建 D:\xjs_springboot\springboot-usersys\src\main\java\com\xjs\springboot\controller\AdminController.java ,处理登录请求 完成测试
package com.xjs.springboot.controller;
import com.xjs.springboot.bean.Admin;
import com.xjs.springboot.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
/**
* @Author: 谢家升
* @Version: 1.0
*/
@Controller
public class AdminController {
//响应用户的登录请求
@PostMapping("/login")
public String login(Admin admin, HttpSession session, Model model) {
//验证用户是否合法
if (StringUtils.hasText(admin.getName()) && "888".equals(admin.getPassword())) {
/**合法 重定向到 manage.html
* 1. 不使用请求转发是防止刷新页面会导致表单重复提交
* 2. 这里为什么写的是 manage.html 因为这样可以更加明确的表示到哪个页面
* 3. 这里的 manage.html 表示要去找 方法的映射路径为 manage.html
*/
return "redirect:/manage.html";
} else {
//不合法 重新登录!
return "adminLogin";
}
}
//处理用户请求 manage.html
@GetMapping("/manage.html")
public String mainPage(Model model) {
//这里集合-模拟用户数据,放入到request域中,并显示
ArrayList<User> users = new ArrayList<>();
users.add(new User(1, "关羽", "123456", 20, "gy@sohu.com"));
users.add(new User(2, "张飞", "123456", 26, "zf@sohu.com"));
users.add(new User(3, "赵云", "123456", 28, "zy@sohu.com"));
users.add(new User(4, "马超", "123456", 22, "mc@sohu.com"));
users.add(new User(5, "黄忠", "123456", 50, "hz@sohu.com"));
//将数据放入到request域中
model.addAttribute("users", users);
return "manage"; //这里才是我们的视图解析到 /template/manage.html
}
}
- 显示登录错误信息和提交 action
- 防止非法进入 manage.html
----- 修改 AdminController.java -----
package com.xjs.springboot.controller;
import com.xjs.springboot.bean.Admin;
import com.xjs.springboot.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
/**
* @Author: 谢家升
* @Version: 1.0
*/
@Controller
public class AdminController {
//响应用户的登录请求
@PostMapping("/login")
public String login(Admin admin, HttpSession session, Model model) {
//验证用户是否合法
if (StringUtils.hasText(admin.getName()) && "888".equals(admin.getPassword())) {
//将登录用户保存到session
session.setAttribute("loginAdmin", admin);
/**合法 重定向到 manage.html
* 1. 不使用请求转发是防止刷新页面会导致表单重复提交
* 2. 这里为什么写的是 manage.html 因为这样可以更加明确的表示到哪个页面
* 3. 这里的 manage.html 表示要去找 方法的映射路径为 manage.html
*/
return "redirect:/manage.html";
} else {
//不合法 重新登录!
model.addAttribute("msg", "账号/用户名错误");
return "adminLogin";
}
}
//处理用户请求 manage.html
@GetMapping("/manage.html")
public String mainPage(Model model, HttpSession session) {
//这里暂时在方法中使用session验证,后面我们统一使用拦截器验证
Object loginAdmin = session.getAttribute("loginAdmin");
if (loginAdmin != null) { //说明成功登录过
//这里集合-模拟用户数据,放入到request域中,并显示
ArrayList<User> users = new ArrayList<>();
users.add(new User(1, "关羽", "123456", 20, "gy@sohu.com"));
users.add(new User(2, "张飞", "123456", 26, "zf@sohu.com"));
users.add(new User(3, "赵云", "123456", 28, "zy@sohu.com"));
users.add(new User(4, "马超", "123456", 22, "mc@sohu.com"));
users.add(new User(5, "黄忠", "123456", 50, "hz@sohu.com"));
//将数据放入到request域中
model.addAttribute("users", users);
return "manage"; //这里才是我们的视图解析到 /template/manage.html
} else {
//这里就返回登录页面,并给出提示
model.addAttribute("msg", "你没有登录/请登录");
return "adminLogin"; //请求转发到 adminLogin.html
}
}
}
----- adminLogin.html -----
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body bgcolor="#CED3FE">
<img src="images/1.GIF"/>
<hr/>
<div style="text-align: center">
<h1>用户登陆</h1>
<form action="#" th:action="@{/login}" method="post">
<label style="color: red" th:text="${msg}"></label><br/>
用户名:<input type="text" style="width:150px" name="name"/><br/><br/>
密 码 :<input type="password" style="width:150px" name="password"/><br/><br/>
<input type="submit" value="登录"/>
<input type="reset" value="重新填写"/>
</form>
</div>
<hr/>
<!--<img src="images/logo.png"/>-->
</body>
</html>
- 显示登录的用户名,修改 manage.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>管理后台</title>
</head>
<body bgcolor="#CED3FE">
<img src="images/1.GIF"/>
<a href='#'>返回管理界面</a> <a href='#'>安全退出</a> 欢迎您:[[${session.loginAdmin.name}]]
<hr/>
<div style="text-align: center">
<h1>管理雇员~</h1>
<table border="1px" cellspacing="0" bordercolor="green" style="width:800px;margin:
auto">
<tr bgcolor="pink">
<td>id</td>
<td>name</td>
<td>pwd</td>
<td>email</td>
<td>age</td>
</tr>
<tr bgcolor="#ffc0cb" th:each="user:${users}">
<td th:text="${user.id}">a</td>
<td th:text="${user.name}">b</td>
<td th:text="${user.password}">c</td>
<td th:text="${user.age}">d</td>
<td th:text="${user.email}">e</td>
</tr>
</table>
<br/>
</div>
<hr/>
<!--<img src="images/logo.png"/>-->
</body>
</html>
- 完成安全退出功能,修改 manage.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>管理后台</title>
</head>
<body bgcolor="#CED3FE">
<img src="images/1.GIF"/>
<a href='#'>返回管理界面</a> <a href='#' th:href="@{/}">安全退出</a> 欢迎您:[[${session.loginAdmin.name}]]
<hr/>
<div style="text-align: center">
<h1>管理雇员~</h1>
<table border="1px" cellspacing="0" bordercolor="green" style="width:800px;margin:
auto">
<tr bgcolor="pink">
<td>id</td>
<td>name</td>
<td>pwd</td>
<td>email</td>
<td>age</td>
</tr>
<tr bgcolor="#ffc0cb" th:each="user:${users}">
<td th:text="${user.id}">a</td>
<td th:text="${user.name}">b</td>
<td th:text="${user.password}">c</td>
<td th:text="${user.age}">d</td>
<td th:text="${user.email}">e</td>
</tr>
</table>
<br/>
</div>
<hr/>
<!--<img src="images/logo.png"/>-->
</body>
</html>