清茶书香

一杯清茶,一本书籍,一个下午。


  • 首页

  • 归档

  • 分类

  • 关于

  • 搜索
Redis JPA Solr SpringData SpringMVC localRepository local Mapper 事务 Mybatis JDBC AOP DI IOC 常用函数 触发器 存储过程 Promise Gateway SpringCloud vue-cli axios es6 webpack npm vue 个性化 zsh 终端 caffeine jvm缓存 guava cache validation Mapping MapStruct comment 小程序 建站 WeHalo config logback plugins database idea maven spring https http nginx password RabbitMQ 秒杀系统 Windows MySQL 数据备份 halo SpringBoot shell Linux ip Optional Stream Lambda k8s Docker 列编辑 vim MacOS 图片合成 Java 远程联调 nps 内网穿透

参数校验框架之spring-vaildation

发表于 2020-12-13 | 分类于 spring系列 | 0 | 阅读次数 340

安装使用

在springboot 2.3.x以前的版本中,spring-boot-start-web中会将其默认引入,之后的版本将其剔除,需要手动引入下面的依赖

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

可用的注解

常用来使用的注解包括以下这些:

javax包里的注解

也就是javax.validation.constraints包里的注解

  • @Vaild可以加在方法上、属性上、参数前、构造器上、变量类型前,表示这个地方需要校验

  • @NotNull加在方法、属性、参数、构造器、变量类型、注解上,校验必须不为null,支持任何类型

  • @NotBlank加在方法、属性、参数、构造器、变量类型、注解上,校验必须不为null或者空值,支持CharSequence类型

  • @NotEmpty加在方法、属性、参数、构造器、变量类型、注解上,校验必须不为空值,支持CharSequence,Collection,Map,Array类型

  • @Null加在方法、属性、参数、构造器、变量类型、注解上,校验必须为null,支持CharSequence,Collection,Map,Array类型

  • @Digits加在方法、属性、参数、构造器、变量类型、注解上,校验不为空,支持BigDecimal,BigInteger,CharSequence,byte, short, int, long以及它们的包装类

  • @Email加在方法、属性、参数、构造器、变量类型、注解上,校验必须不为null或者空值,支持CharSequence类型

  • @Future加在方法、属性、参数、构造器、变量类型、注解上,校验时间必须是未来时间,支持以下类型时间

    • java.util.Date
    • java.util.Calendar
    • java.time.Instant
    • java.time.LocalDate
    • java.time.LocalDateTime
    • java.time.LocalTime
    • java.time.MonthDay
    • java.time.OffsetDateTime
    • java.time.OffsetTime
    • java.time.Year
    • java.time.YearMonth
    • java.time.ZonedDateTime
    • java.time.chrono.HijrahDate
    • java.time.chrono.JapaneseDate
    • java.time.chrono.MinguoDate
    • java.time.chrono.ThaiBuddhistDate
  • @FutureOrPresent加在方法、属性、参数、构造器、变量类型、注解上,校验时间必须是未来时间或者现在,支持时间类型同@Future

  • @Past加在方法、属性、参数、构造器、变量类型、注解上,校验时间必须是过去时间,支持时间类型同@Future

  • @PastOrPresent加在方法、属性、参数、构造器、变量类型、注解上,校验时间必须是过去时间或者现在,支持时间类型同@Future

  • @Max加在方法、属性、参数、构造器、变量类型、注解上,校验必须为数字且最大为设置的值,支持类型同@Digits

  • @Min加在方法、属性、参数、构造器、变量类型、注解上,校验必须为数字且最小为设置的值,支持类型同@Digits

  • @Size加在方法、属性、参数、构造器、变量类型、注解上,校验元素大小必须在设置的最小值与最大值之间,包含边界值,至持CharSequence,Collection,Map,Array类型

  • @DecimalMax与@Max类似,值是一个符合BigDecimal规则的字符串

  • @DecimalMin与@Min类似,值是一个符合BigDecimal规则的字符串

  • @AssertTrue加在方法、属性、参数、构造器、变量类型、注解上,校验元素必须true,支持boolean和Boolean类型

  • @AssertFalse加在方法、属性、参数、构造器、变量类型、注解上,校验元素必须false,支持boolean和Boolean类型

  • @Negative加在方法、属性、参数、构造器、变量类型、注解上,校验数字必须是一个负数,不包含0,支持类型同@Digits

  • @NegativeOrZero加在方法、属性、参数、构造器、变量类型、注解上,校验数字必须是一个负数,包含0,支持类型同@Digits

  • @Positive加在方法、属性、参数、构造器、变量类型、注解上,校验数字必须是一个正数,不包含0,支持类型同@Digits

  • @PositiveOrZero加在方法、属性、参数、构造器、变量类型、注解上,校验数字必须是一个正数,包含0,支持类型同@Digits

  • @Pattern加在方法、属性、参数、构造器、变量类型、注解上,校验字符必须匹配设置的正则表达式,支持CharSequence类型

  • @List一个特殊的注解,可以用来与上述注解一起使用,用来为这个元素定义多组规则。

