关于 javax.validation.constraints的详细说明

以下是关于 javax.validation.constraints(现为 ​Jakarta Bean Validation)的详细说明,涵盖核心注解、使用场景、代码示例及最佳实践:


一、javax.validation.constraints 是什么?

  • 作用:提供一组标准注解,用于对 Java Bean 的字段或方法参数进行数据校验(如非空、长度、范围等)。
  • 规范演进
    • Java EE 时期:包名为 javax.validation.constraints
    • Jakarta EE 9+:包名迁移为 jakarta.validation.constraints(需注意依赖兼容性)。

二、核心注解列表及用法

1. 常用注解
注解 校验规则 支持类型
@NotNull 值不能为 null 任意类型
@NotBlank 字符串不能为空或纯空格 String
@NotEmpty 集合/数组/字符串不能为空(长度 > 0) Collection, String
@Size(min, max) 元素数量或字符串长度在指定范围内 集合、数组、字符串
@Min(value) 数值必须 ≥ 指定最小值 数值类型(int, long 等)
@Max(value) 数值必须 ≤ 指定最大值 同上
@DecimalMin(value) 数值必须 ≥ 指定最小值(字符串形式,支持精度) BigDecimal, String
@DecimalMax(value) 数值必须 ≤ 指定最大值(字符串形式,支持精度) 同上
@Digits(integer, fraction) 数值整数部分最多 integer 位,小数部分最多 fraction 数值类型
@Pattern(regexp) 字符串必须匹配正则表达式 String
@Email 字符串必须是合法邮箱格式 String
@Positive / @PositiveOrZero 数值必须为正数或零 数值类型
@Negative / @NegativeOrZero 数值必须为负数或零 数值类型
@Future / @FutureOrPresent 日期必须在未来(或包含当前) Date, LocalDate
@Past / @PastOrPresent 日期必须在过去(或包含当前) 同上
2. 注解示例代码
复制代码
public class User {
    @NotBlank(message = "用户名不能为空")
    private String username;

    @Email(message = "邮箱格式无效")
    private String email;

    @Size(min = 6, max = 20, message = "密码长度需在6-20位之间")
    private String password;

    @Min(value = 18, message = "年龄必须≥18岁")
    @Max(value = 100, message = "年龄必须≤100岁")
    private Integer age;

    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式无效")
    private String phone;
}

三、集成到 Spring Boot 中的步骤

1. 添加依赖
复制代码
<!-- Spring Boot 2.x 使用 javax.validation -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

<!-- Jakarta EE 9+ 使用 jakarta.validation -->
<dependency>
    <groupId>jakarta.validation</groupId>
    <artifactId>jakarta.validation-api</artifactId>
    <version>3.0.2</version>
</dependency>
2. 在 Controller 中触发校验

使用 @Valid@Validated 注解触发校验:

复制代码
@PostMapping("/users")
public ResponseEntity<?> createUser(@RequestBody @Valid User user) {
    // 校验通过后执行业务逻辑
    return ResponseEntity.ok("用户创建成功");
}
3. 处理校验异常

通过 @ExceptionHandler 捕获 MethodArgumentNotValidException

复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, String>> handleValidationException(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getAllErrors().forEach(error -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });
        return ResponseEntity.badRequest().body(errors);
    }
}

四、高级用法

1. 分组校验

通过分组接口实现不同场景下的差异化校验:

复制代码
// 定义分组接口
public interface CreateGroup {}
public interface UpdateGroup {}

public class User {
    @NotNull(groups = UpdateGroup.class)
    private Long id;

    @NotBlank(groups = {CreateGroup.class, UpdateGroup.class})
    private String name;
}

// 在 Controller 中指定分组
@PostMapping("/users")
public ResponseEntity<?> createUser(@RequestBody @Validated(CreateGroup.class) User user) { ... }
2. 自定义校验注解

实现自定义校验逻辑(如密码强度校验):

复制代码
@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = PasswordValidator.class)
public @interface StrongPassword {
    String message() default "密码必须包含大小写字母和数字";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class PasswordValidator implements ConstraintValidator<StrongPassword, String> {
    @Override
    public boolean isValid(String password, ConstraintValidatorContext context) {
        return password.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$");
    }
}
3. 级联校验

校验对象内的嵌套对象:

复制代码
public class Order {
    @Valid
    private List<@Valid Product> products; // 校验每个 Product 的字段
}

五、校验失败的错误消息定制

1. 默认消息模板

每个注解的 message 属性支持占位符:

复制代码
@Size(min = 6, max = 20, message = "密码长度需在{min}-{max}位之间")
private String password;
2. 国际化消息

messages.propertiesValidationMessages.properties 中定义:

复制代码
user.email.invalid=邮箱格式无效

注解中使用:

复制代码
@Email(message = "{user.email.invalid}")
private String email;

六、常见问题与解决方案

问题 解决方案
校验未生效 检查是否添加了 @Valid@Validated 注解;确认依赖已正确引入
嵌套对象校验失败 在嵌套对象字段上添加 @Valid 注解
分组校验不生效 @Validated 注解中明确指定分组接口
自定义校验器未触发 确认 @Constraint(validatedBy = MyValidator.class) 并实现 ConstraintValidator

七、总结

  • 核心价值:通过声明式注解简化数据校验逻辑,减少样板代码。
  • 最佳实践
    • 优先使用标准注解,避免重复造轮子。
    • 结合分组校验实现多场景复用。
    • 统一处理校验异常,返回清晰的错误信息。
  • 扩展性:通过自定义注解和校验器满足复杂业务需求。
相关推荐
我来整一篇23 分钟前
用Redis的List实现消息队列
数据库·redis·list
加什么瓦43 分钟前
Redis——数据结构
数据库·redis·缓存
神仙别闹44 分钟前
基于C#+SQL Server开发(WinForm)租房管理系统
数据库·oracle·c#
528301 小时前
MySQL主从复制
数据库·mysql
qq_12498707531 小时前
原生小程序+springboot+vue医院医患纠纷管理系统的设计与开发(程序+论文+讲解+安装+售后)
java·数据库·spring boot·后端·小程序·毕业设计
jie188945758661 小时前
ubuntu----100,常用命令2
数据库·ubuntu
若兰幽竹2 小时前
【HBase整合Hive】HBase-1.4.8整合Hive-2.3.3过程
数据库·hive·hbase
lybugproducer2 小时前
浅谈 Redis 数据类型
java·数据库·redis·后端·链表·缓存
青山是哪个青山2 小时前
Redis 常见数据类型
数据库·redis·bootstrap
廖圣平2 小时前
美团核销 第三方接口供应商 (含接口文档)
开发语言·数据库·php