1. 模板引擎介绍
如果需要服务端页面渲染,优先考虑使用模板引擎
SpringBoot 包含以下模板引擎的自动配置
- FreeMarker
- Groovy
- Thymeleaf
- Mustache
2. SpringBoot整合Thymeleaf
- pom.xml添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
-
自动配置原理
- 开启了org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration自动配置
- 属性绑定在ThymeleafProperties中,对应配置文件spring.thymeleaf内容
- 所有的模板页面默认在classpath:/templates文件夹下,找后缀名为.html的页面
- 参数:
spring.thymeleaf.cache=true
,默认为true,是否将模板进行缓存,建议开发时关闭,上线开启;spring.thymeleaf.check-template=true
,默认为true。模板渲染前,是否检查模板存不存在
-
简单使用
WelcomeController如下:
package com.hh.springboot3test.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
// 前后端不分离模式,使用@Controller,适配服务器渲染
@Controller
public class WelcomeController {
/**
* 利用模板引擎跳转到指定页面
*/
@GetMapping("/welcome")
public String hello(@RequestParam("name") String name,
Model model) {
// request作用域级别
model.addAttribute("name", name);
// 模板的逻辑视图名
// 物理视图 = 前缀 + 逻辑视图名 + 后缀
// 真实地址 = classpath:/templates/welcome.html
return "welcome";
}
}
src/main/resources/templates/welcome.html如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>你好:<span th:text="${msg}">张三</span></h1>
</body>
</html>
访问http://localhost:8080/welcome?name=lisi。效果如下:
2. Thymeleaf基础语法
th:xxx
- th:text:标签体内文本值渲染
- th:utext:不会转义,显示为html原本的样子
<!-- String msg = "<span style='color:red'>"+name+"</span>"; -->
<h1 th:utext="${msg}">显示红色的lisi</h1>
- th:属性:标签指定属性渲染。比如: th:src=“${imgUrl}”。其中imgUrl = “/baidu.jpg”
- th:attr:标签任意属性渲染。比如:
<img src="1.jpg" style="width:100px;" th:attr="src=${imgUrl},style=${style}"/>
- th:if th:each…:其他th指令
表达式:用来动态取值
- ${}:变量取值;使用model共享给页面的值都直接用${}
- @{}:主要用于url路径,如
th:src="@{${imgUrl}}"
。如果application.properties设置了server.servlet.context-path=/demo
根路径,渲染时会自动将根路径/demo添加到src前面,此时页面的源码是src="/demo/baidu.jpg"
- #{}:国际化消息
- ~{}:片段引用
- *{}:变量选择:需要配合th:object绑定对象
系统工具&内置对象:
- param:请求参数对象
- session:session对象
- application:application对象
- #execInfo:模板执行信息
- #messages:国际化消息
- #uris:uri/url工具
- #conversions:类型转换工具
- #dates:日期工具,是java.util.Date对象的工具类
- #calendars:类似#dates,只不过是java.util.Calendar对象的工具类
- #temporals:JDK8+ java.time API工具类
- #numbers:数字操作工具
- #strings:字符串操作。比如
th:text="${#strings.toUpperCase(name)}"
- #objects:对象操作
- #bools:bool操作
- #arrays:array工具
- #lists:list工具
- #sets:set工具
- #maps:map工具
- #aggregates:集合聚合工具(sum、avg)
- #ids:id生成工具
语法示例
- 常见:
- 布尔:true、false
- null: null
- 布尔操作:
- 二进制运算: and、or
- 取反:!、not
- 比较运算:
- 比较:>、<、<=、>=(gt、lt、ge、le)。例如:
th:text="${age > 18}"
- 等值运算:==、!=(eq、ne)
- 比较:>、<、<=、>=(gt、lt、ge、le)。例如:
- 条件运算:
- if-then: (if)?(then)
- if-then-else: (if)?(then):(else)
- default: (value)?:(defaultValue)
- 特殊语法:
- 无操作:_
3. th:each遍历
stats有以下属性:
- index:当前遍历元素的索引,从0开始
- count:当前遍历元素的索引,从1开始
- size:需要遍历元素的总数量
- current:当前正在遍历的元素对象
- even/odd:是否偶数/奇数行
- first:是否第一个元素
- last:是否最后一个元素
使用示例。引入了bootstrap的CSS和Javascript脚本
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Thymeleaf遍历测试</title>
<!-- 需要从远程地址请求,所以网络必须要好 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
</head>
<body>
<!-- bootstrap定义的CSS -->
<table class="table">
<thead>
<tr>
<!-- scope="col"表明是列头 -->
<th scope="col">ID</th>
<th scope="col">名字</th>
<th scope="col">年龄</th>
<th scope="col">状态信息</th>
</tr>
</thead>
<tbody>
<tr th:each="user,stats : ${users}">
<!-- scope="row"表明是行头 -->
<th scope="row" th:text="${user.id}">1</th>
<td>[[${user.name}]]</td>
<td>[(${user.age})]</td>
<td>
index: [[${stats.index}]] <br/>
count: [[${stats.count}]] <br/>
size(总数量): [[${stats.size}]] <br/>
current(当前对象): [[${stats.current}]] <br/>
even/odd: [[${not stats.even} ? 'even' : 'odd']] <br/>
first: [[${stats.first}]] <br/>
last: [[${stats.last}]] <br/>
</td>
</tr>
</tbody>
</table>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
crossorigin="anonymous"></script>
</body>
</html>
显示效果如下:
4. th:switch语法
使用示例:
<td th:switch="${user.name}">
<button th:case="'lily'" type="button" class="btn btn-primary">LILY</button>
<button th:case="*" type="button" class="btn btn-default">DEFAULT</button>
</td>
显示效果
5. 属性优先级
先执行哪个,后执行哪个
Order | Feature | Attributes |
---|---|---|
1 | 片段包含 | th:insert、th:replace |
2 | 遍历 | th:each |
3 | 判断 | th:if、th:unless、th:switch、th:case |
4 | 定义本地变量 | th:object、th:with |
5 | 通用方式属性修改 | th:attr、th:attrprepend、th:attrappend |
6 | 指定属性修改 | th:value、th:href、th:src、… |
7 | 文本值 | th:text、th:utext |
8 | 片段指定 | th:fragment |
9 | 片段移除 | th:remove |
6. 模板布局
- 定义模板: th:fragment
- 引用模板:~{templatename :: selector}
- 插入模板:th:insert、替换模板: th:replace
使用示例:
在src/main/resources/templates目录下新建common.html,内容如下。其使用th:fragment,将整个header封装成一个名称为myheader的模板
header是从https://getbootstrap.com/docs/5.3/examples/headers/,选择其中一份,拷贝源码来的
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>通用的模板</title>
</head>
<body>
<!-- 使用th:fragment,将整个header封装成一个名称为myheader的模板 -->
<header th:fragment="myheader" class="p-3 text-bg-dark">
<div class="container">
<div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start">
<a href="/" class="d-flex align-items-center mb-2 mb-lg-0 text-white text-decoration-none">
<svg class="bi me-2" width="40" height="32" role="img" aria-label="Bootstrap">
<use xlink:href="#bootstrap"></use>
</svg>
</a>
<ul class="nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0">
<li><a href="#" class="nav-link px-2 text-secondary">Home</a></li>
<li><a href="#" class="nav-link px-2 text-white">Features</a></li>
<li><a href="#" class="nav-link px-2 text-white">Pricing</a></li>
<li><a href="#" class="nav-link px-2 text-white">FAQs</a></li>
<li><a href="#" class="nav-link px-2 text-white">About</a></li>
</ul>
<form class="col-12 col-lg-auto mb-3 mb-lg-0 me-lg-3" role="search">
<input type="search" class="form-control form-control-dark text-bg-dark" placeholder="Search..."
aria-label="Search">
</form>
<div class="text-end">
<button type="button" class="btn btn-outline-light me-2">Login</button>
<button type="button" class="btn btn-warning">Sign-up</button>
</div>
</div>
</div>
</header>
</body>
</html>
然后在其它HTML页面,通过th:replace进行引用。如下所示:
<!-- 导航。使用公共部分进行替换 -->
<!-- ~{模板名 :: 片段名} -->
<div th:replace="~{common :: myheader}"></div>
然后该页面打开,就可以显示header。如下所示: