在我们访问Spring Boot应用的时候,出现譬如404,500的错误,默认会跳到如下页面
而做服务端的,浏览器并非为唯一客户端,还有安卓客户端app显示错误数据的方式,如下:(使用postman工具模拟安卓客户端app接受请求),Spring Boot会响应给安卓客户端json数据
这样的页面终归是不友好的,一般会自己定制页面或定制json数据(符合项目风格的错误页面)
前面的文章说了Spring Boot的自动配置一般都会在xxxAutoConfiguration类中
错误页面的自动配置在ErrorMvcAutoConfiguration类中
1、该类中有个errorPageCustomizer方法,返回的类型是ErrorPageCustomizer(错误页面定制器),只要项目中出现4xx或者5xx错误就会执行该方法。
2、我们点进ErrorPageCustomizer类中查看registerErrorPages方法,而该方法呢会发送一个getPath()请求,最终获得是@Value("${error.path:/error}"),意思是从配置文件中获取error.path的值,如果没有就使用"/error"请求url
3、只要请求"/error",那么在ErrorMvcAutoConfigutaion类中注册的BasicErrorController就会起作用了。
4、点进该类中查看发现该类就是映射"/error"请求的
5、该类中有两个方法errorHtml方法返回ModelAndView,这两个方法都能接收"/error"请求,error方法返回ResponseEntity也就是json数据,说明这两个方法对应的就是浏览器和客户端,errorHtml方法上的produces等于"text/html",就是响应html类型的数据,而在浏览器中优先接受的就是该类型,客户端优先接受的是application/json类型,所以Spring Boot就能自适应返回不同的数据了
一、浏览器怎么定制错误页面(errorHtml方法)
1、进入resolveErrorView方法,点进去
this.resolveErrorView(request, response, status, model);
-->resolver.resolveErrorView(request, status, model);
进入到ErrorViewResolver接口,该接口只有一个实现类,进入DefaultErrorViewResolver类中的resolveErrorView方法(DefaultErrorViewResolver也是在ErrorMvcAutoConfiguration类中进行注册了的)
2、resolveErrorView方法会调用resolve方法,会传入状态码和model(后面解释怎么来的)进去,SERIES_VIEWS中有4xx,5xx
3、进入到resolve方法,里面会拼一个视图名称"error/" 加上传进来的状态码(4xx,5xx),
这里会根据你的错误类型是什么就会拼成什么类型的视图名称。接着看下面有个方法判断有没有使用模板,如果使用了模板就直接把拼好的视图名称当作逻辑视图名称创建ModelAndView对象返回(使用了Thymeleaf模板,会有一个Thymeleaf视图解析器:前缀是classpath:templates/,后缀是html),如果没有就调用下面resolveResource方法
4、进入resolveResource方法里面的逻辑就是获得静态资源映射的路径(专栏前面的文章有详细讲过(链接)),然后跟传过来的视图名称拼起来并加上html后缀
5、最后说明我们只要把4xx,5xx命名html错误页面放在error文件夹下,然后把error文件夹放入templates文件夹下Spring Boot就会根据是什么类型的错误而跳转到指定的错误页面中。静态资源文件夹下的错误页面就不测试了,一定也是有用的
6、之前Spring Boot默认的错误处理页面中的数据是怎么获得的呢
回到errorHtml方法,点进getErrorAttributes方法
protected Map<String, Object> getErrorAttributes(HttpServletRequest request,
boolean includeStackTrace)
-->return this.errorAttributes.getErrorAttributes(webRequest,
includeStackTrace);
this.errorAttributes就是ErrorAttributes接口类型的,该类只有一个实现类DefaultErrorAttributes(在ErrorMvcAutoConfiguration类中在容器中注册了)
6.1、看getErrorAttributes方法中会创建一个Map,而下面的方法处理就是往该map中添加一些错误数据,比如status状态码,error错误提示信息,exception异常类型。添加完成之后将该Map返回作为model
6.2、所以我们在模板里面就能通过表达式取到错误信息了,异常必须在全局配置中设置项目中包含异常server.error.include-exception=true
7、Spring Boot默认的页面是怎么组成的呢
如果ModelAndView为空(说明自己在规定的路径中没有自定义错误页面)就自己创建一个ModelAndView,然后返回
7.1、在ErrorMvcAutoConfiguraion类中配置了一个组件name就是error,点进defaultErrorView(StaticView类型)
7.2、该类中有个视图渲染方法,就是一个组装好的html字符串和之前Spring Boot默认处理错误页面中的信息一样。
二、客户端怎么定制错误数据(error方法)
1、error方法中获取Map数据也是和上面一样的逻辑,最后转换成一个json数据返回给安卓客户端
2、之前说了哪个数据的获得其实是在容器中获取一个ErrorAttributes类型的实例然后调用该实例的getErrorAttributes方法,而ErrorAttributes类型的实例又是在ErrorMvcAutoConfiguration中进行了配置。
3、ErrorMvcAutoConfiguration中配置ErrorAttributes的方法上面有@ConditionalOnMissingBean,意思是容器中没有ErrorAttributes这个类型我就自动配置,那我们就可以写一个DefaultErrorAttributes的子类并重写getErrorAttributes方法,然后添加到容器中。这样的话上面Spring Boot的自动配置ErrorAttributes就不会生效,到时候调用getErrorAttributes方法就会调用我们自己重写的方法,以达到我们定制异常数据的效果。
4、我们这里调用父类的方法,先把Spring Boot默认可以获得到的数据先拿到,然后自己可以添加一些额外的数据并返回,最终获得到的model就是我们这个map,浏览器和客户端的数据都是在这获得到的。
5、如果项目中要处理对应的异常类型但是我们又要兼顾Spring Boot的自适应异常处理,在Spring MVC中我们就已经学习了自定义异常处理。这时候我们只需要根据Spring MVC的来做,最终我们请求转发到 "/error"请求,就会由BasicErrorController来处理自适应。最终又会执行到我们重写的getErrorAttributes方法中,我们自定义的异常信息就能放到request域中,在重写的getErrorAttributes中取出来放到map中,在前端就能取到自定义的错误值了。
总结:在ErrorMvcAutoConfiguration类中自动重要的四个组件
1、DefaultErrorAttributes:封装异常数据的,getErrorAttributes方法
2、BasicErrorController:处理异常请求的,映射error请求,进行自适应处理
3、ErrorPageCustomizer:错误页面定制器,出现了4xx,5xx的错误就会执行该类中的
registerErrorPages方法,然后发送error请求
4、DefaultErrorViewResolver:异常视图解析器,resolveErrorView方法根据是什么类型
的异常就解析成什么视图名称
1、在error文件夹下创建4xx,5xx为名的html后缀的页面,用到了模板就把error文件夹放入templates文件夹。没有用到模板就放到静态资源映射路径文件夹下。项目出现了错误,Spring Boot就可以找到对应的页面。
2、页面中可以通过模板中的表达式取到错误信息,也可以通过重写方法配合自定义异常处理器来定制错误信息
<!-- 状态码 -->
<h1>status:[[${status}]]</h1>
<!-- 时间 -->
<h3>time:[[${#dates.format(timestamp, 'yyyy-MM-dd HH:mm:ss')}]]</h3>
<!-- 错误提示 -->
<h3>error:[[${error}]]</h3>
<!-- 异常信息 -->
<h3>message:[[${message}]]</h3>
<!-- 异常对象 -->
<h3>exception:[[${exception}]]</h3>