Spring MVC Hibernate Validator
Hibernate Validator是JSR-303 Bean Validation的参考实现,Spring MVC默认集成了此校验框架。
常用校验注解
| 注解 | 说明 | 示例 |
|---|---|---|
| @NotNull | 不能为null | @NotNull private String name; |
| @NotEmpty | 不能为空(字符串、集合) | @NotEmpty private List<String> list; |
| @NotBlank | 不能为空白字符串 | @NotBlank private String name; |
| @Size | 长度范围 | @Size(min=2, max=10) private String name; |
| @Min | 最小值 | @Min(0) private int age; |
| @Max | 最大值 | @Max(150) private int age; |
| @Range | 数值范围 | @Range(min=0, max=100) private int score; |
| @Pattern | 正则匹配 | @Pattern(regexp="\\d+") private String phone; |
| 邮箱格式 | @Email private String email; | |
| @Length | 字符串长度 | @Length(min=6, max=20) private String pwd; |
基本使用
Java
@Data
public class UserDTO {
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度3-20个字符")
private String username;
@NotBlank(message = "密码不能为空")
@Length(min = 6, max = 20, message = "密码长度6-20个字符")
private String password;
@Email(message = "邮箱格式不正确")
private String email;
@Min(value = 0, message = "年龄不能小于0")
@Max(value = 150, message = "年龄不能超过150")
private Integer age;
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
}
Controller校验
Java
@RestController
@RequestMapping("/api/user")
public class UserController {
@PostMapping
public User create(@Valid @RequestBody UserDTO dto, BindingResult result) {
if (result.hasErrors()) {
throw new ValidationException(result.getAllErrors());
}
return userService.create(dto);
}
@PostMapping("/simple")
public User createSimple(@Valid @RequestBody UserDTO dto) {
// 校验失败会自动抛出MethodArgumentNotValidException
return userService.create(dto);
}
}
全局校验异常处理
Java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleValidation(
MethodArgumentNotValidException e) {
List<Map<String, String>> errors = e.getBindingResult()
.getFieldErrors()
.stream()
.map(error -> {
Map<String, String> err = new HashMap<>();
err.put("field", error.getField());
err.put("message", error.getDefaultMessage());
err.put("rejectedValue", String.valueOf(error.getRejectedValue()));
return err;
})
.collect(Collectors.toList());
Map<String, Object> response = new HashMap<>();
response.put("code", 400);
response.put("message", "参数校验失败");
response.put("errors", errors);
return ResponseEntity.badRequest().body(response);
}
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<Map<String, Object>> handleConstraintViolation(
ConstraintViolationException e) {
List<Map<String, String>> errors = e.getConstraintViolations()
.stream()
.map(violation -> {
Map<String, String> err = new HashMap<>();
err.put("property", violation.getPropertyPath().toString());
err.put("message", violation.getMessage());
return err;
})
.collect(Collectors.toList());
Map<String, Object> response = new HashMap<>();
response.put("code", 400);
response.put("message", "参数校验失败");
response.put("errors", errors);
return ResponseEntity.badRequest().body(response);
}
}
方法参数校验
Java
@RestController
@RequestMapping("/api")
@Validated
public class ApiController {
@GetMapping("/user/{id}")
public User getUser(
@PathVariable @Min(1) Long id) {
return userService.findById(id);
}
@GetMapping("/search")
public List<User> search(
@RequestParam @NotBlank String keyword,
@RequestParam @Min(1) @Max(100) Integer size) {
return userService.search(keyword, size);
}
}
嵌套对象校验
Java
@Data
public class OrderDTO {
@NotBlank(message = "订单号不能为空")
private String orderNo;
@Valid // 嵌套对象校验
@NotNull(message = "收货地址不能为空")
private AddressDTO address;
@Valid
@NotEmpty(message = "商品列表不能为空")
private List<ProductDTO> products;
}
@Data
public class AddressDTO {
@NotBlank(message = "省份不能为空")
private String province;
@NotBlank(message = "城市不能为空")
private String city;
@NotBlank(message = "详细地址不能为空")
private String detail;
}
集合校验
Java
@Data
public class BatchDTO {
@Valid
@NotEmpty(message = "列表不能为空")
@Size(max = 100, message = "最多100条数据")
private List<UserDTO> users;
}
自定义校验消息
properties
# ValidationMessages.properties
user.name.required=用户名不能为空
user.name.size=用户名长度必须在{min}和{max}之间
user.email.invalid=邮箱格式不正确
Java
@Data
public class UserDTO {
@NotBlank(message = "{user.name.required}")
@Size(min = 3, max = 20, message = "{user.name.size}")
private String username;
@Email(message = "{user.email.invalid}")
private String email;
}
手动校验
Java
@Service
public class UserService {
@Autowired
private Validator validator;
public void validate(UserDTO dto) {
Set<ConstraintViolation<UserDTO>> violations = validator.validate(dto);
if (!violations.isEmpty()) {
List<String> messages = violations.stream()
.map(ConstraintViolation::getMessage)
.collect(Collectors.toList());
throw new ValidationException(messages);
}
}
public void validateProperty(UserDTO dto, String propertyName) {
Set<ConstraintViolation<UserDTO>> violations =
validator.validateProperty(dto, propertyName);
if (!violations.isEmpty()) {
throw new ValidationException(violations.iterator().next().getMessage());
}
}
}
快速失败模式
Java
@Configuration
public class ValidatorConfig {
@Bean
public Validator validator() {
ValidatorFactory factory = Validation.byProvider(HibernateValidator.class)
.configure()
.failFast(true) // 遇到第一个错误立即返回
.buildValidatorFactory();
return factory.getValidator();
}
}
自定义校验注解
Java
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {
String message() default "手机号格式不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class PhoneValidator implements ConstraintValidator<Phone, String> {
private static final Pattern PHONE_PATTERN =
Pattern.compile("^1[3-9]\\d{9}$");
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null || value.isEmpty()) {
return true; // null由@NotBlank处理
}
return PHONE_PATTERN.matcher(value).matches();
}
}
要点总结
- Hibernate Validator实现JSR-303 Bean Validation规范
- @Valid触发对象校验,BindingResult获取错误信息
- 嵌套对象需加@Valid注解
- 方法参数校验需类上加@Validated
- 支持国际化消息配置
- 可自定义校验注解扩展校验规则
📝 发现内容有误?点击此处直接编辑