SpringBoot之Thymeleaf模板使用
介绍
开发传统Java WEB工程时,我们可以使用JSP页面模板语言,但是在SpringBoot中已经不推荐使用了。SpringBoot支持如下页面模板语言
Thymeleaf
FreeMarker
Velocity
Groovy
JSP
上面并没有列举所有SpringBoot支持的页面模板技术。其中Thymeleaf是SpringBoot官方所推荐使用的,下面来谈谈Thymeleaf一些常用的语法规则。
Thymeleaf默认的页面文件后缀是.html
为什么是Thymeleaf?
简单说, Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP 。相较于其他的模板引擎,它有如下四个极吸引人的特点:
动静结合:Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。
这样提示下: 所谓的动静结合,只是在开发的时候能让前端展示出效果, 如果在标签上添加Thymeleaf标签语法后,就会将html标签内使用的值替换掉,替换成后端传递的值
开箱即用:可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、改jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
多方言支持:Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
与SpringBoot完美整合,SpringBoot提供了Thymeleaf的默认配置,并且为Thymeleaf设置了视图解析器,我们可以像以前操作jsp一样来操作Thymeleaf。代码几乎没有任何区别,就是在模板语法上有区别。
使用
接下来,我们就通过入门案例来体会Thymeleaf的魅力
在pom.xml中加入Thymeleaf的依赖
<!-- 模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
SpringBoot会自动为Thymeleaf注册一个视图解析器:
我们还需要在resources创建templates (名称固定) 这个是Springboot 固定的模板存放地方
static 是SpringBoot的静态资源访问路径不理解的 可以到我博客里找到SpringBoot访问静态资源.md
访问的时候就和SpringMVC中的视图解析器一样,利用 Model 或者 ModelAndView …进行传值
默认前缀:classpath:/templates/
默认后缀:.html
所以如果我们返回视图:users,会指向到 classpath:/templates/users.html
一般我们无需进行修改,默认即可。
注意: 要使用templates模板语法的页面必须放在 templates 目录下才能解析否则解析不了
访问 templates内的页面必须通过解析器才能访问也就是需要在Controller里,写接口然后通过接口进行跳转
小案例
省略数据库连接操作和Serivce … 自己补充就行
使用@RestController+ModelAndView 方式
package cn.boke.controller;
import cn.boke.entity.User;
import cn.boke.service.UserService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.Resource;
import java.util.List;
@RestController
public class MapperController {
@Resource(name = "UserServiceImpl")
private UserService userService;
@RequestMapping("/queryUser")
public ModelAndView queryUser() {
//从数据库中加User表数据全部查询出来返回给页面
List<User> users = userService.queryAll();
ModelAndView mode=new ModelAndView();
mode.addObject("users",users);
mode.setViewName("users");
return mode;
}
}
使用@Controller+String方式
返回String类型通过返回名称自动找对应的文件,但是不能使用@RestController注解
@RestController
@RequestMapping("main")
public class MainController {
@GetMapping("index")
public String index(Model model) {
return "index";
}
}
创建模板
注意,在html 的名称空间里添加 : xmlns:th="http://www.thymeleaf.org"
会有语法提示
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="ch">
<head>
<meta charset="UTF-8">
<title>首页</title>
<style type="text/css">
table {border-collapse: collapse; font-size: 14px; width: 80%; margin: auto}
table, th, td {border: 1px solid darkslategray;padding: 10px}
</style>
</head>
<body>
<div style="text-align: center">
<span style="color: darkslategray; font-size: 30px">欢迎光临!</span>
<hr/>
<table >
<tr>
<th>姓名</th>
<th>密码</th>
</tr>
<tr th:each="user : ${users}">
<td th:text="${user.username}">胡123</td>
<td th:text="${user.password}">123456789</td>
</tr>
</table>
</div>
</body>
</html>
我们看到这里使用了以下语法:
th
是 thymeleaf简写
${}
:这个类似与el表达式
th:each
:类似于c:foreach 遍历集合,但是语法更加简洁
th:text
:声明标签中的文本
更多的语法 会专门来写一篇文档 这里就,简单演示下怎么使用的
我们开始测试 http://localhost/queryUser
Thymeleaf会在第一次对模板解析之后进行缓存,极大的提高了并发处理能力。但是这给我们开发带来了不便,修改页面后并不会立刻看到效果,我们开发阶段可以关掉缓存使用:
如果你使用的是application.yml 在文件中添加
spring:
# 开发阶段关闭thymeleaf的模板缓存 否则每次修改都需要重启引导
thymeleaf:
cache: false
设置后每次需要显示最新数据的时候 在IDEA中按住shift+ctrl +F9 开始更新 不需要在重启引导了
开放静态资源和跨域请求
TemplateConfig
package com.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class TemplateConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST","PUT", "DELETE", "OPTIONS")
.allowCredentials(true).maxAge(3600);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//开放static,templates,public 目录 但是请求时候需要加上对应的前缀,比如我访问static下的资源/static/xxxx/xx.js
registry.addResourceHandler("/static/**","/templates/**","/public/**")
.addResourceLocations("classpath:/static/","classpath:/templates/","classpath:/public/");
}
}