JSR303参数校验与commons-lang3的常见验证

JSR303参数校验与commons-lang3的常见验证

一、JSR303参数校验

1.1、JSR303参数常用校验,使用的如下的包
 在springboot项目中, validation的两个包已经包含在spring-boot-starter-web里面(可自己点进去看),无须再引包,如果不是springboot项目需要引入validation校验的包

  <dependency>
             <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.5.RELEASE</version>
         </dependency
validation的包
  <!--jsr 303-->
      <dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>
        <!-- hibernate validator-->
 <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>7.0.1.Final</version>
</dependency>

使用方法:
①在实体类标注要限制的校验
在这里插入图片描述
例如:

    @Pattern(regexp = "^[a-z0-9]+$", message = "user names can only be alphabetic and numeric")
    @Length(max = 48, message = "user uuid length over 48 byte")
    private String userUuid;

②在控制层参数处要标志@valid
例如:

@PostMapping
public ResponseVO createDataSet(@Valid @RequestBody DataSetSaveVO dataSetVO) {
    return ResponseUtil.success(dataSetService.saveDataSet(dataSetVO));
}
1.2 JSR303 分组校验
1.2.1 写标志接口

这里写两个空接口(只要名字,接口无需内容,名字随意取,仅仅是个标志)

public interface UpdateGroup {
}
public interface AddGroup {
}
1.2.2 在实体类标记哪种情况执行哪种校验
@Data
public class UserEntity {
    @Length(max = 5,message = "名字太长",groups = {UpdateGroup.class})
    private String name;
    @Max(value = 45)
    private Integer age;
    private Double salary;
    @NotEmpty(groups = {UpdateGroup.class})
    @Max(value = 4,message = "address最大长度不能超过4",groups = {AddGroup.class})
    private String address;
    private Long phoneNumber;
    private String url;
}

这里以address字段为例,UpdateGroup标志校验@NotEmpty,而AddGroup标志校验@Max

1.2.3 在参数接收处指明要进行校验的类型
@PostMapping("/insertData")
@ApiOperation(value = "数据校验")
public R insertData(@Validated(value = UpdateGroup.class) @RequestBody UserEntity userEntity){
    return R.ok();
}

①这里@Validated(value = UpdateGroup.class)表示只校验有UpdateGroup标记的字段,其他标记类型或者没标记group的皆不执行校验,相反,当参数接收处只有@Valid没有标记分组,那么实体类只有没标记的注解才会生效,标记了分组的字段反而不生效(重点
②这里是@Validated与基础校验的@Valid不一致
③实体字段的group中可以标记多个接口类,即满足任一条件即可执行:例如

@Max(value = 4,message = "address最大长度不能超过4",groups = {AddGroup.class,UpdateGroup.class})
    private String address;
1.3 JSR303 自定义校验

有时候JSR303自带的校验方法不满足我们的校验规则,那么我们就自定义一个校验规则:
例如:我们想让某字段从 指定数据取值,例如这里的1,2

   @ListValue(vals = {1,2},message = "请选择指定值")
    private int phoneNumber;
1.3.1 写一个注解
@Documented
@Constraint(validatedBy = {ListValueConstraintValidator.class})
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ListValue {
    String message() default "{value not correct}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
    int[] vals() default{};
}

注意:①@Constraint(validatedBy = {ListValueConstraintValidator.class})代表本注解使用哪个校验器来校验参数,可以写多个校验器,用逗号隔开
String message() default "{value not correct}";是注解不写message时,默认的提示信息
Class<?>[] groups() default { };表示可以指定分组(参考1.2)
int[] vals() default{};就是注解上的指定值

1.3.2 写校验器
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
    private Set<Integer> set = new HashSet<>();
    /**
     * 初始化方法vals 是获取注解指定的可选值,例如vals = {1,2}
     * @param constraintAnnotation
     */
    @Override
    public void initialize(ListValue constraintAnnotation) {
        int[] vals = constraintAnnotation.vals();
        if(vals != null && vals.length>0){
            for(int val:vals){
                set.add(val);
            }
        }
    }
    /**
     * 校验参数是否满足条件
     * @param value 需要校验的值(即用户提交的值)
     * @param context
     * @return 校验满足条件返回true,否则返回false
     */
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        return set.contains(value);
    }
}
1.3.3 关联注解和校验器

@Constraint(validatedBy = {ListValueConstraintValidator.class})就是指定本注解使用的校验器,可以使用多个校验器

1.4 异常捕获

参数校验失败的异常是来自controller,来写一个全局异常捕获器

@Slf4j
@RestControllerAdvice(basePackages = "com.sinux.inhaite.idempotent.jsr303")
public class DesignExceptionControllerAdvice {
    /**
     * 捕获MethodArgumentNotValidException型异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleValidException(MethodArgumentNotValidException e) {
        log.error("数据校验出现问题{},异常类型:{}", e.getMessage(), e.getClass());
        BindingResult bindingResult =e.getBindingResult();
        Map<String,String> errorMap = new HashMap<>();
        bindingResult.getFieldErrors().forEach(item -> {
            errorMap.put(item.getField(),item.getDefaultMessage());
        });
        return R.error(400,"数据校验失败").put("data",errorMap);
    }
    /**
     * 通用异常捕获
     * @param throwable
     * @return
     */
    @ExceptionHandler(value = Throwable.class)
    public R handleException(Throwable throwable){
        log.error("错误:",throwable);
        return R.error(400,"系统异常:"+throwable.getMessage());
    }
}

说明:@RestControllerAdvice(basePackages = "com.sinux.inhaite.idempotent.jsr303")是指定本异常捕获类对哪个包生效

1.5 代码中间的校验

有时候对象的转换在service层中的代码,没法像controller层加@Valid注解来校验,在代码中间校验JSR303的办法:

①写一个校验器类

import commonutils.pingan.AssertUtil;
import commonutils.pingan.enums.ComErrorCode;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.text.MessageFormat;
import java.util.Set;
/**
 * 参数校验工具类
 */
@Component
public class ValidatorUtil {
    //校验器
    private static Validator validator;

    /**
     * 参数校验,如果校验失败则抛出异常
     * @param obj
     */
    public static void validate(Object obj){
        //执行检验
        Set<ConstraintViolation<Object>> validate = validator.validate(obj);
        //检验信息为空则表示检验通过,反之不通过并抛出异常
        validate.stream().forEach(constraint ->{
            boolean result = StringUtils.isBlank(constraint.getMessage());
            AssertUtil.assertTrue(result,
                    ComErrorCode.PARAM_VALID_ERROR.getCode(),
                    MessageFormat.format(ComErrorCode.PARAM_VALID_ERROR.getMessage(),constraint.getPropertyPath().toString(),constraint.getMessage()));
        });
    }
    @Autowired
    public void setValidator(Validator validator){
        ValidatorUtil.validator=validator;
    }
}

②代码中调用

ValidatorUtil.validate(要校验的对象);

这样就能在代码中间使用JSR303校验数据

1.6 @Valid和@Validated的区别

在这里插入图片描述

二、commons-lang3参数校验

2.1 引入包
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.4</version>
</dependency>

校验方法汇总:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神雕大侠mu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值