本篇学习SpringBoot如何整合视图层技术,其实这就是学习如何使用SpringBoot并结合视图层可以轻松搭建一个完整的Web应用,这里主要学习Thymeleaf(读作[taɪm lif],百里香)和FreeMarker。尽管在目前企业级的应用开发中,前后端分离是趋势,但是视图层技术还是占用一席之地。SpringBoot对视图层技术也提供了很好的支持,官方推荐使用的模板引擎是Thymeleaf,但是FreeMaker也支持,当然你可以像SSM中使用JSP等,但是非常不推荐使用。因此这里对于ThymeleafFreeMarker的介绍不会太深。

整合Thymeleaf

Thymeleaf是新一代的Java模板引擎,类似于Velocity、FreeMaker等传统的Java模板引擎。但是Thymeleaf与它们的不同之处在于Thymeleaf支持HTML原型。如果你之前使用过JSP的话,你会发现不运行Java后端容器Tomcat,你是无法直接查看jsp网页的。但是Thymeleaf支持HTML原型,既可以让前端人员在浏览器中直接打开查看样式,也可以让后端人员结合数据来查看显示效果。更重要的是SpringBoot提供了Thymeleaf的自动化配置解决方案,因此在SpringBoot中使用Thymeleaf是非常方便的,接下来就介绍如何整合Thymeleaf

创建工程和添加依赖

使用spring Initializr构建工具构建一个SpringBoot的Web应用,名称为thymeleafspringboot,然后添加spring-boot-starter-webspring-boot-starter-thymeleaf依赖:

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--添加Thymeleaf依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

配置 Thymeleaf

SpringBoot为Thymeleaf提供了自动化配置类ThymeleafAutoConfiguration,相关的配置属性在ThymeleafProperties类中,ThymeleafProperties的部分源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@ConfigurationProperties(
prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
private String prefix = "classpath:/templates/";
private String suffix = ".html";
private String mode = "HTML";
private Charset encoding;
private boolean cache;
private Integer templateResolverOrder;
private String[] viewNames;
private String[] excludedViewNames;
private boolean enableSpringElCompiler;
private boolean renderHiddenMarkersBeforeCheckboxes;
private boolean enabled;
private final ThymeleafProperties.Servlet servlet;
private final ThymeleafProperties.Reactive reactive;
......
}

可以看到这个配置类使用了@ConfigurationProperties注解说明它就是一个属性配置类,可以读取到aplication.properties文件中的配置信息。还可以看到它默认的模板位置在classpath:/templates/里面,默认的模板后缀为.html。使用IDEA创建SpringBoot项目它会自动在resources目录下新建templates目录。

前面这个类可以读取到aplication.properties文件中的配置信息,那么你就可以对默认的Thymeleaf配置参数进行自定义的修改,例如下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 是否开启缓存,开发时可设置为false,默认为true
spring.thymeleaf.cache=true
# 检查模板是否存在,默认为true
spring.thymeleaf.check-template=true
# 检查模板位置是否存在,默认为true
spring.thymeleaf.check-template-location=true
# 模板文件编码
spring.thymeleaf.encoding=UTF-8
# 模板文件位置
spring.thymeleaf.prefix=classpath:/templates/
# Content-Type配置
spring.thymeleaf.servlet.content-type=text/html
# 模板文件后缀
spring.thymeleaf.suffix=.html

配置控制器

com.envy.thymeleafspringboot包下新建一个pojo包,接着在里面新建一个Book类,里面的代码为:

1
2
3
4
5
6
7
8
9
package com.envy.thymeleafspringboot.pojo;

public class Book {
private Integer id;
private String name;
private Integer price;

//getter和setter方法,包含三个参数的构造方法
}

接下来继续在com.envy.thymeleafspringboot包下新建一个controller包,接着在里面新建一个BookController类,请注意这里由于返回的是Web信息而不是字符串,因此需要返回一个ModelAndView对象,所以不能使用@RestController注解,而是使用@Controller注解。ModelAndView是模型数据和逻辑视图对象,它装载了模型的数据和逻辑视图,你可以通过modelAndView.addObject("key",ojbect);方式来添加模型数据,然后使用modelAndView.setViewName("视图名称");方式来设置逻辑视图。BookController类里面的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.envy.thymeleafspringboot.controller;

