一.SpringBoot中的默认的错误处理机制
  1.在SpringBootWeb开发中,当我们访问请求出现错误时,会返回一个默认的错误页面:

  2.在使用其他客户端访问的时候,则返回一个json数据:

  3.原理:可以参看原码ErrorMvcAutoConfiguration:
    (1)给容器中添加了以下组件
    DefaultErrorAttributes:帮我们在页面共享信息

     @Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,
boolean includeStackTrace) {
Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>();
errorAttributes.put("timestamp", new Date());
addStatus(errorAttributes, requestAttributes);
addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);
addPath(errorAttributes, requestAttributes);
return errorAttributes;
} private void addStatus(Map<String, Object> errorAttributes,
RequestAttributes requestAttributes) {
Integer status = getAttribute(requestAttributes,
"javax.servlet.error.status_code");
if (status == null) {
errorAttributes.put("status", 999);
errorAttributes.put("error", "None");
return;
}
errorAttributes.put("status", status);
try {
errorAttributes.put("error", HttpStatus.valueOf(status).getReasonPhrase());
}
catch (Exception ex) {
// Unable to obtain a reason
errorAttributes.put("error", "Http Status " + status);
}
}

    --可获取到的属性
      timestamp:时间戳
      status:状态码
      error:错误提示
      exception:异常
      message:异常消息
      errors:JSR303数据校验的错误都在这
    BasicErrorController:处理默认的/eerror请求

     @RequestMapping(produces = "text/html")
