@Valid注解的作用及其与@Validated的区别

1.@Valid注解

用于验证注解是否符合要求,直接加在变量user之前,在变量中添加验证信息的要求,当不符合要求时就会在方法中返回message 的错误提示信息。

@ApiOperation(value = "Shipping receive completion request from shiphub frontend or app client like OMS", tags = {"Completion APIs"})
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "OK"),
            @ApiResponse(code = 401, message = "You are not authorized to access to this API"),
            @ApiResponse(code = 403, message = "Accessing the resource you were trying to reach is forbidden"),
            @ApiResponse(code = 404, message = "The resource you were trying to reach is not found")
    })
    @PostMapping(value = "/completion", produces = {"application/json"}, consumes = {"application/json"})
    public ResponseEntity<ApiResponseDto> actionCompletionShippingOrder(
            @ApiParam(value = "request body", required = true) @RequestBody @Valid CompletionOrderRequestDto completionOrderRequestDto, 
            BindingResult bindingResult) throws Exception {

        ApiResponseDto apiResponseDto = shippingCompletionService.requestActionToOrder(bindingResult, completionOrderRequestDto);
        if (!AppClientResponse.GENERAL_SUCC.getStatus().equals(apiResponseDto.getStatus())) {
            return new ResponseEntity<>(apiResponseDto, HttpStatus.BAD_REQUEST);
        }
        return new ResponseEntity<>(apiResponseDto, HttpStatus.OK);
    }

然后在 CompletionOrderRequestDto 类中添加验证信息的要求:

public class CompletionOrderRequestDto implements Serializable, IShiphubRequestDto {

  private static final long serialVersionUID = -6593240841146979248L;

  @JsonProperty("client_name")
  @ICheckAppClientName
  private String clientName;

  @JsonProperty("ship_group_id")
  @NotBlank(message = "shipGroupId不能为空")
  private String shipGroupId;
}

@NotBlank 注解所指的 password 字段,表示验证密码不能为空,如果为空的话,上面 Controller 中的 create 方法会将message 中的"密码不能为空"返回。

当然也可以添加其他验证信息的要求:

限制说明
@Null限制只能为null
@NotNull限制必须不为null
@AssertFalse限制必须为false
@AssertTrue限制必须为true
@DecimalMax(value)限制必须为一个不大于指定值的数字
@DecimalMin(value)限制必须为一个不小于指定值的数字
@Digits(integer,fraction)限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future限制必须是一个将来的日期
@Max(value)限制必须为一个不大于指定值的数字
@Min(value)限制必须为一个不小于指定值的数字
@Past限制必须是一个过去的日期
@Pattern(value)限制必须符合指定的正则表达式
@Size(max,min)限制字符长度必须在min到max之间
@Past验证注解的元素值(日期类型)比当前时间早
@NotEmpty验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

除此之外还可以自定义验证信息的要求,例如上面的 @ICheckAppClientName:

注解的具体内容:

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {CheckActionNameCompletionOrderValidator.class})
public @interface ICheckActionNameCompletionOrder {

    String message() default "1102";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

 这是校验器:

public class CheckActionNameCompletionOrderValidator implements ConstraintValidator<ICheckActionNameCompletionOrder, String> {

    private static final Logger logger = LoggerFactory.getLogger(CheckActionNameCompletionOrderValidator.class);

    @Value("#{'${Action.completionName}'.split(',')}")
    private List<String> actionCompletionOrderList;

    @Override
    public boolean isValid(String actionName, ConstraintValidatorContext context) {

        logger.info("Action completion order name validator: enter action name is { {} }", actionName);
        return actionName != null && actionCompletionOrderList.stream().anyMatch(x -> actionName.toLowerCase().equals(x.toLowerCase()));
    }
}

2.@Valid与@Validated的区别

