目录
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)默认情况下,Spring Boot提供/error
处理所有错误的映射
2)不同客户端的返回页面不同:
对于浏览器客户端,响应一个“ whitelabel”错误视图,以HTML格式呈现相同的数据
使用方法:
在templates/error中添加4xx、5xx页面,会被自动解析
error/404.html error/5xx.html;有精确的错误状态码页面就匹配精确,没有就找 4xx.html;如果都没有就触发白页
使用方法:
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 支持的
使用方法:
@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、定义 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注解,调整自定义的异常解析器优先级,可以优先调用自定义的异常解析器
ErrorMvcAutoConfiguration 自动配置异常处理规则:
定义错误页面中可以包含哪些数据。
public Map getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
Map 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;
}
1)处理默认 /error 路径的请求;页面响应 new ModelAndView("error", model);
2)容器中有组件 View->id是error;(响应默认错误页)
3)容器中放组件 BeanNameViewResolver(视图解析器);按照返回的视图名作为组件的id去容器中找View对象。
如果发生错误,会以HTTP的状态码 作为视图页地址(viewName),找到真正的页面
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