Springboot中如何优雅进行字段校验

文举
• 阅读 2566
差不多大半年没写文章了,终于将手头上的事忙完了,可以对外输出了。前段时间提交代码审核,同事提了一个代码规范缺陷:参数校验应该放在controller层。到底应该如何做参数校验呢

Controller层 VS Service层

去网上查阅了一些资料,一般推荐与业务无关的放在Controller层中进行校验,而与业务有关的放在Service层中进行校验。那么如何将参数校验写的优雅美观呢,如果都是if - else,就感觉代码写的很low,还好有轮子可以使用

常用校验工具类

使用Hibernate Validate

引入依赖

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>4.3.1.Final</version> 
</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框架中的注解是需要加在实体中一起使用的

  • 定义一个实体
public class DataSetSaveVO {
    //唯一标识符为空
    @NotBlank(message = "user uuid is empty")
    //用户名称只能是字母和数字
    @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;

    //数据集名称只能是字母和数字
    @Pattern(regexp = "^[A-Za-z0-9]+$", message = "data set names can only be letters and Numbers")
    //文件名称过长
    @Length(max = 48, message = "file name too long")
    //文件名称为空
    @NotBlank(message = "file name is empty")
    private String name;

    //数据集描述最多为256字节
    @Length(max = 256, message = "data set description length over 256 byte")
    //数据集描述为空
    @NotBlank(message = "data set description is null")
    private String description;
}

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

  • Controller层中的方法
@PostMapping
public ResponseVO createDataSet(@Valid @RequestBody DataSetSaveVO dataSetVO) {
    return ResponseUtil.success(dataSetService.saveDataSet(dataSetVO));
}

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

使用commons-lang3

引入依赖

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.4</version>
</dependency>

常用方法说明
|方法 | 说明 |
|:-| :-|
| CollectionUtils.isEmpty | 判断集合是否为空,为null或者size==0,返回true |
| CollectionUtils.isNotEmpty | 判断集合是否为非空 |
| StringUtils.isEmpty | 判断字符串是否为空 |
| StringUtils.isNotEmpty | 判断字符串是否非空 |
| StringUtils.isBlank | 判断字符串是否为空,为null或者size==0或者只存在空白字符(如" "),则返回true |
| StringUtils.isNotBlank | 判断字符串是否为非空 |

  • 测试代码
//StringUtils.isEmpty
System.out.println(StringUtils.isEmpty(""));  //true
System.out.println(StringUtils.isEmpty("  "));  //false
//StringUtils.isNotEmpty
System.out.println(StringUtils.isNotEmpty(""));  //false
        
//StringUtils.isBlank
System.out.println(StringUtils.isBlank(""));  //true
System.out.println(StringUtils.isBlank(" "));  //true
//StringUtils.isNotBlank
System.out.println(StringUtils.isNotBlank(" "));  //false

List<Integer> emptyList = new ArrayList<>();
List<Integer> nullList = null;
List<Integer> notEmptyList = new ArrayList<>();
notEmptyList.add(1);

//CollectionUtils.isEmpty
System.out.println(CollectionUtils.isEmpty(emptyList));   //true
System.out.println(CollectionUtils.isEmpty(nullList));   //true
System.out.println(CollectionUtils.isEmpty(notEmptyList));   //false

//CollectionUtils.isNotEmpty
System.out.println(CollectionUtils.isNotEmpty(emptyList));   //false
System.out.println(CollectionUtils.isNotEmpty(nullList));   //false
System.out.println(CollectionUtils.isNotEmpty(notEmptyList));   //true
自定义注解

当上面的方面都无法满足校验的需求以后,可以考虑使用自定义注解,如何写一个自定义注解,可以参考之前写的文章:Spring自定义注解从入门到精通

点赞
收藏
评论区
推荐文章
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Easter79 Easter79
4年前
SpringBoot如何优雅的校验参数
原文地址(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Flqcoder.com%2Fp%2F4cd8a59d.html)原文地址(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Flqcoder.com%2Fp%2
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
4年前
mysql中时间比较的实现
MySql中时间比较的实现unix\_timestamp()unix\_timestamp函数可以接受一个参数,也可以不使用参数。它的返回值是一个无符号的整数。不使用参数,它返回自1970年1月1日0时0分0秒到现在所经过的秒数,如果使用参数,参数的类型为时间类型或者时间类型的字符串表示,则是从1970010100:00:0
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
Java中的参数验证(非Spring版)
1\.Java中的参数验证(非Spring版)1.1.前言为什么我总遇到这种非正常问题,我们知道很多时候我们的参数校验都是放在controller层的传入参数进行校验,我们常用的校验方式就是引入下列的jar包,在参数中添加@Validated,并对Bean对象的参数做不
Stella981 Stella981
4年前
SpringBoot 如何优雅的进行参数校验
参数的合法性直接影响到程序的安全和性能,因此在进行相关操作前必须检测对象是否为null,是否为blank,是否被初始化等等。我们先来看看SpringBoot是如何来检验参数的。!(https://oscimg.oschina.net/oscnet/f7be43101103a164a62b8804a9de256bca1.jpg)!(htt
Stella981 Stella981
4年前
SpringBoot如何优雅的校验参数
原文地址(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Flqcoder.com%2Fp%2F4cd8a59d.html)原文地址(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Flqcoder.com%2Fp%2
SpringBoot如何优雅的进行参数校验(一)
SpringBoot如何优雅的进行参数校验一.为什么要进行参数校验在日常的开发过程中,我们常常需要对传入的参数进行校验,比如在web前后端分离项目中,参数校验有两个方面:前端进行参数校验后端进行参数校验那这两种有什么区别呢?只完成一个可不可以呢?答案是不可