在我们使用Spring Boot的过程中肯定有遇到过发生错误的时候,这个时候可能页面上出现的就是Spring Boot默认的错误界面,有的时候我们希望能显示我们自己设置的错误界面,或者携带我们自己的错误响应参数,比如查询用户是否存在的时候,如果用户不存在,控制器可以选择抛出一个用户不存在异常,这个时候我们希望错误响应参数可以携带一个message响应参数表示用户不存在,而不是Spring Boot为我们配置好的那几个参数,这个时候我们应该这么做呢,这就是本文的目的。

如果要配置自己的错误界面,首先我们需要先了解一下Spring Boot是如何处理错误的。Spring Boot在自动配置类ErrorMvcAutoConfiguration中为我们添加了4个错误处理相关的组件,具体可以在IDEA中使用Ctrl+N来查找这个类,他们的作用可以查看下面代码中的注释:

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;
}

2、BasicErrorController

//处理/error请求,根据请求头中的信息(Accept参数)来判断优先返回html页面,还是JSON数据
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {@RequestMapping(produces = "text/html")//产生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 //产生json数据,其他客户端来到这个方法处理;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);}
}

3、ErrorPageCustomizer

/**
配置错误发生后,到哪去。这里是系统出现错误以后来到error请求进行处理;
也就是到上面的BasicErrorController处理器,(相当于以前web.xml注册的错误页面规则)。
可以看到这个参数是可配置的。
**/
@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), 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/404String errorViewName = "error/" + viewName;//模板引擎可以解析这个页面地址就用模板引擎解析TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);if (provider != null) {//模板引擎可用的情况下返回到errorViewName指定的视图地址return new ModelAndView(errorViewName, model);}//模板引擎不可用,就在静态资源文件夹下找errorViewName对应的页面error/404.htmlreturn resolveResource(errorViewName, model);
}

错误响应步骤如下:

一但系统出现4xx或者5xx之类的错误;ErrorPageCustomizer就会生效(定制错误的响应规则);就会来到/error请求;就会被BasicErrorController处理;如果决定产生html数据,而不是直接返回JSON数据,就使用DefaultErrorViewResolver试图解析器来解析我们的ModelAndView,最终决定返回哪个html文件。我们可以使用4xx和5xx作为错误页面的文件名来匹配这种类型的所有错误,精确优先(优先寻找精确的状态码.html,比如发生404错误,有404.html就不去4xx.html了);我们将这些错误响应的.html文件放到静态资源路径下的/error文件夹下即可。

通过上面的描述如果需要返回自己的错误返回界面,直接在静态资源文件夹下新建/error文件夹,将自己的错误响应.html文件放到里面即可,这些.html文件可能是4xx.html、404.html、5xx.html、500.html。具体响应哪个.html文件根据错误代码来决定。如果需要自定义错误响应信息,那么你还需要像下面这样做:

1、只响应JSON数据,而不管请求的是什么(比如请求.html页面,也返回JSON数据)

首先新建@ControllerAdvice类,而后在其中写@ExceptionHandler方法即可,如下:

@ControllerAdvice
public class MyExceptionHandler {@ResponseBody@ExceptionHandler(UserNotExistException.class)public Map<String,Object> handleException(Exception e){Map<String,Object> map = new HashMap<>();map.put("code","user.notexist");map.put("message",e.getMessage());return map;}
}

关于@ControllerAdvice注解更加详细的解释你可以看这里,在本文章中主要是结合@ExceptionHandler注解来处理错误。另外UserNotExistException是我们自定义的一个错误,由Controller抛出。

2、自适应响应

上面处理的方式有一个问题,就是不管是页面请求,还是JSON数据请求,我们都是返回JSON数据,如何做到请求JSON数据就返回JSON数据,请求页面就返回页面呢?我们可以回到上面说到的BasicErrorController组件,这个组件会自适应的处理/error请求,所以我们可以转发到/error界面,如下所示:

