博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SpringBoot 的错误处理机制
阅读量:6229 次
发布时间:2019-06-21

本文共 6266 字,大约阅读时间需要 20 分钟。

hot3.png

1,大致流程

一但系统出现4xx或者5xx之类的错误;ErrorPageCustomizer就会生效(定制错误的响应规则);就会来到/error请求;就会被BasicErrorController处理;

响应页面;去哪个页面是由DefaultErrorViewResolver解析得到的;

2,错误自动配置类

ErrorMvcAutoConfiguration ,此类帮我们自动配置了:

@Bean	public ErrorPageCustomizer errorPageCustomizer() {		return new ErrorPageCustomizer(this.serverProperties);	}private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered {       /*添加错误映射,即发生错误时会发送 /error 请求*/	   @Override		public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {            			ErrorPage errorPage = new ErrorPage(					this.properties.getServlet().getServletPrefix()							+ this.properties.getError().getPath());         			errorPageRegistry.addErrorPages(errorPage);		}}public class ErrorProperties {	@Value("${error.path:/error}")	private String path = "/error";

3,BasicErrorController 处理 /error 请求

/*返回页面响应*/@RequestMapping(produces = "text/html")	public ModelAndView errorHtml(HttpServletRequest request,			HttpServletResponse response) {        /*得到错误响应码*/		HttpStatus status = getStatus(request);        /*得到错误要显示的响应数据*/		Map
model = Collections.unmodifiableMap(getErrorAttributes( request, isIncludeStackTrace(request, MediaType.TEXT_HTML))); response.setStatus(status.value()); ModelAndView modelAndView = resolveErrorView(request, response, status, model); /*如果没有找到对应的 /error/5xx.html 视图 就会返回一个名为 error 的ModelAndView*/ return (modelAndView != null ? modelAndView : new ModelAndView("error", model)); }/*返回json响应*/ @RequestMapping @ResponseBody public ResponseEntity
> error(HttpServletRequest request) { Map
body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL)); HttpStatus status = getStatus(request); /*将响应状态码和响应数据封装成ResponseEntity 返回*/ return new ResponseEntity<>(body, status); }

①,getStatus

protected HttpStatus getStatus(HttpServletRequest request) {        /*从request 获取key为 javax.servlet.error.status_code 的值*/		Integer statusCode = (Integer) request				.getAttribute("javax.servlet.error.status_code");		if (statusCode == null) {            /*获取不到就响应一个500*/			return HttpStatus.INTERNAL_SERVER_ERROR;		}		try {			return HttpStatus.valueOf(statusCode);		}		catch (Exception ex) {            /*发生错误也响应一个500*/			return HttpStatus.INTERNAL_SERVER_ERROR;		}	}

②,getErrorAttributes 获取错误响应数据

public abstract class AbstractErrorController implements ErrorController {	private final ErrorAttributes errorAttributes;    protected Map
getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) { WebRequest webRequest = new ServletWebRequest(request); /*就是调用ErrorAttributes 里的 getErrorAttributes 方法获取响应数据*/ return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace); }}public class ErrorMvcAutoConfiguration {/*为我们注册了一个DefaultErrorAttributes */@Bean @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT) public DefaultErrorAttributes errorAttributes() { return new DefaultErrorAttributes( this.serverProperties.getError().isIncludeException()); }}//即调用了DefaultErrorAttributes 的 getErrorAttributes 方法,如下: @Override public Map
getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) { Map
errorAttributes = new LinkedHashMap<>(); errorAttributes.put("timestamp", new Date()); addStatus(errorAttributes, webRequest); addErrorDetails(errorAttributes, webRequest, includeStackTrace); addPath(errorAttributes, webRequest); return errorAttributes; }/*总的来说就是放了如下数据页面能获取的信息;timestamp:时间戳status:状态码error:错误提示exception:异常对象message:异常消息errors:JSR303数据校验的错误都在这里*/

③,name为error 的ModelAndView

public class ErrorMvcAutoConfiguration {    @Configuration	@ConditionalOnProperty(prefix = "server.error.whitelabel", name = "enabled", matchIfMissing = true)	@Conditional(ErrorTemplateMissingCondition.class)	protected static class WhitelabelErrorViewConfiguration {        //这个即我们经常看到的错误页		private final SpelView defaultErrorView = new SpelView(				"

Whitelabel Error Page

" + "

This application has no explicit mapping for /error, so you are seeing this as a fallback.

" + "
${timestamp}
" + "
There was an unexpected error (type=${error}, status=${status}).
" + "
${message}
"); // 即是这个View @Bean(name = "error") @ConditionalOnMissingBean(name = "error") public View defaultErrorView() { return this.defaultErrorView; }}

4,定制错误响应

①,编写一个错误处理类,这里还是用到了@ControllerAdvice 注解

import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import javax.servlet.http.HttpServletRequest;import java.util.HashMap;import java.util.Map;//声明是一个错误处理器@ControllerAdvicepublic class ErrorControllAdvice {//    处理那种类型的错误    @ExceptionHandler(Exception.class)    public String errorHandle(HttpServletRequest request){//        添加额外错误响应数据        Map
map=new HashMap<>();// 添加一个公司的响应数据 map.put("company","小米");// 放到request 中,然后在我们定制的DefaultErrorAttributes 里获取 request.setAttribute("ext",map);// 设置响应状态码 request.setAttribute("javax.servlet.error.status_code",500);// 转发到/error 请求,这样就能根据客户端优化接收何种类型数据,决定响应html还是json return "forward:/error"; }}

②,定制DefaultErrorAttributes

import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;import org.springframework.stereotype.Component;import org.springframework.web.context.request.RequestAttributes;import org.springframework.web.context.request.WebRequest;import java.util.Map;@Componentpublic class MyDefaultErrorAttributes extends DefaultErrorAttributes {    /*重写getErrorAttributes 方法*/    @Override    public Map
getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {// 获取原来的响应数据 Map
map = super.getErrorAttributes(webRequest, includeStackTrace); //从请求域中拿值 Map
ext = (Map
) webRequest.getAttribute("ext", RequestAttributes.SCOPE_REQUEST); //添加我们定制的响应数据 map.put("ext",ext);// 返回带有我们定制的数据的map return map; }}

5,测试

转载于:https://my.oschina.net/u/3574106/blog/1823125

你可能感兴趣的文章
Qt笔记(1)连接 SQL Server 数据库
查看>>
记一次使用官方zabbix官方模板监控redis自己犯的错
查看>>
ASP.NET CS文件中输出JavaScript脚本的3种方法以及区别
查看>>
mysql 分隔某个字段
查看>>
《从零开始学Swift》学习笔记(Day 17)——Swift中数组集合
查看>>
traceroute路由追踪
查看>>
Bacula笔记
查看>>
我的友情链接
查看>>
svn merge以及Unknown action received: skipped conflicted path冲突解决
查看>>
CSS: the different of using CSS between @import and link
查看>>
f2fs 系列之七:page cache相关操作和接口
查看>>
马士兵教学语录
查看>>
ubuntu server 13.10修改引导等待时间与配置更新源
查看>>
leetCode 121. Best Time to Buy and Sell Stock 数组
查看>>
Jquery学习笔记-过滤选择器
查看>>
Android 一个apk多个ICON执行入口
查看>>
我的友情链接
查看>>
nginx安装
查看>>
一个backup exec 2012的真实故障案例,服务无法启动1068
查看>>
我的友情链接
查看>>