1.场景还原
在项目开发中,对于各种异常都有不同的报错提示或策略,无疑对于用户或者开发来说,是一个很好的用户体验;如何在java定义一个全局异常捕捉呢?
2.实现方案
2.1 自定义一个业务异常类
@Setter
@Getter
public class BizException extends RuntimeException {
private static final long serialVersionUID = -6233506444097954612L;
/**
* 错误码
*/
private String errorCode;
/**
* 错误信息
*/
private String errorMsg;
/**
* 返回错误对象信息
*/
private Object data;
public BizException() {
super();
}
public BizException(String errorMsg) {
super(errorMsg);
this.errorMsg = errorMsg;
}
public BizException(String errorCode, String errorMsg) {
super(errorCode);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public BizException(String errorCode, String errorMsg, Throwable cause) {
super(errorCode, cause);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public BizException(ResultEnum resultEnum) {
super(resultEnum.code());
this.errorCode = resultEnum.code();
this.errorMsg = resultEnum.message();
}
public BizException(ResultEnum resultEnum, Throwable cause) {
super(resultEnum.code(), cause);
this.errorCode = resultEnum.code();
this.errorMsg = resultEnum.message();
}
public BizException(ResultEnum resultEnum, Object data) {
this.errorCode = resultEnum.code();
this.errorMsg = resultEnum.message();
this.data = data;
}
}
2.2 定义一个错误枚举类
public enum ResultEnum {
SUCCESS("200", "success"),
FAIL("0", "failed"),
PARAM_INVALID("-1", "param is invalid");
private String code;
private String message;
ResultEnum(String code, String message){
this.code = code;
this.message = message;
}
public String code(){
return this.code;
}
public String message(){
return this.message;
}
}
2.3 定义一个全局异常捕捉类
@Slf4j
@ResponseBody
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理自定义的业务异常
*
* @param e
* @return
*/
@ExceptionHandler(value = BizException.class)
public RestResponse bizExceptionHandler(BizException e) {
log.error("业务异常!原因:{}", e.getErrorMsg());
return RestResponse.fail(e.getErrorCode(), e.getErrorMsg());
}
/**
* 处理空指针的异常
*
* @param e
* @return
*/
@ExceptionHandler(value = NullPointerException.class)
public RestResponse exceptionHandler(NullPointerException e) {
log.error("空指针异常!原因:{}", e);
return RestResponse.fail("空指针异常");
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public RestResponse exceptionHandler(Exception e) {
StringBuilder errMsg = new StringBuilder();
// 方法参数无效 异常
if (e instanceof MethodArgumentNotValidException) {
BindingResult bindResult = ((MethodArgumentNotValidException) e).getBindingResult();
List<FieldError> fieldErrorList = bindResult.getFieldErrors();
fieldErrorList.forEach(fieldErrors -> {
if (StringUtils.isNotBlank(errMsg.toString())) {
errMsg.append(",");
}
errMsg.append(fieldErrors.getDefaultMessage());
}
);
} else {
return RestResponse.fail(ResultEnum.INTERNAL_ERROR);
}
return RestResponse.fail(errMsg.toString());
}
}
2.4 定义一个restful response类
@Setter
@Getter
public class RestResponse {
private String code;
private String message;
private Object data;
public RestResponse(){
}
public static RestResponse success(){
RestResponse restResponse = new RestResponse();
restResponse.setResultCode(ResultEnum.SUCCESS);
return restResponse;
}
public static RestResponse success(Object data){
RestResponse restResponse = new RestResponse();
restResponse.setResultCode(ResultEnum.SUCCESS);
restResponse.setData(data);
return restResponse;
}
public static RestResponse fail() {
RestResponse restResponse = new RestResponse();
restResponse.setResultCode(ResultEnum.FAIL);
return restResponse;
}
public static RestResponse fail(ResultEnum resultEnum) {
RestResponse restResponse = new RestResponse();
restResponse.setResultCode(resultEnum);
return restResponse;
}
public static RestResponse fail(String message) {
RestResponse restResponse = new RestResponse();
restResponse.setCode(ResultEnum.FAIL.code());
restResponse.setMessage(message);
return restResponse;
}
public static RestResponse fail(String code, String message) {
RestResponse restResponse = new RestResponse();
restResponse.setCode(code);
restResponse.setMessage(message);
return restResponse;
}
public static RestResponse fail(ResultEnum resultEnum, Object data) {
RestResponse restResponse = new RestResponse();
restResponse.setResultCode(resultEnum);
restResponse.setData(data);
return restResponse;
}
private void setResultCode(ResultEnum resultEnum){
this.code = resultEnum.code();
this.message = resultEnum.message();
}
}
2.5 从service或controller抛出具体异常
@GetMapping("/getInfo")
@ApiOperation(value = "get user info api")
public RestResponse getUserInfo(HttpServletRequest request) {
return RestResponse.fail(ResultEnum.USER_NOY_EXISTS);
}
本文主要@ControllerAdvice+@ExceptionHandler两个注解结合实现全局异常捕捉,对于两个注解的原理,有兴趣的同学可以去研究下底层是怎么工作的,我这里就不再赘述!