当前位置 博文首页 > li5672的专栏:Java全局异常捕获处理

    li5672的专栏:Java全局异常捕获处理

    作者:[db:作者] 时间:2021-08-30 15:58

    为了项目的正常运行中,异常捕获,记录也是非常重要的,方便我们排查问题,定位问题

    定义异常

    为了方便定位异常,自定义了几种异常类,方便我们快速定位异常。

    基类

    public class HttpException extends RuntimeException {
        protected String code;
        protected Integer httpStatusCode = 500;
    }
    
    

    ParameterException

    public class ParameterException extends HttpException {
        public ParameterException(String code){
            this.code = code;
            this.httpStatusCode = 400;
        }
    }
    

    ServerErrorException

    public class ServerErrorException extends HttpException {
        public ServerErrorException(String code) {
            this.code = code;
            this.httpStatusCode = 500;
        }
    }
    
    

    UnAuthenticatedException

    public class UnAuthenticatedException extends HttpException{
        public UnAuthenticatedException(String code){
            this.code = code;
            this.httpStatusCode = 401;
        }
    }
    
    

    ForbiddenException

    public class ForbiddenException extends HttpException {
        public ForbiddenException(String code) {
            this.code = code;
            this.httpStatusCode = 403;
        }
    }
    

    NotFoundException

    public class NotFoundException extends HttpException {
        public NotFoundException(String code){
            this.httpStatusCode = 404;
            this.code = code;
        }
    }
    
    

    这里定义了我在项目中常用的几种异常,也可根据实际情况定义自己所需的异常。

    捕获异常

    捕获异常需要用到一个注解@ControllerAdvice,关于它的详细解释可查看文档。

    使用方法如下,定义一个异常捕获类

    @ControllerAdvice
    public class GlobalExceptionAdvice {
    
    }
    

    这个类就已经实现了捕获全局异常的功能,下面在加上上面定义的几种异常

    @ControllerAdvice
    public class GlobalExceptionAdvice {
      @ExceptionHandler(UnAuthenticatedException.class)
      public ResponseEntity unAuthenticatedException(UnAuthenticatedException e) {
          return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getCode());
      }
    
    
      @ExceptionHandler(ParameterException.class)
      public ResponseEntity handleParameterException(ParameterException e) {
          return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getCode());
      }
    
      @ExceptionHandler(ForbiddenException.class)
      public ResponseEntity handleForbiddenException(ForbiddenException e) {
          return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getCode());
      }
    
      @ExceptionHandler(NotFoundException.class)
      public ResponseEntity handleNotFoundException(NotFoundException e) {
          return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getCode());
      }
    
      @ExceptionHandler(RuntimeException.class)
      public ResponseEntity handleRunTimeException(RuntimeException e) {
    
          return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(500);
      }
    
    
    }
    

    @ExceptionHandler注解表示该方法捕获的异常类型,就可以在不同的异常中进行不同的处理方式。

    记录异常

    捕获到异常之后我们要记录下来,方便我们对bug的追踪解决。

    记录方法有多种多样的,比如记录到数据库或者log文件中。我使用了第二种方式。

    加入依赖

       <dependency>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
              <optional>true</optional>
          </dependency>
         <dependency>
              <groupId>commons-logging</groupId>
              <artifactId>commons-logging</artifactId>
              <version>1.2</version>
          </dependency>
          <dependency>
              <groupId>org.apache.logging.log4j</groupId>
              <artifactId>log4j-api</artifactId>
              <version>2.2</version>
          </dependency>
          <dependency>
              <groupId>org.apache.logging.log4j</groupId>
              <artifactId>log4j-core</artifactId>
              <version>2.2</version>
          </dependency>
          <dependency>
              <groupId>org.apache.logging.log4j</groupId>
              <artifactId>log4j-jcl</artifactId>
              <version>2.2</version>
          </dependency>
    

    增加日志配置文件

    logback.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
    
      <!-- 控制台 appender, 几乎是默认的配置 -->
      <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
          <encoder charset="UTF-8">
              <!-- 输出的日志文本格式, 其他的 appender 与之相同 -->
              <pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n</pattern>
              <charset>UTF-8</charset>
          </encoder>
      </appender>
    
      <!-- info 级别的 appender -->
      <appender name="info" class="ch.qos.logback.core.rolling.RollingFileAppender">
          <!-- 日志写入的文件名, 可以是相对目录, 也可以是绝对目录, 如果上级目录不存在会自动创建 -->
          <file>./logs/info/log-stack.log</file>
          <!-- 如果是 true, 日志被追加到文件结尾; 如果是 false, 清空现存文件. 默认是true -->
          <append>true</append>
          <!-- 日志级别过滤器, 只打 INFO 级别的日志-->
          <filter class="ch.qos.logback.classic.filter.LevelFilter">
              <level>INFO</level>
              <!-- 下面2个属性表示: 匹配 level 的接受打印, 不匹配的拒绝打印 -->
              <onMatch>ACCEPT</onMatch>
              <onMismatch>DENY</onMismatch>
          </filter>
          <!-- 最常用的滚动策略, 它根据时间来制定滚动策略, 既负责滚动也负责触发滚动 -->
          <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
              <!-- 设置滚动文件规则, 如果直接使用 %d, 默认格式是 yyyy-MM-dd -->
              <fileNamePattern>./logs/info/log-stack.%d{yyyy-MM-dd}.log</fileNamePattern>
              <!-- 保留14天的日志 -->
              <maxHistory>30</maxHistory>
          </rollingPolicy>
          <!-- 定义日志输出格式 -->
          <encoder charset="UTF-8">
              <pattern> %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} %L - %msg%n</pattern>
              <charset>UTF-8</charset>
          </encoder>