本文最后更新于 2025-05-29,文章内容可能已经过时。

1、spring-boot-starter-validation

spring-boot-starter-validation 是 Spring Boot 提供的一个依赖启动器,用于在项目中快速集成 Bean Validation(JSR-380) 功能。它基于 Hibernate Validator(Spring Boot 默认的验证实现),可以方便地对 Java Bean 的属性进行校验。

一、作用

spring-boot-starter-validation 主要用于:

  • 对控制器方法参数进行校验(常用于 REST API 接口中)
  • 验证实体类字段是否符合预期规则(如非空、长度、格式等)

二、常用注解(Validation Annotations)

注解说明
@NotNull不能为 null
@Null必须为 null
@NotBlank字符串不能为 null 或空白字符串(仅适用于字符串)
@NotEmpty不能为 null 或空(适用于字符串、集合、数组等)
@Size(min=, max=)长度或大小范围限制
@Min(value) / @Max(value)数值最小/最大值限制
@Email必须是合法邮箱地址
@Pattern(regexp="正则表达式")符合指定的正则表达式

三、使用步骤

1. 添加依赖

Maven:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Gradle:

implementation 'org.springframework.boot:spring-boot-starter-validation'

2. 在 DTO 或实体类上添加验证注解

public class UserDTO {

    @NotBlank(message = "姓名不能为空")
    private String name;

    @Email(message = "邮箱格式不正确")
    private String email;

    @Min(value = 18, message = "年龄不能小于18岁")
    private int age;

    // getter/setter
}

3. 在 Controller 中启用验证

在 controller 方法的参数前加上 @Valid 注解,并捕获异常:

@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping
    public ResponseEntity<String> createUser(@Valid @RequestBody UserDTO userDTO, BindingResult result) {
        if (result.hasErrors()) {
            return ResponseEntity.badRequest().body(result.getAllErrors().toString());
        }
        // 处理业务逻辑
        return ResponseEntity.ok("用户创建成功");
    }
}

4. 全局异常处理(可选)

使用 @ControllerAdvice 统一处理验证错误:

@ControllerAdvice
public class ValidationHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<String> handleValidationExceptions(MethodArgumentNotValidException ex) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(ex.getBindingResult().getAllErrors().toString());
    }
}

四、注意事项⚠️

  • @Valid 只能在 controller 层使用,不能直接用于 service。
  • 如果你需要嵌套对象验证,需要在内部对象字段上也加上 @Valid
  • @Validated 支持 AOP,在 service 层使用时需要配合 @Validated 和类级别注解。

五、总结

功能是否支持
JSR 380 标准验证
常用验证注解
控制器参数验证
自定义验证规则
嵌套对象验证
全局异常统一处理

2、@Valid和@Validated

在 Spring 框架中,@Valid@Validated 都用于数据校验(Validation),但它们的使用场景和功能有所不同。下面是它们的详细对比与使用说明:


一、基本区别

特性@Valid@Validated
来源javax.validation.Validorg.springframework.validation.annotation.Validated
是否支持分组校验❌ 不支持✅ 支持
是否支持类级别验证(Class-level validation)❌ 不支持✅ 支持
是否可以在非控制器层使用❌ 只能在 controller 层使用✅ 可以用在 service、component 等
是否基于 AOP 实现✅ 是 Spring AOP 的一部分

二、使用场景对比

1. @Valid

适用于 Controller 层参数校验,通常配合 @RequestBody 使用。

示例:

@PostMapping("/users")
public ResponseEntity<?> createUser(@Valid @RequestBody UserDTO userDTO, BindingResult result) {
    if (result.hasErrors()) {
        return ResponseEntity.badRequest().body(result.getAllErrors());
    }
    // 业务逻辑
}

⚠️ 注意:@Valid 不支持嵌套对象的自动验证,除非你在嵌套对象上也加上 @Valid


2. @Validated

适用于更广泛的场景,包括:

  • Controller 层
  • Service 层
  • Component 或 Configuration 类

并且支持:

  • 分组校验(Group Validation)
  • 类级别校验(如整个类满足某种规则)

示例(Service 层校验):

@Service
@Validated
public class UserService {

    public void validateUser(@Valid UserDTO userDTO) {
        // 如果不符合约束会抛出异常
    }
}

三、嵌套对象校验示例

假设你有如下结构:

public class UserDTO {
    @NotBlank
    private String name;

    @Valid
    private AddressDTO address;
}

public class AddressDTO {
    @NotBlank
    private String city;
}