@ControllerAdvice
public class MyExceptionHandler {@ExceptionHandler(UserNotExistException.class)public String handleException(Exception e, HttpServletRequest request){//传入我们自己的错误状态码 4xx 5xx,否则就不会进入定制错误页面的解析流程request.setAttribute("javax.servlet.error.status_code",500);//转发到/errorreturn "forward:/error";}
}

但是,这个时候我们又无法响应我们自己定制的错误响应数据了,我们希望不但可以自适应,又可以携带我们自定义的数据。如果你足够细心的话,可以发现,在上面BasicErrorController组件中,不论是响应HTML页面还是反回JSON数据,都会调用getErrorAttributes这个方法,来设置错误响应数据,这个方法来自容器中的DefaultErrorAttributes组件,这个组件会在我们没有在容器中添加ErrorAttributes组件的前提下添加到容器中作为默认的ErrorAttributes以返回错误响应数据;所以我们如果要响应我们自己的数据,我们就要写一个ErrorAttributes,并且实现它的getErrorAttributes方法,然后加入到容器中,为了简单起见我们直接,继承DefaultErrorAttributes然后重写getErrorAttributes方法即可:

//给容器中加入我们自己定义的ErrorAttributes
@Component
public class MyErrorAttributes extends DefaultErrorAttributes {@Overridepublic Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,boolean includeStackTrace) {//保留默认的错误处理数据Map<String, Object> map = super.getErrorAttributes(requestAttributes,includeStackTrace);//由具体的错误处理器填入的数据,第二个参数的意思是scope,也就是从哪个域中获取,0:request,1:session, .....map.put("ext", RequestAttributes.getAttribute("ext", 0));//所有错误都会填入的错误响应数据map.put("company","BaiDu");return map;}
}

上面注释中说到的 “由具体的错误处理器填入的数据” 的意思是如下:

@ControllerAdvice
public class MyExceptionHandler {@ExceptionHandler(UserNotExistException.class)public String handleException(Exception e, HttpServletRequest request){//传入我们自己的错误状态码 4xx 5xx,否则就不会进入定制错误页面的解析流程request.setAttribute("javax.servlet.error.status_code",500);//填入额外的错误响应处理数据:Map<String,Object> map = new HashMap<>();map.put("code","user.notexist");map.put("message",e.getMessage());request.setAttribute("ext", map);//转发到/errorreturn "forward:/error";}
}

这样一来我们就不但可以自适应响应数据,还可以定制自己的错误响应信息了。

总结:
上面详细讲述了Spring Boot中发生错误后,如何处理的的流程,并且自定义错误响应数据和界面。读者可以选择自己需要的功能来选择如何处理,主要是懂得原理,这些处理方式就能使用的游刃有余。简单分为以下两点:

  • 不需要自定义错误响应数据,只要到我们自己的错误响应界面,则编写错误代码对应的HTML文件,并将这些错误响应的.html文件放到静态资源路径下的/error文件夹下即可。
  • 需要自定义错误响应数据,并且自适应响应,则在容器中加入我们自己的ErrorAttributes组件即可。

Spring Boot错误处理机制以及定制自己的错误页面相关推荐

  1. 基于Spring Boot自动化装配机制实现多数据库适配

    1. 背景说明 一个应用服务可能会用到多种数据库,可以采用多版本方式去管理运作,实际当中,同一套数据库版本可能又会适配不同的客户需求, 这时候再增加版本去维护会比较复杂, 不利于维护,有没办法根据配置 ...

  2. 面试官:聊一聊 Spring Boot 服务监控机制

    欢迎关注方志朋的博客,回复"666"获面试宝典 任何一个服务如果没有监控,那就是两眼一抹黑,无法知道当前服务的运行情况,也就无法对可能出现的异常状况进行很好的处理,所以对任意一个服 ...

  3. Spring Boot 全局异常机制

