😊 @ 作者: 一恍过去
💖 @ 主页: https://blog.csdn.net/zhuocailing3390
🎊 @ 社区: Java技术栈交流
🎉 @ 主题: Spring Boot 中的参数验证和自定义响应处理,使用 @Valid 注解
⏱️ @ 创作时间: 2023年09月13日
目的:
对前端请求的数据进行格式、长度、是否为空等进行校验,可以防止脏数据对数据库的影响。
操作方式
通过在controller中加入@valid对请求参数进行校验
方式一、配合AOP实现
方式二、配合全局异常实现
@valid基本注解
常用主要注解如下:
注解 | 作用 | 参数 |
---|---|---|
@Null | 验证是否为null | message=“返回信息” |
@NotNull | 验证是否不为null, 无法查检长度为0的字符串 | message=“返回信息” |
@NotBlank | 验证是否不为null, 并且不会过滤空格字符串 | message=“返回信息” |
@NotEmpty | 验证String是否为null,或者对象是否empty | message=“返回信息” |
@Min | 参数必须大于等于该值 | value=数值,message=“返回信息” |
@Max | 参数必须小于等于该值 | value=数值,message="返回信息 |
@Pattern | 参数必须满足正则表达式 | regexp=“正则”,message="返回信息 |
参数必须为电子邮箱 | message=“返回信息” | |
@Valid | 对关联对象进行递归校验 | - |
@Range | 验证数字的最大值与最小值 | min=, max= |
@Size | 验证对象(Array,Collection,Map,String)长度最大值与最小值 | min=, max= |
@Length | 验证String的长度最大值与最小值 | min=, max= |
准备内容
pom:
<dependency><groupId>jakarta.validation</groupId><artifactId>jakarta.validation-api</artifactId>
</dependency>
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
@RestController
public 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
@Aspect
public 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
@Slf4j
public 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