------错误处理机制------

  默认效果

    1 返回一个默认的错误页面

  浏览器发送请求的请求头:优先接收 text/html 数据

  客户端则默认响应json数据 : accept 没有说明返回什么数据 默认返回json

  原理:参照 ErrorMvcAutoConfiguration 错误的自动配置

    1 DefaultErrorAttributes

  // 帮助我们共享页面信息
  public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> errorAttributes = new LinkedHashMap();
errorAttributes.put("timestamp", new Date());
this.addStatus(errorAttributes, webRequest);
this.addErrorDetails(errorAttributes, webRequest, includeStackTrace);
this.addPath(errorAttributes, webRequest);
return errorAttributes;
}

    2 BasicErrorController

@Controller
@RequestMapping({"${server.error.path:${error.path:/error}}"}) // 都是响应 /error请求
public class BasicErrorController extends AbstractErrorController {
  
  @RequestMapping(
  produces = {"text/html"} // 产生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 ? new ModelAndView("error", model) : modelAndView;
  }   @RequestMapping
  @ResponseBody // 产生json数据
  public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
  Map<String, Object> body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL));
  HttpStatus status = this.getStatus(request);
   return new ResponseEntity(body, status);
  }

    3 ErrorPageCustomizer

@Value("${error.path:/error}")
private String path = "/error"; 系统出现错误 到 error请求 (web.xml 注册的错误规则)

    4 DefaultErrorViewResolver

  public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
ModelAndView modelAndView = this.resolve(String.valueOf(status), model);
if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {
modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model);
} return modelAndView;
} private ModelAndView resolve(String viewName, Map<String, Object> model) {
     // 默认可以找到一个页面 error/404
String errorViewName = "error/" + viewName;
     // 模板引擎可以解析这个页面地址就用模板引擎解析
// 模板引擎可以用的情况下返回得到errorViewName指定视图地址
     // 模板引擎不可用 就在静态资源文件夹下找 errorViewName 对应的页面
     TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);
return provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);
}

    步骤:

      一旦系统出现4xx或者5xx错误:ErrorPageCustomizer 生效(定制错误的响应规则) 就会来到/error 请求

      就会被 BasicErrorController 处理:

        1) 响应页面: 去哪个页面由 DefaultErrorViewResolver 决定

protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map<String, Object> model) {
Iterator var5 = this.errorViewResolvers.iterator();
     // 所有的ErrorViewResolver 得到 ModelAndView
ModelAndView modelAndView;
do {
if (!var5.hasNext()) {
return null;
} ErrorViewResolver resolver = (ErrorViewResolver)var5.next();
modelAndView = resolver.resolveErrorView(request, status, model);
} while(modelAndView == null); return modelAndView;
}

  2 如何定制错误响应

    1) 定制错误页面

      1) 有模板引擎的情况下error/ 状态码 ( error/404.html) 将错误页面命名为错误状态码.html 发生此状态码到此错误页面

        也可以使用 4xx.html或者5xx.html 来匹配 4开头的或者5开头的错误 如果有精确的会优先到精确的错误提示页面

        页面能获取的信息:

          timestamp:时间戳

          status:状态码

          error:错误提示

          exception:异常对象

          message:异常消息

          errors:JSR303 数据校验的错误信息

          

          

      2) 没有模板引擎,在静态资源文件夹下寻找 static文件夹下寻找

      3) 模板引擎静态资源都没有 就是默认来到springboot 默认的错误提示页面

    2) 定制json 错误数据

      1) 自定义异常处理&返回json数据

//异常处理器
@ControllerAdvice
public class MyExceptionHandler {

   // 浏览器客户端返回都是json数据
@ResponseBody
@ExceptionHandler(UserNotExistException.class)
public Map<String , Object> handleException(Exception e) {
Map<String , Object> map = new HashMap<String, Object>();
map.put("code", "user.notexist");
map.put("message", e.getMessage()); return map;
}
}
// 没有自适应效果...

      2) 转发到/error 进行自适应响应 实现功能但是 map.put 信息无法接受

    @ResponseBody
@ExceptionHandler(UserNotExistException.class)
public String handleException(Exception e, HttpServletRequest request) {
Map<String , Object> map = new HashMap<String, Object>();
// 传入我们自己设置的状态码 4xx 5xx 否则不会进入到错误页面的解析流程
request.setAttribute("javax.servlet.error.status_code", 400);
map.put("code", "user.notexist");
map.put("message", e.getMessage()); // 转发到 /error页面
return "forward:/error";
}

      3) 将我们的定制数据携带出去

        出现错误以后 会来到 /error 请求 会被 ErrorBaseController 处理,响应出去的数据可以

        获取的数据时由 getErrorAttributes 得到的(是 AbstractErrorController规定的方法)

        ---1完全来编写一个 ErrorController【或者编写AbstractErrorController类子类】 的实现类放在容器中

        ---2页面上能用的数据 或者json 能用的返回数据 通过 errorAttributes.getErrorAttributes得到

          容器中DefaultErrorAttributes.getErrorAttributes 此方法定义返回数据可以自己写一个

// 给容器加入自己定义的ErrorAttributes
@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("company", "lixuchun");
// scope
// request 0
// session 1
Map<String , Object> ext = (Map<String , Object>)webRequest.getAttribute("ext", 0);
map.put("ext", ext);
return map;
}
}

          在MyExceptionHandler 中加入

    @ResponseBody
