有天上飞的概念,就要有落地的实现

  • 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍

  • 先赞后看,养成习惯

SpringBoot 图文教程系列文章目录

  1. SpringBoot图文教程1—SpringBoot+Mybatis 环境搭建
  2. SpringBoot图文教程2—日志的使用「logback」「log4j」
  3. SpringBoot图文教程3—「‘初恋’情结」集成Jsp
  4. SpringBoot图文教程4—SpringBoot 实现文件上传下载
  5. SpringBoot图文教程5—SpringBoot 中使用Aop
  6. SpringBoot图文教程6—SpringBoot中过滤器的使用
  7. SpringBoot图文教程7—SpringBoot拦截器的使用姿势这都有
  8. SpringBoot图文教程8—SpringBoot集成MBG「代码生成器」
  9. SpringBoot图文教程9—SpringBoot 导入导出 Excel 「Apache Poi」
  10. SpringBoot图文教程10—模板导出|百万数据Excel导出|图片导出「easypoi」
  11. SpringBoot图文教程11—从此不写mapper文件「SpringBoot集成MybatisPlus」
  12. SpringBoot图文教程12—SpringData Jpa的基本使用
  13. SpringBoot图文教程13—SpringBoot+IDEA实现代码热部署
  14. SpringBoot图文教程14—阿里开源EasyExcel「为百万数据读写设计」

前言

本文教程示例代码见码云仓库:https://gitee.com/bingqilinpeishenme/boot-demo

异常处理在Java中是一种很常规的操作,在代码中我们常用的方法是try catch或者上抛异常。

但是,如果Controller发生异常了怎么办?业务层的异常可以在Controller捕获,Controller抛出的异常怎么捕获?SpringMvc的异常怎么捕获?

这个时候常见的操作有两种:

  1. 跳转错误页面,例如:找不到路径的时候跳转404,代码报错的时候跳转500等
  2. 响应统一的报错信息,使用Result对象(自定义的实体类)封装错误码,错误描述信息响应【分布式服务调用的时候推荐使用】

今天我们就简单的来讲解一下SpringBoot中如何进行异常处理,跳转404或者封装错误信息响应。

跳转错误页面

SpringBoot 错误页面的默认配置

在SpringBoot中 error page错误页面是有默认配置的,默认配置是这样

  • 如果在static目录中存在error文件夹,并且文件夹中存在400.html,或者500.html,出现对应的响应状态的时候(404和500的使用),会跳转到对应的页面

  • 如果你使用的是webapp目录,也是一样的,只要在webapp目录中存在400.jsp页面(html也一样),出现对应的响应状态的时候(404和500的使用),会跳转到对应的页面

以上是默认配置,只要是SpringBoot的项目都会生效,接下来我们来测试一下

  1. 在static目录下创建error文件夹,400.html以及500.html

  2. 写一个会报错的Controller方法 test500

  3. 启动项目分别访问一个不存在的路径【测试】和访问会报错的Controller方法,效果如下

自定义错误页面的配置

以上是SpringBoot关于错误页面的默认配置,但是很多时候我们的需求比SpringBoot的默认配置要复杂很多,例如:404页面不想放在error文件夹下,500错误的时候也不想跳转页面,而是响应给页面一个json的数据等。

这个时候需要做的就是修改SpringBoot的默认配置了。

实现的目标:

  • 404的时候跳转到static下的404页面
  • 500的时候响应页面一句话:“后台错误 请联系管理员”

第一步:创建一个能够响应 “后台错误 请联系管理员” 这句话的Controller方法,将404页面放在static下面【如果是webapp也一样】

第二步:创建错误页面的配置类,修改默认的配置


  1. /**
  2. * 错误页面配置
  3. *
  4. * 继承错误页面注册器 ErrorPageRegistrar
  5. */
  6. @Configuration
  7. public class ErrorConfig implements ErrorPageRegistrar {
  8. @Override
  9. public void registerErrorPages(ErrorPageRegistry registry) {
  10. /**
  11. * 配置错误页面
  12. *
  13. * ErrorPage 有两个参数
  14. * 参数1 响应状态码 NOT_FOUND 404 INTERNAL_SERVER_ERROR 500
  15. * 参数2 出现响应状态码的时候的跳转路径 可以自定义跳转路径
  16. */
  17. ErrorPage error404 = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html");
  18. ErrorPage error500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/testData");
  19. /**
  20. * 将ErrorPage 注册到注册器中
  21. */
  22. registry.addErrorPages(error404,error500);
  23. }
  24. }

第三步:启动项目,可以看到如下效果

访问不存在的路径,跳转404页面

访问 http://localhost:8802/test500 效果如下:

以上就是跳转404和统一响应数据的操作,但是还有问题,什么问题呢?

以上的操作实际上没有针对异常进行捕获,而是根据响应的状态码进行不同的处理的,那么如果才能针对不同的异常进行捕获呢?这就要用到全局异常捕获了。

