springboot统一拦截全局异常处理

springboot统一拦截全局异常处理

  • 1 需求场景
    • (1)破坏代码美观
    • (2)定位问题难
    • (3)复用性差
  • 2 解决方案
    • 2.1Controller异常拦截类
    • 2.2 辅助类
      • 2.2.1 异常枚举类
      • 2.2.1 异常信息类
      • 2.2.1 自定义异常类
    • 2.3 测试类
      • 2.3.1 测试没有判断和捕获的异常
      • 2.3.2 测试自定义抛出异常
  • 3 结语

1 需求场景

在编写代码的时候,尤其是在服务类中,经常会报各种异常信息,比如空指针异常,数据角标越界异常和数据库数据异常。尤其是数据库数据异常信息最难控制,因为数据库添加的数据不一定受你控制,就容易导致脏数据。
针对上面情况通常采用trycatch捕获异常。但有以下缺点:

(1)破坏代码美观

trycatch会占用很多行代码,影响代码的简洁。

(2)定位问题难

由于你不知道会抛出哪个异常。只能捕获异常的根类Exception,返回的信息也只能知道出异常了,不利于排查问题。

(3)复用性差

2 解决方案

不卖关子,直接复制我下面列举的四个类,放在异常包中就可以自动拦截异常,然后根据自己需要丰富异常拦截类。

2.1Controller异常拦截类

解决方案用到了注解@RestControllerAdvice,这个注解会拦截所有的RequestMapping注解,从而对http请求的返回信息进行封装。类信息如下:

package com.casic.finance.exception;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletResponse;

/**
 * @author: 董胜得
 * @date: 2021/3/12 18:08
 * 此类为:
 * 主要提供的功能为:
 */
@RestControllerAdvice
public class CtrollerExceptionHandler {
    /**
     * 处理系统异常,当发生数组角标越界异常的时候,会执行此方法
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ArrayIndexOutOfBoundsException.class)
    public ExceptionMessage handleValidationBodyException(ArrayIndexOutOfBoundsException e) {
        e.printStackTrace();
        return new ExceptionMessage(ExceptionEnum.ARRAY_INDEX_OUT_OF_BOUND.getExcepCode(), e.getMessage());
    }

    /**
     * 主动throw的异常,主动抛出异常会执行此方法
     *
     * @param e
     * @param response
     * @return
     */
    @ExceptionHandler(MyThrowException.class)
    public ExceptionMessage handleUnProccessableServiceException(MyThrowException e, HttpServletResponse response) {
        e.printStackTrace();
        response.setStatus(e.getStatusCode().value());
        return new ExceptionMessage(e.getErrorCode(), e.getMessage());
    }

    /**
     * 其他异常,如果发生了异常,但不属于上面的异常类别,就会执行此方法
     *
     * @param e
     * @param response
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ExceptionMessage handleAllException(Exception e, HttpServletResponse response) {
        e.printStackTrace();
        return new ExceptionMessage(ExceptionEnum.OTHER_EXCEPTION.getExcepCode(), e.getMessage());
    }
}

此类主要分为了三类异常:
1、可能发生但没有识别判断的异常,如角标越界,空指针一类的,在类中我只写了一个,这个可以自定义添加。
2、可能发生进行抛出的异常,也就是对信息判断,然后抛出指定的异常种类和信息,这个方法是抛出异常通用的。
3、没有想到的异常,我们不能列举所有异常,所以总会有我们没有想到的异常,就执行此方法。
注意:打印返回的信息最好用异常信息,容易定位异常

2.2 辅助类

下面附上2.1中用到的几个类的源码

2.2.1 异常枚举类

package com.casic.finance.exception;

import java.io.Serializable;

/**
 * @author: 董胜得
 * @date: 2021/3/15 10:03
 * 此类为:
 * 主要提供的功能为:自定义异常的编码和信息类
 */
public enum ExceptionEnum implements Serializable {
    ARRAY_INDEX_OUT_OF_BOUND("200001","数组角标越界异常"),
    NULL_POINTER_EXCEPTION("200002","空指针异常"),
    SQL_EXCEPTION("200010","sql语句查询异常"),
    OTHER_EXCEPTION("200030","其他异常"),
    ;
    /**
     * 异常代码
     */
    private String excepCode;
    /**
     * 异常信息
     */
    private String excepMessage;

    ExceptionEnum() {
    }

    ExceptionEnum(String excepCode, String excepMessage) {
        this.excepCode = excepCode;
        this.excepMessage = excepMessage;
    }

    public String getExcepCode() {
        return excepCode;
    }

    public void setExcepCode(String excepCode) {
        this.excepCode = excepCode;
    }

    public String getExcepMessage() {
        return excepMessage;
    }

    public void setExcepMessage(String excepMessage) {
        this.excepMessage = excepMessage;
    }
}

2.2.1 异常信息类

package com.casic.finance.exception;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @author: 董胜得
 * @date: 2021/3/12 18:09
 * 此类为:
 * 主要提供的功能为:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ExceptionMessage implements Serializable {
    private static final long serialVersionUID = 8065583911104112360L;
    private String excepCode;
    private String excepMessage;
}

2.2.1 自定义异常类

package com.casic.finance.exception;

import org.springframework.http.HttpStatus;

/**
 * @author: 董胜得
 * @date: 2021/3/12 18:10
 * 此类为:
 * 主要提供的功能为:
 */
public class MyThrowException extends RuntimeException  {
    private static final long serialVersionUID = 8109469326798389194L;
    protected HttpStatus statusCode = HttpStatus.INTERNAL_SERVER_ERROR;


    private String errorCode;


    public HttpStatus getStatusCode() {
        return statusCode;
    }

    public void setStatusCode(HttpStatus statusCode) {
        this.statusCode = statusCode;
    }

    public MyThrowException(String errorCode, String message) {
        super(message);
        this.errorCode = errorCode;
    }

    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }
}

在我的工程中异常信息处理是放在一个包中,可以直接拷贝复用,如下:
springboot统一拦截全局异常处理_第1张图片

2.3 测试类

2.3.1 测试没有判断和捕获的异常

package com.casic.finance.controller;

import com.casic.finance.exception.MyThrowException;
import com.casic.integrationFrame.common.http.HttpResult;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("test")
@CrossOrigin
public class TestController {
    Logger logger = LoggerFactory.getLogger(TestController.class);
    
    @GetMapping(value = "/exception")
    @ApiOperation(value = "测试异常请求")
    public HttpResult exception() {
        if (1/0==3)
            throw new MyThrowException("505","服务异常");
        return HttpResult.ok("hello");
    }
}

上面代码在执行1/0的时候抛出了异常,这个异常属于我们没有考虑到的异常,属于其他类别。返回结果如下:

{
  "excepCode": "200030",
  "excepMessage": "/ by zero"
}

2.3.2 测试自定义抛出异常

package com.casic.finance.controller;

import com.casic.finance.exception.MyThrowException;
import com.casic.integrationFrame.common.http.HttpResult;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("test")
@CrossOrigin
public class TestController {
    Logger logger = LoggerFactory.getLogger(TestController.class);
    
    @GetMapping(value = "/exception")
    @ApiOperation(value = "测试异常请求")
    public HttpResult exception() {
        if (true)
            throw new MyThrowException("200050","服务异常");
        return HttpResult.ok("hello");
    }
}

上面代码执行throw new MyThrowException(“505”,“服务异常”),这个异常属于我们直接抛出的异常,我们可以自定义异常的代码和错误信息

3 结语

以上就是本章内容了,欢迎大家一起讨论,共同学习

你可能感兴趣的:(spring,boot,exception,spring,java)