ErrorInfoBuilder.java 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. package com.simuwang.deploy.components;
  2. import cn.hutool.core.exceptions.ExceptionUtil;
  3. import cn.hutool.core.util.StrUtil;
  4. import com.simuwang.base.common.exception.APIException;
  5. import com.simuwang.base.common.exception.ErrorInfo;
  6. import com.smppw.common.pojo.enums.status.ResultCode;
  7. import jakarta.servlet.ServletException;
  8. import jakarta.servlet.http.HttpServletRequest;
  9. import jakarta.servlet.http.HttpServletResponse;
  10. import jakarta.validation.ConstraintViolationException;
  11. import org.apache.commons.lang3.StringUtils;
  12. import org.apache.shiro.authc.AuthenticationException;
  13. import org.apache.shiro.authc.IncorrectCredentialsException;
  14. import org.apache.shiro.authc.UnknownAccountException;
  15. import org.apache.shiro.authz.UnauthenticatedException;
  16. import org.apache.shiro.authz.UnauthorizedException;
  17. import org.slf4j.Logger;
  18. import org.slf4j.LoggerFactory;
  19. import org.springframework.boot.context.properties.bind.validation.BindValidationException;
  20. import org.springframework.core.Ordered;
  21. import org.springframework.http.HttpStatus;
  22. import org.springframework.http.converter.HttpMessageNotReadableException;
  23. import org.springframework.lang.Nullable;
  24. import org.springframework.stereotype.Component;
  25. import org.springframework.validation.BindException;
  26. import org.springframework.validation.ObjectError;
  27. import org.springframework.web.servlet.HandlerExceptionResolver;
  28. import org.springframework.web.servlet.ModelAndView;
  29. import org.springframework.web.servlet.resource.NoResourceFoundException;
  30. import org.springframework.web.util.WebUtils;
  31. import java.time.LocalDateTime;
  32. import java.util.List;
  33. /**
  34. * @author wangzaijun
  35. * @date 2023/8/12 16:23
  36. * @description 错误信息构造工具
  37. */
  38. @Component
  39. public class ErrorInfoBuilder implements HandlerExceptionResolver, Ordered {
  40. /**
  41. * 错误KEY
  42. */
  43. private final static String ERROR_NAME = "simuwang.error";
  44. private final Logger logger = LoggerFactory.getLogger(this.getClass());
  45. // /**
  46. // * 错误配置(ErrorConfiguration)
  47. // */
  48. // private final ErrorProperties errorProperties;
  49. //
  50. // /**
  51. // * 错误构造器 (Constructor) 传递配置属性:server.xx -> server.error.xx
  52. // */
  53. // public ErrorInfoBuilder(ServerProperties serverProperties) {
  54. // this.errorProperties = serverProperties.getError();
  55. // }
  56. /**
  57. * 构建错误信息.(ErrorInfo)
  58. */
  59. public ErrorInfo getErrorInfo(HttpServletRequest request) {
  60. return getErrorInfo(request, getError(request));
  61. }
  62. /**
  63. * 构建错误信息.(ErrorInfo)
  64. */
  65. public ErrorInfo getErrorInfo(HttpServletRequest request, Throwable error) {
  66. String url = request.getAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE).toString();
  67. ErrorInfo errorInfo = new ErrorInfo();
  68. errorInfo.setTime(LocalDateTime.now().toString());
  69. errorInfo.setUrl(url);
  70. String msg;
  71. int code = getHttpStatus(request).value();
  72. if (error instanceof NoResourceFoundException) {
  73. msg = "请求资源找不到";
  74. } else if (error instanceof UnauthorizedException) {
  75. msg = "没有对应接口的权限";
  76. } else if (error instanceof UnknownAccountException || error instanceof IncorrectCredentialsException) {
  77. msg = ResultCode.AUTH_FAILD.getMsg();
  78. } else if (error instanceof AuthenticationException) {
  79. code = HttpStatus.UNAUTHORIZED.value();
  80. msg = "登录认证失败";
  81. } else if (error instanceof APIException e) {
  82. msg = e.getMsg();
  83. code = e.getCode();
  84. } else if (error instanceof UnauthenticatedException e) {
  85. msg = e.getMessage();
  86. } else if (error instanceof HttpMessageNotReadableException || error instanceof BindValidationException) {
  87. msg = "请求参数错误";
  88. } else if (error instanceof BindException e) {
  89. // 参数绑定或校验错误
  90. List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
  91. msg = allErrors.get(0).getDefaultMessage();
  92. } else if (error instanceof ConstraintViolationException e) {
  93. // 约束验证错误
  94. msg = e.getMessage();
  95. } else {
  96. msg = "未知的错误";
  97. }
  98. errorInfo.setError(msg);
  99. errorInfo.setStatusCode(code);
  100. errorInfo.setReasonPhrase(getHttpStatus(request).getReasonPhrase());
  101. errorInfo.setStackTrace(ExceptionUtil.stacktraceToString(error));
  102. logger.error(StrUtil.format("{} 接口请求错误:{}", url, errorInfo.getStackTrace()));
  103. return errorInfo;
  104. }
  105. /**
  106. * 获取错误.(Error/Exception)
  107. *
  108. * @see org.springframework.boot.web.servlet.error.DefaultErrorAttributes #addErrorDetails
  109. */
  110. public Throwable getError(HttpServletRequest request) {
  111. //根据HandlerExceptionResolver接口方法来获取错误.
  112. Throwable error = (Throwable) request.getAttribute(ERROR_NAME);
  113. //根据Request对象获取错误.
  114. if (error == null) {
  115. error = (Throwable) request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE);
  116. }
  117. //当获取错误非空,取出RootCause.
  118. if (error != null) {
  119. while (error instanceof ServletException && error.getCause() != null) {
  120. error = error.getCause();
  121. }
  122. } else {
  123. //当获取错误为null,此时我们设置错误信息即可.
  124. String message = (String) request.getAttribute(WebUtils.ERROR_MESSAGE_ATTRIBUTE);
  125. if (StringUtils.isEmpty(message)) {
  126. HttpStatus status = getHttpStatus(request);
  127. message = "Unknown Exception But " + status.value() + " " + status.getReasonPhrase();
  128. }
  129. error = new Exception(message);
  130. }
  131. return error;
  132. }
  133. /**
  134. * 获取通信状态(HttpStatus)
  135. *
  136. * @see org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController #getStatus
  137. */
  138. public HttpStatus getHttpStatus(HttpServletRequest request) {
  139. Integer statusCode = (Integer) request.getAttribute(WebUtils.ERROR_STATUS_CODE_ATTRIBUTE);
  140. try {
  141. return statusCode != null ? HttpStatus.valueOf(statusCode) : HttpStatus.INTERNAL_SERVER_ERROR;
  142. } catch (Exception ex) {
  143. return HttpStatus.INTERNAL_SERVER_ERROR;
  144. }
  145. }
  146. // /**
  147. // * 获取堆栈轨迹(StackTrace)
  148. // *
  149. // * @see org.springframework.boot.web.servlet.error.DefaultErrorAttributes #addStackTrace
  150. // */
  151. // public String getStackTraceInfo(Throwable error, boolean flag) {
  152. // if (!flag) {
  153. // return "omitted";
  154. // }
  155. // StringWriter stackTrace = new StringWriter();
  156. // error.printStackTrace(new PrintWriter(stackTrace));
  157. // stackTrace.flush();
  158. // return stackTrace.toString();
  159. // }
  160. // /**
  161. // * 判断是否包含堆栈轨迹.(isIncludeStackTrace)
  162. // *
  163. // * @see org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController #isIncludeStackTrace
  164. // */
  165. // public boolean isIncludeStackTrace(HttpServletRequest request) {
  166. //
  167. // //读取错误配置(server.error.include-stacktrace=NEVER)
  168. // ErrorProperties.IncludeAttribute includeStacktrace = errorProperties.getIncludeStacktrace();
  169. //
  170. // //情况1:若IncludeStacktrace为ALWAYS
  171. // if (includeStacktrace == ErrorProperties.IncludeAttribute.ALWAYS) {
  172. // return true;
  173. // }
  174. // //情况2:若请求参数含有trace
  175. // if (includeStacktrace == ErrorProperties.IncludeAttribute.ON_PARAM) {
  176. // String parameter = request.getParameter("trace");
  177. // return parameter != null && !"false".equalsIgnoreCase(parameter);
  178. // }
  179. // //情况3:其它情况
  180. // return false;
  181. // }
  182. /**
  183. * 保存错误/异常.
  184. *
  185. * @see org.springframework.web.servlet.DispatcherServlet #processHandlerException 进行选举HandlerExceptionResolver
  186. */
  187. @Override
  188. public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
  189. request.setAttribute(ERROR_NAME, ex);
  190. return null;
  191. }
  192. /**
  193. * 提供优先级 或用于排序
  194. */
  195. @Override
  196. public int getOrder() {
  197. return HIGHEST_PRECEDENCE;
  198. }
  199. }