SpringBoot Web开发——异常处理

目录

1、错误处理

1.1、默认规则

1.2、自定义错误规则

1.2.1、自定义错误页

1.2.2、@ControllerAdvice+@ExceptionHandler处理全局异常;

1.2.3、@ResponseStatus+自定义异常

1.2.4、自定义HandlerExceptionResolver(异常解析器)处理异常

2、异常处理自动配置原理

2.1、容器中的组件

2.1.1、DefaultErrorAttributes

2.1.2、BasicErrorController

2.1.3、DefaultErrorViewResolver

3、异常处理步骤流程


1、错误处理

1.1、默认规则

1)默认情况下,Spring Boot提供/error处理所有错误的映射

2)不同客户端的返回页面不同:

  • 对于机器客户端,将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。

  • 对于浏览器客户端,响应一个“ whitelabel”错误视图,以HTML格式呈现相同的数据

1.2、自定义错误规则

1.2.1、自定义错误页

使用方法:

        在templates/error中添加4xx、5xx页面,会被自动解析

         error/404.html error/5xx.html;有精确的错误状态码页面就匹配精确,没有就找 4xx.html;如果都没有就触发白页

1.2.2、@ControllerAdvice+@ExceptionHandler处理全局异常;

使用方法:

        1、在异常类标注@ControllerAdvice注解,在方法上标注@ExceptionHandler注解。

        2、@ExceptionHandler注解含有参数,用于表示可以处理的异常。

              代码中为数学运算异常和空指针异常。

        3、此异常不需要调用,在发生自定义异常时,由框架自动返回异常

异常代码:

/**
 * 处理整个Web的异常
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    //异常处理器,用于处理数学运算异常和空指针异常
    @ExceptionHandler({ArithmeticException.class, NullPointerException.class})
    public String handlerArithException(Exception e) {

        log.error("异常是:{}", e);
        return "login";
    }
}

原理:底层是 ExceptionHandlerExceptionResolver 支持的

1.2.3、@ResponseStatus+自定义异常

使用方法:

        @ResponseStatus(value= HttpStatus.FORBIDDEN, reason = "用户数量太多")

                1.1、value为发生自定义错误时需要返回的Http状态码(4xx,5xx等)

                1.2、reason为发生错误时页面所返回的错误信息

                1.3、在需要的地方,调用定义的异常方法

异常代码:

//返回403异常,自定义提示信息:用户数量太多
@ResponseStatus(value= HttpStatus.FORBIDDEN, reason = "用户数量太多")
public class UserTooManyException extends RuntimeException {
    public UserTooManyException() {

    }
//    public UserTooManyException(String message) {
//        super(message);
//    }
}

自定义异常调用代码:

@Controller
public class TableController {

    @GetMapping("dynamic_table")
    public String dynamic_table(Model model) {

        model.addAttribute("users", users);

        if (users.size() > 3) {
            throw new UserTooManyException();
        }

        return "/table/dynamic_table";
    }

异常页面信息:

原理:

        底层是 ResponseStatusExceptionResolver ,把responsestatus注解的信息底层调用response.sendError(statusCode, resolvedReason);tomcat发送的/error

1.2.4、自定义HandlerExceptionResolver(异常解析器)处理异常

使用方法:

        1、定义 HandlerExceptionResolver(异常解析器) 接口的实现类

        2、重写 HandlerExceptionResolver 中的 resolveException 方法

        3、在 response.sendError(511, "我喜欢的错误"); 中加入异常返回的状态码和错误信息

        4、注意调整自定义的异常解析器的优先级

        5、此异常不需要调用,在发生异常时,由框架自动返回异常

异常代码:

@Order(value = Ordered.HIGHEST_PRECEDENCE)  //设置异常解析器的优先级
@Component
public class CustomerHandlerExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response,
                                          Object handler, Exception ex) {
        try {
            response.sendError(511, "我喜欢的错误");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new ModelAndView();
    }
}

异常页面信息:

原理:

        1、框架默认有三种异常解析器

        2、自定义的异常解析器默认优先级在最后,即默认异常解析器无法匹配时才会调用

        3、利用@Order注解,调整自定义的异常解析器优先级,可以优先调用自定义的异常解析器

2、异常处理自动配置原理

ErrorMvcAutoConfiguration 自动配置异常处理规则:

2.1、容器中的组件

2.1.1、DefaultErrorAttributes

定义错误页面中可以包含哪些数据。

    public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
        Map<String, Object> errorAttributes = this.getErrorAttributes(webRequest, options.isIncluded(Include.STACK_TRACE));
        if (!options.isIncluded(Include.EXCEPTION)) {
            errorAttributes.remove("exception");
        }

        if (!options.isIncluded(Include.STACK_TRACE)) {
            errorAttributes.remove("trace");
        }

        if (!options.isIncluded(Include.MESSAGE) && errorAttributes.get("message") != null) {
            errorAttributes.remove("message");
        }

        if (!options.isIncluded(Include.BINDING_ERRORS)) {
            errorAttributes.remove("errors");
        }

        return errorAttributes;
    }

2.1.2、BasicErrorController

        1)处理默认/error 路径的请求;页面响应newModelAndView("error", model);

        2)容器中有组件 View->id是error;(响应默认错误页)

        3)容器中放组件 BeanNameViewResolver(视图解析器);按照返回的视图名作为组件的id去容器中找View对象。

2.1.3、DefaultErrorViewResolver

        如果发生错误,会以HTTP的状态码 作为视图页地址(viewName),找到真正的页面

3、异常处理步骤流程

1)执行目标方法,目标方法运行期间有任何异常都会被catch、而且标志当前请求结束;并且用 dispatchException

2)进入视图解析流程(页面渲染)

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

3)mv= processHandlerException;处理handler发生的异常,处理完成返回ModelAndView

        3.1)遍历所有的 handlerExceptionResolvers,看谁能处理当前异常

        3.2)系统默认的 异常解析器;

        1.DefaultErrorAttributes先来处理异常。把异常信息保存到rrequest域,并且返回null; 

        2.默认没有任何方法能处理异常,所以异常会被抛出:

           底层就会发送 /error 请求。会被底层的BasicErrorController处理

           解析错误视图;遍历所有的ErrorViewResolver 看谁能解析。

           默认的DefaultErrorViewResolver ,作用是把响应状态码作为错误页的地址,500.html

           模板引擎最终响应这个页面error/500.html


版权声明:本文为weixin_44302046原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。