  • @Valid是使用Hibernate validation的时候使用
  • @Validated是只用Spring Validator校验机制使用

说明:java的JSR303声明了@Valid这类接口,而Hibernate-validator对其进行了实现

@Validation对@Valid进行了二次封装,在使用上并没有区别,但在分组、注解位置、嵌套验证等功能上有所不同,这里主要就这几种情况进行说明。

注解位置:

@Validated:用在类型、方法和方法参数上。但不能用于成员属性(field)

@Valid:可以用在方法、构造函数、方法参数和成员属性(field)上

如:

 

如果@Validated注解在成员属性上,则会报  '@Validdated' not applicable to field 错误:

 

分组校验:

@Validated:提供分组功能,可以在参数验证时,根据不同的分组采用不同的验证机制

@Valid:没有分组功能

举例:

定义分组接口:

public interface IGroupA {
}
 
public interface IGroupB {
}

定义需要检验的参数bean:

public class StudentBean implements Serializable{
    @NotBlank(message = "用户名不能为空")
    private String name;
    //只在分组为IGroupB的情况下进行验证
    @Min(value = 18, message = "年龄不能小于18岁", groups = {IGroupB.class})
    private Integer age;
    @Pattern(regexp = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$", message = "手机号格式错误")
    private String phoneNum;
    @Email(message = "邮箱格式错误")
    private String email;
    @MyConstraint
    private String className;

测试代码:

检验分组为IGroupA的情况

@RestController
public class CheckController {
    @PostMapping("stu")
    public String addStu(@Validated({IGroupA.class}) @RequestBody StudentBean studentBean){
        return "add student success";
    }
}

这里对分组IGroupB的就没检验了

如果把测试代码改成下面这样,就会检验B了

@RestController
public class CheckController {
    @PostMapping("stu")
    public String addStu(@Validated({IGroupA.class, IGroupB.class}) @RequestBody StudentBean studentBean){
        return "add student success";
    }
}

 说明:

1、不分 配groups,默认每次都要进行验证

2、对一个参数需要多种验证方式时,也可通过分配不同的组达到目的。

组序列:

默认情况下 不同级别的约束验证是无序的,但是在一些情况下,顺序验证却是很重要。

一个组可以定义为其他组的序列,使用它进行验证的时候必须符合该序列规定的顺序。在使用组序列验证的时候,如果序列前边的组验证失败,则后面的组将不再给予验证。

举例:

定义组序列:

@GroupSequence({Default.class, IGroupA.class, IGroupB.class})
public interface IGroup {
}

需要校验的Bean,分别定义IGroupA对age进行校验,IGroupB对className进行校验: 

public class StudentBean implements Serializable{
    @NotBlank(message = "用户名不能为空")
    private String name;
    @Min(value = 18, message = "年龄不能小于18岁", groups = IGroupA.class)
    private Integer age;
    @Pattern(regexp = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$", message = "手机号格式错误")
    private String phoneNum;
    @Email(message = "邮箱格式错误")
    private String email;
    @MyConstraint(groups = IGroupB.class)
    private String className;

测试代码:

@RestController
public class CheckController {
    @PostMapping("stu")
    public String addStu(@Validated({IGroup.class}) @RequestBody StudentBean studentBean){
        return "add student success";
    }
}

测试发现,如果age出错,那么对组序列在IGroupA后的IGroupB不进行校验,即例子中的className不进行校验,结果如下:

嵌套校验:

一个待验证的pojo类,其中还包含了待验证的对象,需要在待验证对象上注解@Valid,才能验证待验证对象中的成员属性,这里不能使用@Validated。

举例:

需要约束校验的bean:

public class TeacherBean {
    @NotEmpty(message = "老师姓名不能为空")
    private String teacherName;
    @Min(value = 1, message = "学科类型从1开始计算")
    private int type;
public class StudentBean implements Serializable{
    @NotBlank(message = "用户名不能为空")
    private String name;
    @Min(value = 18, message = "年龄不能小于18岁")
    private Integer age;
    @Pattern(regexp = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$", message = "手机号格式错误")
    private String phoneNum;
    @Email(message = "邮箱格式错误")
    private String email;
    @MyConstraint
    private String className;
 
    @NotNull(message = "任课老师不能为空")
    @Size(min = 1, message = "至少有一个老师")
    private List<TeacherBean> teacherBeans;

注意:

这里对teacherBeans只校验了NotNull, 和 Size,并没有对teacher信息里面的字段进行校验,具体测试如下: 

这里teacher中的type明显是不符合约束要求的,但是能检测通过,是因为在student中并没有做 嵌套校验

可以在teacherBeans中加上 @Valid,具体如下:

    @Valid
    @NotNull(message = "任课老师不能为空")
    @Size(min = 1, message = "至少有一个老师")
    private List<TeacherBean> teacherBeans;

 

这里再来测试,会发现如下结果: 

### 回答1: @Valid注解和@Validated注解都是用于校验数据的注解,但是它们的使用场景略有不同。 @Valid注解是JSR-303规范中定义的注解,用于校验JavaBean中的属性值是否符合规范。它可以用在方法参数、方法返回值、方法参数中的属性、方法返回值中的属性等位置上。在Spring Boot中,我们可以在Controller中使用@Valid注解校验请求参数是否符合规范。 @Validated注解是Spring框架中提供的注解,它可以用于校验方法参数是否符合规范。它支持分组校验,可以根据不同的场景对参数进行不同的校验。在Spring Boot中,我们可以在Service层或者Controller中使用@Validated注解校验方法参数是否符合规范。 总的来说,@Valid注解用于校验JavaBean中的属性值,而@Validated注解用于校验方法参数。两者都可以用于校验数据,但是使用场景略有不同。 ### 回答2: @Valid注解和@Validated注解都用于校验数据的有效性,但是它们有所不同。 @Valid注解是来自于javax.validation规范中的注解,是用于Bean Validation校验的,它可以用于校验Java Bean对象中的字段。@Valid注解只能加在某个目标类型参数上,并且该参数类型需要是一个对象,它可以递归验证对象中的所有字段和对象。 @Validated注解则是Spring框架提供的注解,是用于Spring校验的,它可以用于校验方法和参数。@Validated注解用于验证参数和返回值,通常放在接口方法上。@Validated注解描述的约束条件必须是JSR303支持的约束条件的JavaBean,而@Valid注解不支持约束条件。 总的来说,@Valid注解是制定了JSR303规范而来的,属于Bean Validation更多的是参数校验,而@Validated注解是Spring框架专门提供的注解,用于控制层的校验,其作用与@Valid注解类似,但更加灵活,能进行更多的分组约束、级联验证等。 ### 回答3: @Valid注解和@Validated注解Java中用于数据校验的两个注解。它们都是基于Bean Validation规范的,提供了对Java Bean属性进行校验的功能。 @Valid注解用于进行简单的数据校验,它可以在Controller层的方法参数中对参数进行校验。它的作用是告诉Spring框架对该参数进行数据校验,如果校验失败,则会抛出ConstraintViolationException异常。该注解使用时需要配合bindingResult参数一起使用,bindingResult参数用于接收校验结果。 @Validated注解更加强大,除了提供了@Valid注解的功能外,它还可以在Service层和Dao层对方法参数进行校验。它支持Spring Expression Language(SpEL)表达式,并提供了基于分组校验的功能。基于分组校验可以根据不同的校验场景,对同一个实体进行不同的校验,增强了数据校验的灵活性。 除了以上的差异,还有一个重要区别:@Valid注解是标准的Java注解,而@Validated注解是Spring提供的注解。因此,如果项目中只使用了Spring框架,那么可以直接使用@Validated注解。但如果使用的是标准的Java环境,则需要使用@Valid注解
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值