spring里的常用注解

  • @Validated同@Valid,不同的是@Validated支持分组,而@Valid不支持分组,相当于是@Valid的增强版

hibernate里的常用注解

  • @Length加在方法、属性、参数、构造器、变量类型、注解上,校验字符串的长度不能超过设置的值,支持String类型
  • @ISBN加在方法、属性、参数、构造器、变量类型、注解上,校验字符必须是一个标准的ISBN图书编号,支持CharSequence类型
  • @Range加在方法、属性、参数、构造器、变量类型、注解上,校验数字必须在设置的最小值与最大值之间,包含边界值,支持所有的数字类型
  • @URL加在方法、属性、参数、构造器、变量类型、注解上,校验字符串必须是一个URL,协议包含http,https,file,ftp,jar等java.net.URL支持的协议
  • @EAN加在方法、属性、参数、构造器、变量类型、注解上,校验字符必须是一个国际商品编码,支持CharSequence类型
  • CreditCardNumber加在方法、属性、参数、构造器、变量类型、注解上,校验字符串必须是一个信用卡号的格式

validation使用方式

参数绑定

@Slf4j
@RestController
public class DemoController {

    @RequestMapping("/test")
    public String test(@Validated Foo foo, BindingResult bindingResult) {
        if(bindingResult.hasErrors()){
            for (FieldError fieldError : bindingResult.getFieldErrors()) {
                String fieldName = fieldError == null ? "" : fieldError.getField();
                String defaultMessage = fieldError == null ? "" : fieldError.getDefaultMessage();
                String errorMsg = "[" + fieldName + "]" + defaultMessage;
                log.info("捕捉到参数校验异常: {}", errorMsg);
                //...
            }
            return "fail";
        }
        return "success";
    }
}

异常捕获

@Slf4j
@RestController
public class DemoController {

    @RequestMapping("/test")
    public String test(@Validated Foo foo) {
        // ...
        return "success";
    }
}
@Slf4j
@RestControllerAdvice
public class ExceptionHandle {
  
    /**
     * 处理validation框架中的{@link MethodArgumentNotValidException}异常
     * <p>该异常一般出在用{@code @RequestBody}注解标记的参数校验,在对象中的参数有问题是抛出</p>
     *
     * @param e {@link MethodArgumentNotValidException}
     * @return string
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public String doNoValidExceptionHandler(MethodArgumentNotValidException e) {
        // 默认捕获第一个不符合校验规则的错误信息
        return validationExceptionHandler(e.getBindingResult(), e.getMessage());
    }

    /**
     * 处理validation框架中的{@link ConstraintDeclarationException}异常
     * <p>该异常一般出在用{@code @RequestParam}注解标记的参数校验</p>
     *
     * @param e {@link ConstraintDeclarationException}
     * @return string
     */
    @ExceptionHandler(ConstraintDeclarationException.class)
    public String doNoValidExceptionHandler(ConstraintDeclarationException e) {
        String errorMsg = e.getMessage();
        log.info("捕捉到参数校验异常: [{}]", errorMsg, e);
        return errorMsg;
    }

