GroupSequenceProvider动态校验入参;@Validated和@Valid的区别;自定义校验注解;控制注解校验顺序

您所在的位置:网站首页 动画短片纸人 GroupSequenceProvider动态校验入参;@Validated和@Valid的区别;自定义校验注解;控制注解校验顺序

GroupSequenceProvider动态校验入参;@Validated和@Valid的区别;自定义校验注解;控制注解校验顺序

2024-06-16 06:18| 来源: 网络整理| 查看: 265

需求场景

平时在controller的入参校验中大多都是单个参数校验 一般都是直接用javax的注解 + javax.validation.Valid注解一把梭。

不过也有场景是需要动态校验。 假设入参的年龄和地区相关。 上海地区的年龄范围需要在10-20 浙江地区的年龄范围需要在10-30

这个时候要么就是直接硬编码了,但是前人肯定遇到过这种问题。

org.hibernate.validator.group.GroupSequenceProvider注解就能帮我们稍微实现的漂亮一点。

如果当前项目中没有对应依赖的话先引入依赖

org.hibernate.validator hibernate-validator 6.2.0.Final 代码Demo

自定义编码实现动态校验

package com.xxx.xxx.valid.group; /** * 根据动态条件来决定是否判断 NotNull */ public interface NotNullByConditionGroup { } package com.xxx.xxx.xxx; import com.xxx.xxx.valid.group.NotNullByConditionGroup; import com.xxx.xxx.valid.ProductAccessoriesSkuQueryProvider; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.hibernate.validator.group.GroupSequenceProvider; import javax.validation.constraints.NotNull; import java.io.Serializable; @GroupSequenceProvider(ProductAccessoriesSkuQueryProvider.class) @Data public class ProductAccessoriesSkuQueryListDTO implements Serializable { private static final long serialVersionUID = 8297881653432975830L; @ApiModelProperty(value = "产品id") @NotNull(message = "产品id不能为空", groups = NotNullByConditionGroup.class) private Long productId; @ApiModelProperty(value = "颜色id,详情见数据字典 color") @NotNull(message = "颜色id不能为空", groups = NotNullByConditionGroup.class) private Long colorId; @ApiModelProperty(value = "尺寸id,详情见数据字典 sales_size") @NotNull(message = "尺寸id不能为空", groups = NotNullByConditionGroup.class) private Long sizeId; @ApiModelProperty(value = "产品skuId") private Long productSkuId; } package com.xxx.xxx.valid; import com.xxx.xxx.xxx.ProductAccessoriesSkuQueryListDTO; import com.xxx.xxx.xxx.group.NotNullByConditionGroup; import org.hibernate.validator.spi.group.DefaultGroupSequenceProvider; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * 校验当 productSkuId 不存在的时候 sizeId + productId + colorId 不能为空 */ public class ProductAccessoriesSkuQueryProvider implements DefaultGroupSequenceProvider { @Override public List getValidationGroups(ProductAccessoriesSkuQueryListDTO bean) { List defaultGroupSequence = new ArrayList(); defaultGroupSequence.add(ProductAccessoriesSkuQueryListDTO.class); // 这一步不能省,否则Default分组都不会执行了,会抛错的 if(Objects.nonNull(bean)){ Long productSkuId = bean.getProductSkuId(); if(Objects.isNull(productSkuId)){ defaultGroupSequence.add(NotNullByConditionGroup.class); } } return defaultGroupSequence; } } @PostMapping("queryList") public CommonResult queryList(@RequestBody @Validated ProductAccessoriesSkuQueryListDTO queryList){ return CommonResult.success(); } @Validated指定分组校验 public class ValidatedGroup { public interface CREATE{} public interface DELET{} public interface UPDATE{} public interface QUERY{} } import lombok.Data; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; @Data public class ValidatedVO { //更新、删除时不能为空 @NotNull(message = "id不能为空", groups = {ValidatedGroup.UPDATE.class, ValidatedGroup.DELET.class}) private Long id; //新增、更新时不能为空 @NotBlank(message = "name不能为空", groups = {ValidatedGroup.CREATE.class ,ValidatedGroup.UPDATE.class}) private String name; //查询时不能为空 @NotBlank(message = "queryParam不能为空", groups = {ValidatedGroup.QUERY.class}) private String queryParam; } public ValidatedVO bindValidate(@RequestBody @Validated(value= {ValidatedGroup.DELET.class}) ValidatedVO validatedVO/*, BindingResult result*/) { return validatedVO; } @Validated和@Valid的区别

在校验的时候会发现有2个很类似的注解,@Valid和@Validated 首先这两个的包都是不同的 javax.validation.Valid org.springframework.validation.annotation.Validated

其次 @Valid:标准JSR-303规范的标记型注解,用来标记验证属性和方法返回值,进行级联和递归校验 @Valid可以用在属性级别约束,用来表示级联校验。 @Valid可用于方法、字段、构造器和参数上

@Validated:Spring的注解,是标准JSR-303的一个变种(补充),提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制。上面提到的分组校验就是利用了其分组功能 @Validated注解可以用于类级别,用于支持Spring进行方法级别的参数校验。 @Validated只能用在类、方法和参数上;

自定义校验注解

定义一个校验注解

package com.xx.xx.xx; import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE}) @Retention(RetentionPolicy.RUNTIME) @Documented //这里指向的是我们自定义的校验规则,可以治党多个不同校验器,适配不同的情况 @Constraint(validatedBy = {DataCheckVaildator.class}) public @interface DataCheck { //当然这里的message也可以去属性文件中指定 String message() default "请提交规范数据"; Class[] groups() default {}; Class[] payload() default {}; //用来获取注解属性值 int[] vals() default {}; }

