本章带你用Spring Boot创建一个服务器应用,包含一个有验证功能的表单。
本文目标
我们将会构建一个简单的Spring MVC应用,可以接受用户输入,并用标准的注解配置输入的验证规则。输出错误信息,让用户可以重新输入正确的信息。
你需要
- 15分钟左右
- IntelliJ IDEA
- JDK 1.8+
- Maven 3.2+
用Spring Initializr生成项目代码
对于所有的Spring应用,你都可以使用Spring Initializr生成基本的项目代码。Initializr提供了一个快速的方式去引入所有你需要的依赖,并且为你做了很多设置。当前例子需要Spring Web、Thymeleaf和Validation依赖。具体设置如下图:
如上图所示,我们选择了Maven作为编译工具。你也可以选择Gradle来进行编译。然后我们分别把Group和Artifact设置为“com.hansy”和“validating-form-input”。
生成的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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hansy</groupId>
<artifactId>validating-form-input</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>validating-form-input</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<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>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
创建一个PersonForm类
应用涉及到验证一个用户的名字和年龄,所以我们需要首先创建一个类来代表这个用户,代码如下:
package com.hansy.validatingforminput;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class PersonForm {
@NotNull
@Size(min = 2,max =30)
private String name;
@NotNull
@Min(18)
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "PersonForm{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
PersonForm类有两个属性:name和age。这里用到了一些标准的验证注解:
- @Size(min=2, max=30) 限制 name 属性的长度为2到30之间。
- @NotNull 不允许Null值。
- @Min(18) 不允许年龄小于18。
附带的,你可以看到name和age的getter和setter,和一个方便查看的toString()方法。
创建要给Web控制器
现在我们已经创建了一个表单返回对象,接下来需要再创建要给简单的Web控制器。代码如下:
package com.hansy.validatingforminput;
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.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.validation.Valid;
@Controller
public class WebController implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry){
registry.addViewController("/results").setViewName("results");
}
@GetMapping("/")
public String showForm(PersonForm personForm){
return "form";
}
@PostMapping("/")
public String checkPersonInfo(@Valid PersonForm personForm, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "form";
}
return "redirect:/results";
}
}
这个控制器包括一个GET方法和一个POST方法。两个方法都映射到了 /。
showForm方法返回了form模板。这个方法签名中包含了一个PersonForm 类型的参数,让模板可以把表达的属性绑定到PersonForm上面。
checkPersonFormInfo方法接受两个参数:
- personForm对象,它标记了**@Valid**注解,用来收集表单中填写的属性字段。
- bindingResult对象,我们可以用它测试,并取回验证结果。
我们可以从表单里面取回所有的属性字段,他们会被绑定到PersonForm对象里面。在代码里面,你可以测试验证错误。如果有错误,我可以用原来的form模板返回。所以的错误属性都可以显示。
如果用户的所有属性都是可用,浏览器会跳转到最终的results模板。
创建一个HTML前端模板
form模板,代码如下:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>validating-form-input</title>
</head>
<body>
<form action="#" th:action="@{/}" th:object="${personForm}" method="post">
<table>
<tr>
<td>Name:</td>
<td><input type="text" th:field="*{name}"></td>
<td th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name Error</td>
</tr>
<tr>
<td>Age:</td>
<td><input type="text" th:field="*{age}"></td>
<td th:if="${#fields.hasErrors('age')}" th:errors="*{age}">Age Error</td>
</tr>
<tr>
<td><button type="submit">Submit</button> </td>
</tr>
</table>
</form>
</body>
</html>
这个页面包含了一个简单的表单,每个字段都在table的单独的单元格里面。这个表单会被post提交到 /。它的字段和personForm对象进行了绑定,我们可以看到通过 th:field="*{name}" 和 th:field="*{age}" 进行了标记。每个字段相邻的第二个元素被用来显示所有的验证错误。
最后,表单里面有一个可以用来提交的按钮。点击提交之后,用户输入的名字、年龄跟 @Valid 对应的约束有冲突的话,页面会返回当前页并显示错误信息。如果名字、年龄都有效的话,用户会被路由到下一个页面。
results模板,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Success</title>
</head>
<body>
Congratulations! You are old enough to sign up for this sale.
</body>
</html>
本例中,这些网页模板没有包含任何复杂的 CSS和JavaScript。
运行程序
运行程序,访问http://localhost:8080/,我们可有看到如下的页面:
名字和年龄分别输入 A 和 15,点击Submit提交,结果如下:
上面的图片之所以这样显示,是因为输入的值和PersonForm类里面的约束相冲突。如果我们输入有效的名字和年龄,页面最终会跳转到results页,如下:
小结
我们编码了一个简单的网站应用,使用一个内置约束的对象进行表单验证。通过这种方式,我们可以确保数据符合特定的条件,用户可以输入正确的数据。
源码下载
参考资料
https://spring.io/guides/gs/validating-form-input/