建设购物网站多少钱/个人网页设计
错误处理机制
一、SpringBoot默认的错误处理机制
1、默认效果:
1)、浏览器,返回一个默认的错误页面
2)、如果是其他客户端调用出错,默认响应一个json数据,因为客户端一般都以接口的形式调用 。
2、默认处理机制原理:
SpringBoot处理的原理可以参考ErrorMvcAutoConfiguration.class
,因为在此类中给容器添加了如下几个组件,我们看看各个组件的源码:
(1)、ErrorPageCustomizer.class
:生成错误请求
private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {private final ServerProperties properties;protected ErrorPageCustomizer(ServerProperties properties) {this.properties = properties;}public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {ErrorPage errorPage = new ErrorPage(this.properties.getServlet().getServletPrefix() + this.properties.getError().getPath());errorPageRegistry.addErrorPages(new ErrorPage[]{errorPage});}public int getOrder() {return 0;}}
其中this.properties.getError().getPath()
获取的path可以在 ErrorProperties.class
中找到:
public class ErrorProperties {@Value("${error.path:/error}")private String path = "/error";public String getPath() {return this.path;}
由此可以看出:系统出现错误以后,以/error请求进行处理;
(2)、BasicErrorController.class
:用于处理默认/error请求
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {@RequestMapping(produces = "text/html")//产生html类型的数据;浏览器发送的请求来到这个方法处理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());//去哪个页面作为错误页面?包含页面地址和页面内容,通过resolveErrorView获取//其中错误页面的信息【model】就是通过DefaultErrorAttributes获取的ModelAndView modelAndView = resolveErrorView(request, response, status, model);return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);}@RequestMapping@ResponseBody //产生json数据,其他客户端来到这个方法处理;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)、DefaultErrorAttributes.class
:BasicErrorController中(getErrorAttributes(request,
)用于获取错误响应数据的工具。
isIncludeStackTrace(request, MediaType.ALL))
@Overridepublic 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;}
(4)、DefaultErrorViewResolver.class
:用于决定错误请求响应的页面或数据是什么
@Overridepublic ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,Map<String, Object> model) {//所有的ErrorViewResolver得到ModelAndViewModelAndView 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) {//默认SpringBoot可以去找到一个页面? error/404String errorViewName = "error/" + viewName;//模板引擎可以解析这个页面地址就用模板引擎解析TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);if (provider != null) {//模板引擎可用的情况下返回到errorViewName指定的视图地址return new ModelAndView(errorViewName, model);}//模板引擎不可用,就在静态资源文件夹下找errorViewName对应的页面(error/404.html)return resolveResource(errorViewName, model);}
总结:总体而言SpringBoot默认处理错误的机制原理是:
①、一但系统出现4xx(404)或者5xx(500)之类的错误,ErrorPageCustomizer
就会生效(定制错误的响应规则,发起/error)请求;
②/error请求就会被BasicErrorController
处理;
③、响应数据由DefaultErrorAttributes
获取;
④、响应页面;去哪个页面是由DefaultErrorViewResolver
解析得到的;
二、如何自定义错误处理机制
1、如何自定义错误页面?
(1)、有模板引擎的情况下:
①、error/状态码; 【将错误页面命名为 【错误状态码.html 】 放在模板引擎文件夹里面的 error文件夹下】,发生此状态码的错误就会此页面;
②、我们可以使用4xx和5xx作为错误页面的文件名来匹配这种类型的所有错误,当出现4xx或者5xx类型的错误时,优先匹配是否有对应的【错误码.html页面】, 没有的话就匹配 4xx.html或者5xx.html。
(2)、没有模板引擎(模板引擎找不到这个错误页面),静态资源文件夹下找,寻找规则和有模板引擎一样,只是其不进入模板引擎的文件夹找;
(3)、以上都没有错误页面,就是默认来到SpringBoot默认的错误提示页面;
2、如何自定义错误json数据?
①、利用统一异常处理:
@ControllerAdvice
public class MyExceptionHandler {@ResponseBody@ExceptionHandler(UserNotExistException.class)/* 指定要处理的异常 */public Map<String,Object> handleException(Exception e){Map<String,Object> map = new HashMap<>();map.put("code","user.notexist");map.put("message",e.getMessage());return map;}
}
这样没有BasicErrorController
的自适应效果…浏览器和客户端都返回json、不合理;做如下改造:
②、利用异常统一处理,带上错误数据后,转发到/error,由BasicErrorController
进行自适应响应效果处理;
但是需要自定义【ErrorAttributes】放置到容器中,获取我们定义的错误数据。
@ControllerAdvice
public class MyExceptionHandler {@ResponseBody@ExceptionHandler(UserNotExistException.class)/* 指定要处理的异常 */public Map<String,Object> handleException(Exception e){Map<String,Object> map = new HashMap<>();map.put("code","user.notexist");map.put("message",e.getMessage());// 转发到/errorreturn "forward:/error";}
}
自定义ErrorAttributes:
//给容器中加入我们自己定义的ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {@Overridepublic Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);map.put("myErrorMsg","出错啦");//自定义的【ErrorAttributes】可以从request中取出上一步异常处理器定义的消息//ext===> {code:user.notexist, message:xxxx}Map<String,Object> ext = (Map<String, Object>) requestAttributes.getAttribute("ext", 0);map.put("ext",ext);return map;}
}
最终的效果:响应是自适应的(浏览器或者客户端调用),可以通过定制MyErrorAttributes获取自定义的异常信息。
其原理就是,出现错误以后,会来到/error请求,会被BasicErrorController处理,响应出去的数据经查源码可以发现DefaultErrorAttributes.getErrorAttributes()方法拿到的数据,即容器中DefaultErrorAttributes.getErrorAttributes();进行数据处理的;那么如果我们要将自己的错误信息带到错误页面或者json中,那么可以自定义【ErrorAttributes】,放置到容器中既可实现,这样错误数据不仅有默认的那些,还可以带上自己的数据。而且可自动响应浏览器和客户端调用区分;