@ExceptionHandler(UserNotExistException.class)
public String handleException(Exception e, HttpServletRequest request) {
Map<String , Object> map = new HashMap<String, Object>();
// 传入我们自己设置的状态码 4xx 5xx 否则不会进入到错误页面的解析流程
request.setAttribute("javax.servlet.error.status_code", 400);
map.put("code", "user.notexist");
map.put("message", e.getMessage());
request.setAttribute("ext", map);
// 转发到 /error页面
return "forward:/error";
}

          访问结果:

          

spring boot 尚桂谷学习笔记06 异常处理 ---Web的更多相关文章

  1. spring boot 尚桂谷学习笔记08 Docker ---Web

    ------Docker------ 简介:Docker是一个开元的应用容器引擎,性能非常高 已经安装好的软件打包成一个镜像放到服务器中运行镜像 MySQL容器,Redis容器...... Docke ...

  2. spring boot 尚桂谷学习笔记10 数据访问02 mybatis

    数据访问 mybatis 创建一个 springboot 工程,模块选择 sql 中 mysql(数据驱动), jdbc(自动配置数据源), mybatis Web模块中选择 web pom 引入: ...

  3. spring boot 尚桂谷学习笔记04 ---Web开始

    ------web开发------ 1.创建spring boot 应用 选中我们需要的模块 2.spring boot 已经默认将这些场景配置好了 @EnableAutoConfiguration ...

  4. spring boot 尚桂谷学习笔记11 数据访问03 JPA

    整合JPA SpringData 程序数据交互结构图 (springdata jpa 默认使用 hibernate 进行封装) 使用之后就关注于 SpringData 不用再花多经历关注具体各个交互框 ...

  5. spring boot 尚桂谷学习笔记09 数据访问

    springboot 与数据库访问 jdbc, mybatis, spring data jpa,  1.jdbc原生访问 新建项目 使用 springboot 快速构建工具 选中 web 组件 sq ...

  6. spring boot 尚桂谷学习笔记07 嵌入式容器 ---Web

    ------配置嵌入式servlet容器------ springboot 默认使用的是嵌入的Servlet(tomcat)容器 问题? 1)如何定制修改Servlet容器的相关配置: 1.修改和se ...

  7. spring boot 尚桂谷学习笔记05 ---Web

    ------web 开发登录功能------ 修改login.html文件:注意加粗部分为 msg 字符串不为空时候 才进行显示 <!DOCTYPE html> <!-- saved ...

  8. springboot 尚桂谷学习笔记03

    ------spring boot 与日志------ 日志框架: 市面上的日志框架: jul jcl jboss-logging logback log4j log4j2 ...... 左边一个门面 ...

  9. 初次搭建spring boot 项目(实验楼-学习笔记)

    首先说一下springboot 的优点: 使用Spring Initializr可以在几秒钟就配置好一个Spring Boot应用. 对大量的框架都可以无缝集成,基本不需要配置或者很少的配置就可以运行 ...

随机推荐

  1. vue 使用 computed 结合 filter 实现数据的的过滤和排序

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  2. Codeforces Round #535 (Div. 3) F

    F. MST Unification 题目传送门 题意: 给你n个顶点,m条边:保证没有重边,其中存在多个MST(最小生成树), 你可以修改一些边的权值,让其中有且仅有一个最小生成树,求最少操作的边数 ...

  3. JQuery的链式编程与隐式迭代

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. day64--pymysql模块的使用、视图、触发器、函数、存储过程、事务

    一.pymysql的下载和使用 (一)pymysql模块的下载:pip3 install pymysql # 实现:使用Python实现用户登录,如果用户存在则登录成功(假设该用户已在数据库中) im ...

  5. 全栈开发系列学习2——django项目搭建

    项目代码:http://yunpan.cn/cHajgT4HvgHqx (提取码:8350) 配置项目: 1. 首先确保你的机器安装了python和pip,这两种安装比较简单,这里就不说了. 2. 在 ...

  6. JS-04 JS中的函数都是按值传递的

    JS中的函数都是按值传递的 1.传递参数是基本类型 如例子:基本类型传入函数后,函数内部参数生成一个参数副本,把num变量的值赋给num参数,num参数再去参与函数中的运算,但不会影响外面num变量的 ...

  7. 4.ireport基本使用

    转自:https://wenku.baidu.com/view/104156f9770bf78a65295462.html 第一部分,下载与安装 Ireport官网:http:// jasperfor ...

  8. Solr的学习使用之(一)部署

    Solr的主要功能是全文检索,该功能分为两个过程:创建索引和对索引进行搜索 一.心得体会 第一次写技术博客,这次写的基本上都是从网络上整理的来的,外加自己的一些实践,以后争取全部原创哈,都说写技术博客 ...

  9. __kindof的用法

    简介: _kindof是苹果声明的一个新特性 使用方法如下: 正常我们声明一个属性: @property (nonatomic,strong) NSArray *viewArray; 看属性我们知道v ...

  10. smbumount - 为普通用户卸载smb文件系统

    总览 smbumount 装载点 描述 普通用户使用这个程序可以卸载smb文件系统.它在工作时会suid到root身份,并且向普通linux用户提供了对资源更多的控制能力.在suid方面,它拥有足够的 ...