Appearance
项目在运行时出现异常时,如若没有对异常进行捕获并处理,就会出现如下页面:
这样显然对用户是及其不友好的。 后端不应该直接返回错误页面,而应返回统一的错误信息,比如:
{ "code": 500, "data": null, "message": " ==服务异常,请稍后重试==
" } 然后,前端根据返回的信息,显示友好的提示页面。 Spring提供了三种方式对异常统一处理:
@ExceptionHandler- 实现
HandlerExceptionResolver接口 @ControllerAdvice + @ExceptionHandler
下面我们来实际操作下。 具体实现@ExceptionHandler 在【统一基类、接口、返回对象设计】这一篇文章中, 定义了Controller的基类BaseController,所以只要在BaseController中使用@ExceptionHandler处理异常, 其它Controller继承BaseController即可。实现如下:
package com.minchengjianshe.organizationalandpersonal.controller; import com.minchengjianshe.organizationalandpersonal.common.ApiResult; import com.minchengjianshe.organizationalandpersonal.common.Common; import com.minchengjianshe.organizationalandpersonal.exception.BusinessException; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Date; @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接口
package com.minchengjianshe.organizationalandpersonal.exception; import com.minchengjianshe.organizationalandpersonal.common.ApiResult; import com.minchengjianshe.organizationalandpersonal.util.WebUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @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数据,如下: 安装gson依赖 <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.5</version> package com.minchengjianshe.organizationalandpersonal.util; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; /** * @author Zhu.Qianchang * @date 2020-05-21 / 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,需要引用:
- <dependency>
- <groupId>com.google.code.gson</groupId>
- <artifactId>gson</artifactId>
- </dependency>
@ControllerAdvice + @ExceptionHandler 该方式与第一种方式类似,如下:
@Slf4j@ControllerAdvicepublic class GlobalExceptionHandler { /** * BusinessException 异常处理
 */@ResponseBody@ExceptionHandler(BusinessException.class) public ApiResult businessExceptionHandler(BusinessException e) { log.error(e.getMessage(), e); // do somethingreturnApiResult.fail(e.getMessage()); } /** * Exception 异常处理
 */@ResponseBody@ExceptionHandler(Exception.class) publicApiResultexceptionHandler(Exception e) { log.error(e.getMessage(), e); returnApiResult.fail(" ==服务异常,请稍后重试==
"); }} ==复制代码== 总结 三种方式都能很好对异常进行统一处理,但是一般推荐使用@ControllerAdvice + @ExceptionHandler方式, 这样能够使异常处理与业务逻辑分离,并且不用自己处理Json数据返回。 > 来自
<https://juejin.cn/post/6844904164837818376\>
