在 Web 应用中,表单是用户与后端交互的主要界面之一。为了确保数据的有效性和一致性,我们经常需要对提交的表单数据进行验证。Spring 提供了强大的数据校验机制,结合注解和验证器,能够轻松地在服务器端完成数据校验。本博客将介绍如何使用 Spring 进行 Web 表单的校验。
项目中需要引入 spring-boot-starter-web
和 hibernate-validator
两个依赖
pom.xml
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
创建一个代表表单数据的实体类,并在该实体类中添加数据校验注解
User.java
package com.cheney.koala.model;
import jakarta.validation.constraints.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
@NotBlank(message = "姓名不能为空")
private String name;
private String gender;
@NotNull(message = "年龄不能为空")
@Min(value = 18, message = "年龄不能小于18岁")
private Integer age;
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^\\d{11}$", message = "手机号必须是11位数字")
private String phoneNumber;
@NotBlank(message = "邮箱号不能为空")
@Email(message = "邮箱号格式不正确")
private String email;
}
上述 User 实体类中使用了 @NotBlank
、@Min
、@Pattern
和 @Email
等注解,这些注解定义了相应字段的验证规则。
@NotBlank
用于验证字符串不为空。如果为空,会产生带有指定消息的验证错误
@Min
用于验证数值的最小值。指定了年龄的最小值为 18 岁,如果小于 18,会产生带有指定消息的验证错误
@Pattern
用于验证字段的值是否匹配指定的正则表达式。此处使用 ^\\d{11}$
来验证手机号是否是11位数字
@Email
:用于验证字段是否是有效的电子邮件地址格式
在控制器中处理表单提交,并使用 @Valid
注解标记需要验证的实体类。如果验证失败,Spring 将自动将错误信息添加到 BindingResult
对象中。
package com.cheney.koala.controller;
import com.cheney.koala.model.User;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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;
@Controller
@RequestMapping("user")
@Slf4j
public class UserController {
@PostMapping("register")
public String registerUser(@Valid User user, BindingResult result, Model model) {
if (result.hasErrors()) {
log.info("检验错误 " + result.getAllErrors().size() + " 个");
result.getAllErrors().forEach(
e -> System.out.println(e.getDefaultMessage())
);
return "register";
}
log.info(user.toString());
return "redirect:/login";
}
}
在上述代码中,@Valid
注解用于标记需要验证的实体类对象 User
,而 BindingResult
对象用于收集验证错误信息。此处如果校验出错误,则在控制台打印错误的个数以及错误信息。
创建一个 Thymeleaf 模板(例如,register.html
),用于展示用户注册的表单。在表单中使用 Thymeleaf 标签来显示错误信息:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Koala Registration Page</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body class="bg-light">
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-header">
<h3 class="text-center">Koala System Registration</h3>
</div>
<div class="card-body">
<form th:action="@{/user/register}" method="post">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" class="form-control" id="name" name="name">
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label for="gender">Gender:</label>
<select class="form-control" id="gender" name="gender" required>
<option value="male">Male</option>
<option value="female">Female</option>
</select>
</div>
<div class="form-group col-md-6">
<label for="age">Age:</label>
<input type="number" class="form-control" id="age" name="age" required>
</div>
</div>
<div class="form-group">
<label for="phoneNumber">Phone Number:</label>
<input type="tel" class="form-control" id="phoneNumber" name="phoneNumber" required>
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" class="form-control" id="email" name="email" required>
</div>
<button type="submit" class="btn btn-primary btn-block">Register</button>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
http://localhost:8080/register
输入个人信息,点击 Register 按钮
如我们所想,我们看到了,相应的错误信息。
统一的验证框架
Spring 表单校验使用 Java 标准的 Bean Validation(JSR 380)规范,通过注解对模型对象进行验证。这提供了一种统一的验证框架,使得验证逻辑与具体的实现细节解耦。
注解简化验证逻辑
使用注解标记在模型类字段上,简化了验证逻辑的编写。通过使用注解,可以在模型类中直观地定义验证规则,使代码更加清晰和易于维护。
可扩展性
Spring 表单校验支持自定义的验证注解,使得可以根据业务需求创建特定的验证规则。这增强了验证框架的可扩展性,使其能够满足不同项目的需求。
集成框架支持
Spring 框架天然支持表单校验,并提供了与其他模块的良好集成。特别是在 Spring MVC 中,表单校验与控制器方法的参数验证、错误处理等集成得非常紧密,简化了整个验证流程。
错误处理和消息国际化
Spring 表单校验提供了灵活的错误处理机制,可以方便地将验证错误消息与用户界面进行关联。支持消息的国际化,使得应用能够轻松地适应不同语言环境。
前端交互支持
Spring 表单校验生成的错误信息可以方便地传递到前端,通过合适的技术(例如 Thymeleaf、FreeMarker 等)在用户界面上显示。这样,用户可以获得实时的反馈,提高了用户体验。
防止恶意输入
表单校验不仅可以验证字段是否为空,还能验证字段的格式、长度等。这有助于防止恶意用户通过非法输入对系统进行攻击。
https://github.com/cheney09/spring-practical-combat/tree/main/14/koala
使用 Spring 表单校验可以提高开发效率,减少代码冗余,增加系统的可维护性和稳定性。通过在模型层面进行验证,可以确保数据的合法性,提升应用的质量。 本文通过了一个小例子说明了常见的用法,其他的校验在需要的时候再去查看啦。