import com.envy.thymeleafspringboot.pojo.Book;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

import java.util.Arrays;
import java.util.List;

@Controller
public class BookController {

@GetMapping(value = "/books")
public ModelAndView books(){
List<Book> books = Arrays.asList(
new Book(1, "三国演义", 168),
new Book(2, "红楼梦", 188),
new Book(2, "西游记", 128),
new Book(2, "水浒传", 108)
);
//实例化模型数据和逻辑视图对象
ModelAndView modelAndView = new ModelAndView();
//添加模型数据
modelAndView.addObject("books",books);
//设置逻辑视图
modelAndView.setViewName("books");
return modelAndView;
}
}

创建视图

在resources目录下的templates文件夹中新建books.html(请注意这里的books就是你在modelAndView.setViewName("books")中设置的逻辑视图名称,这个需要保持一致),里面的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>图书列表</title>
</head>
<body>
<h2>图书列表</h2>
<table border="1px">
<tr>
<td>图书编号</td>
<td>图书名称</td>
<td>图书价格</td>
</tr>
<tr th:each="book:${books}">
<td th:text="${book.id}"></td>
<td th:text="${book.name}"></td>
<td th:text="${book.price}"></td>
</tr>
</table>
</body>
</html>

请注意首先你需要在第2行导入Thymeleaf的名称空间,其次使用Thymeleaf中的th:each来对集合对象进行遍历,并通过th:text来展示数据。

运行项目

启动项目,在浏览器地址栏中输入http://localhost:8080/books即可看到运行结果,如下图所示:

发现没有除了后面html中使用的是thymeleaf模板引擎,其他的其实就是SpringMVC的内容。请注意这里只是介绍SpringBoot如何整合Thymeleaf,而不是Thymeleaf的基础使用,关于Thymeleaf的更多资料可以点击 这里,后续也会出一些关于Thymeleaf的文章。

整合FreeMarker

FreeMarker是一个非常古老的Java模板引擎。可以用在Web环境或者非Web环境中。与Thymeleaf不同的是FreeMarker需要经过解析才能够在浏览器中展示出来。FreeMarker不仅可以用来配置HTML页面模板,也可以作为电子邮箱模板、配置文件模板以及源码模板等。正是由于它可以适应不同的应用场景,因此它虽然古老但是依旧还是有人愿意使用它。SpringBoot对FreeMarker整合也提供了很好的支持,接下来就介绍如何整合FreeMarker

创建工程和添加依赖

使用spring Initializr构建工具构建一个SpringBoot的Web应用,名称为freemarkerspringboot,然后添加spring-boot-starter-webspring-boot-starter-freemarker依赖:

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--添加FreeMarker依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

配置 FreeMarker

SpringBoot为FreeMarker也提供了自动化配置类FreeMarkerAutoConfiguration,相关的配置属性在FreeMarkerProperties类中,FreeMarkerProperties的部分源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
@ConfigurationProperties(
prefix = "spring.freemarker"
)
public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties {
public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/templates/";
public static final String DEFAULT_PREFIX = "";
public static final String DEFAULT_SUFFIX = ".ftlh";
private Map<String, String> settings = new HashMap();
private String[] templateLoaderPath = new String[]{"classpath:/templates/"};
private boolean preferFileSystemAccess = true;
......
}

可以看到这个配置类使用了@ConfigurationProperties注解说明它就是一个属性配置类,可以读取到aplication.properties文件中的配置信息。还可以看到它默认的模板位置在classpath:/templates/里面,默认的模板后缀为.ftlh。使用IDEA创建SpringBoot项目它会自动在resources目录下新建templates目录。

