在现代Web开发中,数据校验是确保应用安全性和稳定性的重要步骤。即使在前端已经进行了校验,后端仍需再次验证数据的合法性,以防止潜在的安全漏洞。Spring Boot 提供了多种方式来简化和标准化数据校验,包括 @Valid
和 @Validated
注解。本篇博文将深入探讨如何在 Spring Boot 项目中使用这些注解,以及如何统一处理异常。
1. 引入依赖
根据 Spring Boot 的版本不同,数据校验的依赖引入方式有所不同。
1.1 Spring Boot 版本小于2.3
在 Spring Boot 2.3 版本之前,spring-boot-starter-web
依赖已经包含了校验所需的依赖包,因此不需要额外引入。
1.2 Spring Boot 版本大于等于2.3
从 Spring Boot 2.3 开始,需要手动引入校验相关的依赖。可以选择以下三种方式之一:
<!-- 第一种方式导入校验依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 第二种方式导入校验依赖 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<!-- 第三种方式导入校验依赖 -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
2. @Valid 和 @Validated 的用法和区别
2.1 @Valid 注解
- 所属包:
javax.validation.Valid
- 用途:常用于校验方法参数和对象的字段,支持嵌套验证。
- 适用场景:方法参数校验、成员属性(字段)校验。
2.2 @Validated 注解
- 所属包:
org.springframework.validation.annotation.Validated
- 用途:Spring 提供的校验机制,可以用于方法参数校验和分组校验。
- 适用场景:主要用于方法级别的参数校验,特别是当需要分组校验时。
3. 常用校验注解
以下是一些常用的校验注解及其用途:
@NotEmpty
: 被注释的字符串不能为 null 或空。@NotBlank
: 被注释的字符串不能为 null,且必须包含至少一个非空白字符。@NotNull
: 被注释的元素不能为 null。@AssertTrue
: 被注释的元素必须为 true。@Email
: 被注释的元素必须是有效的 Email 格式。@Min(value)
: 被注释的元素必须是一个数字,其值必须大于等于指定的最小值。@Max(value)
: 被注释的元素必须是一个数字,其值必须小于等于指定的最大值。@Size(max=, min=)
: 被注释的集合或数组的大小必须在指定的范围内。@Past
: 被注释的日期必须是过去的日期。@Future
: 被注释的日期必须是未来的日期。
4. 参数校验的实现
4.1 控制器层的校验
在控制器方法中使用 @Valid
或 @Validated
注解,可以自动对传入的参数进行校验。例如:
@RestController
@RequestMapping("/record")
@Validated
public class ReadRecordController {
@Autowired
private ReadRecordService readRecordService;
@PostMapping("/addRecord")
public ResponseResult addRecord(@RequestBody @Valid ReadRecord readRecord) {
return readRecordService.addRecord(readRecord);
}
@GetMapping("/getReadRecord")
public ResponseResult getReadRecord(@Valid @NotBlank(message = "fileCode不能传空值") String fileCode) {
return readRecordService.getReadRecord(fileCode);
}
}
4.2 实体类的校验注解
实体类中的字段可以使用校验注解进行约束,例如:
@Data
public class ReadRecord {
private String id;
@NotBlank(message = "loginName不能传空")
private String loginName;
@NotBlank(message = "fileCode不能传空")
private String fileCode;
}
5. 自定义校验注解
当内置的校验注解不能满足需求时,可以自定义注解。例如,自定义一个校验手机号码格式的注解。
5.1 创建自定义注解
@Documented
@Constraint(validatedBy = PhoneNumberValidator.class)
@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
public @interface PhoneNumber {
String message() default "Invalid phone number";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
5.2 实现校验逻辑
public class PhoneNumberValidator implements ConstraintValidator<PhoneNumber, String> {
@Override
public boolean isValid(String phoneField, ConstraintValidatorContext context) {
if (phoneField == null) {
return true;
}
return phoneField.matches("^1[3-9]\\d{9}$");
}
}
5.3 使用自定义注解
public class User {
@PhoneNumber(message = "phoneNumber 格式不正确")
@NotNull(message = "phoneNumber 不能为空")
private String phoneNumber;
}
6. 统一异常处理
为确保校验失败的错误信息能够正确返回给前端,我们需要进行统一的异常处理。可以通过 @ControllerAdvice
和 @ExceptionHandler
来实现。
@ControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public ResponseResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
List<String> errorMessages = allErrors.stream()
.map(ObjectError::getDefaultMessage)
.collect(Collectors.toList());
return ResponseResult.errorResult(501, errorMessages.toString());
}
}
以上代码示例中,当 MethodArgumentNotValidException
异常被抛出时,CustomExceptionHandler
将捕获异常并返回格式化的错误信息。
7. 总结
在Spring Boot中,数据校验是确保数据完整性和安全性的关键环节。通过合理使用 @Valid
、@Validated
以及常用的校验注解,我们可以高效地实现数据校验。同时,结合自定义注解和统一异常处理机制,可以更好地满足实际项目中的特殊需求,并确保用户能够获得及时准确的反馈。
希望本篇文章能为您提供有价值的参考,帮助您在项目中更好地实现数据校验和异常处理。如果有任何问题或建议,欢迎交流和讨论。