    导语   在项目开发中遇到一个问题,就是通过校验规则判断的内容抛出的异常,并没有被Spring Boot的全局异常捕获机制锁处理.这里提供了如下的解决方案 校验规则引入   在项目的POM文件中引入如 ...

  4. 架狗屎:聊一聊 Spring Boot 服务监控机制

    任何一个服务如果没有监控,那就是两眼一抹黑,无法知道当前服务的运行情况,也就无法对可能出现的异常状况进行很好的处理,所以对任意一个服务来说,监控都是必不可少的. 就目前而言,大部分微服务应用都是基于  ...

  5. java403forbidden_java – Spring boot – 返回403 Forbidden而不是重定向到登录页面

    在Spring Boot Web应用程序中,我有以下安全配置: @Override public void configure(HttpSecurity http) throws Exception ...

  6. 【spring boot】5.spring boot 创建web项目并使用jsp作前台页面

    贼烦的是,使用spring boot 创建web项目,然后我再idea下创建的,but 仅仅启动spring boot的启动类,就算整个项目都是好着的,就算是能够进入controller中,也不能成功 ...

  7. Spring Boot内置Tomcat的静态资源配置(在页面中显示项目外的某个图片)

    哇~我现在只想长长的舒一口气,终于解决了 ~    记录一下 好,下面开始我的第一个博客,写的不好还请大家见谅~ Spring Boot项目是在官网自动生成的,目录如下: 在红线圈住的"ap ...

  8. Spring Boot 四大核心机制

    起步依赖机制:通过起步依赖机制(Starter),简化jar包的引用,解决jar版本冲突问题. 自动配置:可以实现简单配置,甚至是零配置,就能搭建整套框架. StringBoot CLI:一种命令工具 ...

  9. 全网最完美地解决使用spring boot的@Value(“${xxx}“)注解时报出的错误:Could not resolve placeholder ‘xxx‘ in value “${xxx}“

    文章目录 1. 复现问题 2. 分析问题 3. 解决问题 4. 其他解决方案 4.1 检测语法是否正确 4.2 检测配置文件中是否有进行配置 4.3 检测是否增加注解 4.4 检测代码中的书写方式 4 ...

最新文章

  1. perl use 命令中指定路径
  2. Elasticlunr.js 简单介绍
  3. 基于ARM的GCC编译器,各版本arm-gcc区别与安装
  4. 为什么TCP连接至少3次握手
  5. scipy.interpolate: 插值和平滑处理
  6. esxi服务器与虚拟机时间不符,vsphere6.7-虚拟机与ESXI时间同步
  7. 【论文】Awesome Relation Extraction Paper(关系抽取)(PART III)
  8. C中的extern-static-const关键词
  9. 响应式Web设计:HTML5和CSS3实战 笔记
  10. 多模态综述 | 一文了解Language-Vision预训练最新进展和新领域
  11. php 时间日期转为时间戳,PHP日期格式转时间戳
  12. 广义线性模型的计算机应用技术学院,SPSS数据分析—广义线性模型
  13. 动规-Raucous Rockers
  14. 抛出异常关键字throw与定义异常关键字throws
  15. Bochs源码分析 - 28:bochs开启x2apic与SMP编译说明
  16. oracle的date_add,SQL Server 中add函数到 oracle date add的操作
  17. python 容联云测试短信接口
  18. 转载:stm32的引脚有两种用途
  19. WordPress数据库连接错误解决方案!
  20. ListView接收另一个页面的数值显示

热门文章

  1. docker多主机网络方案
  2. Levenberg-Marquardt快速入门教程
  3. CRS中常用的OCR和Votedisk的操作命令小结
  4. 欢迎参与Java 事务讨论
  5. 高通平台modem部分mbn文件的OTA和PDC升级方法
  6. Android开发概要记录
  7. WINCE6.0+S3C6410下的DM9000A驱动
  8. painticon java_新人,关于java的 paintIcon()方法
  9. window下建立vue.js项目
  10. 一出好戏不止是部电影,它也正接近你的生活。