Spring Boot Validation 接口校验:从零到掌握

打印 上一主题 下一主题

主题 880|帖子 880|积分 2640

在开发 Web 应用时,数据校验是不可忽视的一部门。无论是注册用户信息、提交表单数据,照旧处理业务逻辑,数据的有效性和完整性都必要得到保证。Spring Boot 提供了强盛的验证功能,基于 Hibernate Validator 框架,通过注解方式简化了数据校验的实现。本文将详细先容 Spring Boot 的 Validation 接口校验机制,包括其核心功能、常用注解、自定义校验、以及现实应用场景。

1. 什么是 Spring Validation?

Spring Validation 是一个用于数据校验的框架,它基于 JSR-303(Bean Validation API) 和 Hibernate Validator 实现。通过在 JavaBean 的字段上添加特定的注解,可以定义数据的校验规则。Spring Boot 通过整合 Hibernate Validator,使得在 Web 应用中使用数据校验变得更加简朴。

2. Spring Boot Validation 的核心功能


  • 注解式校验:通过注解定义数据校验规则。
  • 自动化校验:Spring Boot 提供了对校验的自动支持,无需手动编写校验逻辑。
  • 非常处理:Spring Boot 可以自动将校验失败的错误信息返回给客户端。
  • 支持分组校验:可以为差别的场景定义差别的校验分组。
  • 支持自定义校验:可以扩展注解,定义自定义的校验逻辑。

3. 常用的校验注解

以下是 Spring Boot 中常用的校验注解:
注解功能描述@NotNull确保字段不为 null@Null确保字段为 null@NotBlank确保字段不为空(字符串)@NotEmpty确保字段不为空(集合、数组)@Length确保字段的长度在指定范围内@Size确保字段的长度在指定范围内(适用于集合、数组、字符串)@Range确保字段的值在指定范围内@Min确保字段的值大于等于指定值@Max确保字段的值小于等于指定值@Email确保字段为有效的电子邮件所在@Pattern确保字段的值匹配指定的正则表达式@Past确保字段的值是已往的日期@Future确保字段的值是未来的日期
4. Spring Boot Validation 的实现步骤

步骤 1:添加依赖

在 pom.xml 文件中添加以下依赖:
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-validation</artifactId>
  4. </dependency>
复制代码
步骤 2:创建 JavaBean

创建一个必要校验的 JavaBean 类,并在字段上添加校验注解:
  1. import jakarta.validation.constraints.*;
  2. public class User {
  3.    
  4.     @NotNull(message = "用户名不能为空")
  5.     @Size(min = 2, max = 10, message = "用户名长度必须在2到10之间")
  6.     private String username;
  7.    
  8.     @NotNull(message = "密码不能为空")
  9.     @NotBlank(message = "密码不能为空")
  10.     @Pattern(regexp = "^(?=.*\\d)(?=.*[A-Za-z])(?=.*[@$!%*#?&])[A-Za-z\\d@$!%*#?&]{8,20}$", message = "密码格式不正确")
  11.     private String password;
  12.    
  13.     @Email(message = "邮箱格式不正确")
  14.     private String email;
  15.    
  16.     @Min(value = 18, message = "年龄必须大于等于18岁")
  17.     private Integer age;
  18.    
  19.     public User() {}
  20.    
  21.     // Getters and Setters
  22. }
复制代码
步骤 3:在控制器中使用 @Valid 注解

在控制器的参数中使用 @Valid 注解启用校验:
  1. import org.springframework.http.ResponseEntity;
  2. import org.springframework.web.bind.annotation.PostMapping;
  3. import org.springframework.web.bind.annotation.RequestBody;
  4. import org.springframework.web.bind.annotation.RestController;
  5. import jakarta.validation.Valid;
  6. import jakarta.validation.constraints.NotNull;
  7. @RestController
  8. public class UserController {
  9.    
  10.     @PostMapping("/register")
  11.     public ResponseEntity<?> register(@Valid @RequestBody User user) {
  12.         // 业务逻辑
  13.         return ResponseEntity.ok("注册成功");
  14.     }
  15. }
复制代码
步骤 4:处理校验非常

Spring Boot 会自动将校验失败的错误信息封装到 MethodArgumentNotValidException 非常中。可以通过全局非常处理来同一返回错误信息:
  1. import org.springframework.http.HttpStatus;
  2. import org.springframework.http.ResponseEntity;
  3. import org.springframework.validation.FieldError;
  4. import org.springframework.web.bind.MethodArgumentNotValidException;
  5. import org.springframework.web.bind.annotation.ControllerAdvice;
  6. import org.springframework.web.bind.annotation.ExceptionHandler;
  7. import jakarta.validation.ConstraintViolation;
  8. import jakarta.validation.ConstraintViolationException;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. @ControllerAdvice
  12. public class GlobalExceptionHandler {
  13.    
  14.     @ExceptionHandler(MethodArgumentNotValidException.class)
  15.     public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
  16.         Map<String, String> errors = new HashMap<>();
  17.         ex.getBindingResult().getAllErrors().forEach((error) -> {
  18.             String fieldName = ((FieldError) error).getField();
  19.             String errorMessage = error.getDefaultMessage();
  20.             errors.put(fieldName, errorMessage);
  21.         });
  22.         return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
  23.     }
  24. }
