在spring boot中定制一下应景的错误页面,要比不定制的来说,视觉效果好很多,不进行定制的话,spring boot就会默认的返回一个白底黑字的错误页面给我买,如图:
这样给用户的体验当然是不好的,我们自然是想要一个视觉效果良好的错误页面,让用户体验更好,如图:
这样一个好看的页面也要比spring boot默认的错误页面好很多。
如何配置错误页面呢?在spring boot中,通过ErrorMvcAutoConfiguration类来,这个类中,有着如下的配置:
@ConditionalOnClass({Servlet.class, DispatcherServlet.class})
@AutoConfigureBefore({WebMvcAutoConfiguration.class})
@EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
public class ErrorMvcAutoConfiguration {
@Bean
@ConditionalOnMissingBean(
value = {ErrorAttributes.class},
search = SearchStrategy.CURRENT
)
public DefaultErrorAttributes errorAttributes() {
return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());
}
@Bean
@ConditionalOnMissingBean(
value = {ErrorController.class},
search = SearchStrategy.CURRENT
)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(), this.errorViewResolvers);
}
BasicErrorController这个bean,查看BasicErrorController的源码:
@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"})
public class BasicErrorController extends AbstractErrorController {
private final ErrorProperties errorProperties;
@RequestMapping(
produces = {"text/html"}
)
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = this.getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = this.resolveErrorView(request, response, status, model);
return modelAndView != null?modelAndView:new ModelAndView("error", model);
}
在此类上,可以看到注解中有这样一段"${server.error.path:${error.path:/error}}",可以看出,默认的错误路径是在/error文件夹下,也可以自己在application.properties文件中进行配置修改,如果都找不到,就会调用spring boot的默认错误页面(为一段HTML代码片段)。
只需要在根目录下创建一个error文件夹,然后往其中添加一些HTML页面即可,其命名规则为 错误码.html(如:404.html),当然,也可以用4xx.html、5xx.html,这样的就是统一匹配错误码为4、5开头的错误页面。当然,都存在的话,会优先匹配精确的错误码页面。
定制错误的JSON数据用于返回给客户端。
@ControllerAdvice注解,再写一个方法,在方法体上添加@ExceptionHandler( Exception.class )注解,Exception.class表示处理所有的异常,如果只想处理自定义异常,换成对应的自定义异常即可。具体代码如下:
@ControllerAdvice
public class MyException {
@ResponseBody
@ExceptionHandler(Exception.class)
public Map<String,Object> handlerException(Exception e){
Map<String,Object> map = new HashMap<>();
map.put("code","错误代码");
map.put("message",e.getMessage());
return map;
}
}
定制ErrorAttributes改变需要返回的内容。
继承DefaultErrorAttributes类,重写getErrorAttributes方法,在处理错误的类中,用转发的方式,以及最重要的一点,向请求域中设置状态码。首先,改写MyException这个类,具体代码如下:
@ControllerAdvice
public class MyException {
// @ResponseBody
// @ExceptionHandler(Exception.class)
// public Map<String,Object> handlerException(Exception e){
// Map<String,Object> map = new HashMap<>();
// map.put("code",1005);
// map.put("message",e.getMessage());
// return map;
// }
@ExceptionHandler(Exception.class)
public String handlerException(Exception e, HttpServletRequest request){
//这里设置状态码
request.setAttribute("javax.servlet.error.status_code",500);
Map<String,Object> map = new HashMap<>();
map.put("code",1005);
map.put("msg","这是 put 进来的异常!");
//将自定义的信息set到request 域中
request.setAttribute("me",map);
//使用转发,交给spring boot进行处理
return "forward:/error";
}
}
然后,编写定制错误类MyErrorAttributes,具体代码如下:
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
//调用父类方法
Map<String,Object> map = super.getErrorAttributes(webRequest,includeStackTrace);
//写自己额外的信息
map.put("msg","这是自定义的错误消息");
Map<String,Object> me = (Map<String, Object>) webRequest.getAttribute("me",0);
map.put("me",me);
return map;
}
}
代码中:Map<String,Object> me = (Map<String, Object>) webRequest.getAttribute("me",0);的作用是取得在MyException这个类中request进行set的值,第二参数为0,表示是request域中,原因如下:
public interface WebRequest extends RequestAttributes {
...
}
public interface RequestAttributes {
int SCOPE_REQUEST = 0;
int SCOPE_SESSION = 1;
...
}
发送相同的错误请求,查看客户端(postman)和浏览器的响应结果:
如图,自定义错误响应完成。