在 springboot 中基于 @Validated、@Valid 对接口参数进行校验
背景目前司内系统的技术架构正在逐步切换到微服务(SpringCloud),而微服务相互之间是通过 Feign 进行通信的,就一个微服务来说由两个部分组成:接口,例如:annoroad-alpha-facade,这里只提供接口的定义实现接口的服务,例如:annoroad-alpha,这里是对接口的实现(spring boot)目前,对于微服务接口上参数的校验要不就是不进行任何校验,要不...
背景
目前司内系统的技术架构正在逐步切换到微服务(SpringCloud),而微服务相互之间是通过 Feign 进行通信的,就一个微服务来说由两个部分组成:
- 接口,例如:annoroad-alpha-facade,这里只提供接口的定义
- 实现接口的服务,例如:annoroad-alpha,这里是对接口的实现(spring boot)
目前,对于微服务接口上参数的校验要不就是不进行任何校验,要不就是通过硬编码到代码里的校验逻辑来实现,这两种方式都不理想。 spring-boot-starter-validation 很好的解决了这些问题,通过在接口的参数上加上对应的注解(例如:@NotNull 等等),就可以很优雅的完成对参数的校验,完美~~~~
配置使用
如何在微服务(一个 spring boot 项目)中使用 spring-boot-starter-validation 呢?下面,我们就一起来看下需要进行怎么样的配置:
-
在负责接口定义的项目(anoroad-alpha-facade)中的 pom.xml 文件增加 spring-boot-starter-validation 依赖,如下:
<dependencies> ... <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> <version>2.1.1.RELEASE</version> </dependency> ... </dependencies>
-
还是在负责接口定义的项目(anoroad-alpha-facade)中,对需要进行参数校验的接口上增加相关注解,如下:
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import javax.validation.constraints.Min; import javax.validation.constraints.NotEmpty; import java.util.List; @FeignClient(value = "annoroad-alpha", url = "${annoroad.ms.annoroad-alpha.url}") @Validated public interface UserFacade { @PostMapping(value = "/user/hello") UserDto hello(@RequestParam("name") @NotEmpty String name); @PostMapping(value = "/user/detail") UserDto detail(@RequestParam("id") @Min(1) long id); @PostMapping("/user/add") UserDto add(@RequestBody @Validated UserDto userDTO); @PostMapping("/param/list") void testParamList(@RequestBody @Valid List<UserDto> userList); }
在这段儿代码片段中列举出来的 4 个接口,展示了 3 种不同的使用场景
-
对 @RequestParam 注解修饰的参数(name、id)进行校验
对于这样的情形,要想让注解生效,除了在参数上加注解以外,例如:@NotEmpty、@Min,同时还需要在类上增加 @Validated 注解
注:这里把 @Validated 注解放在方法上或者是方法参数前都是可以的,@Validated 注解统一放在类上边省去了一个一个方法上或者入参上添加该注解,如果如下:在方法上加 @Validated 注解:
在方法参数前加 @Validated 注解:
-
对 @RequestBody 注解修饰的对象(UserDto)进行校验
对于这样的情形,首选需要在接口定义那里对参数(UserDto)加上 @Validated 注解
同时还需要在 UserDto 中那些要校验的属性上增加注解,例如:@NotEmpty、@Min
注:这里需要注意的是 @Validated 注解如果放在类或者放在方法参数前,UserDto 中的校验是无法生效,必须在参数前加 @Validated 注解 -
对 @RequestBody 注解修饰的 List(List<UserDto> ) 对象进行校验
该情形与上边介绍的第二种情形,主要是在接口定义那里的注解有区别,第二种情形使用的是 @Validated 注解,而这里需要使用 @Valid 注解(如果使用 @Validated 注解,则 List 中的 UserDto 里的注解(@NotEmpty、@Min 等等)将全都失效!!!! )
-
嵌套验证的问题
上述的3种场景中没有涉及到嵌套验证,那什么是嵌套验证呢?简单的来说,就是一个需要验证的对象里嵌套了另外一个需要验证的对象,代码如下:
此时,我们在 UserFacade 的 add 方法的入参(UserDto)上使用 @Validated,就能对 UserDt o内嵌的 GroupDto 的参数进行验证了,代码如下:
总结
通过以上相关配置,只是基本的实现了参数校验。目前还没有对错误信息进行统一处理的需求,所以这里也就没有再进行更多的扩展开发了。但是,这里还是需要再明确一个问题,以上介绍的 3 个场景对应的错误返回格式是不相同的,主要分为两种:
-
对于场景【1】、场景【3】,会抛出 javax.validation.ConstraintViolationException 异常,如下:
场景【1】:
javax.validation.ConstraintViolationException: hello.arg0: must not be
empty场景【3】:
javax.validation.ConstraintViolationException:
testParamList.arg0[1].loginName: must not be empty,
testParamList.arg0[0].loginName: must not be empty -
对于场景【2】,Response Status 将返回 400(Bad Request)
附上一些常用的校验注解
限制 | 说明 |
---|---|
@Null | 限制只能为null |
@NotNull | 限制必须不为null |
@AssertFalse | 限制必须为false |
@AssertTrue | 限制必须为true |
@DecimalMax(value) | 限制必须为一个不大于指定值的数字 |
@DecimalMin(value) | 限制必须为一个不小于指定值的数字 |
@Digits(integer,fraction) | 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction |
@Future | 限制必须是一个将来的日期 |
@Max(value) | 限制必须为一个不大于指定值的数字 |
@Min(value) | 限制必须为一个不小于指定值的数字 |
@Pattern(value) | 限制必须符合指定的正则表达式 |
@Size(max,min) | 限制字符长度必须在min到max之间 |
@Past | 验证注解的元素值(日期类型)比当前时间早,即必须是一个过去的日期 |
@NotEmpty | 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0) |
@NotBlank | 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格 |
验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式 |
更多推荐
所有评论(0)