SpringBoot使用@Vaild数据验证及自定义验证注解

SpringBoot使用@Vaild数据验证及自定义验证注解

常用注解

@NotNull:不能为null,但可以为empty
@NotEmpty:不能为null,而且长度必须大于0,用于集合
@NotBlank: 不能为null,而且不为空字符串 用于String

@AssertTrue //用于boolean字段,该字段只能为true
@AssertFalse//该字段的值只能为false
@CreditCardNumber//对信用卡号进行一个大致的验证
@DecimalMax//只能小于或等于该值
@DecimalMin//只能大于或等于该值
@Digits(integer=2,fraction=20)//检查是否是一种数字的整数、分数,小数位数的数字。
@Email//检查是否是一个有效的email地址
@Future//检查该字段的日期是否是属于将来的日期
@Length(min=,max=)//检查所属的字段的长度是否在min和max之间,只能用于字符串
@Max//该字段的值只能小于或等于该值
@Min//该字段的值只能大于或等于该值
@NotNull//不能为null
@NotBlank//不能为空,检查时会将空格忽略
@NotEmpty//不能为空,这里的空是指空字符串
@Null//检查该字段为空
@Past//检查该字段的日期是在过去
@Size(min=, max=)//检查该字段的size是否在min和max之间,可以是字符串、数组、集合、Map等
@URL(protocol=,host,port)//检查是否是一个有效的URL,如果提供了protocol,host等,则该URL还需满足提供的条件
@Valid//该注解只要用于字段为一个包含其他对象的集合或map或数组的字段,或该字段直接为一个其他对象的引用,//这样在检查当前对象的同时也会检查该字段所引用的对象

首先导入依赖

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

第一种方式(@Validated+校验注解)

需要在Controller类头部添加@Validated注解,不加注解不会错误信息,这种方法不用手动抛出异常,不过这种方式感觉应用场景不是很多,毕竟我们接收数据大多都是使用dto封装的

	/**
     * 使用注解校验get请求平面参数,需要在Controller类头部添加@Validated注解,否则不能成功校验,这种方法不用手动抛出异常
     *
     * @param username
     * @return	
     */
    @GetMapping("/testGetByValidated")
    public ResponseResult testGetByValidated(@Length(max = 4) @RequestParam("username") String username) {
        return new ResponseResult(ResultEnum.SUCCESS);
    }

第二种方式(@Vaild+全局异常处理器+校验注解)最常用

post方法传入单个对象进行校验,在参数前添加@Valid注解,校验失败时会抛出异常并使用全局异常进行处理

	/**
     * post方法传入单个对象进行校验,在参数前添加@Valid注解,校验失败时会抛出异常并使用全局异常进行处理
     *
     * @param userInfo 用户信息
     * @return ResponseResult
     */
    @PostMapping("/testUserInfo")
    public ResponseResult testUserInfo(@Valid @RequestBody UserInfo userInfo) {
        return new ResponseResult(ResultEnum.SUCCESS);
    }
    @Data
    public class UserInfo {
        @NotBlank(message = "年龄不为空")
        @Max(value = 18, message = "不能超过18岁")
        private String age;

        @NotBlank(message = "性别不能为空")
        private String gender;
    }

其中为了避免多次请求后错误信息不一致(注:年龄不为空和不能超过18岁随机出现),可以用以下配置

    @Configuration
    public class ValidationConfig {

        @Bean
        public Validator validator(final AutowireCapableBeanFactory autowireCapableBeanFactory) {
            ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                    .configure()
                    .constraintValidatorFactory(new SpringConstraintValidatorFactory(autowireCapableBeanFactory))
                    //设置有一个错误就直接返回
                    .failFast(true)
                    .buildValidatorFactory();
            return validatorFactory.getValidator();
        }
    }

第三种方式(工具类手动校验)

post方法传入对象,手动校验,此时参数前没有添加@Valid注解,所以不会自动进行校验,手动调用validate方法进行校验,失败时会抛出异常

	/**
     * post方法传入对象,手动校验,此时参数前没有添加@Valid注解,所以不会自动进行校验,手动调用validate方法进行校验,失败时会抛出异常
     *
     * @param userInfo
     * @return ResponseResult
     */
    @PostMapping("/checkByMethod")
    public ResponseResult checkByMethod(@RequestBody UserInfo userInfo) {
        //调用api校验
        MyValidationUtils.validate(userInfo);
        return new ResponseResult(ResultEnum.SUCCESS);
    }


    /**
     * 手动调用api方法校验对象
     */
    public class MyValidationUtils {
        public static void validate(@Valid Object user) {
            Set<ConstraintViolation<@Valid Object>> validateSet = Validation.buildDefaultValidatorFactory()
                    .getValidator()
                    .validate(user, new Class[0]);
            if (!CollectionUtils.isEmpty(validateSet)) {
                String messages = validateSet.stream()
                        .map(ConstraintViolation::getMessage)
                        .reduce((m1, m2) -> m1 + ";" + m2)
                        .orElse("参数输入有误!");
                //抛出异常进入到异常处理器中
                throw new IllegalArgumentException(messages);

            }
        }
    }

第四种方式(校验集合+@Vaild+@Validated)

post方法传入多个对象,当使用@Valid校验对象集合时,要在控制层添加@Validated注解,否则不会对集合中的每个对象进行校验

 	/**
     * post方法传入多个对象,当使用@Valid校验对象集合时,要在控制层添加@Validated注解,否则不会对集合中的每个对象进行校验
     *
     * @param userInfo
     * @return ResponseResult
     */
    @PostMapping("/testUserList")
    public ResponseResult testUserList(@Valid @RequestBody List<UserInfo> userInfo) {
        return new ResponseResult(ResultEnum.SUCCESS);
    }

第五种方式(BindingResult+异常处理器)

将校验结果放进BindingResult里面,用户自行判断并处理

	/**
     * 将校验结果放进BindingResult里面,用户自行判断并处理
     *
     * @param userInfo
     * @param bindingResult
     * @return
     */
    @PostMapping("/testBindingResult")
    public String testBindingResult(@RequestBody @Valid UserInfo userInfo, BindingResult bindingResult) {
        // 参数校验
        if (bindingResult.hasErrors()) {
            String messages = bindingResult.getAllErrors()
                    .stream()
                    .map(ObjectError::getDefaultMessage)
                    .reduce((m1, m2) -> m1 + ";" + m2)
                    .orElse("参数输入有误!");
            //这里可以抛出自定义异常,或者进行其他操作
            throw new IllegalArgumentException(messages);
        }
        return "操作成功!";
    }

自定义校验注解

随着业务不断壮大,基本的注解已不能满足需求,这时候我们需要自定义一些校验注解,例如需要身份证号校验


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

    String message() default "身份证号码不合法";

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

    Class<? extends Payload>[] payload() default {};
		
    class IdentityCardNumberValidator implements ConstraintValidator<IdentityCardNumber, Object> {

        @Override
        public boolean isValid(Object value, ConstraintValidatorContext context) {
            return IdCardValidatorUtils.isValidatedAllIdcard(value.toString());
        }
    }
}

    @Data
    public class UserInfo {
        @NotBlank(message = "年龄不为空")
        @Max(value = 18, message = "不能超过18岁")
        private String age;

        @NotBlank(message = "性别不能为空")
        private String gender;

        @NotBlank(message = "身份证号不能为空")
        @IdentityCardNumber
        private String idCard;
    }

image.png
右边附有源码,有兴趣的小伙伴可以下载下来看看custom-annotation.zip

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值