在这种情况下,如果不加 @Validaddress 字段上,Spring 不会自动校验嵌套对象。


四、分组校验(Groups)

只有 @Validated 支持分组校验。

定义接口作为分组标记:

public interface GroupA {}
public interface GroupB {}

DTO 中指定分组:

public class UserDTO {

    @NotBlank(groups = GroupA.class)
    private String username;

    @Min(value = 18, groups = GroupB.class)
    private int age;

    // getter/setter
}

使用时指定分组:

@Validated
public interface UserService {
    void validateUser(@Validated(GroupA.class) UserDTO user);
}

五、全局异常处理

你可以通过统一的异常处理器来捕获验证错误:

@RestControllerAdvice
public class ValidationExceptionAdvice {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<String> handleValidationExceptions(MethodArgumentNotValidException ex) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(ex.getBindingResult().getAllErrors().toString());
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<String> handleConstraintViolationException(ConstraintViolationException ex) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(ex.getMessage());
    }
}

六、总结对比表

功能@Valid@Validated
JSR-380 标准
可用于 Controller 参数
可用于 Service 方法参数
支持分组校验
支持类级别验证
基于 AOP
嵌套对象验证❌(需手动加 @Valid✅(同理)

七、推荐使用方式

场景推荐注解
REST API 参数校验@Valid
Service/Component 方法参数校验@Validated
需要分组校验@Validated
需要类级别校验@Validated

如果你正在开发一个复杂的项目,并且希望实现统一的数据校验机制,建议优先使用 @Validated,它更强大、灵活,适合大型项目或模块化设计。

3、@Valid和@Validated如何结合使用?

@Valid@Validated 在 Spring 应用中可以结合使用,以发挥两者的优势。@Valid 主要用于触发单个对象的校验,而 @Validated 提供了更高级的功能,比如分组校验、AOP 支持等。下面是如何结合这两者的具体方法和示例。

一. 基本概念回顾

  • @Valid: 用于触发标准 JSR-303/JSR-380 规范下的数据校验。
  • @Validated: 是 Spring 提供的一个注解,它不仅支持 @Valid 的所有功能,还增加了对校验组(groups)的支持,并且可以在类级别上使用。

二. 结合使用的场景

通常情况下,你可能会在控制器层使用 @Valid 来校验传入的数据模型,并在服务层使用 @Validated 进行更复杂的校验逻辑,如基于分组的校验。

三. 示例代码

3.1 定义校验组

首先定义一些校验组,以便我们可以根据需要启用不同的校验规则。

public interface OnCreate {}
public interface OnUpdate {}

3.2 DTO 类与校验注解

接下来,在你的 DTO 类中应用这些校验规则,并指定它们属于哪个组。

public class UserDTO {

    @NotNull(groups = {OnCreate.class, OnUpdate.class})
    private Long id;

    @NotBlank(groups = OnCreate.class)
    private String name;

    // getters and setters
}

3.3 控制器层使用 @Valid

在控制器中,你可以直接使用 @Valid 或者 @Validated 加上特定的校验组来触发校验。

@RestController
@RequestMapping("/users")
@Validated
public class UserController {

    @PostMapping
    public ResponseEntity<String> createUser(@Validated(OnCreate.class) @RequestBody UserDTO userDTO) {
        // 处理业务逻辑
        return ResponseEntity.ok("User created successfully");
    }

    @PutMapping("/{id}")
    public ResponseEntity<String> updateUser(@PathVariable("id") Long id,
                                             @Validated(OnUpdate.class) @RequestBody UserDTO userDTO) {
        // 处理业务逻辑
        return ResponseEntity.ok("User updated successfully");
    }
}

注意:在这个例子中,我们在控制器的方法参数上使用了 @Validated 而不是 @Valid,这是因为我们希望利用其分组校验的功能。

3.4 服务层使用 @Validated

在服务层,如果需要进行额外的校验,可以将 @Validated 注解应用于服务类,并通过方法参数或类属性的方式调用校验逻辑。

@Service
@Validated
public class UserService {

    public void validateUser(@Validated(OnCreate.class) UserDTO userDTO) {
        // 可能会有一些额外的业务逻辑检查
    }
}

四. 总结

  • @Valid 更适合于简单的校验场景,尤其是在控制器层接收请求时。
  • @Validated 则提供了更多的灵活性,包括但不限于分组校验、类级别的校验以及更广泛的应用范围(如服务层)。

通过这种方式,你可以灵活地组合使用 @Valid@Validated,以满足不同的校验需求。