当前位置: 首页 > 科技观察

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

时间:2023-03-13 08:55:39 科技观察

前言运行时出现异常,如果不捕获并处理异常,就会出现如下页面:这显然对用户极其不友好的用户。后端不要直接返回错误页面,而应该返回统一的错误信息,如:{"code":500,"data":null,"message":"服务异常,请稍后再试"}复制code然后,前端根据返回的信息显示一个友好的提示页面。Spring统一提供了三种异常处理方式:@ExceptionHandler实现了HandlerExceptionResolver接口@ControllerAdvice+@ExceptionHandler我们来看看实际操作。《统一基类、接口、返回对象设计》一文中@ExceptionHandler的具体实现定义了Controller的基类BaseController,所以只要在BaseController中使用@ExceptionHandler来处理异常,其他Controller就可以继承BaseController。实现如下:@Slf4jpublicabstractclassBaseController{/***BusinessException异常处理*/@ResponseBody@ExceptionHandler(BusinessException.class)publicApiResultbusinessExceptionHandler(BusinessExceptione){log.error(e.getMessage(),e);//dosomethingreturnApiResult.fail(e.getMessage());}/***Exception异常处理*/@ResponseBody@ExceptionHandler(Exception.class)publicApiResultexceptionHandler(Exceptione){log.error(e.getMessage(),e);returnApiResult.fail("服务异常,请稍后重试");}}复制代码这里处理异常的BusinessException和Exception。BusinessException是约定业务异常的基类。如果是主动抛出,一般要求是BusinessException的子类,由businessExceptionHandler处理。如果是其他异常,可能是意想不到的异常,会由exceptionHandler处理。统一处理后,返回结果如下:实现HandlerExceptionResolver接口@Slf4j@ComponentpublicclassGlobalHandlerExceptionResolverimplementsHandlerExceptionResolver{@OverridepublicModelAndViewresolveException(HttpServletRequestrequest,HttpServletResponseresponse,Objecto,Exceptione){log.error(e.getMessage(),e);ApiResultapiResult;if(einstanceofBusinessException){BusinessExceptionbe=(BusinessException)e;//dosomethingapiResult=ApiResult.fail(be.getMessage());}else{apiResult=ApiResult.fail("服务异常,请稍后重试");}WebUtils.writeJson(response,apiResult);returnnull;}}复制代码该方法需要实现HandlerExceptionResolver接口,然后将实现类注入到Spring容器中。但是第一种方式,Spring通过@ResponseBody注解帮我们返回json格式的数据,这个需要我们自己实现。这里实现工具类WebUtils返回json数据,如下:*@paramresponse*@paramobject*/publicstaticvoidwriteJson(HttpServletResponseresponse,intstatus,Objectobject){response.setHeader("Content-Type","application/json;charset=UTF-8");response.setContentType("application/json;charset=UTF-8");response.setStatus(status);PrintWriterout=null;try{Stringdata=objectinstanceofString?(String)object:gson.toJson(object);out=response.getWriter();out.print(data);out.flush();}catch(Exceptione){log.error(e.getMessage(),e);}finally{if(out!=null){out.close();}}}/***返回json数据**@paramresponse*@paramobject*/publicstaticvoidwriteJson(HttpServletResponseresponse,Objectobject){writeJson(response,HttpServletResponse.SC_OK,object);}/***返回json数据**@paramresponse*@paramobject*/publicstaticsonvoidSwriteJResponseresponse,Objectobject){if(responseinstanceofHttpServletResponse){writeJson((HttpServletResponse)response,object);}}}复制代码工具类中使用了gson,需要参考:com.google.code.gsongson复制代码@ControllerAdvice+@ExceptionHandler这个方法和第一种方法类似,如下:@Slf4j@ControllerAdvicepublicclassGlobalExceptionHandler{/***BusinessException异常处理*/@ResponseBody@ExceptionHandler(BusinessException.class)publicApiResultbusinessExceptionHandler(BusinessExceptione){log.error(e.getMessage(),e);//dosomethingreturnApiResult.fail(e.getMessage());}/***Exception异常处理*/@ResponseBody@ExceptionHandler(Exception.class)publicApiResultexceptionHandler(Exceptione){log.error(e.getMessage(),e);returnApiResult.fail("服务异常,请稍后再试");}}这样处理比较好异常统一,但一般推荐使用@ControllerAdvice+@ExceptionHandler,可以将异常处理和业务逻辑分离,返回源码,无需自己处理Json数据github.com/zhuqianchan...