什么是全局异常处理

当我看到同事的代码,controller层,service层,一箩筐try-catch,让我对同事的代码瞬间没了"可读欲",大量的try-catch代码不只是观赏性的陨落,还是我们的程序产生了大量的冗余代码,这个时候,"全局异常处理"就诞生了。

全局性异常处理

全局性异常处理,是项目中所有的异常,全部都会跑到该全局异常类中去处理,并统一返回。
首先,要处理全局异常,自定义的异常是必不可少的,因为,我们需要自定义异常去处理我们的业务。

1. 定义业务异常

public class BaseException extends Exception {

    private static final long serialVersionUID = 5860621285152904631L;

    public BaseException() {
    }

    public BaseException(Throwable cause) {
        super(cause);
    }

    public BaseException(String message) {
        super(message);
    }
}

2. 定义全局异常处理类

@RestControllerAdvice
@Slf4j
public class GlobalHandler {

    /**
     * 自定义异常
     *
     * @param e 异常
     * @return BaseResult
     */
    @ExceptionHandler(BaseException.class)
    public BaseResult doBaseExceptionHandler(BaseException e) {
        system(e);
        return BaseResult.buildFailure(HttpStatus.BAD_REQUEST.value(), e.getMessage());
    }

    /**
     * 参数异常
     *
     * @param e 异常
     * @return BaseResult
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public BaseResult doMethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        system(e);
        return BaseResult.buildFailure(HttpStatus.BAD_REQUEST.value(), e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
    }

    /**
     * 参数异常
     *
     * @param e 异常
     * @return BaseResult
     */
    @ExceptionHandler(NullPointerException.class)
    public BaseResult doNullPointerExceptionHandler(NullPointerException e) {
        system(e);
        return BaseResult.buildFailure(HttpStatus.BAD_REQUEST.value(), e.getMessage());
    }

    /**
     * 运行时异常
     *
     * @param e 异常
     * @return BaseResult
     */
    @ExceptionHandler(RuntimeException.class)
    public BaseResult doRuntimeExceptionHandler(RuntimeException e) {
        system(e);
        return BaseResult.buildFailure(HttpStatus.BAD_REQUEST.value(), e.getMessage());
    }

    @ExceptionHandler(LoginException.class)
    public BaseResult doAuthExcetion(LoginException e) {
        system(e);
        return BaseResult.buildFailure(HttpStatus.BAD_REQUEST.value(), e.getMessage());
    }

    @ExceptionHandler(AuthException.class)
    public BaseResult doAuthExcetion(AuthException e) {
        system(e);
        return BaseResult.buildFailure(HttpStatus.BAD_REQUEST.value(), e.getMessage());
    }

    /**
     * 参数异常
     *
     * @param e 异常
     * @return BaseResult
     */
    @ExceptionHandler(BindException.class)
    public BaseResult doBindExceptionHandler(BindException e) {
        system(e);
        return BaseResult.buildFailure(HttpStatus.BAD_REQUEST.value(), e.getBindingResult().getFieldError().getDefaultMessage());
    }

    /**
     * 参数异常
     *
     * @param e 异常
     * @return BaseResult
     */
    @ExceptionHandler(Exception.class)
    public BaseResult doExceptionHandler(Exception e) {
        system(e);
        return BaseResult.buildFailure(HttpStatus.BAD_REQUEST.value(), e.getMessage());
    }

    /**
     * 输出到控制台
     *
     * @param e 异常
     */
    public void system(Throwable e) {
        StackTraceElement element = e.getStackTrace()[0];
        log.error("[异常报错信息]:{}[出现异常文件名]:{}[出现异常所在类]:{}[出现异常所在方法]:{}[出现异常具体行数]:{}",
                e.getMessage(), element.getFileName(), element.getClassName(), element.getMethodName(), element.getLineNumber());
    }
}

此时我们的自定义异常继承了最大的程序异常-->Exception,当我们处理业务逻辑时,可以填写具体的描述信息,给前端返回。下面时接收自定义异常的全局异常处理类。
@RestController注解本身使用@ControllerAdvicer和@ResponseBody注解。
使用了@RestControllerAdvice注解的类会被看作一个ControllerAdvicer,
而该类中所有使用@ExceptionHandler注解的方法都默认使用了的@ResponseBody注解。

以下是RestControllerAdvice注解的源代码
image.png
也就是说,该注解下有@ControllerAdvice注解和@ResponseBody注解,属于组合注解,也就是说,该注解下的类,是全局异常处理类,返回的参数是以Json的形式返回的。

注解@ExceptionHandler:标明我们该方法拦截的异常类型,如果拦截Exception异常,则为@ExceptionHandler(Exception.class)

模块异常处理

当我们的项目组中,并不是所有人都想用这个全局异常处理,来拦截我们项目中所有的异常的时候,那我们可以用接口的形式,谁用,则谁的控制层去继承。

1. 定义异常处理模块接口
public interface DataExceptionSolver {


    /**
     * 定义统一异常处理
     *
     * @param e 参数
     * @return Response
     */
    @ExceptionHandler
    @ResponseBody
    default Response exceptionHandler(Exception e) {
        try {
            throw e;
        } catch (CustomException exception) {
            exception.printStackTrace();
            return Response.buildFailure(String.valueOf(HttpStatus.BAD_REQUEST.value()), exception.getMessage());
        } catch (IllegalAccessException exception) {
            exception.printStackTrace();
            return Response.buildFailure(String.valueOf(HttpStatus.UNAUTHORIZED.value()), "访问权限异常:" + exception.getMessage());
        } catch (NullPointerException exception) {
            exception.printStackTrace();
            return Response.buildFailure(String.valueOf(HttpStatus.UNAUTHORIZED.value()), "空指针异常" + exception.getMessage());
        } catch (BadSqlGrammarException exception) {
            exception.printStackTrace();
            return Response.buildFailure(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()), "sql语法异常:" + exception.getMessage());
        } catch (SQLSyntaxErrorException exception) {
            return Response.buildFailure(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()), "sql语法非法符号异常:" + exception.getMessage());
        } catch (SQLException exception) {
            exception.printStackTrace();
            return Response.buildFailure(String.valueOf(HttpStatus.UNAUTHORIZED.value()), "操作数据库异常" + e.getMessage());
        } catch (RuntimeException exception) {
            exception.printStackTrace();
            return Response.buildFailure(String.valueOf(HttpStatus.UNAUTHORIZED.value()), "运行时异常" + e.getMessage());
        } catch (Exception exception) {
            exception.printStackTrace();
            return Response.buildFailure(String.valueOf(HttpStatus.UNAUTHORIZED.value()), "程序最大异常:" + e.getMessage());
        }
    }
}

这样只要你模块的控制层类去实现这个接口,就可以处理你模块的异常啦。

注解异常处理

未完待续。。。


Zeran
32 声望4 粉丝

学而不思则罔,思而不学则殆。