    /**
     * 处理validation框架中的{@link BindException}异常
     * <p>该异常一般出在用{@code @RequestBody}注解标记的参数校验,在对象嵌套类型参数有问题时抛出</p>
     *
     * @param e {@link BindException}
     * @return string
     */
    @ExceptionHandler(BindException.class)
    public String doNoValidExceptionHandler(BindException e) {
        return validationExceptionHandler(e.getBindingResult(), e.getMessage());
    }

    /**
     * 处理validation框架的异常
     *
     * @param bindingResult {@link BindingResult} 异常绑定的对象信息
     * @param message       异常信息
     * @return string
     */
    private String validationExceptionHandler(BindingResult bindingResult, String message) {
        // 一般只捕获第一个不符合校验规则的错误信息即可,与配置的快速失败搭配更好
        // 错误字段对象
        FieldError fieldError = bindingResult.getFieldError();
        // 错误字段名
        String fieldName = fieldError == null ? "" : fieldError.getField();
        // 具体错误信息
        String defaultMessage = fieldError == null ? "" : fieldError.getDefaultMessage();
        String errorMsg = "[" + fieldName + "]" + defaultMessage;
        log.info("捕捉到参数校验异常: [{}]", message);
        return errorMsg;
    }
}

ConstraintDeclarationException类型异常出现的方式

@Slf4j
@Validated
@RestController
public class DemoController {

    @RequestMapping("/test")
    public String test(@RequestParam("foo") @NotBlank(message = "foo不可为空") String foo) {
        // ...
        return "success";
    }
}

这种校验方式会抛出ConstraintDeclarationException异常,并且如果使用校验结果绑定的方式,并不会获取到错误的信息,只能通过异常捕获的方式处理。而且还需要在类上加@Validated,如果不加这种简单参数校验将不会有任何作用。

配置快速失败

@Configuration
public class ValidatorConfiguration {
    @Bean
    public Validator validator() {
        ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                .configure()
                // 快速失败
                .failFast(true)
                .buildValidatorFactory();
        return validatorFactory.getValidator();
    }
}

分组校验

分组校验需要定义一个空接口,然后将这个接口设置到校验的graoups里和@Validate里即可。

public class Foo {
  	@NotNull(message="姓名不能为null", groups={Test.class})
  	@NotBlank(message="姓名不能为空字符串", groups={TestBlank.class})
		private String name;
  
  	public interface Test {}
  	public interface TestBlank {}
}
@Slf4j
@RestController
public class DemoController {

    @RequestMapping("/test")
    public String test(@Validated(Foo.Test.class) Foo foo) {
        // ...
        return "success";
    }

  	@RequestMapping("/test/blank")
    public String test(@Validated(Foo.TestBlank.class) Foo foo) {
        // ...
        return "success";
    }
}

嵌套校验

嵌套校验就是需要对一个对象里的对象属性进行嵌套校验,具体如下

public class Foo {
  	@NotNull(message="姓名不能为null", groups={Test.class})
  	@NotBlank(message="姓名不能为空字符串", groups={TestBlank.class})
		private String name;
  	
  	@Valid// 在需要嵌套校验的字段上加入@Valid或者@Vaildated
  	@NotNull(message="inner不可为null")
  	private InnerFoo inner;
  
  	public interface Test {}
  	public interface TestBlank {}
}


public class InnerFoo {
  	@NotBlank(message="手机号不能为空")
		private String mobile;
}
Bennett wechat
欢迎收藏我的微信小程序,方便查看更新的文章。
  • 本文作者: Bennett
  • 本文链接: https://hibennett.cn/archives/spring-vaildation
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# Java # SpringBoot # spring # validation
Mapstruct——类型转换神器
学习JVM缓存之GuavaCache
  • 文章目录
  • 站点概览
Bennett

Bennett

60 日志
28 分类
74 标签
RSS
Github E-mail Gitee QQ
Creative Commons
Links
  • MacWk
  • 知了
0%
© 2020 — 2023 hibennett.cn版权所有
由 Halo 强力驱动
|
主题 - NexT.Pisces v5.1.4

浙公网安备 33010802011246号

    |    浙ICP备2020040857号-1