全局异常捕获

还记得文章开头说过的第二个场景吗?使用Result对象(自定义的实体类)统一封装异常状态码,异常信息,进行返回。通过全局异常捕获就可以实现。

测试的要求是:

  • 捕获自定义异常,封装Result对象以json的格式响应
  • 捕获自定义异常,跳转到错误页面

1.自定义异常

在应用开发过程中,除系统自身的异常外,不同业务场景中用到的异常也不一样,很多时候需要自定义异常,所以我们自定义两个异常,分别是:

  • ErrorReturnResultException 如果出现这个异常,就返回统一Result对象
  • ErrorReturnPageException 如果出现这个异常,就跳转错误页面

ErrorReturnResultException

  1. package com.lu.bootexception.exception;
  2. public class ErrorReturnResultException extends RuntimeException {
  3. /**
  4. * 错误码
  5. */
  6. private int code;
  7. public ErrorReturnResultException() {
  8. }
  9. public ErrorReturnResultException(String message) {
  10. super(message);
  11. }
  12. public ErrorReturnResultException(String message, int code) {
  13. super(message);
  14. this.code = code;
  15. }
  16. public int getCode() {
  17. return code;
  18. }
  19. public void setCode(int code) {
  20. this.code = code;
  21. }
  22. }

ErrorReturnPageException

  1. package com.lu.bootexception.exception;
  2. public class ErrorReturnPageException extends RuntimeException {
  3. /**
  4. * 错误码
  5. */
  6. private int code;
  7. public ErrorReturnPageException() {
  8. }
  9. public ErrorReturnPageException(String message, int code) {
  10. super(message);
  11. this.code = code;
  12. }
  13. public ErrorReturnPageException(String message) {
  14. super(message);
  15. }
  16. public int getCode() {
  17. return code;
  18. }
  19. public void setCode(int code) {
  20. this.code = code;
  21. }
  22. }

2.自定义响应实体

定义返回的异常信息的格式,这样异常信息风格更为统一

  1. package com.lu.bootexception.exception;
  2. import lombok.Data;
  3. @Data
  4. @NoArgsConstructor
  5. @AllArgsConstructor
  6. public class Result {
  7. private int code;
  8. private String message;
  9. }

3.全局异常捕获实现

利用Spring的API定义一个全局异常处理的类,代码和注释如下:

  1. package com.lu.bootexception.exception;
  2. import org.springframework.web.bind.annotation.ControllerAdvice;
  3. import org.springframework.web.bind.annotation.ExceptionHandler;
  4. import org.springframework.web.bind.annotation.ResponseBody;
  5. /**
  6. * @ControllerAdvice 增强Controller的注解 可以实现全局异常捕获
  7. */
  8. @ControllerAdvice
  9. public class GlobalExceptionHandler {
  10. /**
  11. * @ExceptionHandler 指明要捕获那个异常
  12. * 不加@ResponseBody 会使用视图解析器跳转页面
  13. * 形参处是Exception 简单来说就是会把捕获到的异常通过形参传入方法中
  14. */
  15. @ExceptionHandler(ErrorReturnPageException.class)
  16. public String errorReturnPageException(Exception e){
  17. // 打印错误信息
  18. System.out.println(e.getMessage());
  19. // 跳转500页面
  20. return "forward:/500.html";
  21. }
  22. /**
  23. * 捕获 ErrorReturnResultException 异常
  24. * 通过 @ResponseBody 注解响应数据 会以json的格式响应
  25. */
  26. @ExceptionHandler(ErrorReturnResultException.class)
  27. @ResponseBody
  28. public Result errorReturnResultException(final Exception e) {
  29. ErrorReturnResultException exception = (ErrorReturnResultException) e;
  30. /**
  31. * Result 中可以写入自定义的异常状态码
  32. */
  33. return new Result(5001, exception.getMessage());
  34. }
  35. /**
  36. * 捕获 RuntimeException 异常
  37. */
  38. @ExceptionHandler(RuntimeException.class)
  39. @ResponseBody
  40. public Result runtimeExceptionHandler(final Exception e) {
  41. RuntimeException exception = (RuntimeException) e;
  42. /**
  43. * Result 中可以写入自定义的异常状态码
  44. */
  45. return new Result(4004, exception.getMessage());
  46. }
  47. }

代码中用到的注解

  • @ControllerAdvice 捕获抛出的异常,如果添加 @ResponseBody 返回信息则为JSON格式。
  • @RestControllerAdvice 相当于 @ControllerAdvice@ResponseBody 的结合体。
  • @ExceptionHandler 指明要捕获那个异常

4.写两个测试方法 测试全局异常捕获的效果

访问 http://localhost:8802/testReturnPage 会跳转错误页面

访问 http://localhost:8802/testReturnResult 会返回统一的json数据

总结

