一、SpringBoot默认的错误处理机制
默认效果:
使用浏览器访问时会跳转到错误页面

如果是其他设备访问会返回json数据

原理:
对于错误处理的自动配置在spring-boot-autoconfigure-2.0.6.RELEASE.jar的org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration中配置
ErrorMvcAutoConfiguration.class给容器中添加了以下组件:
@Bean
@ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT)
public DefaultErrorAttributes errorAttributes() {
return new DefaultErrorAttributes();
}
@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes,
ObjectProvider<ErrorViewResolver> errorViewResolvers) {
return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
errorViewResolvers.orderedStream().collect(Collectors.toList()));
}
@Bean
public ErrorPageCustomizer errorPageCustomizer(DispatcherServletPath dispatcherServletPath) {
return new ErrorPageCustomizer(this.serverProperties, dispatcherServletPath);
}
@Bean
@ConditionalOnBean(DispatcherServlet.class)
@ConditionalOnMissingBean(ErrorViewResolver.class)
DefaultErrorViewResolver conventionErrorViewResolver() {
return new DefaultErrorViewResolver(this.applicationContext, this.resources);
}
1、DefaultErrorAttributes :帮我们在页面共享信息
页面能获取的信息:
timestamp:时间戳
status:状态码
error:错误提示
exception:异常对象
message:异常消息
errors:JSR303数据校验的错误在这里
@Override
@Deprecated
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> errorAttributes = new LinkedHashMap<>();
errorAttributes.put("timestamp", new Date());
addStatus(errorAttributes, webRequest);
addErrorDetails(errorAttributes, webRequest, includeStackTrace);
addPath(errorAttributes, webRequest);
return errorAttributes;
}
2、BasicErrorController :处理默认/error请求
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {
//产生html类型的页面,浏览器发送的请求头中的Accept为text/html,所以浏览器发送的请求来到这个方法处理
@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);
}
//产生json数据,其他客户端发送的请求头中的Accept为/*,所以其他客户端发送的请求来到这个方法处理
@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);
}
3、ErrorPageCustomizer
//系统出现错误以后来到error请求进行处理
@Value("${error.path:/error}")
private String path = "/error";
4、DefaultErrorViewResolver
@Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
ModelAndView modelAndView = resolve(String.valueOf(status.value()), 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/404
String errorViewName = "error/" + viewName;
//模板引擎可以解析这个地址就用模板引擎解析
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName,
this.applicationContext);
if (provider != null) {
//模板引擎可用的情况下返回到errorViewName指定的设置地址
return new ModelAndView(errorViewName, model);
}
//模板引擎如果不可用,就在静态资源文件夹下找errorViewName对应的页面
return resolveResource(errorViewName, model);
}
步骤:
一旦系统出现4xx或5xx之类的错误,ErrorPageCustomizer就会生效(定制错误的响应规则)就会来到/error请求;然后就会被BasicErrorController处理;
两种方式处理:
1、响应页面:去哪个界面是由DefaultErrorViewResoulver解析得到的。
2、返回json数据:
二、如何定制错误响应:
1、如何定制错误的页面
- 有模板引擎的情况下,在template下创建error/状态码;[将错误页面命名为 错误状态码.html 放在error文件夹下] 发生此状态错误就会来到对应的页面。
我们可以使用4xx或者5xx作为错误页面的文件名来匹配这种类型的所有错误,有精确文件,精确文件优先。 - 没有模板引擎的情况下(template下找不到错误页面),静态资源文件下找
- 以上都没有错误页面,就是默认来到springboot默认的提示界面
2、如何定制错误的json数据
- 没有自适应浏览器访问和其他终端访问效果,即不管通过浏览器或是其他客户端访问返回的都是json数据
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class MyExceptionHandler {
@ExceptionHandler(MyException.class)//捕获自定义异常
@ResponseBody
public Map<String,Object> handlerException(Exception e) {//出现异常时会将异常传递过来
Map<String,Object> map = new HashMap<String,Object>();
map.put("code", "自定义状态码");
map.put("msg", e.getMessage());
return map;
}
}
- 转发到/error进行自适应响应效果处理,但是在返回的json数据中无法获得我们自定义的信息
@ExceptionHandler(MyException.class)
public String handlerException(Exception e,HttpServletRequest request) {
Map<String,Object> map = new HashMap<String,Object>();
map.put("code", "自定义状态码");
map.put("msg", e.getMessage());
//设置错误状态码,一定要设置,否者就不会进入到自定义页面中
request.setAttribute("javax.servlet.error.status_code", 404);
//将自己的异常信息加入到request
request.setAttribute("extMap", map);
//转发到/error
return "forward:/error";
}
- 响应是自适应的,可以通过ErrorAttributes改变需要返回的内容
实现方式:既然页面和json的错误信息都是通过getErrorAttributes(HttpServletRequest, boolean)获取,那么我们就写一个类继承DefaultErrorAttributes(上面提到的组件一),重写getErrorAttributes()方法就可以啦
import java.util.Map;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.WebRequest;
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {
//返回的map就是页面和json能获取的所有字段
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
Map<String, Object> map = (Map<String, Object>)
//我们的异常处理器携带的数据
webRequest.getAttribute("extMap", 0);//0标识从request中获取
errorAttributes.put("message", "用户出错啦");
errorAttributes.put("extMap",map);
return errorAttributes;
}
版权声明:本文为weixin_53107227原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。