public ModelAndView errorHtml(HttpServletRequest request,
HttpServletResponse response) {
HttpStatus status = getStatus(request);
Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(
request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
response.setStatus(status.value());
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);
} @RequestMapping
@ResponseBody
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,
isIncludeStackTrace(request, MediaType.ALL));
HttpStatus status = getStatus(request);
return new ResponseEntity<Map<String, Object>>(body, status);
}  

    --将会存在两种情况,得到一个html页面或者一个JSON数据,在浏览器发起的请求中,可发现其请求头accept中标识着优先接收html页面:

    --当其他客户端发送请求时,可以发现其请求头没有标注优先接收html数据(使用了*/*)

    --浏览器发送的请求将来到错误的html页面,而其他客户端则会接收到一个错误的JSON数据.在浏览器发送错误请求时,使用了ModelAndView声明了当前错误页面的地址和页面内容.

     protected ModelAndView resolveErrorView(HttpServletRequest request,
HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
for (ErrorViewResolver resolver : this.errorViewResolvers) {
ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);
if (modelAndView != null) {
return modelAndView;
}
}
return null;
}

    --在该方法中将所有的ErrorViewResolver都获取到,而后返回,而我们去哪个页面则是由ErrorViewResolver得到的.
    ErrorPageCustomizer:系统出现错误时,来到error请求进行处理
    DefaultErrorViewResolver:

 @Override
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
Map<String, Object> model) {
ModelAndView modelAndView = resolve(String.valueOf(status), 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) {
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/404,如果模板引擎可以解析这个地址,那么就是用模板引擎解析.如果模板引擎不可用,就在静态资源文件夹下寻找errorViewName对应的页面
    (2)一旦系统出现4XX或者5XX之类的错误,ErrorPageCustomizer就会生效(定制错误的响应规则),就会来到/error请求,就会被BasicErrorController进行处理

二.如何定制错误响应
  1.如何定制错误的页面:在我们有模板引擎的情况下(error/404.html),将错误页面命名为错误状态码.html,放在模板引擎文件夹里面的error文件夹下,发生此状态码的错误就会来到对应的页面.如果我们为每一个状态码都配置一个错误页面的话,十分麻烦,我们可以给页面命名为4xx.html,这样当错误码不匹配的时候,将默认来到该html页面(优先寻找精确的状态码).
  当没有相对应的模板引擎时,将会在静态资源文件夹中寻找
  当模板引擎和静态资源的错误文件夹都没有的时候,将会来到SpringBoot的默认提示信息页面.
  2.如何定制错误的JSON数据

 package com.zhiyun.springboot.web_restfulcrud.exception;

 /**
* @author : S K Y
* @version :0.0.1
*/
public class UserNotExistException extends RuntimeException {
public UserNotExistException() {
super("用户不存在");
}
}
     @ResponseBody
@RequestMapping("/hello")
public String hello(@RequestParam("user") String user) {
if (user.equals("AAA")) {
throw new UserNotExistException();
}
return "hello";
}

三.自定义JSON错误数据响应
  1.使用SpringMvc的异常处理机制(ExceptionHandler)捕获到这个异常之后,运行自定义的方法

 package com.zhiyun.springboot.web_restfulcrud.controller;

 import com.zhiyun.springboot.web_restfulcrud.entity.Employee;
import com.zhiyun.springboot.web_restfulcrud.exception.UserNotExistException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody; import java.util.HashMap;
import java.util.Map; /**
* @author : S K Y
* @version :0.0.1
*/
//在Spring中要成为一个异常处理器,需要使用该注解
@ControllerAdvice
public class MyExceptionHandler { @ResponseBody
@ExceptionHandler(UserNotExistException.class)
public Map<String, Object> handlerException(Exception e) {
Map<String, Object> map = new HashMap<>();
map.put("code", "user.not exist");
map.put("message", e.getMessage());
return map;
} }

  2.到目前为止还没有实现我们的自适应效果(如果是浏览器访问则返回页面,其他客户端访问则是返回JSON数据):

     @ExceptionHandler(UserNotExistException.class)
public String handlerException(Exception e) {
/* Map<String, Object> map = new HashMap<>();
map.put("code", "user.not exist");
map.put("message", e.getMessage());*/
//转发到error请求
return "forward:/error";
}

  3.按照上述的方法,可以实现自适应的页面响应,但是此时响应的是默认的页面 ,想要实现自适应的效果,需要传入我们自定义的状态码:

     @ExceptionHandler(UserNotExistException.class)
public String handlerException(Exception e, HttpServletRequest request) {
//传入我们自己的错误状态码
request.setAttribute("javax.servlet.error.status_code",500);
//转发到error请求
return "forward:/error";
}

  4.将我们的定制数据携带出去:
  (1)出现错误以后会来到error请求,这个请求会被BasicErrorController处理,他要返回的内容是由getErrorAttributes()方法得到的,而该方式是AbstractErrorController中随规定的方法,因此我们完全可以自定义一个Controller的实现类,或者是编写AbstractErrorController的子类来完成.
  (2)页面上能用的数据或者是JSON返回能用的数据都是通过errorAttributes.getErrorAttributes(requestAttributes,includeStackTrace);来得到的
  容器中DefaultErrorAttributes默认来进行数据处理,我们可以扩展该类来自定义返回信息:

 package com.zhiyun.springboot.web_restfulcrud.component;

 import org.springframework.boot.autoconfigure.web.DefaultErrorAttributes;
import org.springframework.web.context.request.RequestAttributes; import java.util.Map; /**
* @author : S K Y
* @version :0.0.1
*/
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
map.put("company", "skykuqi");
return map;
}
}

  (3)想要传递更多的信息,我们可以使用request来进行传递

     @ExceptionHandler(UserNotExistException.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", "user.not exist");
map.put("message", e.getMessage());
request.setAttribute("errorMessage", map);
//转发到error请求
return "forward:/error";
}
 package com.zhiyun.springboot.web_restfulcrud.component;

 import org.springframework.boot.autoconfigure.web.DefaultErrorAttributes;
import org.springframework.web.context.request.RequestAttributes; import java.util.Map; /**
* @author : S K Y
* @version :0.0.1
*/
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
map.put("company", "skykuqi");
//自定义异常处理器所携带的数据
Map errorMap = (Map) requestAttributes.getAttribute("errorMessage", RequestAttributes.SCOPE_REQUEST);
map.put("errorMessage", errorMap);
return map;
}
}

  --最终的效果:我们可以定制ErrorAttributes来进行自定义错误信息的响应

