在一个项目中,我们是会经常处理异常的,像下面这样

try {
    // 要执行的语句
} catch (Exception e) {
    // 异常处理
}

但是,一旦项目中处理的异常的多起来之后,就会显得特别杂乱,代码阅读性也会直线下降。

那么这个时候,就需要将放置在各个代码处的异常处理都集中到一个地方进行处理,也就是-全局异常处理。

一、创建全局异常处理类

首先我们创建一个类,名字叫GlobalExceptionHandler

然后,给这个类添加一个注解,@ControllerAdvice

这里说明下这个注解的含义。

@ControllerAdvice就是@Controller的增强版。@ControllerAdvice主要用来处理全局数据,一般搭配@ExceptionHandler@ModelAttribute以及@InitBinder使用。

二、处理全局异常

第一步中,我们创建了全局异常处理的类,那么这一步就是定义方法,来处理那些异常了。

首先写一个方法叫errorHandler

@ControllerAdvice
public class GlobalExceptionHandler {
    public void errorHandler(Exception e) {
        // 异常处理
    }
}

当然,只有这个方法那是一点用都没有。我们还需要在方法上加上注解@ExceptionHandler

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(value = Exception.class)
    public void errorHandler(Exception e) {
        // 异常处理
    }
}

@ExceptionHandler注解一般用来自定义异常,可以认为它是一个异常拦截器。在方法上加上这个注解后,方法就可以在整个项目出现异常的时候,捕获并去处理异常。

三、示例

那我们做个测试,以此来展示全局异常的用法。

我们先创建一个接口,这个接口作用是计算100除以0的结果。那么想必小伙伴们也都明白,这个计算语句是一定会出现异常的。毕竟我们的这个接口就是用来展示异常处理的,所以写成这样。上代码:

@RestController
public class TestController {
    @GetMapping("/exception")
    public void exceptionHandler() {
        int number = 100 / 0;
    }
}

其次呢,我们需要在处理全局异常的方法中将异常的堆栈信息给打印到控制台中,方便我们查看。

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(value = Exception.class)
    public void errorHandler(Exception e) {
        System.out.println("我要开始打印异常的堆栈信息了");
        e.printStackTrace();
        System.out.println("异常的堆栈信息我已经打印完了");
    }
}

这里我加了两行输出语句,目的是为了能看出来是在全局异常处理的方法中打印的堆栈信息,而不是其他地方打印的堆栈信息。

然后,我们启动项目,并访问这个接口。我的项目并没有设置端口号,因此用的是默认的端口号。访问地址为:http://localhost:8080/exception

之后,我们可以看到控制台里打印的异常信息

我要开始打印异常的堆栈信息了
java.lang.ArithmeticException: / by zero
    at online.yangcloud.controller.TestController.exceptionHandler(TestController.java:14)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:888)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
异常的堆栈信息我已经打印完了

可以看到,我们的输出语句已经完美的打印在控制台上。如果小伙伴们打印的两行输出语句均在异常的堆栈信息前打印的话,那么可以在打印堆栈信息的那行代码上打个断点,这样就可以输出像我这样的。

未完待续~~

下一篇