Java SpringBoot 参数校验

校验应该在那一层

一般推荐与业务无关的放在Controller层中进行校验,而与业务有关的放在Service层中进行校验。那么如何将参数校验写的优雅美观呢?

常用校验工具类

使用Hibernate Validate

引入依赖

  1. <dependency>
  2. <groupId>org.hibernate</groupId>
  3. <artifactId>hibernate-validator</artifactId>
  4. <version>4.3.1.Final</version>
  5. </dependency>

常用注解说明

注解 说明
@Length(min=,max=) 检查所屋的字段的长度是否在min和max之间,只能用于字符串
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内
@Max 该字段的值只能小于或等于该值
@Min 该字段的值只能大于或等于该值
@NotNull 不能为null
@NotBlank 不能为空,检查时会将空格忽略
@NotEmpty 不能为空,这里的空是指空字符串
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式

使用方式

需要搭配在Controller中搭配@Validated@Valid注解一起使用,@Validated@Valid注解区别不是很大,一般情况下任选一个即可,区别如下:

注解 @Validated @Valid
所属的包 属于org.springframework.validation.annotation包下的,是Spring提供的 属于javax.validation包下,是jdk提供的
是否支持分组和排序

虽然@Validated@Valid更加强大,在@Valid之上提供了分组功能和验证排序功能,不过在实际项目中一直没有用到过
Hibernate-validate框架中的注解是需要加在实体中一起使用的

  • 定义一个实体

    1. public class DataSetSaveVO {
    2. //唯一标识符为空
    3. @NotBlank(message = "user uuid is empty")
    4. //用户名称只能是字母和数字
    5. @Pattern(regexp = "^[a-z0-9]+$", message = "user names can only be alphabetic and numeric")
    6. @Length(max = 48, message = "user uuid length over 48 byte")
    7. private String userUuid;
    8. //数据集名称只能是字母和数字
    9. @Pattern(regexp = "^[A-Za-z0-9]+$", message = "data set names can only be letters and Numbers")
    10. //文件名称过长
    11. @Length(max = 48, message = "file name too long")
    12. //文件名称为空
    13. @NotBlank(message = "file name is empty")
    14. private String name;
    15. //数据集描述最多为256字节
    16. @Length(max = 256, message = "data set description length over 256 byte")
    17. //数据集描述为空
    18. @NotBlank(message = "data set description is null")
    19. private String description;
    20. }

    说明:message字段为不符合校验规则时抛出的异常信息

  • Controller层中的方法

    1. @PostMapping
    2. public ResponseVO createDataSet(@Valid @RequestBody DataSetSaveVO dataSetVO) {
    3. return ResponseUtil.success(dataSetService.saveDataSet(dataSetVO));
    4. }

    说明:在校验的实体DataSetSaveVO旁边添加@Valid@Validated注解

    SpringBoot封装的Validated普通校验

    普通检验是基础用法,非常容易,首先需要在SpringBootWeb项目中添加数据校验相关的依赖:

    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-validation</artifactId>
    4. </dependency>

    查看LocalValidatorFactoryBean类的源码,发现默认的ValidationMessageSource(校验出错时的提示文件) 是resources目录下的ValidationMessages.properties 文件,因此在resources目录下创建ValidationMessages.properties文件,内容如下

    1. user.name.size=用户名长度介于510个字符之间
    2. user.address.notnull=用户地址不能为空
    3. user.age.size=年龄输入不正确
    4. user.email.notnull=邮箱不能为空
    5. user.email.pattern=邮箱格式不正确

    创建User类,配置数据校验

    1. public class User {
    2. private Integer id;
    3. @Size(min = 5, max = 10, message = "{user.name.size}")
    4. private String name;
    5. @NotNull(message = "{user.address.notnull}")
    6. private String address;
    7. @DecimalMin(value = "1", message = "{user.age.size}")
    8. @DecimalMax(value = "200", message = "{user.age.size}")
    9. private Integer age;
    10. @Email(message = "{user.email.pattern}")
    11. @NotNull(message = "{user.email.notnull}")
    12. private String email;
    13. //省略getter和setter
    14. }
  • @Size表示一个字符串的长度或者一个集合的大小,必须在某一个范围中;min参数表示范围的下限;max参数表示范围的上限;message表示校验失败时的提示信息。

  • @NotNull注解表示该字段不能为空
  • @DecimalMin注解表示对应属性值的下限
  • @DecimalMax注解表示对应属性值的上限
  • @Email注解表示对应属性格式是一个Email

创建UserController

  1. @RestController
  2. public class UserController {
  3. @PostMapping("/user")
  4. public List<String> addUser(@Validated User user, BindingResult result){
  5. List<String> errors = new ArrayList<>();
  6. if(result.hasErrors()){
  7. List<ObjectError> allErrors = result.getAllErrors();
  8. for(ObjectError error : allErrors){
  9. errors.add(error.getDefaultMessage());
  10. }
  11. }
  12. return errors;
  13. }
  14. }
  • 给User参数添加@Validated注解,表示需要对该参数做校验,紧接着的BindingResult参数表示在校验出错时保存的出错信息。
  • 如果BindingResult中的haiErrors方法返回true,表示有错误信息,此时遍历错误信息,将之返回给前端

    分组校验

    在实际开发中,可能对于不同的情况,需要做不同的校验,这时候分组校验就起作用了
    首先创建两个分组接口
    1. public interface ValidationGroup1 {
    2. }
    3. public interface ValidationGroup2 {
    4. }
    在实体类中添加分组信息
    1. public class User {
    2. private Integer id;
    3. //groups属性,表示该校验属性规则所属的分组
    4. @Size(min = 5, max = 10, message = "{user.name.size}", groups = ValidationGroup1.class)
    5. private String name;
    6. @NotNull(message = "{user.address.notnull}", groups = ValidationGroup2.class)
    7. private String address;
    8. @DecimalMin(value = "1", message = "{user.age.size}")
    9. @DecimalMax(value = "200", message = "{user.age.size}")
    10. private Integer age;
    11. @Email(message = "{user.email.pattern}")
    12. @NotNull(message = "{user.email.notnull}", groups = {ValidationGroup1.class, ValidationGroup2.class})
    13. private String email;
    14. }
    @Validated注解中指定校验分组
    1. @RestController
    2. public class UserController {
    3. //@Validated(ValidationGroup2.class) 表示这里的校验使用ValidationGroup2分组的校验规则,即只校验邮箱地址是否为空、用户地址是否为空
    4. @PostMapping("/user")
    5. public List<String> addUser(@Validated(ValidationGroup2.class) User user, BindingResult result){
    6. List<String> errors = new ArrayList<>();
    7. if(result.hasErrors()){
    8. List<ObjectError> allErrors = result.getAllErrors();
    9. for(ObjectError error : allErrors){
    10. errors.add(error.getDefaultMessage());
    11. }
    12. }
    13. return errors;
    14. }
    15. }

    自定义注解

    当上面的方面都无法满足校验的需求以后,可以考虑使用自定义注解。