在介绍 Thymeleaf 之前,首先要了解下 Spring Boot 怎么返回 String、resources/templates 和 resources/static 目录下的文件。
返回 String、resources/templates 和 resources/static 目录下的文件
1. 返回 String
返回 String,用注解是 @RestController,它是由 @Controller 和 @ResponseBody 两个注解组合而成的。
例如:
@RestController
@RequestMapping("/rest/controller")
public class ReturnStringController {
@RequestMapping("/")
public String getIndex() {
return "restController";
}
@RequestMapping("/page")
public String getPage() {
return "restController page";
}
}
2. 返回 resources/templates 下的模板文件
返回模板,用的注解是 @Controller
3. 返回 resources/static 下的静态文件
返回静态文件最简单了,直接在 resources/static 添加文件即可
例如:新建一个 resources/static/public/test.html
然后在浏览器输入 localhost:8080/public/test.html 就可以访问该网页了。
@Controller 与 @RestController 的区别
在 POJO(普通Java对象,Plain Ordinary Java Object)类定义处标注 @Controller,再通过 <content:component-scan /…> 扫描相应的类包,即可使 POJO 类成为一个能处理HTTP请求的控制器。
使用 @RequestMapping 后,返回值通常解析为跳转路径。
加上 @Responsebody 后,返回结果直接写入HTTP response body中,不会被解析为跳转路径。
thymeleaf 简介
java的引擎模板主要有:thymeleaf、freemarker、volecity等等。下面只介绍 thymeleaf。
thymeleaf 在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。
引入 Thymeleaf 依赖
在 build.gradle 中添加 thymeleaf 的引用
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
在 properties.yml 中添加如下内容
spring:
thymeleaf:
# 开发时关闭缓存,不然没法看到实时页面
# 这个必须配合 spring-boot-devtools 才能生效
cache: false
# 默认配置下,thymeleaf对.html的内容要求很严格,比如<meta charset="UTF-8" />,如果少最后的标签封闭符号/,就会报错而转到错误页。
# 比如你在使用Vue.js这样的库,然后有<div v-cloak></div>这样的html代码,也会被thymeleaf认为不符合要求而抛出错误。
# LEGACYHTML5需要搭配一个额外的库NekoHTML(net.sourceforge.nekohtml)才可用
mode: LEGACYHTML5
# 模板路径
prefix: classpath:/templates/
# 模板后缀
suffix: .html
# 文件编码
encoding: UTF-8
servlet:
# 文件类型
content-type: text/html
配置不重启直接刷新html
光是禁用了缓存(spring.thymeleaf.cache=false)还是不能查看到实时页面的,原因是 spring boot 实质上是将tomcat和资源全部打成一个jar来运行的,因此还需要开启自动编译。
首先在build.gradle中新增依赖
implementation 'org.springframework.boot:spring-boot-devtools'
然后,File -> Settings -> Build,Execution,Deployment -> Compiler
确认已经开启了 Build project automatically 选项
最后 Ctrl + Alt + Shift + / ,打开 维护(maintenance)面板,选择注册(Registry)选项,勾选 “compile.automake.allow.when.app.run”
测试用例
先添加几个测试用的 Bean
PersonBean.java
package com.example.demo.bean;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
import java.util.List;
@AllArgsConstructor
@Getter
@Setter
public class PersonBean {
private long id;
private String name;
private int age;
private Sex sex;
private Date recordDate;
private List<DogBean> dogList;
}
Sex.java
package com.example.demo.bean;
public enum Sex {
Male((byte)0x01),
Female((byte)0x02);
private byte value;
Sex(byte value) {
this.value = value;
}
}
DogBean.java
package com.example.demo.bean;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@AllArgsConstructor
@Getter
@Setter
public class DogBean {
private String name;
private boolean isMale;
}
在 controller 目录下,添加 PersonController.java 作为控制器
package com.example.demo.controller;
import com.example.demo.bean.DogBean;
import com.example.demo.bean.PersonBean;
import com.example.demo.bean.Sex;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.ArrayList;
import java.util.Date;
@Controller
public class PersonController {
@GetMapping("/person")
public String getPerson(Model model) {
System.out.println("getPerson");
ArrayList<DogBean> dogList = new ArrayList<>();
dogList.add(new DogBean("dogA", true));
dogList.add(new DogBean("dogB", false));
PersonBean personBean = new PersonBean(1001, "bob", 27, Sex.Male, new Date(), dogList);
model.addAttribute("person", personBean);
return "person";
}
}
在 resources/templates 目录下添加模板文件
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="'Hello World!' + ${#dates.format(person.recordDate, 'yyyy-MM-dd HH:mm:ss.SSS')}"></h1>
<p th:text="${person.id} + ' ' + ${person.name} + ', age is ' + ${person.age} + ' ' + ${person.sex.toString()}"></p>
<ul th:each="dog,stat:${person.dogList}">
<li th:text="${stat.count} + '. ' + ${dog.name} + ' ' + (${dog.isMale()} ? '公狗': '母狗')"></li>
</ul>
</body>
</html>
现在就可以在浏览器上看到结果了。当然你也可以使用之前介绍过的插件(RestfulToolkit)来调试。