java实现统一异常处理的示例
对于Dao层 和Service产生的异常要一直网上抛,直至Controller层,但是对于controller层不能处理的异常也不能直接抛给前端。
为什么不能在service处理异常?
答:Service 层往往涉及数据库事务,出现异常同样不适合捕获,否则事务无法自动回滚。此外 Service 层涉及业务逻辑,有些业务逻辑执行中遇到业务异常,可能需要在异常后转入分支业务流程。如果业务异常都被框架捕获了,业务功能就会不正常。【引用:极客时间的Java业务开发常见错误100例】
实现统一异常处理:
在spring框架下实现一个异常处理的类,用 @RestControllerAdvice + @ExceptionHandler
进行修饰:
即@RestControllerAdvice默认会拦截 controller类上抛出的不能处理的异常
一个全局异常处理类需要处理三类异常: 1.业务类异常,2.运行时异常 ,3.Error
1.运行时异常
/** * @创建人: liup * @创建时间: 2021/6/18 * @描述 全局异常捕获处理类 */ @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * @Author: liup * @date: 2021/6/18 14:34 方法实现说明: 拦截运行时异常 */ @ExceptionHandler(value = RuntimeException.class) public R runtimeExceptionHandle(RuntimeException e){ log.error("捕捉到运行时异常",e); return R.failed("未知错误"); } }
目前仅是拦截运行时异常
R 是返回的消息体:
那如果不使用GlobalExceptionHandler,会报出什么错误呢?
这个错误是在service层抛出的,当从redis 通过key获取一个已删除的value时,redis返回的是null,但是我没有判断这个value是否为null,就将其打印出来:
log.info(authInfoVo.toString());
注意:这是要返回给前端的,msg的内容,是对用户十分不友好的。
2.Error
RuntimeException只是异常中的一个类,不能包含所有的异常体系,还有一大类是叫Error(系统级异常),所以需要有一个兜底的异常捕获:
/** * @Author: liup * @date: 2021/6/18 15:01 方法实现说明: 捕获系统级异常 */ @ExceptionHandler(value = Throwable.class) public R throwableHandle(Throwable th){ log.error("捕捉到Throwable异常",th); return R.failed("系统异常"); }
和上面那个运行时异常同时存在 。
3.业务类异常
【自己定义的异常】
首先创建业务异常类
/** * @创建人: liup * @创建时间: 2021/6/18 * @描述 业务类异常 */ public class BusinessException extends RuntimeException{ @Getter private final String code; /** * @Author: liup * @date: 2021/6/18 15:10 方法实现说明: 根据消息码【可用枚举类】 构造业务类异常 */ public BusinessException(String code) { this.code = code; } /** * @Author: liup * @date: 2021/6/18 15:08 方法实现说明: 自定义消息体构造业务类异常 */ public BusinessException(String code,String message) { super(message); this.code = code; } /** * @Author: liup * @date: 2021/6/18 15:09 方法实现说明: 根据异常 构造业务类异常 */ public BusinessException(String code,Throwable cause) { super(cause); this.code = code; } }
三种异常拦截同时存在;
/** * @创建人: liup * @创建时间: 2021/6/18 * @描述 全局异常捕获处理类 */ @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * @Author: liup * @date: 2021/6/18 15:14 方法实现说明: 拦截业务类异常 */ @ExceptionHandler(value = BusinessException.class) public R businessExceptionHandle(BusinessException e){ log.error("捕获业务类异常:",e); return R.failed("业务类异常:"+e.getMessage()); } /** * @Author: liup * @date: 2021/6/18 14:34 方法实现说明: 拦截运行时异常 // */ @ExceptionHandler(value = RuntimeException.class) public R runtimeExceptionHandle(RuntimeException e){ log.error("捕捉到运行时异常",e); return R.failed("未知错误:"); } /** * @Author: liup * @date: 2021/6/18 15:01 方法实现说明: 捕获系统级异常 */ @ExceptionHandler(value = Throwable.class) public R throwableHandle(Throwable th){ log.error("捕捉到Throwable异常",th); return R.failed("系统异常"); } }
4.对服务器友好:
以上是对前端友好,但是在服务器上,不是容易定位错误,
但是若是在参数上添加上HttpServletRequest req, HandlerMethod method,就很容易定位到错误
private static int GENERIC_SERVER_ERROR_CODE = 2000; private static String GENERIC_SERVER_ERROR_MESSAGE = "服务器忙,请稍后再试"; @ExceptionHandler public R handle(HttpServletRequest req, HandlerMethod method, Exception ex) { if (ex instanceof BusinessException) { BusinessException exception = (BusinessException) ex; log.warn(String.format("访问 %s -> %s 出现业务异常!", req.getRequestURI(), method.toString()), ex); return R.failed(GENERIC_SERVER_ERROR_MESSAGE); } else if (ex instanceof RuntimeException){ log.error(String.format("访问 %s -> %s 出现运行时异常!", req.getRequestURI(), method.toString()), ex); return R.failed(GENERIC_SERVER_ERROR_MESSAGE); } else { log.error(String.format("访问 %s -> %s 出现系统异常!", req.getRequestURI(), method.toString()), ex); return R.failed(GENERIC_SERVER_ERROR_MESSAGE); } }
到此这篇关于java实现统一异常处理的文章就介绍到这了,更多相关java异常处理内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!