前面这个类可以读取到aplication.properties文件中的配置信息,那么你就可以对默认的FreeMarker配置参数进行自定义的修改,例如下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# HttpServletRequest的属性是否可以覆盖Controller中的model的同名项
spring.freemarker.allow-request-override=false
# HttpSession的属性是否可以覆盖Controller中的model的同名项
spring.freemarker.allow-session-override=false
# 是否开启缓存,开发时可设置为false,默认为true
spring.freemarker.cache=false
# 检查模板位置是否存在,默认为true
spring.freemarker.check-template-location=true
# 模板文件编码
spring.freemarker.charset=UTF-8
# 模板文件位置
spring.freemarker.prefix=classpath:/templates/
# Content-Type配置
spring.freemarker.content-type=text/html
# 模板文件后缀
spring.freemarker.suffix=.ftlh
# 是否将HttpServletRequest中的属性添加到Model中
spring.freemarker.expose-request-attributes=false
# 是否将HttpSession中的属性添加到Model中
spring.freemarker.expose-session-attributes=false

配置控制器

com.envy.freemarkerspringboot包下新建一个pojo包,接着在里面新建一个Book类,里面的代码为:

1
2
3
4
5
6
7
8
9
package com.envy.freemarkerspringboot.pojo;

public class Book {
private Integer id;
private String name;
private Integer price;

//getter和setter方法,包含三个参数的构造方法
}

接下来继续在com.envy.freemarkerspringboot包下新建一个controller包,接着在里面新建一个BookController类,请注意这里由于返回的是Web信息而不是字符串,因此需要返回一个ModelAndView对象,所以不能使用@RestController注解,而是使用@Controller注解。ModelAndView是模型数据和逻辑视图对象,它装载了模型的数据和逻辑视图,你可以通过modelAndView.addObject("key",ojbect);方式来添加模型数据,然后使用modelAndView.setViewName("视图名称");方式来设置逻辑视图。BookController类里面的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.envy.freemarkerspringboot.controller;

import com.envy.freemarkerspringboot.pojo.Book;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

import java.util.Arrays;
import java.util.List;

@Controller
public class BookController {

@GetMapping(value = "/books")
public ModelAndView books(){
List<Book> books = Arrays.asList(
new Book(1, "三国演义", 168),
new Book(2, "红楼梦", 188),
new Book(2, "西游记", 128),
new Book(2, "水浒传", 108)
);
//实例化模型数据和逻辑视图对象
ModelAndView modelAndView = new ModelAndView();
//添加模型数据
modelAndView.addObject("books",books);
//设置逻辑视图
modelAndView.setViewName("books");
return modelAndView;
}
}

创建视图

在resources目录下的templates文件夹中新建books.ftlh(请注意这里的books就是你在modelAndView.setViewName("books")中设置的逻辑视图名称,这个需要保持一致),里面的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图书列表</title>
</head>
<body>
<h2>图书列表</h2>
<table border="1px">
<tr>
<td>图书编号</td>
<td>图书名称</td>
<td>图书价格</td>
</tr>
<#if books ??&&(books?size>0)>
<#list books as book>
<tr>
<td>${book.id}</td>
<td>${book.name}</td>
<td>${book.price}</td>
</tr>
</#list>
</#if>
</table>
</body>
</html>

请注意首先你需要判断model中的books不为空且books中有数据,然后才能进行遍历。后续通过遍历books集合,将集合中的数据通过表格展示出来。

运行项目

启动项目,在浏览器地址栏中输入http://localhost:8080/books即可看到运行结果,如下图所示:

发现没有这个freemarker的用法与前面的thymeleaf非常相似,唯一不同的就是待渲染的模板的格式,前者为ftlh,而后者为html,还有就是对于数据的遍历输出方式不同。

请注意这里只是介绍SpringBoot如何整合FreeMarker,而不是FreeMarker的基础使用,关于FreeMarker的更多资料可以点击 这里,后续也会出一些关于FreeMarker的文章。

视图层整合小结

本篇学习了SpringBoot整合视图层技术,举了如何整合ThymeleafFreeMarker这两个例子。通过上面的学习你会发现整合ThymeleafFreeMarker的步骤几乎一致。如果开发人员使用的是目前最流行的前后端分离技术的话,那么在开发过程中不需要整合视图层技术,后端直接提供接口即可,目前大部分都是这样操作。