文章目录
本页将介绍Spring Boot
+ Thymeleaf
+ Maven
的例子。
我们将提供如何使用Spring Boot
的Thymeleaf
来实现国际化(i18n
)、表单验证和日志记录。
如果Spring Boot
在类路径中扫描到Thymeleaf
库,它将自动配置Thymeleaf
。
我们可以使用application.properties
改变默认的Thymeleaf
配置。
Thymeleaf
是一个服务器端的模板引擎,可以处理XML
、HTML
等。
Thymeleaf
可以从i18n
消息文件中访问类字段和消息属性。
我们可以使用Thymeleaf
将我们的类字段与HTML
表单元素绑定。
我们可以使用Thymeleaf
迭代我们的java
集合。
在我们的例子中,我们将使用Thymeleaf
执行表单验证和解除i18n
消息。
如果Spring Boot
启动器使用的是较低版本的Thymeleaf
,我们还将提供如何使用Maven
来使用Thymeleaf
的高版本。
我们还将在Thymeleaf
视图中使用CSS
文件。
现在让我们一步一步地讨论这个完整的例子。
示例工具版本
- Java 8
- Spring Boot 1.5.3.RELEASE
- Thymeleaf 3.0
- Maven 3.3
- Eclipse Mars
在 Spring Boot 中集成 Thymeleaf 3
为了将Thymeleaf
与Spring Boot
集成,我们需要在构建工具(如Maven
和Gradle
)中使用以下Spring Boot
启动器。
假设我们使用的是Maven
,那么我们将使用以下Maven
依赖项。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
这都是关于在Spring Boot
中配置Thymeleaf
。当Spring Boot
在类路径中找到Thymeleaf
库时,Spring Boot
会自动为Thymeleaf
进行必要的配置。
在写这篇文章的时候,Thymeleaf
启动器的最新版本是1.5.3.RELEASE
,它使用Thymeleaf 2.1
版本。
如果我们想使用更高版本的Thymeleaf
,例如Thymeleaf 3.0
,那么我们需要在pom.xml
中配置以下属性。
1. thymeleaf.version
2. thymeleaf-layout-dialect.version
假设我们使用的是Maven
,那么上述属性将被配置为如下。
<properties>
<thymeleaf.version>3.0.6.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
<java.version>1.8</java.version>
</properties>
现在Spring Boot
将使用Thymeleaf 3.0.6.RELEASE
版本和Thymeleaf
布局方言2.2.2
版本和java 1.8
版本。
使用 Thymeleaf
如果Spring Boot
在其类路径中扫描到Thymeleaf
库,那么我们就可以使用Thymeleaf
了。
Spring Boot
为Thymeleaf
提供了属性配置,这些属性将在application.properties
或application.yml
中配置,以改变Thymeleaf
与Spring Boot
的配置。
我们在此列出其中的一些属性。
spring.thymeleaf.mode: 将应用于模板的模板模式。默认值是HTML 5
。
spring.thymeleaf.prefix: 这是将在视图名称前面加上的值,用于构建URL
。默认值为classpath:/templates/
。
spring.thymeleaf.suffix: 这是将为视图名称添加后缀以生成URL的值。默认值为.html
。
在默认的Spring Boot
和Thymeleaf
配置下,我们可以将Thymeleaf
文件以html
为扩展名放在以下位置。
src\main\resources\templates
现在我们将讨论如何使用Thymeleaf
创建表单元素。
使用 Thymeleaf 创建 < form >
假设我们在控制器类中有一个方法。
@Controller
@RequestMapping("app")
public class UserController {
@GetMapping("create-user")
public ModelAndView createUserView() {
ModelAndView mav = new ModelAndView();
mav.setViewName("user-creation");
mav.addObject("user", new User());
mav.addObject("allProfiles", getProfiles());
return mav;
}
---
}
当我们访问/app/create-user
时,名为user-creation.html
的Thymeleaf
文件将被打开,在那里我们将创建一个表单来创建用户。现在看看下面的代码片段。
mav.addObject("user", new User());
属性名称user
将在<form>
中与Thymeleaf
的th:object
属性一起使用。
<form action="#" th:action="@{/app/create-user}" th:object="${user}" method="POST">
th:action
被指定为行动URL
,将在表单提交时被调用。
在表单提交时,/app/create-user
将访问控制器类中的以下方法。
@Controller
@RequestMapping("app")
public class UserController {
---
@PostMapping("create-user")
public ModelAndView createUser(@Valid User user, BindingResult result) {
---
}
}
现在我们将创建一些表单元素。假设我们有一个类,它有对应于表单元素的字段。
public class User {
private String userId;
private String userName;
private String gender;
private Boolean married;
private String profile;
}
与表单元素如<input>
和<select>
的数据绑定是通过Thymeleaf
的th:field
属性实现的。
假设我们想创建一个输入文本框来获取用户ID
。
用户类的字段userId
将使用Thymeleaf
的th:field
绑定到输入文本框,如下所示。
<input type="text" th:field="*{userId}" />
以同样的方式,其他表单元素将与用户类字段绑定。找到用户类的userName
字段的输入框。
<input type="text" th:field="*{userName}" />
找到用户类的gender
字段的单选按钮。
<input type="radio" th:field="*{gender}" value="Male"/>
<input type="radio" th:field="*{gender}" value="Female"/>
找到用户类的married
字段的复选框。
<input type="checkbox" th:field="*{married}" />
找到用户类的profile
字段的选择元素。
<select th:field="*{profile}">
<option th:each="profile : ${allProfiles}" th:value="${profile}" th:text="${profile}">Profile</option>
</select>
Thymeleaf
的th:each
将遍历该集合。Thymeleaf
的th:value
属性赋值。
allProfiles
是属性名称,将被添加到ModelAndView
的每个请求中。
mav.addObject("allProfiles", getProfiles());
getProfiles()
方法将返回所有profile
的列表。
private List<String> getProfiles() {
List<String> list = new ArrayList<>();
list.add("Developer");
list.add("Manager");
list.add("Director");
return list;
}
Thymeleaf
提供了th:text="${...}"
的语法,可以用来访问java
对象中的一个值。
如果我们想显示一个表格中所有项的值,我们写的代码如下。
<table>
<tr th:each="user : ${allUsers}">
<td th:text="${user.userId}">Id</td>
<td th:text="${user.userName}">Title</td>
</tr>
</table>
在Thymeleaf
中,我们可以使用th:href="@{..}"
的语法来加载CSS
或创建一个链接来重定向一个URL
。
国际化(i18n)
当我们使用Spring Boot
启动器时,我们的Spring Boot
应用程序就可以使用国际化(i18n
)。
我们需要在以下位置创建属性文件。
src\main\resources\messages.properties
src\main\resources\messages_en.properties
如果locale
是en
,那么Spring
应用程序将选择 messages_en.properties
文件。
默认的i18n
文件将是 messages.properties
。
我们可以使用application.properties
文件中的spring
属性改变默认的spring
消息配置。例如:
spring.messages.basename:它为消息文件配置了逗号分隔的基础名称。默认是messages。
spring.messages.encoding: 它配置了消息包的编码。默认是UTF-8。
为了显示i18n
信息,我们需要使用Thymeleaf
的th:text="#{...}"
语法。假设我们想为我们的页面标题显示i18n
信息,为此我们在信息属性文件中定义了一个key
,如下所示。
app.title= Spring Boot + Thymeleaf
然后它将被Thymeleaf
以如下方式显示。
<title th:text="#{app.title}"> Title </title>
Thymeleaf
提供了#locale
上下文,使用该上下文我们可以显示特定地区的细节,如语言、国家,如下所示。
<p th:text="${#locale.language}"> language</p>
<p th:text="${#locale.country}"> country</p>
验证 | Validation
为了验证一个字段,我们可以使用Hibernate
验证器。当我们使用Spring Boot
启动器时,Hibernate
验证器库被自动配置在类路径中。
现在我们将在我们的类中使用验证器注解,以绑定表单。
验证器注解包括@NotNull
、@Size
等,来自javax.validation
库。
public class User {
@NotNull
@Size(min=3, max=10)
private String userId;
@NotNull
@Size(min=5, max=20)
private String userName;
@NotNull
private String gender;
private Boolean married;
private String profile;
}
要启用表单验证,我们需要在Spring
控制器方法参数中使用javax.validation
库中的@Valid
注释,该参数将在表单提交时调用。
我们还需要Spring
的BindingResult
的实例来知道表单是否经过验证。
@PostMapping("create-user")
public ModelAndView createUser(@Valid User user, BindingResult result) {
ModelAndView mav = new ModelAndView();
if(result.hasErrors()) {
logger.info("Validation errors while submitting form.");
mav.setViewName("user-creation");
mav.addObject("user", user);
mav.addObject("allProfiles", getProfiles());
return mav;
}
userService.addUser(user);
mav.addObject("allUsers", userService.getAllUserArticles());
mav.setViewName("user-info");
logger.info("Form submitted successfully.");
return mav;
}
如果表单有验证错误,那么result.hasErrors()
将返回true
。如果表单中存在验证错误,那么我们应该再次调用同一个Thymeleaf
视图,如果没有验证错误,则执行业务逻辑并重定向到成功视图。
现在在Thymeleaf
视图中,我们需要显示验证错误信息。为了检查一个给定的字段名是否存在验证错误,Thymeleaf
提供了#fields.hasErrors(...)
,它返回布尔值。
<label th:if="${#fields.hasErrors('userId')}" th:errors="*{userId}" th:class="'error'">Id Error</label>
th:errors
将在Hibernate
验证器注解的基础上显示Spring
的默认验证错误信息,我们已经在与表单元素绑定的类域中使用了该注解。
如果我们想对验证错误使用i18n
消息,那么使用th:text="#{...}"
。
<label th:if="${#fields.hasErrors('userId')}" th:text="#{error.user.id}" th:class="'error'">Id Error</label>
error.user.id
是在messages_en.properties
文件中定义的i18n
属性。
日志 | Logging
在Spring Boot
应用程序中,Logback
依赖性是自动解决的。
每个Spring Boot
启动器都会自行添加spring-boot-starter-logging
。
要改变日志的默认配置,我们需要在application.properties
文件中配置日志属性。
找到其中的一些属性。
logging.level.*: 它作为包名的前缀,用于设置日志级别。
logging.file: 它配置了一个日志文件名来记录日志的信息。
logging.path: 它只配置了日志文件的路径。Spring boot
创建了一个名为spring.log
的日志文件。
假设我们的类包是com.concretepage
,那么可以在application.properties
文件中使用logging.level.*
来定义日志级别,如下所示。
logging.level.com.concretepage= INFO
现在,在com.concretepage
包或其子包下的任何类中,都将应用INFO
级别的日志。我们可以使用org.slf4j.Logger
,如下所示。
1. 在类级别实例化org.slf4j.Logger
。
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
2. 现在,根据需要在类的任何地方使用logger
。
logger.info("Validation errors while submitting form.");
完整示例
查找Spring boot
与Thymeleaf
的完整示例。
我们将创建具有国际化(i18n
)、表单验证和日志的应用程序。
找到完整的代码。
1. 在 Eclipse 中项目结构
使用eclipse
找到演示项目的结构。
2. Maven 文件
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>
<groupId>com.concretepage</groupId>
<artifactId>spring-boot-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-demo</name>
<description>Spring Boot Demo Project</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
</parent>
<properties>
<thymeleaf.version>3.0.6.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
找到我们的例子中使用的Spring Boot
启动器描述。
spring-boot-starter-parent: 依赖性管理的父级POM
。
spring-boot-starter-web: 构建Web
、REST
应用程序的启动器。它使用Tomcat
服务器作为默认的嵌入式服务器。
spring-boot-starter-thymeleaf : 用于Thymeleaf
与Spring
框架的集成。
spring-boot-devtools : 它提供了开发者工具。这些工具在应用开发模式中很有帮助。开发者工具的一个特点是在代码发生任何变化时自动重新启动服务器。
3. 创建 Domain 和 Service
User.java
package com.concretepage.domain;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class User {
@NotNull
@Size(min=3, max=10)
private String userId;
@NotNull
@Size(min=5, max=20)
private String userName;
@NotNull
private String gender;
private Boolean married;
private String profile;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Boolean getMarried() {
return married;
}
public void setMarried(Boolean married) {
this.married = married;
}
public String getProfile() {
return profile;
}
public void setProfile(String profile) {
this.profile = profile;
}
}
我们在上述类中使用Hibernate
验证器进行表单验证。现在找到服务类。
UserService.java
package com.concretepage.service;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import com.concretepage.domain.User;
@Service
public class UserService {
private List<User> allUsers = new ArrayList<>();
public List<User> getAllUserArticles(){
return allUsers;
}
public void addUser(User user) {
allUsers.add(user);
}
}
4. 创建 Controller
UserController.java
package com.concretepage.controller;
import java.util.ArrayList;
import java.util.List;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.concretepage.domain.User;
import com.concretepage.service.UserService;
@Controller
@RequestMapping("app")
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
@Autowired
private UserService userService;
@GetMapping("create-user")
public ModelAndView createUserView() {
ModelAndView mav = new ModelAndView();
mav.setViewName("user-creation");
mav.addObject("user", new User());
mav.addObject("allProfiles", getProfiles());
return mav;
}
@PostMapping("create-user")
public ModelAndView createUser(@Valid User user, BindingResult result) {
ModelAndView mav = new ModelAndView();
if(result.hasErrors()) {
logger.info("Validation errors while submitting form.");
mav.setViewName("user-creation");
mav.addObject("user", user);
mav.addObject("allProfiles", getProfiles());
return mav;
}
userService.addUser(user);
mav.addObject("allUsers", userService.getAllUserArticles());
mav.setViewName("user-info");
logger.info("Form submitted successfully.");
return mav;
}
private List<String> getProfiles() {
List<String> list = new ArrayList<>();
list.add("Developer");
list.add("Manager");
list.add("Director");
return list;
}
}
5. 创建 application.properties
application.properties
logging.level.root= WARN
logging.level.org.springframework.web= ERROR
logging.level.com.concretepage= INFO
6. 创建用于国际化的 Message Properties
找到en
语言的信息属性。
messages_en.properties
app.title= Spring Boot + Thymeleaf
app.create-user= Create User
app.user-details= User Details
user.id= Id
user.name= Name
user.gender= Gender
user.married= Married
user.profile= Profile
user.gender.male= Male
user.gender.female= Female
user.form.submit= Submit
user.form.reset= Reset
user.add-more-users= Add More Users
error.user.id= Id must be between 3 to 10 characters.
error.user.name= User name must be between 5 to 20 characters.
error.user.gender= Select gender.
7. 创建 Thymeleaf 模板
当我们访问该应用程序时,将打开以下页面。
user-creation.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="#{app.title}"> Title </title>
<link rel="stylesheet" th:href="@{/css/styles.css}"/>
</head>
<body>
<h1 th:text="#{app.create-user}">Create</h1>
<form action="#" th:action="@{/app/create-user}" th:object="${user}" method="POST">
<table>
<tr><td th:text="#{user.id}"/></td>
<td>
<input type="text" th:field="*{userId}" />
<label th:if="${#fields.hasErrors('userId')}" th:text="#{error.user.id}" th:class="'error'">Id Error</label>
</td>
</tr>
<tr><td th:text="#{user.name}"></td>
<td>
<input type="text" th:field="*{userName}" />
<label th:if="${#fields.hasErrors('userName')}" th:text="#{error.user.name}" th:class="'error'">Name Error</label>
</td>
</tr>
<tr><td th:text="#{user.gender}"></td>
<td>
<input type="radio" th:field="*{gender}" value="Male"/><label th:text="#{user.gender.male}">M</label>
<input type="radio" th:field="*{gender}" value="Female"/><label th:text="#{user.gender.female}">F</label>
<label th:if="${#fields.hasErrors('gender')}" th:text="#{error.user.gender}" th:class="'error'">Gender Error</label>
</td>
</tr>
<tr><td th:text="#{user.married}+ '?'"></td>
<td>
<input type="checkbox" th:field="*{married}" />
</td>
</tr>
<tr><td th:text="#{user.profile}"></td>
<td>
<select th:field="*{profile}">
<option th:each="profile : ${allProfiles}" th:value="${profile}" th:text="${profile}">Profile</option>
</select>
</td>
</tr>
<tr><td colspan="2">
<input type="submit" th:value="#{user.form.submit}"/>
<input type="reset" th:value="#{user.form.reset}"/>
</td>
</tr>
</table>
</form>
</body>
</html>
成功提交表格后,将打开以下页面。
user-info.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="#{app.title}"> Title </title>
<link rel="stylesheet" th:href="@{/css/styles.css}"/>
</head>
<body>
<h1 th:text="#{app.user-details}">Details</h1>
<table>
<tr>
<th th:text="#{user.id}"/></th>
<th th:text="#{user.name}"></th>
<th th:text="#{user.gender}"></th>
<th th:text="#{user.married}+ '?'"></th>
<th th:text="#{user.profile}"></th>
</tr>
<tr th:each="user : ${allUsers}">
<td th:text="${user.userId}">Id</td>
<td th:text="${user.userName}">Title</td>
<td th:text="${user.gender}">Gender</td>
<td th:text="${user.married}">Married</td>
<td th:text="${user.profile}">Profile</td>
</tr>
</table>
<a href="#" th:href="@{/app/create-user}" th:text="#{user.add-more-users}">Add User</a>
</body>
</html>
8. 创建CSS文件
styles.css
.error{
color: red;
font-size: 15px;
}
.user{
color: blue;
font-size: 15px;
}
table {
border-collapse: collapse;
}
table, th, td {
border: 1px solid black;
}
9. Spring Boot 主类
找到Spring boot
的主类来运行应用程序。
MyApplication.java
package com.concretepage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
运行应用程序
我们可以通过以下方式运行我们的应用程序。
1. 使用Eclipse
使用页面末尾的下载链接下载项目的源代码。
将该项目导入eclipse
。
使用命令提示符,进入项目的根文件夹并运行。
mvn clean eclipse:eclipse
然后在eclipse
中刷新该项目。点击Run as
-> Java Application
来运行主类MyApplication
。
Tomcat
服务器将被启动。
2. 使用Maven命令
下载项目的源代码。使用命令提示符进入项目的根文件夹并运行命令。
mvn spring-boot:run
Tomcat
服务器将被启动。
3. 使用可执行的JAR
使用命令提示符,转到项目的根文件夹并运行该命令。
mvn clean package
我们将在目标文件夹中得到可执行的spring-boot-demo-0.0.1-SNAPSHOT.jar
。以下列方式运行这个JAR
。
java -jar target/spring-boot-demo-0.0.1-SNAPSHOT.jar
Tomcat
服务器将被启动。
现在我们准备测试该应用程序。访问下面给出的URL。
http://localhost:8080/app/create-user
我们将得到以下界面来创建用户。
成功提交表格后,我们将得到用户的报告页面。
参考文献
【1】Spring Boot Reference Guide
【2】Using Thymeleaf
【3】Spring Boot + Thymeleaf + Maven Example