SpringBoot参数校验,弄懂@Valid注解实现,返回自定义响应类
目的:
对前端请求的数据进行格式、长度、是否为空等进行校验,可以防止脏数据对数据库的影响。
操作方式
通过在controller中加入@valid对请求参数进行校验
方式一、配合AOP实现
方式二、配合全局异常实现
@valid基本注解
注解 | 作用 | 参数 |
---|---|---|
@Null | 参数必须为null | message=“返回信息” |
@NotNull | 参数必须不为null | message=“返回信息” |
@NotBlank | 参数必须不为null,并且长度必须大于0 | message=“返回信息” |
@NotEmpty | 参数必须不为空 | message=“返回信息” |
@Min | 参数必须大于等于该值 | value=数值,message=“返回信息” |
@Max | 参数必须小于等于该值 | value=数值,message="返回信息 |
@Pattern | 参数必须满足正则表达式 | regexp=“正则”,message="返回信息 |
参数必须为电子邮箱 | message=“返回信息” |
更多可参考:https://www.cnblogs.com/1nchaos/p/11442559.html
准备内容
0、响应类
public class ResponseObject { private Integer status; private Object data; private String message; public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public static ResponseObject failure(String message) { ResponseObject responseObject = new ResponseObject(); responseObject.setStatus(500); responseObject.setData(false); responseObject.setMessage(message); return responseObject; }}
1、实体类
public class User implements Serializable { /** * 用户名 */ @NotEmpty(message = "不能为空") private String username; @Max(value = 20, message = "不能超过20") @Min(value = 10, message = "不能小于10") private Integer num; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Integer getNum() { return num; } public void setNum(Integer num) { this.num = num; }}
2、Controller
@RestControllerpublic class UserController { @ParamValid @GetMapping("/get") public ResponseObject getUser(@Valid User user, BindingResult bindingResult) { return ResponseObject.failure(""); } @PostMapping("/post") public ResponseObject postUser(@Valid @RequestBody User user) { return ResponseObject.failure(""); }}
3、自定义注解
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface ParamValid {}
4、AOP类
@Component@Aspectpublic class ParameterValidAop { @Before("@annotation(paramValid)") public void paramValid(JoinPoint point, ParamValid paramValid) throws Exception { Object[] paramObj = point.getArgs(); for (Object obj : paramObj) { if (obj instanceof BindingResult) { BindingResult result = (BindingResult) obj; if (result.hasErrors()) { List<ObjectError> allErrors = result.getAllErrors(); //返回第一个错误 String defaultMessage = allErrors.get(0).getDefaultMessage(); throw new Exception(defaultMessage); } } } }}
5、全局异常
@RestControllerAdvice@Slf4jpublic class GlobalException { /** * 参数校验异常 */ @ResponseStatus(HttpStatus.OK) @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseObject handlerMethodArgumentNotValidException(MethodArgumentNotValidException e) { BindingResult bindingResult = e.getBindingResult(); // 所有参数异常信息 List<ObjectError> allErrors = bindingResult.getAllErrors(); return ResponseObject.failure(allErrors.get(0).getDefaultMessage()); } @ResponseStatus(HttpStatus.OK) @ExceptionHandler(BindException.class) public ResponseObject handlerBindException(BindException e) { BindingResult bindingResult = e.getBindingResult(); // 所有参数异常信息 List<ObjectError> allErrors = bindingResult.getAllErrors(); return ResponseObject.failure(allErrors.get(0).getDefaultMessage()); }}
实现
方法一:AOP、
在controller中加入@Valid、 @ParamValid注解,以及BindingResult参数
@ParamValid @GetMapping("/get") public ResponseObject getUser(@Valid User user, BindingResult bindingResult) { return ResponseObject.failure(""); }
通过postman访问conrtoller地址,写入的参数并且不满足规则,可以看到会抛出错误异常
可以看到在抛出的异常中,并是不自己定义的格式,如果想要返回自定义的响应实体,需要在全局异常中写一个自定义异常,并且获取在AOP中抛出的差异,是不是觉得有点麻烦,在用的AOP以后,还需要进行额外的代码操作,所以推荐第二中方式,直接使用全局异常进行拦截 ,并且返回自定义响应。
方式二:全局异常拦截(推荐)
controller如下:
@GetMapping("/get") public ResponseObject getUser(@Valid User user) { return ResponseObject.failure(""); } @PostMapping("/post") public ResponseObject postUser(@Valid @RequestBody User user) { return ResponseObject.failure(""); }
进行请求
可以看到控制台打印了错误信息,意思就是如果出现了不满足条件的参数请求,会自动抛出异常,那么我们就可以在自定义异常中进行捕获,代码看上面(5、全局异常)。
最后返回结果,就是自己打印的数据格式:
补充:
可以将所有错误提示一起返回
List<ObjectError> allErrors = result.getAllErrors();//装载为集合 List<ObjectError> allErrors = result.getAllErrors(); List<String> lists = new ArrayList<>(); for (ObjectError objectError : allErrors) { lists.add(objectError.getDefaultMessage()); }
参考:@1nchaos https://www.cnblogs.com/1nchaos/p/11442559.html