新闻资讯
一文学会JSR-303 参数校验
早期的参数校验形式
在早期的时候,java的参数校验停留在获取参数之后在代码层面做校验,类似如下操作:
@PostMapping("/test") public String test(@RequestBody TestRequest request) { if (StringUtils.isEmpty(request.getName())) { return "姓名不能为空"; } if (request.getName().length() > 6) { return "姓名长度不能超过6"; } if (StringUtils.isEmpty(request.getPhone())) { return "电话不能为空"; } if (!isPhone(request.getPhone())) { return "电话号码格式不正确"; } return "SUCCESS"; } /** * 校验电话格式 */ private boolean isPhone(String phone) { return true; }
如代码中看到,每一种校验规则都需要在代码里面实现,那么光是参数校验也会耗费开发人员大量的精力,开发效率也会大幅降低。
JSR-303简介
java6里面推出了一种规范:JSR-303,JSR是Java Specification Requests的缩写,意思是Java 规范提案,又叫做Bean Validation。
JSR 303是Java为bean数据合法性校验提供的标准框架。Hibernate Validator是Bean Validation的参考实现。
JSR-303参数校验注解
Bean Validation中内置的注解
Hibernate Validator 附加的注解
使用JSR303规范来做参数校验
我们将上面那个没使用JSR303的代码做改造
@Data public class TestRequest { @NotEmpty(message = "姓名不能为空") @Length(min = 1, max = 6, message = "姓名长度必须在1-6之间") private String name; @NotBlank(message = "电话号码不能为空") @Pattern(regexp = "^134[0-8]\\d{7}$|^13[^4]\\d{8}$|^14[5-9]\\d{8}$|^15[^4]\\d{8}$|^16[6]\\d{8}$|^17[0-8]\\d{8}$|^18[\\d]{9}$|^19[8,9]\\d{8}$", message = "电话号码格式不正确") private String phone; @Email(message = "邮件格式不正确") private String email; @NotNull(message = "年龄不能为空") @Max(value = 18,message = "年龄不能超过18") private Integer age; }
用@Valid对controller校验
@PostMapping("/test") public String test(@RequestBody @Valid TestRequest request) { return "SUCCESS"; }
改造效果
@Valid与@Validated区别
首先看一下他们所属的包:
可以看到@Validated属于spring,而@Valid属于javax。
-
@Validated :org.springframework.validation.annotation.Validated
-
@Valid:javax.validation.Valid
但是在实际的基本使用中,这2者是没有区别的(注意这里说的是基本使用,也就是说,使用@Valid与@Validated是等价的)。
@Validated对controller校验
@PostMapping("/test") public String test(@RequestBody @Validated TestRequest request) { return "SUCCESS"; }
将注解替换一下,也能得到相同的结果:
两个注解源码
- @Valid
@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) @Documented public @interface Valid { }
- @Validated
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Validated { Class<?>[] value() default {}; }
通过源码可以看到@Validated可以在类上面使用,并且多了一个value属性。
@Validated提供了一个分组功能,在校验参数时,可以根据不同的分组采用不同的校验机制。没有添加分组属性时,默认验证没有分组的验证属性。
@Validated分组校验
编写校验分组标识:
public class ValidatedGroup { public interface Add extends Default {} public interface Delete extends Default {} public interface Update extends Default {} public interface Query extends Default {} }
测试请求类:
@Data public class TestSaveRequest { @NotNull(groups = {ValidatedGroup.Update.class, ValidatedGroup.Delete.class}, message = "更新或者删除时id不能为空") private Long id; @NotBlank(groups = {ValidatedGroup.Update.class}, message = "更新时姓名不能为空") private String name; @NotNull(groups = {ValidatedGroup.Add.class}, message = "新增时余额不能为空") @Digits(integer = 10, fraction = 2) private BigDecimal balance; @NotBlank(groups = {ValidatedGroup.Add.class}, message = "新增时电话不能为空") @Pattern(regexp = "^134[0-8]\\d{7}$|^13[^4]\\d{8}$|^14[5-9]\\d{8}$|^15[^4]\\d{8}$|^16[6]\\d{8}$|^17[0-8]\\d{8}$|^18[\\d]{9}$|^19[8,9]\\d{8}$", message = "电话号码格式不正确") private String phone; @NotBlank(groups = {ValidatedGroup.Add.class}, message = "新增时邮件不能为空") @Email private String email; }
根据我们编写的测试请求类型可预期:
-
校验分组为Add时,会校验balance、phone、email三个请求字段
-
校验分组为Update时,会校验id、name字段
测试如下:
@PostMapping("/testAdd") public String testAdd(@RequestBody @Validated(value = ValidatedGroup.Add.class) TestSaveRequest request) { return "SUCCESS"; } @PostMapping("/testUpdate") public String testUpdate(@RequestBody @Validated(value = ValidatedGroup.Update.class) TestSaveRequest request) { return "SUCCESS"; }
testAdd结果:
testUpdate结果:
结果与预期完全符合。@Validated注解在分组校验时候,可以节省很多额外的开发,特别是当新增和更新时。
一个需要传递主键一个不需要传递主键的情形,以前需要一个AddRequest、一个UpdateRequest,现在只有需要一个就够了。
嵌套校验
什么是嵌套校验呢?上代码:
@Data public class TestNestRequest { @NotNull(message = "id不能为空") private Long id; @NotNull(message = "嵌套对象请求数据不能为空") private ItemRequest itemRequest; }
@Data public class ItemRequest { @NotEmpty(message = "name不能为空") private String name; }
@PostMapping("/testNest") public String testNest(@RequestBody @Valid TestNestRequest request) { return "SUCCESS"; }
测试结果如下:
只校验了id,没有校验嵌套对象中的name属性。
如果需要校验嵌套对象中的属性,需要改造一下TestNestRequest类。
在itemRequest属性上加上@Valid注解,方能校验嵌套对象中的属性
改造如下:
@Data public class TestNestRequest { @NotNull(message = "id不能为空") private Long id; @Valid @NotNull(message = "嵌套对象请求数据不能为空") private ItemRequest itemRequest; }
测试结果:
本内容属于网络转载,文中涉及图片等内容如有侵权,请联系编辑删除
回复列表