4
使用 springboot 2.4.0,OpenJDK 11

背景

在使用 SpringBoot 实现 Controller 的 Request InDto 时,需要校验参数的取值、格式等

所以使用到 spring-boot-starter-validation 来实现校验。然后发现有 @Valid@Validated 两个 annotation。

以下介绍它们之间的区别和用法。

@Valid

所在 package

javax.validation

定义

Marks a property, method parameter or method return type for validation cascading.
Constraints defined on the object and its properties are be validated when the property, method parameter or method return type is validated.
This behavior is applied recursively.

它标记一个属性、方法参数或方法返回值需要级联地验证,这意味着每当使用它标记一个参数时,这个参数里面的各个属性都被验证

例子

Controller(@Valid)

@RestController
public class MembershipController{
    @PostMapping("/create-membership-remark")
    public MembershipRemarkOutDto createMembershipRemark(
        @RequestBody @Valid CreateMembershipRemarkInDto aCreateMembershipRemarkInDto) {
        return membershipFacade.createMembershipRemark(aCreateMembershipRemarkInDto);
    }
}

CreateMembershipRemarkInDto(不检查 CreateBarInDto bar)

public class CreateMembershipRemarkInDto {

    @NotBlank
    private String remark;

    @NotBlank
    private String fooStr;

    @NotNull    // 此处不加 @Valid 则不会检查 CreateBarInDto
    private CreateBarInDto bar;

    public static class CreateBarInDto {
        @NotBlank
        private String barStr;
    }
}

解释

在参数中使用 @Valid意味着 参数中的各个属性都会被校验(如 remark, uselessbar)

但是 bar 只会被校验它本身 @NotNull, 不会校验它的属性是否满足要求

CreateMembershipRemarkInDto(检查 CreateBarInDto bar)

如果需要检查 CreateBarInDto,则需要改为如下的形式:

public class CreateMembershipRemarkInDto {

    @NotBlank
    private String remark;

    @NotBlank
    private String fooStr;

    @NotNull
    @Valid  // 增加 @Valid 注解
    private CreateBarInDto bar;

    public static class CreateBarInDto {
        @NotBlank
        private String barStr;
    }
}

解释

此时 bar会被校验它的属性(如 barStr)是否满足要求

@Validated

所在 package

org.springframework.validation.annotation

定义

@Validated@Valid 的变体(variant)。
通过声明 InDto 中属性的 groups,再搭配使用 @Validated,就能决定哪些属性需要校验,哪些不需要校验

例子

Controller(@Validated)

@RestController
public class MembershipController{
    @PostMapping("/create-membership-remark")
    public MembershipRemarkOutDto createMembershipRemark(
        @RequestBody @Validated({Useful.class}) CreateMembershipRemarkInDto aCreateMembershipRemarkInDto) {
        return membershipFacade.createMembershipRemark(aCreateMembershipRemarkInDto);
    }
}

CreateMembershipRemark

public class CreateMembershipRemarkInDto {

    @NotBlank(groups = Useful.class)
    private String remark;

    @NotBlank(groups = Useless.class)
    private String fooStr;

    @NotNull(groups = Useless.class)
    @Valid
    private CreateBarInDto bar;

    @Getter
    public static class CreateBarInDto {

        @NotBlank
        private String barStr;
    }
}

Useful interface & Useless interface

public interface Useful {
}
public interface Useless {
}

声明两个空的interface:UsefulUseless,便于区分。
此时就只有声明为 Useful 的会被校验,而 Useless 则不会被校验。

参考文章

Differences in @Valid and @Validated Annotations in Spring
Deep understanding of the role of data validation @Valid (cascade validation)


依斯特
14 声望1 粉丝

忘记背后,努力面前