全局异常处理

全局异常处理


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切面处理

如果对你有用,就帮忙点个赞支持一下吧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值