aop+注解实现对实体类的字段校验_快速上⼿:SpringBoot⾃
定义请求参数校验
作者:UncleChen
最近在⼯作中遇到写⼀些API,这些API的请求参数⾮常多,嵌套也⾮常复杂,如果参数的校验代码全部都⼿动去实现,写起来真的⾮常痛苦。正好Spring轮⼦⾥⾯有⼀个Validation,这⾥记录⼀下怎么使⽤,以及怎么⾃定义它的返回结果。
⼀、Bean Validation基本概念
Bean Validation是Java中的⼀项标准,它通过⼀些注解表达了对实体的限制规则。通过提出了⼀些API和扩展性的规范,这个规范是没有提供具体实现的,希望能够Constrain once, validate everywhere。现在它已经发展到了2.0,兼容Java8。
hibernate validation实现了Bean Validation标准,⾥⾯还增加了⼀些注解,在程序中引⼊它我们就可以直接使⽤。
Spring MVC也⽀持Bean Validation,它对hibernate validation进⾏了⼆次封装,添加了⾃动校验,并将
校验信息封装进了特定的BindingResult类中,在SpringBoot中我们可以添加implementation('org.springframework.boot:spring-boot-starter-validation')引⼊这个库,实现对bean的校验功能。
⼆、基本⽤法
在name属性上,添加@NotBlank和@Size(max=10)的注解,表⽰User对象的name属性不能为字符串且长度不能超过10个字符。
然后我们暂时不添加任何多余的代码,直接写⼀个UserController对外提供⼀个RESTful的GET接⼝,注意接⼝的参数⽤到了@Validated 注解。
启动SpringBoot程序,发⼀个测试请求看⼀下:
127.0.0.1:8080/validation/get?name=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 返回的结果是,注意此时的HTTP STATUS CODE = 400:
此时已经可以实现参数的校验了,但是返回的结果不太友好,下⾯看⼀下怎么定制返回的消息。在定制返回结果前,先看下⼀下内置的校验注解有哪些,在这⾥我不⼀个个去贴了,写代码的时候根据需要进⼊到源码⾥⾯去看即可。
早期Spring版本中,都是在Controller的⽅法中添加Errors/BindingResult参数,由Spring注⼊Errors/BindingResult对象,再在Controller中⼿写校验逻辑实现校验。新版本提供注解的⽅式(Controller上⾯bean加⼀个@Validated注解),将校验逻辑和Controller分离。
三、⾃定义校验
3.1 ⾃定义注解
validation框架显然除了⾃带的NotNull、NotBlank、Size等注解,实际业务上还会需要特定的校验规则。
假设我们有⼀个参数address,必须以Beijing开头,那我们可以定义⼀个注解和⼀个⾃定义的Validator。
然后在User.java中增加⼀个address属性,并给它加上上⾯这个⾃定义的注解,这⾥我们定义了⼀个可以传⼊start参数的注解,表⽰应该以什么开头。
@StartWithValidation(message = "Param 'address' must be start with 'Beijing'.", start = "Beijing")private String address;
除了定义可以作⽤于属性的注解外,其实还可以定义作⽤于class的注解(@Target({TYPE})),⽤于校验class的实例。
3.2 ⾃定义Validator
第⼀步,实现⼀个Validator。(这种⽅法不需要我们的bean⾥⾯有任何注解之类的东西)
第⼆步,修改Controller代码,注⼊上⾯的UserValidator实例,并给Controller的⽅法参数加上@Validated注解,即可完成和前⾯⾃定义注解⼀样的校验功能。
这个⽅法和⾃定义注解的区别在于不需要在Bean⾥⾯添加注解,并且可以更加灵活的把⼀个Bean⾥⾯所有的Field的校验代码都搬到⼀起,⽽不是每⼀个属性都去加注解,如果校验的属性⾮常多,且默认注解的能⼒⼜不够的话,这种⽅式也是不错的,可以避免⼤量的⾃定义注解。
3.3 以编程的⽅式校验(⼿动)
这种⽅式可以算是原始的Hibernate-Validation的⽅式。直接看代码,这⾥有⼀个⽐较不同的是,可以使⽤Hibernate-Validation的Fail fast mode。因为前⾯的⽅式,都将所有的参数都验证完了,再把错误
返回。有时我们希望遇到⼀个参数错误,就⽴即返回。
设置fast-fail为true可以达到这个⽬的。不过貌似不能再⽤@Validated注解⽅法参数了,⽽是要⽤ValidatorFactory创建Validator。
在实际开发中,不必每次都编写代码创建Validator,可以采⽤@Configuration的⽅式创建,然后再@Autowired注⼊到每个需要使⽤Validator的Controller当中。
3.4 定义分组校验
有的时候,我们会有两个不同的接⼝,但是会使⽤到同⼀个Bean来作为VO(意思是两个接⼝的URI不
同,但参数中都⽤到了同⼀个Bean)。⽽在不同的接⼝上,对Bean的校验需求可能不⼀样,⽐如接⼝2需要校验studentId,⽽接⼝1不需要。那么此时就可以⽤到校验注解的分组groups。
到这⾥,也可以带⼀嘴Valid和Validated注解的区别,其代码注释写着后者是对前者的⼀个扩展,⽀持了group分组的功能。
3.5 定制返回码和消息
第⼆节中定义了⼀个ServiceResponse,其实作为⼀个开放的API,不论⽤户传⼊任何参数,返回的结果都应该是预先定义好的格式,并且可以写明在接⼝⽂档中,即使发⽣了校验失败,应该返回⼀个包含错误码code(发⽣错误时⼀般⼤于0)和message字段。
{ "code": 51000, "message": "Param 'name' must be less than 10 characters."}
的结果,⽽HTTP STATUS CODE⼀直都是200。
为了实现这个⽬的,我们加⼀个全局异常处理⽅法。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论