如何优雅的处理SpringBoot接口中参数校验
相信我们在处理接口参数校验时,都不会使用大量的if,else 进行来处理,这样显得太繁琐,下面就来介绍一下如何能够简单而有效的处理方式:
一、使用注解来处理参数校验
1、实体类
package com.dongl.bean.mybean; import com.dongl.utils.annotation.CheckField; import lombok.Data; import org.hibernate.validator.constraints.Range; import javax.validation.constraints.NotNull; import java.util.Date;
@Data public class User { /**主键*/ private Long id; /**姓名*/ @NotNull private String name; /**性别*/ @CheckField(fieldValues = {"男", "女"}) private String sex; /**出生日期*/ private Date birthDay; /**年龄*/ @Range(min = 20 , max = 99) private Short age; /**详细地址*/ private String address; }
2、Controller层
package com.dongl.controller; import com.dongl.bean.mybean.User; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; /** * @author D-L * @Classname AnnotationController * @Version 1.0 * @Description 接口参数校验异常处理 * @Date 2020/8/26 */ @RestController @RequestMapping("Annotation") public class AnnotationController { @PostMapping(value = "user") public String test(@Validated @RequestBody User user /*, BindingResult bindingResult*/) { System.out.println(user); return "do something you like ------"; } }
3、响应结果
测试参数:
{ "name":"admin", "sex":"男", "age":120, "address":"杭州市西湖区" }
response:
{ "timestamp": "2020-08-26T07:25:45.547+0000", "status": 400, "error": "Bad Request", "errors": [ { "codes": [ "Range.user.age", "Range.age", "Range.java.lang.Short", "Range" ], "arguments": [ { "codes": [ "user.age", "age" ], "arguments": null, "defaultMessage": "age", "code": "age" }, 99, 20 ], "defaultMessage": "需要在20和99之间", "objectName": "user", "field": "age", "rejectedValue": 120, "bindingFailure": false, "code": "Range" } ], "message": "Validation failed for object='user'. Error count: 1", "trace": "org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public java.lang.String com.dongl.controller.AnnotationController.test(com.dongl.bean.mybean.User): [Field error in object 'user' on field 'age': rejected value [120]; codes [Range.user.age,Range.age,Range.java.lang.Short,Range]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.age,age]; arguments []; default message [age],99,20]; default message [需要在20和99之间]] \r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.lang.Thread.run(Thread.java:748)\r\n", "path": "/Annotation/user" }
【结论】:这样的响应结果显然有点不够优雅,太繁琐,有没有更好的处理方式,当然有,下面使用 BindResult 处理。
二、针对接口处理 Validator + BindResult进行校验
1、处理响应结果
package com.dongl.controller; import com.dongl.bean.mybean.User; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.util.List; /** * @author D-L * @Classname AnnotationController * @Version 1.0 * @Description 处理参数校验异常 * @Date 2020/8/24 */ @RestController @RequestMapping("Annotation") public class AnnotationController { @PostMapping(value = "user") public String test(@Validated @RequestBody User user , BindingResult bindingResult) { List<ObjectError> allErrors = bindingResult.getAllErrors(); // 如果有参数校验失败,会将错误信息封装成对象组装在BindingResult里 for(ObjectError error : allErrors){ return error.getDefaultMessage(); } System.out.println(user); return "do something you like ------"; } }
2、响应结果
需要在20和99之间
【结论】当然这种方式已经解决了返回体繁琐的问题,但是每一处理接口参数都需要添加,还是有点不尽人意,有没有更好的解决方法,当然有,下面通过全局的方式处理。
三、全局异常处理 Validator + 自动抛出异常
1、全局处理响应结果
首先,我们需要新建一个类,在这个类上加上@ControllerAdvice或@RestControllerAdvice注解,这个类就配置成全局处理类了。(这个根据你的Controller层用的是@Controller还是@RestController来决定)
这里就以@RestController为例:
package com.dongl.utils.error; import org.springframework.validation.ObjectError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; /** * @author D-L * @Classname ExceptionControllerAdvice * @Version 1.0 * @Description 全局处理参数校验异常返回提示 * @Date 2020/8/26 */ @RestControllerAdvice public class ExceptionControllerAdvice { @ExceptionHandler(MethodArgumentNotValidException.class) public String MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) { // 从异常对象中拿到ObjectError对象 ObjectError objectError = e.getBindingResult().getAllErrors().get(0); // 然后提取错误提示信息进行返回 return objectError.getDefaultMessage(); } }
2、测试结果:
需要在20和99之间
【注释】:这里说明一下如果你进行了全局的处理,但在接口上又进行了手动处理,这时命中的是接口上的,也就是全局配置不生效了。