Quick Start: SpringBoot custom verification request parameter

Recently encountered in the work write API, the API request parameters is very large, very complex nested, check if the code of all parameters manually to achieve, to write really painful. Spring is just a wheel inside Validation, recorded here about how to use and how to customize it returns the result.

A, Bean Validation basic concepts

Bean Validation is a standard Java, it notes expressed by a number of restrictions on the rules of the entity. By proposing a number of API specifications and scalability, this specification is not provided concrete realization of the hope Constrain once, validate everywhere. Now it has grown to 2.0, compatible Java8.

hibernate validation to achieve the Bean Validation standard, which also added a few comments, we introduced it in the program can be used directly.

Spring MVC also supports Bean Validation, it was the second package hibernate validation, add automatic calibration and verification information is encapsulated into the specific BindingResult class, we can add in SpringBoot implementation ( 'org.springframework. boot: spring-boot-starter-validation ') introduced into the library, to achieve the checking function of the bean.

Second, the basic usage

gradle dependencies如下:

Quick Start: SpringBoot custom verification request parameter


An example of the definition of Bean, e.g. User.java below.

Quick Start: SpringBoot custom verification request parameter


In the name attribute, and adding @NotBlank @Size (max = 10) of annotation indicating User name attribute object can not be a string and a length of no more than 10 characters.

Then we do not add any extra code to write directly to a Foreign UserController provide a RESTful GET interface Note interface parameters used in the @Validated comment.

Quick Start: SpringBoot custom verification request parameter


Start SpringBoot program, send a request to look at the test:

http://127.0.0.1:8080/validation/get?name=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

返回的结果是,注意此时的HTTP STATUS CODE = 400:

Quick Start: SpringBoot custom verification request parameter


此时已经可以实现参数的校验了,但是返回的结果不太友好,下面看一下怎么定制返回的消息。在定制返回结果前,先看下一下内置的校验注解有哪些,在这里我不一个个去贴了,写代码的时候根据需要进入到源码里面去看即可。

Quick Start: SpringBoot custom verification request parameter


早期Spring版本中,都是在Controller的方法中添加Errors/BindingResult参数,由Spring注入Errors/BindingResult对象,再在Controller中手写校验逻辑实现校验。新版本提供注解的方式(Controller上面bean加一个@Validated注解),将校验逻辑和Controller分离。

三、自定义校验

3.1 自定义注解

显然除了自带的NotNull、NotBlank、Size等注解,实际业务上还会需要特定的校验规则。

假设我们有一个参数address,必须以Beijing开头,那我们可以定义一个注解和一个自定义的Validator。

Quick Start: SpringBoot custom verification request parameter


然后在User.java中增加一个address属性,并给它加上上面这个自定义的注解,这里我们定义了一个可以传入start参数的注解,表示应该以什么开头。

Quick Start: SpringBoot custom verification request parameter


除了定义可以作用于属性的注解外,其实还可以定义作用于class的注解(@Target({TYPE})),用于校验class的实例。

3.2 自定义Validator

第一步,实现一个Validator。(这种方法不需要我们的bean里面有任何注解之类的东西)

Quick Start: SpringBoot custom verification request parameter


第二步,修改Controller代码,注入上面的UserValidator实例,并给Controller的方法参数加上@Validated注解,即可完成和前面自定义注解一样的校验功能。

Quick Start: SpringBoot custom verification request parameter


这个方法和自定义注解的区别在于不需要在Bean里面添加注解,并且可以更加灵活的把一个Bean里面所有的Field的校验代码都搬到一起,而不是每一个属性都去加注解,如果校验的属性非常多,且默认注解的能力又不够的话,这种方式也是不错的,可以避免大量的自定义注解。

3.3 以编程的方式校验(手动)

这种方式可以算是原始的Hibernate-Validation的方式。直接看代码,这里有一个比较不同的是,可以使用Hibernate-Validation的Fail fast mode。因为前面的方式,都将所有的参数都验证完了,再把错误返回。有时我们希望遇到一个参数错误,就立即返回。

设置fast-fail为true可以达到这个目的。不过貌似不能再用@Validated注解方法参数了,而是要用ValidatorFactory创建Validator。

