7、錯(cuò)誤處理機(jī)制
1)既棺、SpringBoot默認(rèn)的錯(cuò)誤處理機(jī)制
默認(rèn)效果:
? 1)讽挟、瀏覽器,返回一個(gè)默認(rèn)的錯(cuò)誤頁面
瀏覽器發(fā)送請(qǐng)求的請(qǐng)求頭:
? 2)丸冕、如果是其他客戶端耽梅,默認(rèn)響應(yīng)一個(gè)json數(shù)據(jù)
原理:
? 可以參照ErrorMvcAutoConfiguration;錯(cuò)誤處理的自動(dòng)配置胖烛;
給容器中添加了以下組件
? 1眼姐、DefaultErrorAttributes:
幫我們?cè)陧撁婀蚕硇畔ⅲ?@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
boolean includeStackTrace) {
Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>();
errorAttributes.put("timestamp", new Date());
addStatus(errorAttributes, requestAttributes);
addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);
addPath(errorAttributes, requestAttributes);
return errorAttributes;
}
? 2、BasicErrorController:處理默認(rèn)/error請(qǐng)求
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
@RequestMapping(produces = "text/html")//產(chǎn)生html類型的數(shù)據(jù)佩番;瀏覽器發(fā)送的請(qǐng)求來到這個(gè)方法處理
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());
//去哪個(gè)頁面作為錯(cuò)誤頁面众旗;包含頁面地址和頁面內(nèi)容
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);
}
@RequestMapping
@ResponseBody //產(chǎn)生json數(shù)據(jù),其他客戶端來到這個(gè)方法處理趟畏;
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request);
return new ResponseEntity<Map<String, Object>>(body, status);
}
? 3贡歧、ErrorPageCustomizer:
@Value("${error.path:/error}")
private String path = "/error"; 系統(tǒng)出現(xiàn)錯(cuò)誤以后來到error請(qǐng)求進(jìn)行處理;(web.xml注冊(cè)的錯(cuò)誤頁面規(guī)則)
? 4赋秀、DefaultErrorViewResolver:
@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
Map<String, Object> model) {
ModelAndView modelAndView = resolve(String.valueOf(status), model);
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);
}
return modelAndView;
}
private ModelAndView resolve(String viewName, Map<String, Object> model) {
//默認(rèn)SpringBoot可以去找到一個(gè)頁面利朵? error/404
String errorViewName = "error/" + viewName;
//模板引擎可以解析這個(gè)頁面地址就用模板引擎解析
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders
.getProvider(errorViewName, this.applicationContext);
if (provider != null) {
//模板引擎可用的情況下返回到errorViewName指定的視圖地址
return new ModelAndView(errorViewName, model);
}
//模板引擎不可用,就在靜態(tài)資源文件夾下找errorViewName對(duì)應(yīng)的頁面 error/404.html
return resolveResource(errorViewName, model);
}
? 步驟:
? 一但系統(tǒng)出現(xiàn)4xx或者5xx之類的錯(cuò)誤猎莲;ErrorPageCustomizer就會(huì)生效(定制錯(cuò)誤的響應(yīng)規(guī)則)绍弟;就會(huì)來到/error請(qǐng)求;就會(huì)被BasicErrorController處理著洼;
? 1)響應(yīng)頁面晌柬;去哪個(gè)頁面是由DefaultErrorViewResolver解析得到的;
protected ModelAndView resolveErrorView(HttpServletRequest request,
HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
//所有的ErrorViewResolver得到ModelAndView
for (ErrorViewResolver resolver : this.errorViewResolvers) {
ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
if (modelAndView != null) {
return modelAndView;
}
}
return null;
}