目录
- 目的:
- 操作方式
- @valid基本注解
- 准备内容
- 实现
- 方法一:AOP、
- 方式二:全局异常拦截(推荐)
- 补充
目的:
对前端请求的数据进行格式、长度、是否为空等进行校验,可以防止脏数据对数据库的影响。
操作方式
通过在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