在定义个注解校验器

需要声明校验的注解和被校验的数据类型

package com.xxx.xxx.xxx; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.util.HashSet; import java.util.Objects; import java.util.Set; public class DataCheckVaildator implements ConstraintValidator { private Set setNum = new HashSet(); @Override public void initialize(DataCheck constraintAnnotation) { int[] vals = constraintAnnotation.vals(); for (int val : vals) { setNum.add(val); } } @Override public boolean isValid(Long value, ConstraintValidatorContext context) { if(Objects.isNull(value)){ return true; } return setNum.contains(value); } }

使用

@ApiModelProperty(value = "产品skuId") @DataCheck(vals = {1,2,3}, message = "产品skuId不符") private Long productSkuId; //这里使用spring的org.springframework.validation.annotation.Validated //和jsr的javax.validation.Valid //都可以 @PostMapping("queryList") public CommonResult queryList(@RequestBody @Validated ProductAccessoriesSkuQueryListDTO queryList){ return CommonResult.success(); } 控制注解校验顺序

有些时候需要在前一个校验通过后再校验,这个时候就需要控制一下校验顺序了

可以使用javax.validation.GroupSequence来定义顺序,然后声明这个顺序接口class就行了

上代码demo

定义校验顺序

package com.xxx.xxx.xxx.xxx; import javax.validation.GroupSequence; import javax.validation.groups.Default; /** * 定义校验顺序 */ @GroupSequence({Default.class, TaxPriceCalculateValidOrderGroup.TaxPriceCalculateGroup.class}) public interface TaxPriceCalculateValidOrderGroup { interface TaxPriceCalculateGroup {}; }

使用分组

public CommonResult edit(@RequestBody @Validated(value = TaxPriceCalculateValidOrderGroup.class) ProductDTO productDTO){ xxxx

在目标类上使用注解

@TaxPriceCalculate(message = "含税价-不含税价与比例不符", groups = TaxPriceCalculateValidOrderGroup.TaxPriceCalculateGroup.class) public class SkuSupplierBaseInfoDTO { xxx


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3