文章目录
- 官方文档
- 基本介绍
- Thymeleaf机制说明
- Thymeleaf语法
- 表达式
- 运算符
- th属性
- 迭代
- 条件运算
- 使用Thymeleaf th属性需要注意点
- Thymeleaf综合案例
- 需求说明
- 思路分析
- 代码实现
- 作业布置
官方文档
在线文档: https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
离线文档: Thymeleaf离线文档
基本介绍
●Thymeleaf是什么?
1.Thymeleaf 是一个跟 Velocity, FreeMarker 类似的模板引擎, 可完全替代 JSP.
2.Thymeleaf
是一个java
类库, 它是一个 xml/xhtml/html5
的模板引擎, 可以作为mvc
的web
应用的view
层.
●Thymeleaf的优点
1.实现JSTL, OGNL的表达式效果, 语法相似, java程序员上手快.
2.Thymeleaf模板页面无需服务器渲染, 也可以被浏览器运行, 页面简洁.
3.SpringBoot支持FreeMarker, Thymeleaf, veocity.
●Thymeleaf的缺点
1.THymeleaf: Thymeleaf is a modern server-side Java template engine for both web and standalone environments.
2.缺点: 并不是一个高性能的引擎, 适用于单体应用.
3.说明: 如果要做一个高并发的应用, 选择前后端分离更好, 但是作为SpringBoot
推荐的模板引擎, 我们还是要讲解Thymeleaf
的使用, 这样大家在工作中如果使用到, 也能ok.
4.后面我们还要讲解 Vue + ElementPlus + Axios + SpringBoot 前后端分离.
Thymeleaf机制说明
1.Thymeleaf 是服务器渲染技术, 页面数据是在服务端进行渲染的.
2.比如: manage.html
中一段thymeleaf
代码, 是在用户请求该页面时, 用thymeleaf
模板引擎完成处理的(在服务端完成), 并将结果页面返回.
3.因此使用了Thymeleaf
, 并不是前后端分离.
Thymeleaf语法
表达式
1.表达式一览
表达式名字 | 语法 | 用途 |
---|---|---|
变量取值 | ${...} | 获取请求域, session域, 对象等值 |
选择变量 | *{...} | 获取上下文对象 |
消息 | #{...} | 获取国际化等值 |
链接 | @{...} | 生成链接 |
片段表达式 | ~{...} | jsp:include 作用, 引入公共页面片段 |
2.字面量
文本值: ‘zzw hello’, ‘hello’
数字: 10, 2.32, -2.33
布尔值: true, false
空值: null
变量: name, age(变量不能有空格)
3.文本操作
字符串拼接: +
变量替换: age = ${age}
运算符
1.数学运算
运算符: + - * / %
2.布尔运算
运算符: and, or
一元运算: ! not
3.比较运算
比较: > < >= <= (gt lt ge le)
等式: == != (eq ne)
4.条件运算
If-then:(if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
th属性
html
有的属性, Thymeleaf
基本都有, 而常用的属性大概有七八个, 其中th
属性执行的优先级从1~8
, 数字越低优先级越高
1.th:text:
设置当前元素的文本内容, 相同功能的还有th:utext
, 两者的区别在于前者不会转义html
标签, 后者会. 优先级不高: order=7
2.th:value:
设置当前元素的value
值, 类似修改指定属性的还有th:src
, th:href
.优先级不高: order=6
3.th:each:
遍历循环元素, 和th:text
或th:value
一起使用. 注意该属性修饰的标签位置, 优先级很高: order=2
4.th:if:
条件判断, 类似的还有th:unless
, th:switch
, th:case
. 优先级较高: order=3
5.th:insert:
代码块引入, 类似的还有th:replace
, th:include
, 三者的区别较大, 或使用不恰当会破坏html
结构, 常用于公共代码块提取的场景.优先级最高: order=1
6.th:fragment:
定义代码块, 方便被th:insert
引用, 优先级最低: order=8
7.th:object:
声明变量, 一般和*{}
一起配合使用, 达到偷懒的效果.优先级一般, order=4
8.th:attr:
修改任意属性, 实际开发中用的较少, 因为有丰富的其它th
属性帮忙, 类似的还有th:attrappend
, th:attrprepend
. 优先级一般, order=5
迭代
如果没有走服务器渲染, 显示的是默认的值.
条件运算
用th:href
取得的值来替换href
属性
使用Thymeleaf th属性需要注意点
1.若要使用Thymeleaf
语法, 首先要声明名称空间: xmlns:th="http://www.thymeleaf.org"
2.设置文本内容th:text
, 设置input
的值th:value
, 循环输出th:each
, 条件判断th:if
, 插入代码块th:insert
, 定义代码块th:fragment
, 声明变量th:object
3.th:each
的用法需要格外注意, 打个比方: 如果你要循环一个div
中的p
标签, 则th:each
属性必须放在p
标签上. 若你将th:each
属性放在div
上, 则循环的将是整个div
.
4.变量表达式中提供了很多的内置方法, 该内置方法使用#
开头, 请不要与#{}
消息表达式弄混.
Thymeleaf综合案例
需求说明
说明: 使用SpringBoot + Thymeleaf
完成简单的用户登录, 列表功能.
要求:
1.用户名未输入
, 提示信息.
2.密码不是666
, 提示不合法, 将错误信息回显
3.登陆成功在用户列表页面显示用户列表.
思路分析
说明: 使用SpringBoot + Thymeleaf
完成简单的用户登录.
代码实现
1.创建项目, 项目名使用springboot-usersys
, 这里使用灵活创建项目方式.
2.在pom.xml
引入lombok
, 并切换一下springboot
版本
<!--导入springboot父工程-规定写法-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<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>
</dependencies>
3.引入spring-boot-configuration-processor, 在前面我们用过
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
4.引入thymeleaf-start: 项目会完成自动配置, 程序员按照规则开发即可
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
5.springboot系列三: sprintboot自动配置
6.类路径下引入static资源
7.创建templates/login.html
(该目录不能直接访问)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body bgcolor="#CED3FE">
<img src="images/1.GIF">
<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>
密 码:<input type="password" style="width:150px" name="password"><br>
<input type="submit" value="登录">
<input type="reset" value="重新填写">
</form>
</div>
</body>
</html>
8.创建src/main/java/com/zzw/springboot/controller/IndexController.java
@Controller
public class IndexController {
//编写方法, 转发到 adminLogin.html(登陆页面)
@GetMapping(value = {"/", "/login"})
public String login() {
/**
* 解读
* 1.这里我们引入了starter-thymeleaf
* 2.这里就会直接使用视图解析到 thymeleaf 下的模板文件 adminLogin.html
*/
return "adminLogin";
}
}
9.启动, 浏览器请求 http://localhost:8080/
10.创建src/main/java/com/zzw/springboot/bean/Admin.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Admin {
private String name;
private String password;
}
11.创建src/main/java/com/zzw/springboot/bean/User.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String name;
private String password;
private Integer age;
private String email;
}
12.创建src/main/java/com/zzw/springboot/controller/AdminController.java
springboot支持复杂参数
@Controller
public class AdminController {
//响应用户的登录请求
@PostMapping("/login")
public String login(Admin admin, HttpSession session, Model model) {
//验证用户是否合法
if (StringUtils.hasText(admin.getName()) && "666".equals(admin.getPassword())) {
//合法, 携带user信息, 重定向到manage.html
//回忆java web知识, 不使用请求转发, 防止刷新页面会重复提交
//这里我们为什么是写的 manage.html, 因为这样可以更加明确地表示到哪个页面
//manage.html 表示去找 方法的映射路径为 manage.html
return "redirect:/manage.html";
} else {
//不合法, 返回登陆页面
return "adminLogin";//走Thymeleaf的视图解析器
}
}
//处理用户请求 manage.html
@GetMapping("/manage.html")
public String mainPage() {
//用集合模拟用户数据, 放入到request域中, 并显示
return "manage";//这里是我们的视图解析器,到 templates/manage.html
}
}
13.创建 src/main/resources/templates/manage.html
<!DOCTYPE html>
<html lang="en">
<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>age</td>
<td>email</td>
</tr>
<tr>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
<td>e</td>
</tr>
</table>
<br/>
</div>
<hr/>
<img src="images/logo.png"/>
</body>
</html>
14.回填<form action=“login
” method=“post”>, 相对路径是参考浏览器地址栏
不用回填, 因为action="#"
就是action="/"
, 被解析成 http://localhost:8080/
, 没有问题.
15.启动浏览器, http://localhost:8080/login
, 用户名密码错误, 停留在登陆页面.
校验正确, 进入manage.html
16.补充AdminController.java
//处理用户请求 manage.html
@GetMapping("/manage.html")
public String mainPage(Model model) {
//用集合模拟用户数据, 放入到request域中, 并显示
List<User> users = new ArrayList<>();
users.add(new User(1, "张三", "123456", 23, "张三@163.com"));
users.add(new User(2, "李四", "123456", 24, "李四@163.com"));
users.add(new User(3, "王五", "123456", 25, "王五@163.com"));
users.add(new User(4, "赵六", "123456", 26, "赵六@163.com"));
users.add(new User(5, "田七", "123456", 27, "田七@163.com"));
//将数据放入到request域中
model.addAttribute("users", users);
return "manage";//这里是我们的视图解析器,到 templates/manage.html
}
17.补充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>age</td>
<td>email</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>
18.测试
19.修改login.html
(1)显示登录错误信息
//不合法, 请求转发, 返回登陆页面
model.addAttribute("error", "用户名或密码错误");
return "adminLogin";//走Thymeleaf的视图解析器
<label style="color: red" th:text="${error}"></label><br/>
用户:<input type="text" style="width:150px" name="name"><br>
(2)修改提交的action
<form action="#" th:action="@{/login}" method="post">
(3)处理非法登录, 防止非法进入manage.html
@Controller
public class AdminController {
//响应用户的登录请求
@PostMapping("/login")
public String login(Admin admin, HttpSession session, Model model) {
//验证用户是否合法
if (StringUtils.hasText(admin.getName()) && "666".equals(admin.getPassword())) {
//将登陆用户保存到session
session.setAttribute("loginAdmin", admin);
//合法, 携带user信息, 重定向到manage.html
//回忆java web知识, 不使用请求转发, 防止刷新页面会重复提交
//这里我们为什么是写的 manage.html, 因为这样可以更加明确地表示到哪个页面
//manage.html 表示去找 方法的映射路径为 manage.html
return "redirect:/manage.html";
} else {
//不合法, 请求转发, 返回登陆页面
model.addAttribute("error", "用户名或密码错误");
return "adminLogin";//走Thymeleaf的视图解析器
}
}
//处理用户请求 manage.html
@GetMapping("/manage.html")
public String mainPage(Model model,
@SessionAttribute(value = "loginAdmin", required = false) Admin admin) {
//这里暂时在方法中验证, 后面我们统一使用拦截器
if (admin == null) {
model.addAttribute("error", "请先登录");
return "adminLogin";//请求转发到 templates/adminLogin.html
}
//用集合模拟用户数据, 放入到request域中, 并显示
List<User> users = new ArrayList<>();
users.add(new User(1, "张三", "123456", 23, "张三@163.com"));
users.add(new User(2, "李四", "123456", 24, "李四@163.com"));
users.add(new User(3, "王五", "123456", 25, "王五@163.com"));
users.add(new User(4, "赵六", "123456", 26, "赵六@163.com"));
users.add(new User(5, "田七", "123456", 27, "田七@163.com"));
//将数据放入到request域中
model.addAttribute("users", users);
return "manage";//这里是我们的视图解析器,到 templates/manage.html
}
}
(4)登陆成功后信息显示, 行内写法
欢迎您:[[${session.loginAdmin.name}]]
5)安全退出
<a href='#' th:href="@{/}">安全退出</a>
作业布置
1.把前面我们学过的接收参数相关注解, 自定义转换器, 处理JSON
, 内容协商, 相关代码和案例, 自己写一遍, 一定要自己写一遍, 否则没有印象, 理解不会深入.
2.将Thymeleaf
用户管理 改成 妖怪管理列表, 字段做相应的改变, 进行联系.
1)Monster [id, name, skill, age, sal, birth]
2)基本界面保持不变
3)在完成过程中, 小伙伴会遇到各种问题, 要开始培养自己独立解决问题的能力了.