return (modelAndView != null) ? modelAndView : new ModelAndView(“error”, model);
}
/**
-
该方法用于处理机器客户端的请求发生的错误
-
产生 JSON 格式的数据展示错误信息
-
@param request
-
@return
*/
@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, getErrorAttributeOptions(request, MediaType.ALL));
return new ResponseEntity<>(body, status);
}
…
}
复制代码
Spring Boot 通过 BasicErrorController 进行统一的错误处理(例如默认的“/error”请求)。Spring Boot 会自动识别发出请求的客户端的类型(浏览器客户端或机器客户端),并根据客户端类型,将请求分别交给 errorHtml() 和 error() 方法进行处理。
复制代码
| 返回值类型 | 方法声明 | 客户端类型 | 错误信息返类型 |
| — | — | — | — |
| ModelAndView | errorHtml(HttpServletRequest request, HttpServletResponse response) | 浏览器客户端 | text/html(错误页面) |
| ResponseEntity<Map<String, Object>> | error(HttpServletRequest request) | 机器客户端(例如安卓、IOS、Postman 等等) | JSON |
换句话说,当使用浏览器访问出现异常时,会进入 BasicErrorController 控制器中的 errorHtml() 方法进行处理,当使用安卓、IOS、Postman 等机器客户端访问出现异常时,就进入error() 方法处理。
在 errorHtml() 方法中会调用父类(AbstractErrorController)的 resolveErrorView() 方法,代码如下。
protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status,
Map<String, Object> model) {
//获取容器中的所有的错误视图解析器来处理该异常信息
for (ErrorViewResolver resolver : this.errorViewResolvers) {
//调用错误视图解析器的 resolveErrorView 解析到错误视图页面
ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
if (modelAndView != null) {
return modelAndView;
}
}
return null;
}
复制代码
从上述源码可以看出,在响应页面的时候,会在父类的 resolveErrorView 方法中获取容器中所有的 ErrorViewResolver 对象(错误视图解析器,包括 DefaultErrorViewResolver 在内),一起来解析异常信息。
复制代码
DefaultErrorViewResolver
ErrorMvcAutoConfiguration 还向容器中注入了一个默认的错误视图解析器组件 DefaultErrorViewResolver,代码如下。
复制代码
@Bean
@ConditionalOnBean(DispatcherServlet.class)
@ConditionalOnMissingBean(ErrorViewResolver.class)
DefaultErrorViewResolver conventionErrorViewResolver() {
return new DefaultErrorViewResolver(this.applicationContext, this.resources);
}
复制代码
当发出请求的客户端为浏览器时,Spring Boot 会获取容器中所有的 ErrorViewResolver 对象(错误视图解析器),并分别调用它们的 resolveErrorView() 方法对异常信息进行解析,其中自然也包括 DefaultErrorViewResolver(默认错误信息解析器)。
DefaultErrorViewResolver 的部分代码如下。
public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
private static final Map<HttpStatus.Series, String> SERIES_VIEWS;
static {
Map<HttpStatus.Series, String> views = new EnumMap<>(HttpStatus.Series.class);
views.put(Series.CLIENT_ERROR, “4xx”);
views.put(Series.SERVER_ERROR, “5xx”);
SERIES_VIEWS = Collections.unmodifiableMap(views);
}
…
@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
//尝试以错误状态码作为错误页面名进行解析
ModelAndView modelAndView = resolve(String.valueOf(status.value()), model);
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
//尝试以 4xx 或 5xx 作为错误页面页面进行解析
modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
}
return modelAndView;
}
private ModelAndView resolve(String viewName, Map<String, Object> model) {
//错误模板页面,例如 error/404、error/4xx、error/500、error/5xx
String errorViewName = “error/” + viewName;
//当模板引擎可以解析这些模板页面时,就用模板引擎解析
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,
this.applicationContext);
if (provider != null) {
//在模板能够解析到模板页面的情况下,返回 errorViewName 指定的视图
return new ModelAndView(errorViewName, model);
}
//若模板引擎不能解析,则去静态资源文件夹下查找 errorViewName 对应的页面
return resolveResource(errorViewName, model);
}
private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
//遍历所有静态资源文件夹
for (String location : this.resources.getStaticLocations()) {
try {
Resource resource = this.applicationContext.getResource(location);
//静态资源文件夹下的错误页面,例如error/404.html、error/4xx.html、error/500.html、error/5xx.html
resource = resource.createRelative(viewName + “.html”);
//若静态资源文件夹下存在以上错误页面,则直接返回
if (resource.exists()) {
return new ModelAndView(new DefaultErrorViewResolver.HtmlResourceView(resource), model);
}
} catch (Exception ex) {
}
}
return null;
}
…
}
复制代码
DefaultErrorViewResolver 解析异常信息的步骤如下:
-
根据错误状态码(例如 404、500、400 等),生成一个错误视图 error/status,例如 error/404、error/500、error/400。
-
尝试使用模板引擎解析 error/status 视图,即尝试从 classpath 类路径下的 templates 目录下,查找 error/status.html,例如 error/404.html、error/500.html、error/400.html。
-
若模板引擎能够解析到 error/status 视图,则将视图和数据封装成 ModelAndView 返回并结束整个解析流程,否则跳转到第 4 步。
-
依次从各个静态资源文件夹中查找 error/status.html,若在静态文件夹中找到了该错误页面,则返回并结束整个解析流程,否则跳转到第 5 步。
-
将错误状态码(例如 404、500、400 等)转换为 4xx 或 5xx,然后重复前 4 个步骤,若解析成功则返回并结束整个解析流程,否则跳转第 6 步。
-
处理默认的 “/error ”请求,使用 Spring Boot 默认的错误页面(Whitelabel Error Page)。
DefaultErrorAttributes
ErrorMvcAutoConfiguration 还向容器中注入了一个组件默认错误属性处理工具 DefaultErrorAttributes,代码如下。
@Bean
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {
return new DefaultErrorAttributes();
}
复制代码
DefaultErrorAttributes 是 Spring Boot 的默认错误属性处理工具,它可以从请求中获取异常或错误信息,并将其封装为一个 Map 对象返回,其部分代码如下。
public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolver, Ordered {
…
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
Map<String, Object> errorAttributes = 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;
}
private 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;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
总结
对于面试还是要好好准备的,尤其是有些问题还是很容易挖坑的,例如你为什么离开现在的公司(你当然不应该抱怨现在的公司有哪些不好的地方,更多的应该表明自己想要寻找更好的发展机会,自己的一些现实因素,比如对于我而言是现在应聘的公司离自己的家更近,又或者是自己工作到达了迷茫期,想跳出迷茫期等等)
Java面试精选题、架构实战文档
整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~
你的支持,我的动力;祝各位前程似锦,offer不断!
码讲义、实战项目、讲解视频,并且后续会持续更新**
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-cWcOHRjE-1712046359098)]
总结
对于面试还是要好好准备的,尤其是有些问题还是很容易挖坑的,例如你为什么离开现在的公司(你当然不应该抱怨现在的公司有哪些不好的地方,更多的应该表明自己想要寻找更好的发展机会,自己的一些现实因素,比如对于我而言是现在应聘的公司离自己的家更近,又或者是自己工作到达了迷茫期,想跳出迷茫期等等)
[外链图片转存中…(img-BzhzKWqR-1712046359098)]
Java面试精选题、架构实战文档
整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~
你的支持,我的动力;祝各位前程似锦,offer不断!