首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

从零搭建后端框架——异常统一处理的三种方式

前言

项目在运行时出现异常时,如若没有对异常进行捕获并处理,就会出现如下页面:

这样显然对用户是极其不友好的。 后端不应该直接返回错误页面,而应返回统一的错误信息,比如:

代码语言:js
复制
{ 
"code": 500, 
"data": null, 
"message": "服务异常,请稍后重试" 
} 

然后,前端根据返回的信息,显示友好的提示页面。 Spring提供了三种方式对异常统一处理:

  1. @ExceptionHandler
  2. 实现HandlerExceptionResolver接口
  3. @ControllerAdvice + @ExceptionHandler

下面我们来实际操作下。

具体实现

@ExceptionHandler

在【统一基类、接口、返回对象设计】这一篇文章中, 定义了Controller的基类BaseController,所以只要在BaseController中使用@ExceptionHandler处理异常, 其它Controller继承BaseController即可。实现如下:

代码语言:js
复制
@Slf4j 
public abstract class BaseController { 
 
/** 
* BusinessException 异常处理 
*/ 
@ResponseBody 
@ExceptionHandler(BusinessException.class) 
public ApiResult businessExceptionHandler(BusinessException e) { 
log.error(e.getMessage(), e); 
// do something 
return ApiResult.fail(e.getMessage()); 
} 
 
/** 
* Exception 异常处理 
*/ 
@ResponseBody 
@ExceptionHandler(Exception.class) 
public ApiResult exceptionHandler(Exception e) { 
log.error(e.getMessage(), e); 
return ApiResult.fail("服务异常,请稍后重试"); 
} 
} 

这里对异常BusinessException和Exception进行了处理, BusinessException是约定的业务异常的基类,若是主动抛出一般都要求是BusinessException的子类,都会被businessExceptionHandler处理。 若是其它异常,可能是意想不到的异常,则会被exceptionHandler处理。 统一处理后,返回结果如下:

实现HandlerExceptionResolver接口

代码语言:js
复制
@Slf4j 
@Component 
public class GlobalHandlerExceptionResolver implements HandlerExceptionResolver { 
 
@Override 
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) { 
log.error(e.getMessage(), e); 
ApiResult apiResult; 
if (e instanceof BusinessException) { 
BusinessException be = (BusinessException) e; 
// do something 
apiResult = ApiResult.fail(be.getMessage()); 
} else { 
apiResult = ApiResult.fail("服务异常,请稍后重试"); 
} 
WebUtils.writeJson(response, apiResult); 
return null; 
} 
}  

该方式需要实现HandlerExceptionResolver接口,然后将实现类注入到Spring容器中。 但第一种方式中,通过@ResponseBody注解,Spring就帮我们返回了json格式数据,而这需要自己实现。 这里实现了工具类WebUtils,用于返回json数据,如下:

代码语言:js
复制
public class WebUtils { 
 
private static final Logger log = LoggerFactory.getLogger(WebUtils.class); 
 
private static Gson gson = new GsonBuilder().serializeNulls().create(); 
 
/** 
* 返回json数据 
* 
* @param response 
* @param object 
*/ 
public static void writeJson(HttpServletResponse response, int status, Object object) { 
response.setHeader("Content-Type", "application/json;charset=UTF-8"); 
response.setContentType("application/json;charset=UTF-8"); 
response.setStatus(status); 
PrintWriter out = null; 
try { 
String data = object instanceof String ? (String) object : gson.toJson(object); 
out = response.getWriter(); 
out.print(data); 
out.flush(); 
} catch (Exception e) { 
log.error(e.getMessage(), e); 
} finally { 
if (out != null) { 
out.close(); 
} 
} 
} 
 
/** 
* 返回json数据 
* 
* @param response 
* @param object 
*/ 
public static void writeJson(HttpServletResponse response, Object object) { 
writeJson(response, HttpServletResponse.SC_OK, object); 
} 
 
/** 
* 返回json数据 
* 
* @param response 
* @param object 
*/ 
public static void writeJson(ServletResponse response, Object object) { 
if (response instanceof HttpServletResponse) { 
writeJson((HttpServletResponse) response, object); 
} 
} 
} 

  工具类中使用了Gson,需要引用:

代码语言:js
复制
<dependency> 
<groupId>com.google.code.gson</groupId> 
<artifactId>gson</artifactId> 
</dependency> 

@ControllerAdvice + @ExceptionHandler

该方式与第一种方式类似,如下:

代码语言:js
复制
@Slf4j 
@ControllerAdvice 
public class GlobalExceptionHandler { 
 
/** 
* BusinessException 异常处理 
*/ 
@ResponseBody 
@ExceptionHandler(BusinessException.class) 
public ApiResult businessExceptionHandler(BusinessException e) { 
log.error(e.getMessage(), e); 
// do something 
return ApiResult.fail(e.getMessage()); 
} 
 
/** 
* Exception 异常处理 
*/ 
@ResponseBody 
@ExceptionHandler(Exception.class) 
public ApiResult exceptionHandler(Exception e) { 
log.error(e.getMessage(), e); 
return ApiResult.fail("服务异常,请稍后重试"); 
} 
} 

总结

三种方式都能很好对异常进行统一处理,但是一般推荐使用@ControllerAdvice + @ExceptionHandler方式, 这样能够使异常处理与业务逻辑分离,并且不用自己处理Json数据返回。

源码

github.com/zhuqianchan…

  • 发表于:
  • 原文链接http://news.51cto.com/art/202005/617439.htm
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券