全局异常处理
Java编程中,我们经常会遇到对异常的处理,常用的方法有
try...catch
捕获异常处理,但是在写业务代码时候,我们会遇到各种各样的异常,所有可能有业务异常的部分,我们都需要主动的去处理。
那么,如何简单的进行全局异常处理呢?
下面我们来介绍一个简单的全局异常处理方法
自定义异常
在应用开发过程中,除系统自身的异常外,不同业务场景中用到的异常也不一样,为了与标题
轻松搞定全局异常
更加的贴切,定义个自己的异常,看看如何捕获…
自定义异常需要继承 RuntimeException
这个类
@Data
//自定义一个java业务异常
public class MyException extends RuntimeException{
private int code;
public MyException() {
super();
}
public MyException(int code, String message) {
super(message);
this.code = code;
}
}
定义一个统一的返回dto
通常在业务开发中,我们需要返回统一的数据格式,利于代码的统一和格式的规范
通常定义的dto如下
public class ResponseDto<T> {
private int code; //业务代码, 0为成功, -1 失败,更多的自己定制
private String message; //业务信息, 通常失败时候用到,自定信息
private T data; //业务数据, 前端可以通过这个拿到数据
}
这里我们也这样定义一个自己的返回dto
@Data
public class ResponseDto<T> {
private int code;
private String message;
private T data;
public ResponseDto() {}
public ResponseDto(int code, String msg) {
this.code = code;
this.message = msg;
}
public static <T> ResponseDto success(T data) {
ResponseDto responseDto = new ResponseDto();
responseDto.setCode(0);
responseDto.setData(data);
return responseDto;
}
public static <T> ResponseDto fail(String msg) {
ResponseDto responseDto = new ResponseDto();
responseDto.setMessage(msg);
return responseDto;
}
}
异常处理(关键)
第一种方法:使用@ControllerAdvice
注解介绍
@ControllerAdvice
捕获Controller
层抛出的异常,如果添加@ResponseBody
返回信息则为JSON
格式。@RestControllerAdvice
相当于@ControllerAdvice
与@ResponseBody
的结合体。@ExceptionHandler
统一处理一种类的异常,减少代码重复率,降低复杂度。
创建一个 GlobalExceptionHandler
类,并添加上@RestControllerAdvice
注解就可以定义出异常通知类了,然后在定义的方法中添加上@ExceptionHandler
即可实现异常的捕捉
/**
* 定义全局异常处理
*/
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
/**
* 定义要捕获的异常,可以多个@ExceptionHandler({})
*/
@ExceptionHandler(MyException.class)
public ResponseDto myExceptionHandler(HttpServletRequest request, final Exception e, HttpServletResponse response) {
response.setStatus(HttpStatus.BAD_REQUEST.value());
MyException exception = (MyException)e;
return new ResponseDto(400, exception.getMessage());
}
@ExceptionHandler(RuntimeException.class)
public ResponseDto runtimeExceptionHandler(HttpServletRequest request, final Exception e, HttpServletResponse response) {
response.setStatus(HttpStatus.BAD_REQUEST.value());
RuntimeException exception = (RuntimeException) e;
return new ResponseDto(400, exception.getMessage());
}
@Override
protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers,
HttpStatus status, WebRequest request) {
if (ex instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException exception = (MethodArgumentNotValidException) ex;
return new ResponseEntity<>(new ResponseDto(status.value(), exception.getBindingResult().getAllErrors().get(0).getDefaultMessage()), status);
}
if (ex instanceof MethodArgumentTypeMismatchException) {
MethodArgumentTypeMismatchException exception = (MethodArgumentTypeMismatchException) ex;
logger.error("参数转换失败,方法:" + exception.getParameter().getMethod().getName() + ",参数:" + exception.getName()
+ ",信息:" + exception.getLocalizedMessage());
return new ResponseEntity<>(new ResponseDto(status.value(), "参数转换失败"), status);
}
return new ResponseEntity<>(new ResponseDto(status.value(), "参数转换失败"), status);
}
}
第二种方法:aop切面捕获
自定义的异常,可以在统一的aop切面中进行拦截,此时可以用到 try catch进行捕获,关键代码如下
try {
log.info("log aop begin - className:{} methodName:{} args:{}", new Object[]{className, methodName, args});
result = point.proceed();
stopWatch.stop();
log.info("log aop end - className:{} methodName:{} time-used:{} result:{}", new Object[]{className, methodName, stopWatch.getTime(), printResp ? JSON.toJSONString(result) : "..."});
} catch (Throwable var12) {
//这里在抛错的时候,判断是否是我们自定义的MyException,如果是,则定制处理
if (var12 instanceof MyException) {
log.error("log aop end - className:{} methodName:{} BizException:{}", new Object[]{className, methodName, var12.getMessage()});
result = ResponseDto.fail(var12.getMessage());
} else if (var12 instanceof TokenException) {
log.error("log aop end - className:{} methodName:{} TokenException:{}", new Object[]{className, methodName, var12.getMessage()});
result = ResponseDto.fail(LogAspect.TokenError.USER_ACCOUNT_NO_LOGIN.getCode(), LogAspect.TokenError.USER_ACCOUNT_NO_LOGIN.getContent());
} else {
log.error("log aop end - className:{} methodName:{} error:", new Object[]{className, methodName, var12});
result = ResponseDto.fail("服务器开小差了");
}
}
小节
好了,这就是两种简单常用的全局异常处理,总结一下
- 通过@ExceptionAdvice方式拦截
- aop切面处理
如果对你有用,就帮忙点个赞支持一下吧!