Spring Boot全局异常处理非法参数

Spring Boot全局异常处理非法参数

应用场景

在一个项目中我们需要对接口中传入的参数进行非法性检查,当参数非法时,抛出异常,然后返回统一的错误信息。

校验注解

Bean Validation中内置的校验注解:

Constraint 描述
@Null 被注解的元素必须为null
@NotNull 被注解的元素必须不为null
@AssertTrue 被注解的元素必须为true
@AssertFalse 被注解的元素必须为false
@Min(value) 被注解的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注解的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注解的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注解的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max,min) 被注解的元素大小必须在指定的范围内
@Digits(integer,fraction) 被注解的元素必须是一个数组,其值必须在可接受的范围内
@Past 被注解的元素必须是一个过去的日期
@Future 被注解的元素必须是一个将来的日期
@Pattern(value) 被注解的元素必须符合指定的正则表达式

Hibernate Validator附加的校验注解:

Constraint 描述
@NotBlank 被注解的元素必须非null,且长度必须大于0,并只能作用于String类型的字段上
@Email 被注解的元素必须是电子邮箱地址
@Length(min,max) 被注解的元素大小必须在指定的范围内
@NotEmpty 被注解的元素必须非空
@Range(min,max) 被注解的元素必须在合适的范围内

添加测试Bean

添加测试Bean,测试类中定义几个字段,并且每个字段都做一定的限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.zmjwdzjl.demo.bean;

import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Email;

@Data
public class BeanValidation {

@Pattern(regexp = "^[A-Za-z0-9]+$",message="只能输入由数字和26个英文字母组成的字符串")
private String loginNumber;

@NotBlank(message="密码不能为空")
private String passWord;

@Email(message="邮箱地址格式不正确")
private String email;

}

添加测试接口

在接口中使用@Validated注解对参数进行合法性检查,如果参数合法,返回原始数据

1
2
3
4
5
6
@ApiOperation(value = "登录接口")
@PostMapping("/login")
public Object login(@Validated @RequestBody BeanValidation data) {
ResultMsg resultMsg = new ResultMsg(ResultStatusCode.OK.getErrcode(), ResultStatusCode.OK.getErrmsg(), data);
return resultMsg;
}

添加异常返回类

如果未添加全局异常处理,将会使用默认的异常处理,但是返回的结果和自己的数据结构有很大的差异,对于前端处理返回结果也很麻烦。可以自定义参数异常返回的数据类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.zmjwdzjl.demo.bean;

import lombok.Data;

@Data
public class ArgumentInvalidResult {

private String field;

private Object rejectedValue;

private String defaultMessage;

}

添加全局异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.zmjwdzjl.demo.exception;

import com.sinosoft.batchcommon.domain.RestfulResponse;
import com.sinosoft.batchcommon.util.MessageUtils;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.util.stream.Collectors;

@ControllerAdvice
//如果返回的为json数据或其它对象,添加该注解
@ResponseBody
public class GlobalExceptionHandler {
//添加全局异常处理流程,根据需要设置需要处理的异常,本文以MethodArgumentNotValidException为例
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public Object MethodArgumentNotValidHandler(MethodArgumentNotValidException exception) {
//按需重新封装需要返回的错误信息
List<ArgumentInvalidResult> invalidArguments = new ArrayList<>();
//解析原错误信息,封装后返回,此处返回非法的字段名称,原始值,错误信息
for (FieldError error : exception.getBindingResult().getFieldErrors()) {
ArgumentInvalidResult invalidArgument = new ArgumentInvalidResult();
invalidArgument.setDefaultMessage(error.getDefaultMessage());
invalidArgument.setField(error.getField());
invalidArgument.setRejectedValue(error.getRejectedValue());
invalidArguments.add(invalidArgument);
}
ResultMsg resultMsg = new ResultMsg(ResultStatusCode.PARAMETER_ERROR.getErrcode(), ResultStatusCode.PARAMETER_ERROR.getErrmsg(), invalidArguments);
//也可以用stream将异常信息拼接成字符串返回
String msg = String.join("\n",exception.getBindingResult().getFieldErrors().stream().map(error->error.getField+":"+error.getRejectedValue+"捕获异常:"+error.getDefaultMessage()).collect(Collectors.toList()));
return resultMsg;
}
}
如果对您有帮助,可以打赏呦!