springboot之错误处理

2019-12-13  本文已影响0人  eliteTyc
  1. 错误机制处理
    1. 默认效果

      • 浏览器返回一个错误页面,包含错误码,错误信息
      • 其他客户端返回json数据,包含错误码,错误信息
    2. ErrorMvcAutoConfiguration错误处理的自动配置类

      • DefaultErrorAttributes:获取错误页面能展示的错误信息
         @Override
          public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
              Map<String, Object> errorAttributes = new LinkedHashMap<>();
              errorAttributes.put("timestamp", new Date());
              addStatus(errorAttributes, webRequest);
              addErrorDetails(errorAttributes, webRequest, includeStackTrace);
              addPath(errorAttributes, webRequest);
              return errorAttributes;
          }
      
      • BasicErrorController
      //处理默认/error请求
      @Controller
      @RequestMapping("${server.error.path:${error.path:/error}}")
      public class BasicErrorController extends AbstractErrorController {
      
      //返回html数据
      @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
      public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
          HttpStatus status = getStatus(request);
          Map<String, Object> model = Collections
                  .unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
          response.setStatus(status.value());
          ModelAndView modelAndView = resolveErrorView(request, response, status, model);
          return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
      }
      //返回json类型的数据
      @RequestMapping
      public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
          HttpStatus status = getStatus(request);
          if (status == HttpStatus.NO_CONTENT) {
              return new ResponseEntity<>(status);
          }
          Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
          return new ResponseEntity<>(body, status);
      }
      
      • ErrorPageCustomizer
      //系统出现错误以后来到error请求进行处理,web.xml注册的错误页面规则
      @Value("${error.path:/error}")
      private String path = "/error";
      
      • DefaultErrorViewResolver
    - 错误处理步骤:一旦系统出现4XX和5XX的错误时,ErrorPageCustomizer就会生效,就会来到/error请求处理,就会被BasicErrorController处理
    ,DefaultErrorViewResolver决定响应的页面是哪个,DefaultErrorAttributes获取能展示的错误信息
    - 页面能展示的错误信息:
        - timestamp:时间戳
        - status:状态码
        - error:错误提示
        - exception:异常对象
        - message:异常消息
        - errors:JSR303数据校验的错误
3. 如何定制错误响应
    - 定制错误响应页面:
        - 如果使用了模板引擎
            - 直接在resource目录下的template目录下新建error/状态码.html【将精确错误状态码.html放在模板引擎的error目录下】
            - 以文件名4xx.html和5xx.html文件放在模板引擎的目录下,如果没有精确的状态码会直接使用4xx或者5xx的页面返回
        - 没有模板引擎
            - 可以直接放在静态资源文件夹下,可以直接获取出来
        - 如果模板引擎和静态资源文件夹下都没有找到错误页面,就显示springboot的默认空白错误页面
        ```
        @Override
        public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
                throws Exception {
            if (response.isCommitted()) {
                String message = getMessage(model);
                logger.error(message);
                return;
            }
            response.setContentType(TEXT_HTML_UTF8.toString());
            StringBuilder builder = new StringBuilder();
            Date timestamp = (Date) model.get("timestamp");
            Object message = model.get("message");
            Object trace = model.get("trace");
            if (response.getContentType() == null) {
                response.setContentType(getContentType());
            }
            builder.append("<html><body><h1>Whitelabel Error Page</h1>").append(
                    "<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>")
                    .append("<div id='created'>").append(timestamp).append("</div>")
                    .append("<div>There was an unexpected error (type=").append(htmlEscape(model.get("error")))
                    .append(", status=").append(htmlEscape(model.get("status"))).append(").</div>");
            if (message != null) {
                builder.append("<div>").append(htmlEscape(message)).append("</div>");
            }
            if (trace != null) {
                builder.append("<div style='white-space:pre-wrap;'>").append(htmlEscape(trace)).append("</div>");
            }
            builder.append("</body></html>");
            response.getWriter().append(builder.toString());
        }
        ```
        - 抛出一个自己的异常信息
            1. 创建一个自己的异常信息类
            ```
            public class UserNotExistException extends RuntimeException {
                public UserNotExistException() {
                    super("用户不存在");
                }
            }
            ```
            2. templates/error/5xx.html新建文件
            ```html
            <!DOCTYPE html>
            <html lang="en" >
            <head>
                <meta charset="UTF-8">
                <title>错误</title>
            </head>
            <body>
            <h1 >[[${status}]]</h1>
            <h1 >[[${timestamp}]]</h1>
            <h1 >[[${exception}]]</h1>
            <h1 >[[${message}]]</h1>
            </body>
            </html>
            ```
            3. 写一个接口,抛出自己的异常
    - **定制错误响应json信息**
        - 写一个MyExceptionHandler
        ```
        @ControllerAdvice
        public class MyExceptionHandler {
        
        //    指定返回的数据转为json
            @ResponseBody
        //    设置当系统抛出哪个异常的时候执行下面的处理
            @ExceptionHandler(UserNotExistException.class)
            public Map<String, Object> handleException(Exception e){
                Map<String,Object> map = new HashMap<>();
                map.put("code","423");
                map.put("msg",e.getMessage());
                return map;
        
            }
        }

        ```
        - 此时抛出的UserNotException前端接收到的数据为
        ```json
        {"msg":"用户不存在","code":"423"}
        ```
上一篇 下一篇

猜你喜欢

热点阅读