七.Thymeleaf模板引擎
1.模板引擎
由于SpringBoot默认不支持 JSP(因为默认打包方式为jar
包,jsp不支持在jar
包内运行),需要引入第三方模板引擎技术实现页面渲染。
其实jsp就是一个模板引擎,还有用的比较多的freemarker、Thymeleaf。但再多的模板引擎,他们的思想都是一样的,什么样一个思想呢我们来看一下这张图:
模板引擎的作用:写一个页面模板,比如有些值是动态的,我们可以在这些值的地方写一些表达式。而这些值,从哪来呢,就是我们在后台封装一些数据。然后把这个数据和页面模板交给我们模板引擎,模板引擎按照我们这个数据帮你把表达式解析、填充到我们指定的位置,最终把这个数据生成一个我们想要的内容给我们写展现出去
SpringBoot推荐的是Thymeleaf模板引擎
2.Thymeleaf语法
1、表达式
表达式部分官方文档:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#standard-expression-syntax
表达式名字 | 语法 | 用途 |
---|---|---|
变量取值 表达式 | ${…} | 获取请求域、session域、对象等值 |
选择变量 表达式 | *{…} | 获取上下文对象值 |
消息 表达式 | #{…} | 消息(获取国际化等值) |
链接 表达式 | @{…} | 生成适应当前项目根路径的链接 |
片段 表达式 | ~{…} | 导入html片段,获取公共页面片段 |
2、字面量
文本值: `‘one text’ , ‘Another one!’ ,…数字: 0 , 34 , 3.0 , 12.3 ,…布尔值: true , false
空值: null
变量: one,two,… 变量不能有空格
3、文本操作
字符串拼接: +
变量替换: |The name is ${name}|
4、数学运算
运算符: + , - , * , / , %
5、布尔运算
运算符: and , or
一元运算: ! , not
6、比较运算
比较: > , < , >= , <= ( gt , lt , ge , le )等式: == , != ( eq , ne )
7、条件运算
If-then: (if) ? (then)
If-then-else: (if) ? (then) : (else)
Default: (value) ?: (defaultvalue)
8、特殊操作
无操作: _
9、设置属性值: th:attr
设置单个值
<form action="subscribe.html" th:attr="action=@{/subscribe}">
<fieldset>
<input type="text" name="email" />
<input type="submit" value="Subscribe!" th:attr="value=#{subscribe.submit}"/>
</fieldset>
</form>
设置多个值
<img src="../../images/gtvglogo.png" th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />
以上两个的代替写法 th:xxxx
<input type="submit" value="Subscribe!" th:value="#{subscribe.submit}"/>
<form action="subscribe.html" th:action="@{/subscribe}">
所有h5标签属性的兼容写法:(基本h5标签属性都能使用th:xxx代替)
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#setting-value-to-specific-attributes
10、循环遍历
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#iteration
<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>
<tr th:each="prod,iterStat : ${prods}" th:class="${iterStat.odd}? 'odd'">
<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>
11、条件运算
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#conditional-evaluation
<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>
12、属性优先级
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#attribute-precedence
3.使用Thymeleaf
Thymeleaf官网使用文档:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#standard-expression-syntax
1、pom.xml中引入Thymeleaf模板引擎启动器依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
或者在构建项目是,勾选Thymeleaf模板引擎,它会自动导入Thymeleaf模板引擎启动器
2、编写一个HelloController
@Controller
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "hello"; //classpath:/templates/test.html
}
}
3、编写一个测试页面 hello.html 放在 templates 目录下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>hello,Thymeleaf!</h1>
</body>
</html>
4、启动项目请求测试:
4.Thymeleaf自动配置原理
前面呢,我们已经引入了Thymeleaf,并成功通过controller方法跳转页面,其原理是什么?
按照SpringBoot的自动配置原理特点,肯定有个ThymeleafAutoConfiguration
自动配置类来进行Thymeleaf模板引擎的自动配置。有一个ThymeleafProperties
类绑定了配置文件,用于简单的自定义Thymeleaf配置修改
ThymeleafAutoConfiguration:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ThymeleafProperties.class)
@ConditionalOnClass({
TemplateMode.class, SpringTemplateEngine.class })
@AutoConfigureAfter({
WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class })
public class ThymeleafAutoConfiguration {
ThymeleafProperties:
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
我们可以在其中看到默认的前缀DEFAULT_PREFIX
和后缀DEFAULT_SUFFIX
上面就说明了为什么只要导入Thymeleaf启动器,然后在resources/templates/
下写html页面,thymeleaf就可以自动渲染,就可以通过controller方法转发/重定向到指定页面
总的来说:
- 所有thymeleaf的配置值都在 ThymeleafProperties
- 自动配置类配置好了SpringTemplateEngine、ThymeleafViewResolver
- 我们只需要直接开发页面
5.练习
1、修改测试请求,增加数据传输;
@GetMapping("/t1")
public String test1(Model model){
//存入数据
model.addAttribute("msg","test,Thymeleaf!");
model.addAttribute("users", Arrays.asList("唐三","小舞","胖子"));
return "test"; //classpath:/templates/test.html
}
2、我们要使用thymeleaf,需要在html文件中导入命名空间的约束,方便提示。
我们可以去官方文档的中看一下命名空间拿来过来:
xmlns:th="http://www.thymeleaf.org"
3、我们去编写下前端页面test.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--[[${xxx}]]:取值的行内写法,和jsp的${msg}一样-->
<h1>[[${msg}]]</h1>
<!--th:text:将div标签的内容设置为${xxx}中xxx的值-->
<div th:text="${msg}"></div>
<!-- th:each:循环遍历${users}取值的值 遍历的第二个参数state,是状态,count是计数值,每遍历一次+1-->
<div th:each="user : ${users}" th:text="${user}"></div>
<div th:each="user : ${users}">[[${user}]]</div>
<div th:each="user,state : ${users}" th:text="${state.count}"></div>
</body>
</html>
4、启动测试!
我们看完语法,很多样式,我们即使现在学习了,也会忘记。所以我们在学习过程中,需要使用什么,根据官方文档来查询,才是最重要的,要熟练使用官方文档!
八.拦截器
1.实现
1、实现 HandlerInterceptor
接口
LoginInterceptor类:自定义用来拦截登录认证的拦截器
public class LoginInterceptor implements HandlerInterceptor {
//目标方法执行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
System.out.println("preHandle执行了");
//登录检查逻辑
HttpSession session = request.getSession();
Object loginUser = session.getAttribute("loginUser");
if(loginUser != null){
//放行
return true;
}
//拦截住。未登录。跳转到登录页
request.setAttribute("msg","请先登录");
// re.sendRedirect("/");
request.getRequestDispatcher("/").forward(request,response);
return false;
}
//目标方法执行完成以后
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle执行了");
}
//页面渲染以后
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion执行了");
}
}
2、在自定义的配置类中添加配置好的LoginInterceptor拦截器
- 自定义的配置类必须实现WebMvcConfigurer接口
- @Configuration注解该类,表示为一个配置类,会注册到spring容器中
- 在自定义配置类重写addInterceptors方法
- addInterceptor方法:添加自定义的LoginInterceptor拦截器
- addPathPatterns方法:添加拦截的路径
- excludePathPatterns方法:添加不拦截的路径
/**
- 1、编写一个拦截器实现HandlerInterceptor接口
- 2、拦截器注册到容器中(实现WebMvcConfigurer的addInterceptors)
- 3、指定拦截规则【如果是拦截所有,静态资源也会被拦截】
*/
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**") //所有请求都被拦截(包括静态资源)