复制代码
5. 自定义校验注解

如果内置的校验注解无法满足需求,可以通过自定义注解来扩展校验功能。
自定义校验注解

  1. import jakarta.validation.Constraint;
  2. import jakarta.validation.Payload;
  3. import java.lang.annotation.Documented;
  4. import java.lang.annotation.ElementType;
  5. import java.lang.annotation.Retention;
  6. import java.lang.annotation.RetentionPolicy;
  7. import java.lang.annotation.Target;
  8. @Documented
  9. @Constraint(validatedBy = {PhoneValidator.class})
  10. @Target({ElementType.FIELD})
  11. @Retention(RetentionPolicy.RUNTIME)
  12. public @interface Phone {
  13.    
  14.     String message() default "手机号格式不正确";
  15.    
  16.     Class<?>[] groups() default {};
  17.    
  18.     Class<? extends Payload>[] payload() default {};
  19. }
复制代码
自定义校验逻辑

  1. import jakarta.validation.ConstraintValidator;
  2. import jakarta.validation.ConstraintValidatorContext;
  3. public class PhoneValidator implements ConstraintValidator<Phone, String> {
  4.    
  5.     @Override
  6.     public void initialize(Phone constraintAnnotation) {
  7.     }
  8.    
  9.     @Override
  10.     public boolean isValid(String value, ConstraintValidatorContext context) {
  11.         if (value == null) {
  12.             return false;
  13.         }
  14.         // 手机号正则表达式
  15.         String regex = "^1(3\\d|5[i-o]\\d|78\\d|4\\d)\\d{7}$";
  16.         return value.matches(regex);
  17.     }
  18. }
复制代码
使用自定义校验注解

  1. @Phone(message = "手机号格式不正确")
  2. private String phone;
复制代码
6. 分组校验和条件校验

分组校验

通太过组校验,可以为差别的场景定义差别的校验规则。
  1. public interface SaveGroup {
  2. }
  3. public interface UpdateGroup {
  4. }
  5. @NotNull(groups = SaveGroup.class)
  6. @Size(min = 2, max = 10, groups = {SaveGroup.class, UpdateGroup.class})
  7. private String username;
复制代码
在控制器中指定必要校验的分组:
  1. @PostMapping("/save")
  2. public ResponseEntity<?> save(@Validated(SaveGroup.class) @RequestBody User user) {
  3.     // 业务逻辑
  4.     return ResponseEntity.ok("保存成功");
  5. }
复制代码
条件校验

通过 @ScriptAssert 注解,可以基于脚本语言(如 JavaScript 或 Groovy)实现复杂的条件校验。
  1. @ScriptAssert(lang = "javascript", script = "password.length >= 8 && password.match(/^(?=.*\\d)(?=.*[A-Za-z])(?=.*[@$!%*#?&])[A-Za-z\\d@$!%*#?&]{8,20}$/)")
  2. public class User {
  3.     // 字段定义
  4. }
复制代码
7. 结合其他技能

1. 同一非常处理

通过全局非常处理,可以同一返回校验失败的错误信息,提升用户体验。
2. 日记记载

通过 AOP(Aspect Oriented Programming),可以记载校验失败的日记,方便后续分析:
  1. @Aspect
  2. @Component
  3. public class ValidationAspect {
  4.    
  5.     @Around("execution(* *(..)) && @annotation(org.springframework.web.bind.annotation.PostMapping)")
  6.     public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
  7.         try {
  8.             Object[] args = joinPoint.getArgs();
  9.             if (args != null && args.length > 0) {
  10.                 for (Object arg : args) {
  11.                     if (arg != null && arg.getClass().getAnnotation(Valid.class) != null) {
  12.                         // 记录日志
  13.                         System.out.println("开始校验数据:" + arg);
  14.                     }
  15.                 }
  16.             }
  17.             return joinPoint.proceed();
  18.         } catch (MethodArgumentNotValidException ex) {
  19.             // 记录校验失败的日志
  20.             System.out.println("校验失败:" + ex.getBindingResult());
  21.             throw ex;
  22.         }
  23.     }
  24. }
复制代码
8. 常见问题和解决方案

常见问题


  • 校验注解不生效

    • 检查是否添加了 spring-boot-starter-validation 依赖。
    • 确保在控制器中使用了 @Valid 注解。

  • 错误信息不返回

    • 检查是否实现了全局非常处理。
    • 确保控制器的返回类型为 ResponseEntity。

  • 自定义校验注解不生效

    • 检查自定义注解的 ConstraintValidator 是否正确实现。
    • 确保自定义注解使用了 @Constraint 注解。

总结

Spring Boot 的 Validation 功能提供了一种简朴而强盛的数据校验方式,通过注解式校验和自动化处理,能够显著提升开发效率和代码质量。结合 Hibernate Validator 的强盛功能,开发者可以轻松实现复杂的校验逻辑,同时通过自定义校验注解和分组校验,满足差别的业务需求。
盼望本文能帮助你在现实项目中更好地使用 Spring Boot 的 Validation 功能,进步代码的健壮性和用户体验!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王柳

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表