恭喜你完成了本章的学习,为你鼓掌!如果本文对你有帮助,请帮忙点赞,评论,转发,这对作者很重要,谢谢。

让我们再次回顾本文的学习目标

  • 掌握SpringBoot中异常处理的基本使用

要掌握SpringBoot更多的用法,请持续关注本系列教程。

求关注,求点赞,求转发

欢迎关注本人公众号:鹿老师的Java笔记,将在长期更新Java技术图文教程和视频教程,Java学习经验,Java面试经验以及Java实战开发经验。

SpringBoot图文教程15—项目异常怎么办?「跳转404错误页面」「全局异常捕获」的更多相关文章

  1. SpringBoot图文教程17—上手就会 RestTemplate 使用指南「Get Post」「设置请求头」

    有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1-Spr ...

  2. 🔥SpringBoot图文教程2—日志的使用「logback」「log4j」

    有天上飞的概念,就要有落地的实现 概念+代码实现是本文的特点,教程将涵盖完整的图文教程,代码案例 文章结尾配套自测面试题,学完技术自我测试更扎实 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例 ...

  3. SpringBoot图文教程3—「‘初恋’情结」集成Jsp

    有天上飞的概念,就要有落地的实现 概念+代码实现是本文的特点,教程将涵盖完整的图文教程,代码案例 文章结尾配套自测面试题,学完技术自我测试更扎实 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例 ...

  4. SpringBoot图文教程8 — SpringBoot集成MBG「代码生成器」

    有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1「概念+ ...

  5. SpringBoot图文教程9—SpringBoot 导入导出 Excel 「Apache Poi」

    有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1「概念+ ...

  6. SpringBoot图文教程10—模板导出|百万数据Excel导出|图片导出「easypoi」

    有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1「概念+ ...

  7. SpringBoot图文教程11—从此不写mapper文件「SpringBoot集成MybatisPlus」

    有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1「概念+ ...

  8. SpringBoot图文教程「概念+案例 思维导图」「基础篇上」

    有天上飞的概念,就要有落地的实现 概念+代码实现是本文的特点,教程将涵盖完整的图文教程,代码案例 每个知识点配套自测面试题,学完技术自我测试 本文初学向,所以希望文中所有的代码案例都能敲一遍 大哥大姐 ...

  9. SpringBoot图文教程14—SpringBoot集成EasyExcel「上」

    有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1「概念+ ...

随机推荐

  1. 国内外主流的三维GIS软件

    我国GIS经过三十多年的发展,理论和技术日趋成熟,在传统二维GIS已不能满足应用需求的情况下,三维GIS应运而生,并成为GIS的重要发展方向之一.上世纪八十年代末以来,空间信息三维可视化技术成为业界研 ...

  2. Oracle中的 timestamp 和 timestamp with time zone, timestamp with local time zone

    SQL> select dbtimezone, sessiontimezone from dual; DBTIME ------ SESSIONTIMEZONE ---------------- ...

  3. js正则表达式常用的大部分函数

    1.)String方法a.)String.search()参数:可以是正则表达式也可以是普通的字符串.返回值:如果找到匹配则返回首字符的索引位置,找不到则返回-1var s = "Hello ...

  4. OC门与OD门以及线与逻辑

    OC(Open Collector)门又叫集电极开路门,主要针对的是BJT电路(从上往下依次是基极,集电极,发射极)OD(Open Drain)门又叫漏极开路门,主要针对的是MOS管(从上往下依次是漏 ...

  5. Linux_更改主机名

    老师上linux课截图必须改主机名字,每个人一个代号,所以就写篇这个咯 查看主机名 [root@localhost.localdomain Desktop]# hostname localhost.l ...

  6. python后端面试第六部分:git版本控制--长期维护

    ################## git版本控制 ####################### 1,git常见命令作用 2,某个文件夹中的内容进行版本管理:进入文件夹,右键git bash 3, ...

  7. 如何使用iTunes制作iPhone铃声

    新版iTunes(iTunes11)推出以后,界面上发生了一些改变,给人带来一种面貌一新的感觉,但也给许多朋友带来一些操作上的不太适应.下面就大家比较关心的iPhone的铃声制作方法,我在iTunes ...

  8. docker E: Unable to locate package nginx

    在使用docker容器时,有时候里边没有安装vim,敲vim命令时提示说:vim: command not found,这个时候就需要安装vim,可是当你敲apt-get install vim命令时 ...

  9. CentOS 6.5 搭建DNS服务器

    1.安装bind yum install -y bind 2.修改named.conf主配置文件 vim /etc/named.conf 图中圈中的地方改为any 3.配置正向.反向解析 vim /e ...

  10. MOOC(7)- case依赖、读取json配置文件进行多个接口请求-读取json封装成类(13)

    把读取json数据的函数封装成类 # -*- coding: utf-8 -*- # @Time : 2020/2/12 16:44 # @File : do_json_13.py # @Author ...