基于springboot的全局异常处理
1 编写ResultBuilder类
package com.test.domi.common.system; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.web.ErrorProperties; import org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeStacktrace; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; import java.io.StringWriter; public class ResultBuilder implements HandlerExceptionResolver,Ordered { private static final Logger LOGGER = LoggerFactory.getLogger(ResultBuilder.class); private static final String ERROR_NAME = "fp.error"; private ErrorProperties errorProperties; public ErrorProperties getErrorProperties() { return errorProperties; } public void setErrorProperties(ErrorProperties errorProperties) { this.errorProperties = errorProperties; } public ResultBuilder(ServerProperties serverProperties){ LOGGER.info("serverProperties:{}",serverProperties.getError()); this.errorProperties = serverProperties.getError(); } public ResultInfo getErrorInfo(HttpServletRequest request){ return this.getErrorInfo(request,this.getError(request)); } public ResultInfo getErrorInfo(HttpServletRequest request,Throwable error){ ResultInfo resultInfo = new ResultInfo(); resultInfo.setCode(Integer.toString(this.getHttpStatus(request).value())); resultInfo.setMessage(this.getHttpStatus(request).getReasonPhrase()); resultInfo.setData((Object)null); return resultInfo; } public Throwable getError(HttpServletRequest request){ Throwable error = (Throwable)request.getAttribute("fp.error"); if (error == null) { error = (Throwable)request.getAttribute("javax.servlet.error.exception"); } if (error != null) { while (error instanceof ServletException && ((Throwable) error).getCause() != null) { error = ((Throwable) error).getCause(); } } else { String message = (String)request.getAttribute("javax.servlet.error.message"); if (StringUtils.isNotEmpty(message)) { HttpStatus status = this.getHttpStatus(request); message = "Unknown Exception With" + status.value() + " " + status.getReasonPhrase(); } error = new Exception(message); } return (Throwable)error; } public HttpStatus getHttpStatus(HttpServletRequest request){ Integer statusCode = (Integer)request.getAttribute("javax.servlet.error.status_code"); try { return statusCode != null?HttpStatus.valueOf(statusCode.intValue()):HttpStatus.INTERNAL_SERVER_ERROR; } catch (Exception var4) { return HttpStatus.INTERNAL_SERVER_ERROR; } } public String getStackTraceInfo(Throwable error,boolean isPrintStackTrace){ if (!isPrintStackTrace) { return "omitted"; } else { try { StringWriter stackTrace = new StringWriter(); Throwable var4 = null; String var5; try { error.printStackTrace(new PrintWriter(stackTrace)); stackTrace.flush(); var5 = stackTrace.toString(); } catch (Throwable var15) { var4 = var15; throw var15; } finally { if (stackTrace != null) { if (var4 != null) { try { stackTrace.close(); } catch (Throwable var14) { var4.addSuppressed(var14); } } else { stackTrace.close(); } } } return var5; } catch (Exception var17) { var17.printStackTrace(); return "print stack trace error"; } } } public boolean isInCludeStackTrace(HttpServletRequest request){ IncludeStacktrace includeStacktrace = this.errorProperties.getIncludeStacktrace(); if (includeStacktrace == IncludeStacktrace.ALWAYS) { return true; } else if (includeStacktrace != includeStacktrace.ON_TRACE_PARAM) { return false; }else { String parameter = request.getParameter("trace"); return parameter != null && !"false".equals(parameter.toLowerCase()); } } @Override public int getOrder() { return 0; } @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) { httpServletRequest.setAttribute("fp.error", e); return null; } }
2 编写ExceptionConfig类(传入ServerProperties ,实例化ResultBuilder。springboot中ErrorProperties类定义了异常自动映射路径@Value("${error.path:/error}")private String path = "/error")
package com.test.domi.config; import com.test.domi.common.system.ResultBuilder; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import javax.annotation.Resource; @Configuration @Order(Ordered.HIGHEST_PRECEDENCE) public class ExceptionConfig { @Resource private ServerProperties serverProperties; @Bean public ResultBuilder resultBuilder(){ return new ResultBuilder(serverProperties); } }
ErrorProperties:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.boot.autoconfigure.web; import org.springframework.beans.factory.annotation.Value; public class ErrorProperties { @Value("${error.path:/error}") private String path = "/error"; private ErrorProperties.IncludeStacktrace includeStacktrace; public ErrorProperties() { this.includeStacktrace = ErrorProperties.IncludeStacktrace.NEVER; } public String getPath() { return this.path; } public void setPath(String path) { this.path = path; } public ErrorProperties.IncludeStacktrace getIncludeStacktrace() { return this.includeStacktrace; } public void setIncludeStacktrace(ErrorProperties.IncludeStacktrace includeStacktrace) { this.includeStacktrace = includeStacktrace; } public static enum IncludeStacktrace { NEVER, ALWAYS, ON_TRACE_PARAM; private IncludeStacktrace() { } } }
3 定义全局 异常Controller接管所有抛出的异常
package com.test.domi.controller; import com.test.domi.common.system.ResultBuilder; import com.test.domi.common.system.ResultInfo; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.web.ErrorController; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; @Controller @RequestMapping("${error.path:/error}") //来自ErrorProperties设置的默认异常路径 public class GlobalErrorController implements ErrorController { private final static String DEFAULT_ERROR_VIEW = "/error"; private final static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(GlobalErrorController.class); @Resource private ResultBuilder resultBuilder; /** * 针对404的场景 * @return */ @Override public String getErrorPath(){ return resultBuilder.getErrorProperties().getPath(); } /** * 如果请求头返回的类型是text/html,则返回到错误信息页面 * @param request * @return */ @RequestMapping(produces = MediaType.TEXT_HTML_VALUE) @ResponseBody public ModelAndView errorHtml(HttpServletRequest request) { return new ModelAndView(DEFAULT_ERROR_VIEW,"errorInfo",resultBuilder.getErrorInfo(request)); } /** * 除了text/html的请求头信息,其它都返回json格式 * @param request 请求对象 * @return 错误信息字符串 在ResultInfo中封装错误信息 */ @RequestMapping(produces = {MediaType.APPLICATION_JSON_VALUE}) @ResponseBody public ResultInfo error(HttpServletRequest request){ return resultBuilder.getErrorInfo(request); } }
配置完毕,后台的未被捕获的异常将从dao层到dervice层到controller层,然后被全局异常controller统一接管,封装之后返回给前台!