Spring Validation 是 Spring Framework 的一部分,它提供了一种简单的方式来验证 Java 对象的数据。Spring Validation 基于 JSR 303/JSR 349(也称为 Bean Validation)规范,允许开发者使用注解来定义对象的约束条件,从而简化了验证逻辑的编写。
1.导入依赖
xml
<!-- Spring Boot Starter Web 依赖web环境 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Starter Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.1.Final</version>
</dependency>
spring-boot-starter-validation
和 hibernate-validator
在 Spring Boot 中扮演着不同的角色,但它们紧密相关。下面是两者之间的主要区别:
spring-boot-starter-validation
提供了 Spring Boot 中 Bean Validation 的自动配置和支持。它还提供了对 Spring MVC 控制器中验证的支持,例如通过@Valid
和@Validated
注解来验证请求体和方法参数。hibernate-validator
是一个具体的 Bean Validation 实现,它提供了验证逻辑和标准的验证注解。它提供了所有标准的验证注解(如@NotNull
,@Size
,@Pattern
等)的实现。支持创建自定义验证注解和相应的验证器实现。- 通常情况下,只需要添加
spring-boot-starter-validation
即可,因为它会自动包含 Hibernate Validator 或其他 Bean Validation 实现。
2.标准注解
2.1.常用注解
- @Null : 指定字段必须为
null
。 - @NotNull : 指定字段不得为
null
。 - @NotBlank : 指定字符串必须不为空,且不全是空白字符。
- @NotEmpty : 指定字符串、数组、集合、Map 或其他可迭代类型必须不为空。
- @AssertFalse : 指定布尔值必须为
false
。 - @AssertTrue : 指定布尔值必须为
true
。 - @Min(value) : 指定数值必须大于等于指定的最小值。
- @Max(value) : 指定数值必须小于等于指定的最大值。
- @DecimalMin(value) : 指定数值必须大于等于指定的小数值。
- @DecimalMax(value) : 指定数值必须小于等于指定的小数值。
- @Size(min, max) : 指定字符串、数组、集合、Map 或其他可迭代类型的元素数量必须在指定范围内。
- @Digits(integer, fraction) : 指定数值的整数部分和小数部分的最大位数。
- @Past : 指定日期必须在过去。
- @Future : 指定日期必须在未来。
- @PastOrPresent : 指定日期必须在过去或现在。
- @FutureOrPresent : 指定日期必须在未来或现在。
- @Pattern(regexp) : 指定字符串必须匹配指定的正则表达式。
- @Positive : 指定数值必须大于 0。
- @PositiveOrZero : 指定数值必须大于等于 0。
- @Negative : 指定数值必须小于 0。
- @NegativeOrZero : 指定数值必须小于等于 0。
- @Email : 指定字符串必须是有效的电子邮件地址。
- @URL(protocol, host, port) : 指定字符串必须是有效的 URL。
- @CreditCardNumber : 指定字符串必须是有效的信用卡号码。
- @Length(min, max) : 指定字符串长度必须在指定范围内。
- @Range(min, max) : 指定数值必须在指定范围内。
2.2.使用案例
-
定义验证规则。
-
使用
@Valid
注解来验证控制器方法的参数。 -
处理验证错误。
-
实现额外的逻辑,如检查用户名是否唯一。
2.2.1.创建 User 类
定义一个 User
类,使用 Bean Validation 注解来定义验证规则:
java
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public class User {
@NotBlank(message = "用户名不能为空")
@Size(min = 5, max = 20, message = "用户名长度应在5到20个字符之间")
private String username;
@NotBlank(message = "密码不能为空")
@Size(min = 8, max = 32, message = "密码长度应在8到32个字符之间")
private String password;
@Email(message = "邮箱格式不正确")
private String email;
// 构造函数、getter 和 setter 省略
}
2.2.2.创建 UserRepository
创建一个简单的 UserServiceImpl
,用于模拟数据库操作:
java
import com.yuan.springvalidationdemo.domain.User;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl {
public boolean existsByUsername(String username){
// 模拟数据库查询, 验证用户名是否已存在
return false;
}
public void save(User user) {
// 模拟保存用户
}
}
2.2.3.创建 UserController
创建一个 UserController
类,用于处理用户的注册请求,并使用 @Valid
注解来验证传入的用户对象:
java
import com.yuan.springvalidationdemo.domain.User;
import com.yuan.springvalidationdemo.service.impl.UserServiceImpl;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@Autowired
private UserServiceImpl userService;
@PostMapping("/register")
public ResponseEntity<String> register(@Valid @RequestBody User user, BindingResult result) {
if (result.hasErrors()) {
// 如果有验证错误,则返回错误信息
StringBuilder errorMessage = new StringBuilder();
result.getFieldErrors().forEach(error -> {
errorMessage.append(error.getDefaultMessage()).append("\n");
});
return ResponseEntity.badRequest().body(errorMessage.toString());
}
// 检查用户名是否唯一
if (userService.existsByUsername(user.getUsername())) {
return ResponseEntity.badRequest().body("用户名已存在");
}
// 保存用户
userService.save(user);
return ResponseEntity.ok("注册成功");
}
}
2.2.4.测试
运行 Spring Boot 应用程序,并发送 POST 请求到 /register
端点,测试不同的输入情况:
-
正确的输入:
- 发送一个包含有效用户名、密码和电子邮件的 JSON 对象。
- 应该收到响应 "注册成功"。
-
错误的输入:
- 发送一个包含无效用户名、密码或电子邮件的 JSON 对象。
- 应该收到响应,显示验证错误信息。
2.2.5.BindingResult 的作用
BindingResult
是 Spring MVC 中的一个接口,它用于收集和处理模型对象的绑定结果,包括验证错误和其他绑定过程中产生的问题。当你在控制器方法中使用 @Valid
或 @Validated
注解来验证一个对象时,通常会将 BindingResult
作为一个额外的参数传递给该方法。
- 收集验证错误 :
- 当使用
@Valid
或@Validated
注解时,Spring 会自动调用验证器来验证对象。 - 如果发现任何验证错误,这些错误会被收集到
BindingResult
对象中。
- 当使用
- 访问验证错误 :
- 你可以通过
BindingResult
对象来获取验证错误的详细信息。 - 例如,你可以使用
hasErrors()
,getFieldErrors()
,getGlobalErrors()
等方法来检查是否有验证错误,以及获取特定字段的错误信息。
- 你可以通过
- 处理验证错误 :
- 一旦你获取到了验证错误,你可以根据需要处理这些错误。
- 例如,你可以向客户端返回错误信息,或者在前端显示错误消息。
3.@Valid
和 @Validated
@Valid
和 @Validated
是 Spring Validation 中用于触发验证逻辑的注解。它们在不同的上下文中使用,并且有着细微的区别。
3.1.@Valid
-
位置:
@Valid
注解可以放在控制器方法的参数上。
-
作用:
- 当一个对象被
@Valid
注解修饰时,Spring 会尝试对该对象进行验证。 - 如果验证失败,即对象违反了定义的约束条件,那么 Spring 会将验证错误收集到
BindingResult
对象中。 - 如果验证成功,方法将继续执行。
- 当一个对象被
-
使用场景:
- 通常用于单个对象的验证。
- 在控制器方法中,可以与
BindingResult
参数一起使用来处理验证错误。
java
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
@RestController
public class UserController {
@PostMapping("/register")
public String register(@Valid @RequestBody User user, BindingResult result) {
if (result.hasErrors()) {
return "注册异常";
}
// 用户注册逻辑
return "注册成功";
}
}
3.2.@Validated
-
位置:
@Validated
注解可以放在类级别或方法级别。- 当放在类级别时,表示该类的所有方法都需要进行验证。
- 当放在方法级别时,表示该方法需要进行验证。
-
使用场景:
-
用于验证控制器类中的方法参数。
-
通常不需要与
BindingResult
一起使用,因为验证错误通常由控制器类处理。
-
java
import com.yuan.springvalidationdemo.domain.User;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Validated
public class UserController2 {
@PostMapping("/register2")
public String register(@Valid @RequestBody User user) {
// 用户注册逻辑
return "注册成功";
}
}
3.3.比较
-
@Valid:
- 用于单个对象的验证。
- 通常与
BindingResult
一起使用来处理验证错误。
-
@Validated:
- 用于验证控制器类中的方法参数。
- 可以放在类级别或方法级别。
- 通常不需要与
BindingResult
一起使用,因为验证错误通常由控制器类处理。
注意
- 如果您只需要验证一个对象,通常使用
@Valid
就足够了。 - 如果您想要对整个控制器类中的所有方法进行验证,可以使用
@Validated
。 - 在实际应用中,
@Valid
更常用,因为它提供了更细粒度的控制,并且与BindingResult
结合使用时可以方便地处理验证错误。