SpringBoot(六) -- SpringBoot错误处理机制
一.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错误处理机制的更多相关文章
- springboot(六)SpringBoot问题汇总
SpringBoot2.0整合Mybatis,取datetime数据类型字段出来时,发现少了8小时. 过程:mysql中注册时间查询出来结果是正确的,只是java程序运行出来后显示少了8小时.经前辈指 ...
- SpringBoot(六):SpringBoot中如何使用Servlet?
第一种方法: 1.使用Servlet3的注解方式编写一个Servlet 2.在main方法的主类上添加注解: @ServletComponentScan(basePackages = "co ...
- Springboot 错误处理机制
SpringBoot默认的错误处理机制 即我们常见的白色的ErrorPage页面 浏览器发送的请求头: 如果是其他的请求方式,比如客户端,则相应一个json数据: 原理:是通过 ErrorMvcAut ...
- 4_6.springboot2.xWeb开发之错误处理机制
1.SpringBoot默认的错误处理机制 默认效果:1).浏览器,返回一个默认的错误页面 浏览器发送请求的请求头: 2).如果是其他客户端,默认响应一个json数据 原理: 默认情况下,Sp ...
- Springboot 系列(七)Spring Boot web 开发之异常错误处理机制剖析
前言 相信大家在刚开始体验 Springboot 的时候一定会经常碰到这个页面,也就是访问一个不存在的页面的默认返回页面. 如果是其他客户端请求,如接口测试工具,会默认返回JSON数据. { &quo ...
- 【玩转SpringBoot】让错误处理重新由web服务器接管
其实web服务器是会处理错误的 在web.xml还是随处可见的年代时(确实有点老黄历了),下面的这些配置应该都不陌生. 根据错误代码处理错误,如下图01: 根据异常类型处理错误,如下图02: 不过我们 ...
- Netty(一) SpringBoot 整合长连接心跳机制
前言 Netty 是一个高性能的 NIO 网络框架,本文基于 SpringBoot 以常见的心跳机制来认识 Netty. 最终能达到的效果: 客户端每隔 N 秒检测是否需要发送心跳. 服务端也每隔 N ...
- 【玩转SpringBoot】SpringBoot应用的启动过程一览表
SpringBoot应用的启动方式很简单,就一行代码,如下图01: 其实这行代码背后主要执行两个方法,一个是构造方法,一个是run方法. 构造方法主要内容就是收集一些数据,和确认一些信息.如下图02: ...
- 【SpringBoot】SpringBoot Web开发(八)
本周介绍SpringBoot项目Web开发的项目内容,及常用的CRUD操作,阅读本章前请阅读[SpringBoot]SpringBoot与Thymeleaf模版(六)的相关内容 Web开发 项目搭建 ...
随机推荐
- 浅谈C++ allocator内存管理(对比new的局限性)(转)
STL中,对内存管理的alloc的设计,迫使我去学习了allocator类.这里对allocator内存管理做了点笔记留给自己后续查阅.allocator类声明.定义于头文件<memory> ...
- 绑定class -vue
1.值为对象 :class = "{ 'text-red': isActive }" data () { return { isActive : true } } :class = ...
- 微信小程序 背景音频播放遇到的深坑
1.微信前台(聊天页)暂停后回到小程序,再点击播放,播放信息消失,无法续播 ios可以监听到 (onStop已经停止)事件, 安卓无法监听到,只能监听到普通的暂停事件. 2.
- java -cp与java -jar的区别
java -cp 和 -classpath 一样,是指定类运行所依赖其他类的路径,通常是类库,jar包之类,需要全路径到jar包,window上分号“;”格式:java -cp .;myClass.j ...
- 【leetcode】838. Push Dominoes
题目如下: 解题思路:本题题目中有一点要求很关键,“we will consider that a falling domino expends no additional force to a fa ...
- vue中的:is
is string | Object (组件的选项对象) <div id="app"> <span>这是:is的案例</span> <co ...
- 3分钟教会你把封装的js公共方法挂载在vue实例原型上
第一步:首先在src文件夹里面创建一个通用js文件夹,然后在创建的文件夹里面创建一个js文件 第二步:const 一个方法,然后通过export暴露出来(在同一个页面可以写多个方法,和暴露多个方法,在 ...
- overload(重载) 和 override(重写)的区别
overload(重载): 重载是基于一个类中,方法名相同,参数列表不同(如果参数列表相同时,参数的类型要不同),与返回值和访问修饰符都无关 如果在面试中就直接说:"同名不同参" ...
- jquery-时间轴滑动
效果预览图: html: <div class="tim"> <div class="timdiv"> <div class=&q ...
- mysql CREATE DATABASE语句 语法
mysql CREATE DATABASE语句 语法 作用:创建数据库. 大理石构件 语法:CREATE DATABASE database_name mysql CREATE DATABASE语句 ...