3.3 Spring Boot模版引擎调用
模板引擎,是用来生成动态网页内容的,一旦控制器(Controller)收集了足够的数据,就会把数据交给模板引擎来处理,模板引擎根据数据生成HTML,返回给浏览器。
Spring Boot支持多种模板引擎,包括FreeMarker、Thymeleaf、Mustache和Groovy Templates。Spring Boot中不推荐使用jsp,Thymeleaf现在被很多人采用,它的特点就是可以直接在浏览器中打开模板文件,方便前端开发。这里选用Thymeleaf模版引擎,它的使用步骤如下:
(1)添加Thymeleaf引擎依赖:打开pom.xml,添加以下内容。
<dependencies>
......
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
......
</dependencies>
如图3-6所示。
图3-6 修改pom.xml
(2)创建模版文件: src/main/resources/templates是引擎默认的模版文件放置路径的根目录,把网页模版文件都放在这个文件夹下。在templates文件夹下创建user子文件夹,再创建user/register.html,见例3-5所示。
[例3-5]register.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
<form>
<table border='1' align='center'>
<tr>
<td colspan='2' align='center'>新用户注册</td>
</tr>
<tr>
<td align='right'>邮箱/手机号:</td>
<td><input type='text' name='email'></td>
</tr>
<tr>
<td align='right'>密码:</td>
<td><input type='password' name='pwd'></td>
</tr>
<tr>
<td align='right'>重复密码:</td>
<td><input type='password' name='repwd'></td>
</tr>
<tr>
<td colspan='2' align='center'>
<input type='submit' value='注册'>
<input type='reset' value='重置'>
</td>
</tr>
</table>
</form>
</body>
</html>
(3)创建控制器文件:在src/main/java下创建com.controller文件夹,文件夹下再创建UserController.java控制器文件,见例3-6所示。
package com.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
//@RestController //声明本类中所有方法返回的是return中的字符串
@Controller //声明本类中所有方法返回的是某个页面
public class UserController {
@GetMapping("/user/register")
public String hello(HttpServletRequest request) {
return "user/register"; //返回user/register.html页面到前端
}
}
三种注释说明:
@RestController:表示方法返回的是return中的字符串。
@Controller:表示方法返回的是可以被视图解析器解析的jsp,html页面,并且跳转到相应页面。
@ResponseBody:表示方法返回json内容到页面。
(4)入口文件中把controller文件夹添加为加载路径:新项目中默认的入口文件是com.example.demo下的HelloApplication.java文件,此文件默认只加载本路径和本路径的子路径下的java文件,所以需要在入口文件中配置加载路径,把包外的路径加载进来。见例3-7所示。
【例3-7】HelloApplication.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = {"com.example.demo,com.controller"}) //加载com.controller路径,多个路径用逗号分隔
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
运行:HelloApplication.java上右键→Run As→Java Application。
访问:浏览器中访问http://localhost:8080/user/register, 如图3-7所示
图3-7 controller中调用模版显示结果
3.4 Spring Boot模版语法
Spring Boot不推荐使用jsp,它推荐在模版中使用模版语法实现动态显示。Thymeleaf模版可以接受controller传来的各种参数,然后在模版中用模版语法对参数数据进行处理,完成动态页面的渲染。Thymeleaf模版常用语法包括以下内容:
(1)显示文本,th:text 表示把controller中传来的变量作为纯字符串显示到页面上,见例3-8所示。
①在UserController.java中添加1测试方法,
【例3-8】UserController类中添加方法tgrammar
@GetMapping("/user/tgrammar")
public String tgrammar(HttpServletRequest request) {
request.setAttribute("sv", "<b>微服务</b>");
return "user/tgrammar";
}
②在templates/user文件夹下新建一tgrammar.html,见例3-9所示。
【例3-9】tgrammar.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Thymeleaf模版语法</title>
</head>
<body>
hello,<span th:text="${sv}">spring boot</span>
</body>
</html>
访问:http://localhost:8080/user/ggrammar.html,如图3-8所示。
图3-8 th:text标签显示为纯字符串
(2)显示html,th:utext表示从controller中传来的变量作为html代码显示在页面上,还是例3-9的代码,仅仅把th:text=”${sv}”变成th:utext=”${sv}”,显示结果如图3-9所示。
图3-9 把传来的变量作为html代码显示在页面上
(3)解析对象,Java对象中的成员属性可以通过对象变量名直接访问也可以通过*.变量名访问,见例3-10。
【例3-10】UserController.java中添加一个User类,并在tgrammar方法中使用这个类,tgrammar.html中显示user对象的各个属性。
①UserController.java
package com.controller;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
//@RestController //声明本类中所有方法返回的是return中的字符串
@Controller //声明本类中所有方法返回的是某个页面
public class UserController {
@GetMapping("/user/register")
public String hello(HttpServletRequest request) {
return "user/register";
}
@GetMapping("/user/tgrammar")
public String tgrammar(HttpServletRequest request) {
request.setAttribute("sv", "<b>微服务</b>");
User u = new User();
u.setId(101);
u.setName("张三");
u.setAge(20);
u.setBirthday(new Date());
u.setRole(1);
request.setAttribute("user", u);
return "user/tgrammar";
}
}
class User{
private int id; //学号
private String name; //姓名
private int age; //年龄
private Date birthday; //生日
private int role; //角色
public void setId(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return this.name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return this.age;
}
public void setBirthday(Date birthday) {
this.birthday=birthday;
}
public Date getBirthday() {
return this.birthday;
}
public void setRole(int role) {
this.role=role;
}
public int getRole() {
return this.role;
}
}
② tgrammar.html中添加以下代码:
<div th:object="${user}">
id:<span th:text="*{id}"></span><br/>
姓名:<span th:text="*{name}"></span><br/>
年龄:<span th:text="*{age}"></span><br/>
生日:<span th:text="*{birthday}"></span>
</div>
运行后访问:http://localhost:8080/user/tgrammar,显示结果如图3-10所示。
图3-10 模版解析java对象
(4)日期格式化,java中传来的日期格式常常需要做格式化处理,Thymeleaf模版语法中提供了对日期格式的格式化函数dates.format,见例3-11所示。
【例3-11】tgrammar.html中修改生日显示项
生日:<span th:text="*{#dates.format(birthday, 'yyyy-MM-dd HH:mm')}"></span>
显示结果如图3-11所示。
图3-11 日期格式化后显示生日
(5)条件判断,Thymeleaf模版有两种条件判断语法,如下所示:
①if判断,th:if{表达式},表达式为true则整个标签得以显示,否则整个标签不显示,见例3-11。
【例3-11】tgrammar.html添加对年龄的判断。
<div th:object="${user}">
……
<span th:if="*{age>9 and age<15}" > 少年 </span>
<span th:if="*{age>15 and age<35}" > 青年 </span>
<span th:if="*{age>35 and age<55}"> 中年 </span>
<span th:if="*{age>55}"> 老年 </span>
……
</div>
②Switch Case判断,th:switch=”判断条件”、th:case=”表达式”、th:case=”*”(上述条件都不满足走此分支),见例3-12.
【例3-12】tgrammar.html添加对角色的识别。
<span th:switch="*{role}">
<span th:case="0">管理员</span>
<span th:case="1">讲师</span>
<span th:case="*">学生</span>
</span>
增加条件判断后页面的运行结果如图3-12所示。
图3-12 增加条件判断后页面的显示结果
(5)循环语句,模版中的循环遍历采用th:each= "元素 : 数组"方式,具体见例3-13。
【例3-13】在UserController.java的tgrammar方法中生成user链表,然后在tgrammar.html中用循环遍历成列表格式。
- UserController.java中的tgrammar方法。
@GetMapping("/user/tgrammar")
public String tgrammar(HttpServletRequest request) {
request.setAttribute("sv", "<b>微服务</b>");
ArrayList uarr = new ArrayList();
for(int i=1;i<11;i++) {
User u = new User();
u.setId(i);
u.setName("李"+i);
u.setBirthday(new Date());
u.setRole(i%2+1);
uarr.add(u);
}
request.setAttribute("uarr", uarr);
return "user/tgrammar";
}
- tgrammar.html中将uarr循环显示成table表格格式。
<table border='1'>
<tr>
<td>编号</td>
<td>姓名</td>
<td>生日</td>
<td>身份</td>
</tr>
<tr th:each="user:${uarr}" th:object="${user}">
<td th:text="*{id}"></td>
<td th:text="*{name}"></td>
<td th:text="*{#dates.format(birthday, 'yyyy-MM-dd HH:mm')}"></td>
<td>
<span th:switch="*{role}">
<span th:case="0">管理员</span>
<span th:case="1">讲师</span>
<span th:case="*">学生</span>
</span>
</td>
</tr>
</table>
上述代码运行后网页的显示结果如图3-13所示。
图3-13 模版代码循环显示
(6)页面引入:很多时候页面中的一部分内容需要在许多个页面中重复使用,这时就可以把这部分经常重复的页面代码提取到一个模版文件中,在需要的时候再在使用页面中引入。Thymeleaf模版提供了3种引入语法如下:
① th:insert :保留自己的主标签,保留th:fragment的主标签。
② th:replace :不要自己的主标签,保留th:fragment的主标签。
③ th:include :保留自己的主标签,不要th:fragment的主标签。
fragment 是将要被导入者替换的内容,见例3-14所示。
【例3-14】新建一个top.html,写些html内容在内,然后用3种方法分别引入到tgrammar.html中。
- top.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<body>
<div th:fragment='topcopy' style='border:3px solid black;'> <!-- 边框设置为黑色 -->
hello,<span th:utext="${sv}">spring boot</span>,这里是头部内容。
</div>
</body>
</html>
- tgrammar.html中引入top.html中的div内容。
<div th:insert="user/top :: topcopy" style='border:3px solid red;'></div><br/>
<div th:replace="user/top :: topcopy" style='border:3px solid green;'></div><br/>
<div th:include="user/top :: topcopy" style='border:3px solid blue;'></div><br/>
上述代码显示结果如图3-14所示。
图3-14 模版页面引入的3种方式
从上例可以看出,insert保留了自身div的标签,把引入的div放在自身div内;replace用引入页面的标签替换了自身div标签;include则用自身标签替换掉引入div的最外层标签。