Spring Boot自定义错误页
Spring Boot返回的信息类型
Spring Boot在返回错误信息时不一定返回HTML页面,而且根据实际情况返回HTML页面或者一段JSON(若开发者发起Ajax请求,则错误信息时一段JSON)。对于开发者而言,这一段HTML或者JSON都能够自由定制。
BasicErrorController中errorHtml()和error()源码
Spring Boot中的错误默认是由BasicErrorController类来处理的,该类中的核心方法主要有两个:
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map<String, Object> model = Collections
.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
}
@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);
其中,errorHtml方法用来返回错误HTML页面,error用来返回错误JSON,具体返回的是HTML还是JSON,则要看请求头的Accept参数。返回JSON的逻辑很简单,不过多介绍,返回HTML的逻辑稍微有些复杂,在errorHtml方法中,通过调用resolveErrorView方法来获取一个错误视图的ModelAndView。而resolveErrorView方法的调用最终会来到DefaultErrorViewResolver类中。
DefaultErrorViewResolver源码
DefaultErrorViewResolver类是Spring Boot中默认的错误信息视图解析器,部分源码如下:
public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
private static final Map<Series, String> SERIES_VIEWS;
static {
Map<Series, String> views = new EnumMap<>(Series.class);
views.put(Series.CLIENT_ERROR, "4xx");
views.put(Series.SERVER_ERROR, "5xx");
SERIES_VIEWS = Collections.unmodifiableMap(views);
}
private ModelAndView resolve(String viewName, Map<String, Object> model) {
String errorViewName = "error/" + viewName;
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,
this.applicationContext);
if (provider != null) {
return new ModelAndView(errorViewName, model);
}
return resolveResource(errorViewName, model);
}
}
从这一段源码中可以看到,SpringBoot默认是在error目录下查找4xx、5xx的文件作为错误视图,当找不到时会回到errorHtml方法中,然后使用error作为默认的错误视图名,如果名为error的视图也找不到,则用户会看到如下图展示的错误提示页面。
自定义错误页面
自定义错误页面时,提供4xx和5xx页面即可。如果开发者不需要向用户展示详细的错误信息,name可以把错误信息定义成静态页面,直接在resources/static目录下创建error目录,然后再eroor目录中创建错误展示页面。错误展示页面的明明规则有两种:一种是4xx.html、5xx.html;另一种是直接使用响应码命名文件,例如404.html、405.html、500.html。
自定义error数据
Spring Boot返回的Error信息包括timestamp、status、error、message、path。在BasicErrorController的errorHtml方法和error方法中,都是通过getErrorAttribute方法获取Error信息的。该方法最终会调用到DefaultErrorAttributes类的getErrorAttributes方法,而DefaultErrorAttributes类是在ErrorMvcAutoConfiguration中默认提供的。ErrormvcAutoConfiguration类的errorAttributes方法源码如下:
@Bean
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {
return new DefaultErrorAttributes();
}
从这段源码中可以看出,当系统没有 提供ErrorAttributes时才会采用DefaultErrorAttributes。因此自定义错误提示时,只需要自己提供一个ErrorAttributes即可,而DefaultErrorAttributes是ErrorAttributes的子类,因此只需要继承DefaultErrorAttributes即可,代码如下:
@Component
public class MyErrorAttribute extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
errorAttributes.put("custommsg", "出错啦!");
errorAttributes.remove("error");
return errorAttributes;
}
}
代码解释:
- 自定义MyErrorAttribute继承自DefaultErrorAttributes ,重写DefaultErrorAttributes 中的getErrorAttributes方法。MyErrorAttribute类添加@Component注解,该类将被注册到Spring容器中。
- 方法中通过super.getErrorAttributes获取SpringBoot默认提供的错误信息,然后在其基础上添加Error信息或者移除Error信息。