在 Spring Boot 中,Jakarta Validation(原 Hibernate Validator)用于数据验证,主要通过一组 注解 来约束 Java Bean 的字段。Spring Boot 默认集成了 Jakarta Validation,并提供了 Spring Validation 的支持,使其能与 @Valid 或 @Validated 结合使用。
-
常见 Jakarta Validation 注解
Jakarta Validation 提供了一些常见的 约束注解,主要分为:
- 通用约束(字符串、数字等)
- 集合约束(List、Map)
- 对象级约束(级联验证)
| 注解 | 作用 | 示例 |
|---|---|---|
| @NotNull | 不能为空 | @NotNull private String name; |
| @NotBlank | 不能为空,且不能是空白字符(仅字符串) | @NotBlank private String username; |
| @NotEmpty | 不能为空,适用于集合、字符串 | @NotEmpty private List items; |
| @Size(min, max) | 字符串或集合长度范围 | @Size(min = 3, max = 10) private String name; |
| @Pattern(regexp) | 必须符合正则表达式 | @Pattern(regexp = "^[a-zA-Z0-9]+$") private String code; |
| 必须是合法的邮箱格式 | @Email private String email; | |
| @Min(value) | 最小值约束(数字) | @Min(18) private int age; |
| @Max(value) | 最大值约束(数字) | @Max(100) private int age; |
| @Positive | 必须为正数 | @Positive private int count; |
| @Negative | 必须为负数 | @Negative private int loss; |
| @PositiveOrZero | 必须是正数或 0 | @PositiveOrZero private int balance; |
| @NegativeOrZero | 必须是负数或 0 | @NegativeOrZero private int debt; |
| @Future | 必须是未来的日期 | @Future private LocalDateTime eventTime; |
| @FutureOrPresent | 必须是未来或当前日期 | @FutureOrPresent private LocalDate startDate; |
| @Past | 必须是过去的日期 | @Past private LocalDate birthday; |
| @PastOrPresent | 必须是过去或当前日期 | @PastOrPresent private LocalDate lastModified; |
- 进阶验证
(1) 级联验证 ( @Valid )
如果一个类包含另一个 对象类型 的字段,并且该对象也有验证注解,必须使用 @Valid 才能触发子对象的验证。
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
@Data
class Address {
@NotBlank
private String city;
}
@Data
class User {
@NotBlank
private String name;
@Valid // 触发 Address 内的验证
private Address address;
}
(2) 自定义校验
如果内置注解无法满足需求,可以自定义注解:
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.lang.annotation.*;
@Documented
@Constraint(validatedBy = MyConstraintValidator.class)
@Target({ ElementType.FIELD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyConstraint {
String message() default "不符合自定义规则";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
然后实现 ConstraintValidator:
public class MyConstraintValidator implements ConstraintValidator<MyConstraint, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value != null && value.startsWith("ABC");
}
}
使用:
@MyConstraint
private String customField;
-
在 Spring Boot 中使用
(1) Controller 层参数校验
使用 @Valid 或 @Validated 进行参数验证:
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/users")
public class UserController {
@PostMapping
public String createUser(@Valid @RequestBody User user) {
return "User created: " + user.getName();
}
}
@Data
class User {
@NotBlank(message = "用户名不能为空")
private String name;
}
(2) 处理验证异常
Spring Boot 会自动抛出 MethodArgumentNotValidException,可以自定义全局异常处理:
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 Map<String, String> handleValidationException(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage()));
return errors;
}
}
- 结论
- Jakarta Validation 提供了一组标准的数据约束注解,适用于
String、Number、Date等数据类型。 - 在 Spring Boot 中,可以通过
@Valid和@Validated结合使用这些注解。 - 级联验证需要
@Valid,否则不会对子对象进行校验。 - 可以自定义校验规则,满足特殊业务需求。
- 可以使用全局异常处理来返回更友好的错误信息。
这样就能更好地在 Spring Boot 项目中使用 Jakarta Validation 进行数据校验了!🚀