一.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. 最近关于Qt学习的一点碎碎念

    最近关于Qt学习的一点碎碎念 一直在使用Qt,但是最近对Qt的认识更加多了一些.所以想把自己的一些想法记录下来. Qt最好的学习资料应该是官方的参考文档了.对Qt的每一个类都有非常详细的介绍.我做了一 ...

  2. ubuntu 16.04 安装后需要做的事情

    1. 更改软件源 sudo gedit /etc/apt/source.list 在底部加入:(如果可以,把Ubuntu官方源注释掉“#_____”) # deb cdrom:[Ubuntu 16.0 ...

  3. jvm slot复用

    如果当前字节码PC计数器的值已经超出了某个变量的作用域,那这个变量对应的Slot就可以交给其他变量使用. 字节码PC计数器就是程序计数器,程序计数器记录当前线程所执行的字节码的偏移地址.如果这个值超出 ...

  4. LOJ bitset+分块 大内存毒瘤题

    题面 $ solution: $ 真的没有想到可以用分块. 但是可以发现一个性质,每个询问只关心这个点最后一次赋值操作,和这个赋值操作后的所有取 $ min $ 操作.这个感觉很有用,但是真的很难让人 ...

  5. wepy-开发总结(功能点)

    开发小程序中,遇到的wepy的几点坑,记录一下; 更详细的项目总结记录请见我的个人博客:https://fanghongliang.github.io/ 1.定时器: 在页面中有需要用到倒计时或者其他 ...

  6. 安装mod_rpaf让apache获取访客真实IP

    安装mod_rpaf让apache获取访客真实IP 安装mod_rpaf让apache获取访客真实IP 作者:朱 茂海 /分类:Apache  字号:L M S     mod_rpaf是apache ...

  7. CentOS8 安装部署Apache+Php+MariaDB(pdo扩展)

    使用新的CentOS8系统架设PHP服务器,因现在主流数据库mysql已闭源了,所以现在改为使用MariaDB.而php7以后不支持mysqli链接,只有pdo方式,为了安装pdo扩展,所以重新编译安 ...

  8. 3D打印格式STL

    STL格式及其转换 近期接触了3D打印的一些东西,也制作了一个vrml转stl的插件,对该领域多了一些认识. 目前尚没有打印机直接支持stl.obj等格式,在打印之前需使用厂家提供的软件将stl等格式 ...

  9. Quick BI的宝藏工具——交叉表

    对于普通的表格展示数据,相信大家都非常熟悉了,今天给大家介绍的是BI领域的分析利器-交叉表,这个在BI分析场景中使用占比最多的分析利器.通过交叉表对数据的承载和管理,用户可以一目了然地分析出各种场景指 ...

  10. php 客户端调用elasticsearch接口

    1.php调用elasticsearch接口[参考资料:https://www.cnblogs.com/php0916/articles/6587340.html] /data/www/syhuo.n ...