在实际开发中,不必每次都编写代码创建Validator,可以采用@Configuration的方式创建,然后再@Autowired注入到每个需要使用Validator的Controller当中。

Quick Start: SpringBoot custom verification request parameter


3.4 定义分组校验

有的时候,我们会有两个不同的接口,但是会使用到同一个Bean来作为VO(意思是两个接口的URI不同,但参数中都用到了同一个Bean)。而在不同的接口上,对Bean的校验需求可能不一样,比如接口2需要校验studentId,而接口1不需要。那么此时就可以用到校验注解的分组groups。

Quick Start: SpringBoot custom verification request parameter


到这里,也可以带一嘴Valid和Validated注解的区别,其代码注释写着后者是对前者的一个扩展,支持了group分组的功能。

3.5 定制返回码和消息

第二节中定义了一个ServiceResponse,其实作为一个开放的API,不论用户传入任何参数,返回的结果都应该是预先定义好的格式,并且可以写明在接口文档中,即使发生了校验失败,应该返回一个包含错误码code(发生错误时一般大于0)和message字段。

Quick Start: SpringBoot custom verification request parameter


的结果,而HTTP STATUS CODE一直都是200。

为了实现这个目的,我们加一个全局异常处理方法。

Quick Start: SpringBoot custom verification request parameter


在上面的方法中,我们处理了BindException(非请求body参数,例如@RequestParam接收的)和MethodArgumentNotValidException(请求body里面的参数,例如@RequestBody接收的),这两类Exception里面都有一个BindingResult对象,它里面有一个包装成FieldError的List,保存着Bean对象出现错误的Field等信息。

取出它里面defaultMessage,放到统一的ServiceResponse返回即可实现返回码和消息的定制。由于消息内容是有注解默认的DefaultMessage决定的,为了按照自定义的描述返回,在Bean对象的注解上需要手动赋值为希望返回的消息内容。

Quick Start: SpringBoot custom verification request parameter


这样当name参数长度超过10时,就会返回

Quick Start: SpringBoot custom verification request parameter


这里的FieldError fieldError = ex.getFieldError();只会随机返回一个出错的属性,如果Bean对象的多个属性都出错了,可以调用ex.getFieldErrors()来获得,这里也可以看到Spring Validation在参数校验时不会在第一次碰到参数错误时就返回,而是会校验完成所有的参数。

如果不想手动编程去校验,那么这里可以只读取一个随机的FieldError,返回它的错误消息即可。

3.6 更加细致的返回码和消息

其实还有一种比较典型的自定义返回,就是错误码(code)和消息(message)是一一对应的,比如:

  • 51001:字符串长度过长

  • 51002:参数取值过大

这种情况比较特殊,一般当参数错误的时候,会返回一个整体的参数错误的错误码,然后携带参数的错误信息。但有时,业务上就要不同的参数错误,既要错误码不同,错误信息也要不同。我想了下,有两种思路。

  • 第一种:通过message同时包含错误码和错误信息,在全局异常捕获方法中,再把它们拆开。

  • The second: manual calibration, custom throws Exception (inside with a code, message). Manual calibration Here, if each Controller to write again are indeed more strenuous, AOP can be implemented in combination, or a base class BaseController out manner.

IV Summary

In fact, in the actual work, there must have been more complex validation logic, but not necessarily all use the framework to achieve, inside the framework of implementation (such as notes) should be a relatively simple universal calibration, can achieve reuse to reduce duplication of work. While more complex check logic must exist among the specific service, which is preferably implemented in the service code.

Another point to note, Spring Validation of isValid method, if it returns false, then the Controller will no longer be called, but returned directly. If you add on top of AOP in the Controller interface call statistics, it may be missed. This time, we should not let Controller does not call, it is recommended in this case after AOP inside of the section Controller parameters should be verified, throw a unified business exception.

Little brother feel good essays give a point attention to it! Add to my personal fan base (Java technology stack architecture: 644 872 653) to receive a Java interview book "Core Java knowledge finishing .pdf" and "Java208 pavement questions (with answers)" Oh!


Guess you like

Origin blog.51cto.com/14480698/2454791