SpringBoot(六) -- SpringBoot错误处理机制的更多相关文章

  1. springboot(六)SpringBoot问题汇总

    SpringBoot2.0整合Mybatis,取datetime数据类型字段出来时,发现少了8小时. 过程:mysql中注册时间查询出来结果是正确的,只是java程序运行出来后显示少了8小时.经前辈指 ...

  2. SpringBoot(六):SpringBoot中如何使用Servlet?

    第一种方法: 1.使用Servlet3的注解方式编写一个Servlet 2.在main方法的主类上添加注解: @ServletComponentScan(basePackages = "co ...

  3. Springboot 错误处理机制

    SpringBoot默认的错误处理机制 即我们常见的白色的ErrorPage页面 浏览器发送的请求头: 如果是其他的请求方式,比如客户端,则相应一个json数据: 原理:是通过 ErrorMvcAut ...

  4. 4_6.springboot2.xWeb开发之错误处理机制

    1.SpringBoot默认的错误处理机制 默认效果:1).浏览器,返回一个默认的错误页面 浏览器发送请求的请求头: ​ 2).如果是其他客户端,默认响应一个json数据 原理: ​ 默认情况下,Sp ...

  5. Springboot 系列(七)Spring Boot web 开发之异常错误处理机制剖析

    前言 相信大家在刚开始体验 Springboot 的时候一定会经常碰到这个页面,也就是访问一个不存在的页面的默认返回页面. 如果是其他客户端请求,如接口测试工具,会默认返回JSON数据. { &quo ...

  6. 【玩转SpringBoot】让错误处理重新由web服务器接管

    其实web服务器是会处理错误的 在web.xml还是随处可见的年代时(确实有点老黄历了),下面的这些配置应该都不陌生. 根据错误代码处理错误,如下图01: 根据异常类型处理错误,如下图02: 不过我们 ...

  7. Netty(一) SpringBoot 整合长连接心跳机制

    前言 Netty 是一个高性能的 NIO 网络框架,本文基于 SpringBoot 以常见的心跳机制来认识 Netty. 最终能达到的效果: 客户端每隔 N 秒检测是否需要发送心跳. 服务端也每隔 N ...

  8. 【玩转SpringBoot】SpringBoot应用的启动过程一览表

    SpringBoot应用的启动方式很简单,就一行代码,如下图01: 其实这行代码背后主要执行两个方法,一个是构造方法,一个是run方法. 构造方法主要内容就是收集一些数据,和确认一些信息.如下图02: ...

  9. 【SpringBoot】SpringBoot Web开发(八)

    本周介绍SpringBoot项目Web开发的项目内容,及常用的CRUD操作,阅读本章前请阅读[SpringBoot]SpringBoot与Thymeleaf模版(六)的相关内容 Web开发 项目搭建 ...

随机推荐

  1. git 流程 rebase rename

    git流程: git init --bare git checkout -b develop git checkout -b feature1 feature1: git add . git comm ...

  2. 「版本升级」界面控件Kendo UI正式发布R2 2019|附下载

    通过70多个可自定义的UI组件,Kendo UI可以创建数据丰富的桌面.平板和移动Web应用程序.通过响应式的布局.强大的数据绑定.跨浏览器兼容性和即时使用的主题,Kendo UI将开发时间加快了50 ...

  3. Acitiviti的查询及删除(六)

    流程定义查询 查询部署的流程定义. /** * 查询流程定义信息 //act_re_procdef */ public class QueryProcessDefinition { public st ...

  4. 贪心整理&一本通1431:钓鱼题解

    题目传送 (其实有一个更正经的题解) 看了许久,发现这题貌似就是一个动态规划啊,但毕竟是贪心题库里的题,还是想想用贪心解吧. 经过(借鉴大佬思路)十分复杂的思考后,终于理解出了这题的贪心思路.该题的难 ...

  5. .NET(c#) 移动APP开发平台 - Smobiler(2) - 平台介绍

    看到大家很多人在后台问我一些问题,所以准备写一个系列了,下面给个目录 目录: .NET(c#) 移动APP开发平台 - Smobiler(1) 环境的搭建及上手第一个应用 类似开发WinForm的方式 ...

  6. android读取xml

    /*** 从config.xml中获取版本信息以及应用id* * @param urlPath* @return* @throws Exception*/public List getUpdateIn ...

  7. 730KII 打印机 Win7 2017年11月更新系统补丁后无法打印

    卸载11月份编号为KB4048960的系统更新

  8. POJ 1384 Piggy-Bank (完全背包)

    Piggy-Bank 题目链接: http://acm.hust.edu.cn/vjudge/contest/130510#problem/F Description Before ACM can d ...

  9. 百度地图 API 及使用

    如果我们想使用地图的功能,我们就得使用别人的接口,百度地图无疑是个不错的选择 百度地图的网址:http://lbsyun.baidu.com/ 我们想使用里面的功能,就必须要获取密钥 如果时第一次使用 ...

  10. HDU6715 算术(莫比乌斯反演)

    HDU6715 算术 莫比乌斯反演的变形. 对 \(\mu(lcm(i,j))\) 变换,易得 \(\mu(lcm(i,j)) = \mu(i)\cdot\mu(j)\cdot \mu(gcd(i,j ...