什么是全局异常处理
当我看到同事的代码,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注解的源代码
也就是说,该注解下有@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());
}
}
}
这样只要你模块的控制层类去实现这个接口,就可以处理你模块的异常啦。
注解异常处理
未完待续。。。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。