SpringBoot2.x系列教程08--SpringBoot中整合Thymeleaf动态模板
SpringBoot2.x系列教程08--SpringBoot中整合Thymeleaf动态模板
前言
在前面的章节中带各位利用SpringBoot实现了SSM整合,发现现在SSM整合变得的非常简单,通过几个配置就能搭建出一个项目开发环境。但是在之前的案例中,我们并没有提供UI界面,那么在SpringBoot中如何整合UI界面呢?使用JSP展示页面,还是用HTML展示页面,或者还有其他方案?
在今天的内容里会带大家学习如何在SpringBoot中展示UI界面,这样大家以后就可以把数据信息在页面上渲染展示了。
一. Web开发方式简介
SpringBoot作为一个简化项目开发的利器,其实它为我们提供了一套完整的Web开发方案,从前端到后端,再到数据库、定时任务、消息队列等都提供了解决方案。包括UI渲染,SpringBoot也给我们提供了对应的解决方案。而现在我们进行Web应用开发时,一般会遵循两种模式,如下:
前后端分离模式
前后端不分离模式
在SpringBoot中,针对这两种模式也分别提供了对应的解决方案。在今天的内容中主要带大家学习在前后端不分离模式下,如何进行UI的展现。
1. 前后端分离
如果是采用前后端分离模式进行开发,那么前端开发和后端开发则会完全分离,前后端之间只需要协商好接口就行。后端负责提供Restful风格的接口,并以JSON格式传递数据给前端,而前端负责开发页面并调用后端的接口,接收JSON格式的数据并展示即可。
前后端分离的开发模式,是现在企业级项目的主流选择,大多数大型项目现在基本都是前后端分离的。对于我们后端开发人员来说,基本上不需要我们考虑页面UI的开发问题,前面页面的开发属于前端开发团队负责。
2. 前后端不分离
如果我们采用的是前后端不分离的开发模式,在SpringBoot中则是允许我们采用各种主流的后端模板页面技术来实现页面展示,主流的模板如下:
- Thymeleaf
- FreeMarker
- Groovy
- Mustache
- Velocity
- JSP
我们在前面学习SSM的时候,我们知道SpringMVC是支持JSP的,但是Spring Boot中并不建议我们使用JSP。这是因为SpringBoot本身内嵌了一个servlet容器时,这个内嵌的Web容器,对jsp有一些使用限制。另外在2010年后,Velocity模板也已停止了更新,所以这两种页面技术在SpringBoot中都不建议使用。
我在上面说了,现在大型的项目基本都是前后端分离的,后端程序员根本就不用负责页面的编写。但是万一你参与的项目就是一个“老破小”项目,前后端不分离,我们后端程序员就得编写前端页面,那上面的这几个模板,开发时我们到底该用哪个呢?这种情况下,SpringBoot官方推荐我们使用ThemeLeaf模板。
但是对于以上几个模板,Springboot是可以同时支持的,什么叫同时支持呢?简而言之,在SpringBoot项目中,可以同时共存多个不同的模板,我们需要做的仅仅是在pom文件中,引入相关模板引擎的jar包就可以了,SpringBoot可以根据模板的后缀名,来决定到底由哪种模板引擎解析这个动态页面。
3. 常见模板页面后缀
这里我简单列举几个常用的模板文件后缀,大家了解一下。
Thymeleaf : .html
freemaker : .ftl
jsp : jsp
4. 前后端模板区别
我在上面给大家列举的这几种页面模板,都属于后端模板,他们都有别于前端模板(如angular)。
1️⃣. 前端模板:
前端模板通常是通过模板提供的js,根据模板规定的语法规则解析html中的模板标记。
2️⃣. 后端模板:
类似于前端,一个页面请求到达之后,后端模板引擎根据特定的语法规则解析模板中的内容,将数据填充到模板中,最终返回给浏览器的实际上已经是一个完整的html页面了。
了解了这些基本的理论内容之后,壹哥 就带大家看看如何在SpringBoot中编写Web页面,本案例就采用SpringBoot推荐的Thymeleaf模板。
二. 用Spring Boot搭建Web项目
1. 创建Maven项目及其module模块
为了方便我们以后讲述其他SpringBoot知识点,这里我首先创建一个SpringBoot项目,然后在这个项目中创建多个module,每个module讲述一个SpringBoot的知识点,这样我们就不用建立多个intelliJ项目了。
然后选择Maven构建,这里注意不要勾选create from archytype,虽然它会帮你创建项目骨架,但是会从网络中下载一些东西,过程可能比较慢,有可能会卡住。
设置项目的GAV坐标信息。
2. 在父项目中创建一个子模块
创建完项目之后,我们在这个项目里创建一个子模块,子模块的名称各位随便设置即可。
子module也是采用Maven构建出来。
设置module的名称。
设置module的存储位置。
如果我们项目案例中,已经用不到默认的src目录了,就可以把它删除掉。
接下来我就在demo05这个module中,实现一个带有页面的Web项目。
3. 添加必要依赖包
我们在demo05模块的pom.xml文件中,对代码进行改造,把项目改造成spring-boot项目,并且添加web依赖。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
三. 引入Thymeleaf
Thymeleaf是一个XML/XHTML/HTML5模板引擎,可用于Web与非Web环境中的应用开发。它提供了一个用于整合SpringMVC的可选模块,在应用开发中,我们可以使用Thymeleaf来完全代替JSP或其他模板引擎,如Velocity\FreeMarker等。
1. Thymeleaf模板示例
其实Themeleaf与JSP的语法类似,也是在HTML中嵌套了一些自己特有的标签而已,下面是一个Themeleaf模板示例。
<table>
<thead>
<tr>
<th th:text="#{msgs.headers.name}">Name</td>
<th th:text="#{msgs.headers.price}">Price</td>
</tr>
</thead>
<tbody>
<tr th:each="prod : ${allProducts}">
<td th:text="${prod.name}">Oranges</td>
<td th:text="${#numbers.formatDecimal(prod.price,1,2)}">0.99</td>
</tr>
</tbody>
</table>
从上面的代码中,我们可以看到Thymeleaf主要以属性的方式加入到html标签中。当浏览器在解析html时,如果检查到不存在的属性时,会直接忽略掉该属性。所以Thymeleaf模板页面是可以通过浏览器直接打开展现的,这样非常有利于前后端之间的分离。
2. 添加thymeleaf依赖包
我们在上面demo05模块的pom.xml文件中,引入Thymeleaf的依赖包,如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
3. 创建thymeleaf模板文件
在src/main/resources/
目录下,创建一个templates
文件夹``,默认情况下该名称是固定不变的,然后我们在该目录下创建一个index.html文件。
在index.html文件中,我这里先简单的使用了Themeleaf的一个th:text标签。
index.html代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<!--注意:这个meta节点最后有个结束的'/',一定要注意,否则会产生异常!!!后续我们再分析如何解决这个异常-->
<meta charset="UTF-8"/>
<title>index</title>
</head>
<body>
<!--${msg},thymeleaf模板根据key取值-->
<h1 th:text="${msg}">Hello</h1>
</body>
</html>
4. 编写Controller接口
接着我们创建一个HelloController类,里面编写一个Controller接口,如图所示。
@Controller
public class HelloController {
@RequestMapping("/")
public String index(ModelMap map) {
// 添加一个属性,用来在模板中根据这个key来读取对应的值
map.addAttribute("msg", "跟一一哥学习SpringBoot");
// return 模板文件的名称-->对应src/main/resources/templates/index.html
return "index";
}
}
5. 创建Application入口类
为了让我们的程序可以运行起来,再创建一个Application入口类。
package com.yyg.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 创建web项目
*/
@SpringBootApplication
public class WebApplication {
public static void main(String[] args){
SpringApplication.run(WebApplication.class,args);
}
}
6. 完整项目结构
这是我们项目的完整代码结构,各位可以参考创建。
7. 完整的pom.xml文件
这是整个项目的pom.xml文件,各位可以把核心依赖包复制添加到自己的项目中。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>demo05</artifactId>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<!--web依赖包-->
<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模板中,对html标签要求太严格的问题!-->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
8. 启动项目测试
最后我们把项目启动起来,然后在浏览器中输入[http://localhost:8080/,正常情况下会看到如下效果]
这就是利用Thymeleaf模板来渲染的一个页面,很轻松的就做到了在不破坏HTML自身内容的情况下的数据与业务逻辑的分离。
如果你想学习关于Thymeleaf的更多语法,可以参考我另一篇关于Thymeleaf的博客!
四. SAXParseException异常处理方案
1. 问题描述
如果我们的模板文件,也就是index.html文件,在编写的时候是默认生成的html文件,如下图所示:
那么在启动项目后,直接访问接口,可能会产生如下异常:
org.xml.sax.SAXParseException: 元素类型 "meta" 必须由匹配的结束标记 "</meta>" 终止。
2. 异常的原因
如果你出现了上面的异常现象,不要慌告诉你这是为什么,这是因为默认情况下我们编写的html标签没有成对出现,这与themeleaf要求的语法有些不同,具体情况我的截图。
3. 解决方案
出现了问题不可怕,解决掉就好了,这里我把解决方案列举如下:
1️⃣. 首先在application.properties或application.yml文件中,修改
thymeleaf.mode
的值为LEGACYHTML5; 2️⃣. 然后在pom.xml文件中添加一个依赖包。
3.1 application.properties文件如下:
# Enable template caching.
spring.thymeleaf.cache=true
# Check that the templates location exists.
spring.thymeleaf.check-template-location=true
# Content-Type value.
spring.thymeleaf.servlet.content-type=text/html
# Enable MVC Thymeleaf view resolution.
spring.thymeleaf.enabled=true
# Template encoding.
spring.thymeleaf.encoding=UTF-8
# Comma-separated list of view names that should be excluded from resolution.
#spring.thymeleaf.excluded-view-names=
# Template mode to be applied to templates. See also StandardTemplateModeHandlers.
spring.thymeleaf.mode=HTML5
# Prefix that gets prepended to view names when building a URL.
spring.thymeleaf.prefix=classpath:/templates/
# Suffix that gets appended to view names when building a URL.
spring.thymeleaf.suffix=.html
# Order of the template resolver in the chain.
#spring.thymeleaf.template-resolver-order=
# Comma-separated list of view names that can be resolved.
#spring.thymeleaf.view-names=
3.2 新的依赖包如下
<!--为了解决thymeleaf模板中,对html标签要求太严格的问题!-->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
做完以上两步之后,以后的html文件中,即使标签不是成对出现的,或者没有结束标签,也不会再出现解析异常了。
五. SpringBoot中的配置文件简介
在SpringBoot中,如果你需要修改一些默认配置,只需复制下面要修改的属性到application.properties中,并修改成需要的值,如修改模板文件的扩展名,修改默认的模板路径等。
1. Thymeleaf默认的配置属性
# Enable template caching.
spring.thymeleaf.cache=true
# Check that the templates location exists.
spring.thymeleaf.check-template-location=true
# Content-Type value.
spring.thymeleaf.servlet.content-type=text/html
# Enable MVC Thymeleaf view resolution.
spring.thymeleaf.enabled=true
# Template encoding.
spring.thymeleaf.encoding=UTF-8
# Comma-separated list of view names that should be excluded from resolution.
spring.thymeleaf.excluded-view-names=
# Template mode to be applied to templates. See also StandardTemplateModeHandlers.
spring.thymeleaf.mode=HTML5
# Prefix that gets prepended to view names when building a URL.
spring.thymeleaf.prefix=classpath:/templates/
# Suffix that gets appended to view names when building a URL.
spring.thymeleaf.suffix=.html
# Order of the template resolver in the chain.
spring.thymeleaf.template-resolver-order=
# Comma-separated list of view names that can be resolved.
spring.thymeleaf.view-names=
结语
至此就带各位利用Themeleaf编写了一个html页面,感觉和普通的html也没啥区别,两者确实差不多,我们只需要简单学习一下Themeleaf的标签语法即可,别的没有太多需要注意的地方。
今日小作业:
用themleaf技术,编写一个学生信息管理功能页面,实现对学生信息的增删改查。