01 依赖配置
在构建高效的校验体系前,需先完善项目依赖配置。
以下是优化后的依赖示例:
<dependencies><!-- Web 依赖,提供 RESTful 接口支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 校验核心依赖,整合 Hibernate Validator 实现 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
</dependencies>
注解:
- spring-boot-starter-web 依赖引入了 Spring MVC 组件,为构建 Web 应用提供基础支持
- spring-boot-starter-validation 依赖整合了 Hibernate Validator 实现,提供 JSR 380 校验规范支持
02 校验注解体系构建
构建完善的校验注解体系是实现数据校验的基础。
以下是企业级校验注解应用示例:
import javax.validation.constraints.*;
import java.time.LocalDate;public class UserRegistrationRequest {// 用户名校验:非空且长度在 4-20 位之间@NotBlank(message = "用户名不能为空")@Size(min = 4, max = 20, message = "用户名长度需在 4-20 位之间")private String username;// 邮箱校验:非空且符合邮箱格式@NotBlank(message = "邮箱不能为空")@Email(message = "邮箱格式不正确")private String email;// 密码校验:非空且长度不少于 8 位@NotBlank(message = "密码不能为空")@Size(min = 8, message = "密码长度至少为 8 位")private String password;// 年龄校验:必须大于 0 且小于 150@Min(value = 1, message = "年龄必须大于 0")@Max(value = 150, message = "年龄不能超过 150")private Integer age;// 出生日期校验:不能晚于当前日期@PastOrPresent(message = "出生日期不能晚于当前日期")private LocalDate birthDate;// 协议同意校验:必须为 true@NotNull(message = "必须同意服务条款")private Boolean termsAccepted;
}
注解:
- 使用组合注解实现多维度校验,如 @NotBlank + @Size 实现既校验非空又校验长度的双重校验
- 通过明确的错误提示信息,提升系统友好性,便于用户定位问题
- 日期类型使用 @PastOrPresent 校验,避免接收未来日期的非法输入
03 控制器校验集成
在控制器层面集成校验逻辑,确保所有入参经过严格校验:
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;import javax.validation.Valid;@Validated // 启用方法参数校验
@RestController
@RequestMapping("/api/users")
public class UserController {@PostMapping("/register")public ResponseEntity registerUser(@Valid @RequestBody UserRegistrationRequest request) {// 业务逻辑处理return ResponseEntity.ok("用户注册成功");}@GetMapping("/{id}")public ResponseEntity getUserById(@PathVariable Long id) {// 用户查询逻辑return ResponseEntity.ok(new User(id, "示例用户"));}
}
注解:
-
@Validated 注解启用控制器方法参数校验,配合 @Valid 对请求体进行深度校验
-
@RequestBody 结合校验注解,实现复杂对象的自动绑定与校验
-
通过明确的 HTTP 状态码和响应消息,提供标准化的接口反馈
04 全局异常处理机制
构建完善的全局异常处理机制,统一管理校验异常:
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;import java.util.HashMap;
import java.util.Map;@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(MethodArgumentNotValidException.class)public ResponseEntity handleValidationExceptions(MethodArgumentNotValidException ex) {Map<String, String> errors = new HashMap<>();ex.getBindingResult().getFieldErrors().forEach(error -> {errors.put(error.getField(), error.getDefaultMessage());});return ResponseEntity.badRequest().body(errors);}@ExceptionHandler(Exception.class)public ResponseEntity handleGeneralException(Exception ex) {return ResponseEntity.internalServerError().body("系统内部错误");}
}
注解:
- 通过 @RestControllerAdvice 实现全局异常处理,集中管理各类异常
- 针对校验异常提取字段级错误信息,返回结构化的错误响应
- 提供默认异常处理方法,确保所有未被捕获的异常都能得到妥善处理
05 分组校验实现
在复杂业务场景中,通过分组校验实现条件校验逻辑:
// 定义校验分组接口
public interface CreateGroup {}
public interface UpdateGroup {}// 应用分组校验的 DTO 类
public class UserDTO {@NotBlank(groups = CreateGroup.class, message = "创建时用户名必填")@Size(groups = CreateGroup.class, min = 4, message = "用户名长度至少为 4")private String username;@Email(groups = {CreateGroup.class, UpdateGroup.class}, message = "邮箱格式不正确")private String email;// Getter 和 Setter 方法
}
// 控制器方法应用分组校验
@PostMapping("/users")
public ResponseEntity createUser(@Validated({CreateGroup.class}) UserDTO userDTO) {// 创建用户逻辑return ResponseEntity.ok("用户创建成功");
}@PutMapping("/users/{id}")
public ResponseEntity updateUser(@Validated({UpdateGroup.class}) UserDTO userDTO) {// 更新用户逻辑return ResponseEntity.ok("用户更新成功");
}
注解:
-
通过定义接口实现校验分组,灵活控制不同场景下的校验规则
-
在 DTO 类中指定各字段所属的校验分组,实现条件校验
-
控制器方法通过指定校验分组,精确控制校验逻辑的触发场景
06 嵌套对象校验
处理复杂对象嵌套场景下的校验需求:
// 嵌套对象校验示例
public class Order {@NotBlank(message = "订单号不能为空")private String orderId;@DecimalMin(value = "0.01", message = "订单金额必须大于 0.01")private BigDecimal amount;// 嵌套 Customer 对象,启用深度校验@Validprivate Customer customer;
}public class Customer {@NotBlank(message = "客户名称不能为空")private String name;@Email(message = "邮箱格式不正确")private String email;// 嵌套 Address 对象,继续深度校验@Validprivate Address address;
}public class Address {@NotBlank(message = "地址不能为空")private String street;@NotBlank(message = "城市不能为空")private String city;
}
// 控制器方法应用嵌套校验
@PostMapping("/orders")
public ResponseEntity createOrder(@Valid @RequestBody Order order) {// 订单创建逻辑return ResponseEntity.ok("订单创建成功");
}
注解:
- 使用 @Valid 注解启用嵌套对象的深度校验,支持多层对象嵌套
- 校验规则沿用对象关系,自动继承父对象的校验上下文
- 全局异常处理器自动捕获嵌套校验错误,返回详细的错误路径信息
07 自定义校验注解开发
针对特殊业务场景开发自定义校验注解:
// 自定义注解定义
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface ValidPhoneNumber {String message() default "手机号格式不正确";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}// 自定义校验实现
public class PhoneValidator implements ConstraintValidator<ValidPhoneNumber, String> {private static final String PHONE_REGEX = "^1[3-9]\\d{9}$";@Overridepublic void initialize(ValidPhoneNumber constraintAnnotation) {// 初始化逻辑}@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {if (value == null || value.trim().isEmpty()) {return true; // 空值不校验}return Pattern.matches(PHONE_REGEX, value);}
}
// 自定义注解应用示例
public class ContactInfo {@ValidPhoneNumberprivate String phone;// Getter 和 Setter 方法
}
注解:
- 通过 @Constraint 注解指定校验器实现类,完成自定义校验注解开发
- 校验器实现类需继承 ConstraintValidator,重写 isValid 方法定义校验逻辑
- 自定义注解可应用于字段或参数,与内置注解使用方式一致