在项目开发过程中,不管是对底层数据库的操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。如果对每个过程都单独作异常处理,那系统的代码耦合度会变得很高,此外,开发工作量也会加大而且不好统一,这也增加了代码的维护成本。

针对这种实际情况,我们需要将所有类型的异常处理从各处理过程解耦出来,这样既保证了相关处理过程的功能单一,也实现了异常信息的统一处理和维护。同时,我们也不希望直接把异常抛给用户,应该对异常进行处理,对错误信息进行封装,然后返回一个友好的信息给用户。这节主要总结一下项目中如何使用 Spring Boot 如何拦截并处理全局的异常。


1、异常处理问题分析

1.1 异常问题

  • 针对代码中的异常,常规有两种处理方式,一种throws直接抛出,另一种try..catch捕获。

  • 在java项目中,有可能存在人为逻辑的异常,也可能为取得异常的详情,或是保证程序在异常时继续向下执行,会采用第二种处理方式。

  • 但是,代码中每一处异常都来捕获,会使代码什么冗余且不利于维护。

1.2 解决思路

  • 定义一个全局异常处理类,返回统一规范的异常信息;

  • 处理逻辑是,先判定是否会出现异常,再执行后续具体的业务。

1.3 应用示例

本文主要为了实现全局异常处理的逻辑,只举简单业务

某公司部门需增加员工,处理流程:1先根据员工编号查询员工对象,2判断员工对象是否有信息,即是否不为空,3若有信息,则说明已存在,无需再添加,若不是,则直接添加。

举个栗子:

public class MyService {// 注入dao层@AutowiredEmployeeecMapper employeeecMapper;/*** 添加员工信息* @param employee 员工对象* @return 影响的行数*/public int add(Employee employee) {// 根据id查询员工对象Employeeec emp = employeeecMapper.selectByPrimaryKey(employee.getId());// 判断是否已有该员工if (emp != null){// 已有,抛出异常,异常信息为已有该员工throw new RuntimeException("异常代码:1201,错误信息:该员工已存在");}// 没有,插入该员工return employeeecMapper.insert(emp);}
}

2、异常处理流程分析

业务中存在运行时异常和业务逻辑异常,前者不运行时很难察觉,后者在遍及业务时就可以定义出来,因此异常分为不可预知异常和可知异常。流程如下:

  1. 自定义全局异常类,使用@ControllerAdvice,控制器增强
  2. 自定义错误代码及错误信息,两种异常最终会采用统一的信息格式来表示,错误代码+错误信息。
  3. 对于可预知的异常由程序员在代码中主动抛出,由SpringMVC统一捕获。
  4. 不可预知异常通常是由于系统出现bug、或一些外界因素(如网络波动、服务器宕机等),异常类型为RuntimeException类型(运行时异常)。

2.1 可知异常

定义异常信息类,变量为错误代码和错误信息,捕获自定义异常时,直接将该对象返回

2.2 不可知异常

定义一个map,将常见的异常存入其中,并定义错误代码。对于其他不常见的异常,即map中没有的,同一一个异常对象返回即可。


3、 异常处理流程实践

3.1 可知异常

1、定义打印异常信息与返回结果的接口

public interface ResultCode {// 操作是否成功boolean success();// 操作结果代码long code();// 提示信息String message();
}
public interface Response {public static final boolean SUCCESS = true;public static final int SUCCESS_CODE = 10000;
}

2、定义打印异常信息的枚举类和返回结果类

@ToString
public enum  CommonCode implements ResultCode {NO_PAGE(false,404,"没有信息"),FAIL(false,500,"操作失败!"),SUCCESS(true,200,"操作成功!");// 结果信息boolean success;long code;String message;// 带参构造CommonCode(boolean success, long code, String message) {this.success = success;this.code = code;this.message = message;}@Overridepublic boolean success() {return true;}@Overridepublic long code() {return code;}@Overridepublic String message() {return message;}
}
@Data
@ToString
public class ResponseResult implements Response {boolean success = SUCCESS;long code = SUCCESS_CODE;String message;public ResponseResult(ResultCode resultCode){this.success = resultCode.success();this.code = resultCode.code();this.message = resultCode.message();}
}

3、定义错误异常类

public class CustomException extends RuntimeException{@AutowiredResultCode resultCode;// 带参构造public CustomException(ResultCode resultCode){this.resultCode = resultCode;}// getterpublic ResultCode getResultCode(){return resultCode;}
}

4、定义异常抛出类

public class ExceptionCast {// 静态方法public static void cast(ResultCode resultCode){throw new CustomException(resultCode);}
}

5、定义异常捕获类,使用ControllerAdvice控制器增强的注解,并在捕获CustomException异常的方法上加ExceptionHandler注解,即可捕获该类的所有异常,返回json数据。

@ControllerAdvice
public class ExceptionCatch {/*** 捕获CustomException类异常* @param customException* @return 结果信息,json数据*/@ExceptionHandler(CustomException.class)@ResponseBodypublic ResponseResult customException(CustomException customException){ResultCode resultCode = customException.getResultCode();return new ResponseResult(resultCode);}
}

6、在业务中抛出异常

public class MyService {@AutowiredEmployeeecMapper employeeecMapper;public int add(Employee employee) {Employeeec emp = employeeecMapper.selectByPrimaryKey(employee.getId());if (emp != null){ExceptionCast.cast(CommonCode.FAIL);}return employeeecMapper.insert(emp);}
}

3.2 不可知异常处理

1、类似可知异常,先在CommonCode类中添加错误代码,如

UNAUTHORISE(false,510,"没有权限"),

2、在异常捕获类中添加不可知异常的捕获方法。该方法中,定义一个只读的map存储异常类型的错误代码的映射,map中没有的元素,统一用错误代码999来定义。

UNKNOWNERROR(false,999,"未知异常"),
@ControllerAdvice
public class ExceptionCatch {// 定义map,存贮常见错误信息。该类map不可修改private static ImmutableMap<Class<? extends Throwable>,ResultCode> EXCEPTIONS;// 构建ImmutableMapprotected static ImmutableMap.Builder<Class<? extends Throwable>,ResultCode> builder = ImmutableMap.builder();@ExceptionHandler(CustomException.class)@ResponseBodypublic ResponseResult customException(CustomException customException){ResultCode resultCode = customException.getResultCode();return new ResponseResult(resultCode);}/*** 捕获非自定义类异常* @param exception* @return*/@ExceptionHandler(Exception.class)@ResponseBodypublic ResponseResult exception(Exception exception){// 记录日志LOGGER.error("catch exception ==> ",exception.getMessage());if (EXCEPTIONS == null){EXCEPTIONS = builder.build();}ResultCode resultCode = EXCEPTIONS.get(exception.getClass());if (resultCode != null){return new ResponseResult(resultCode);}else {return new ResponseResult(CommonCode.UNKNOWNERROR);}}static {builder.put(HttpMessageNotReadableException.class, CommonCode.INVALID_PARAM);}
}

愿你就像早晨八九点钟的太阳,活力十足,永远年轻。

SpringBoot系列(10):SpringBoot中的全局异常处理相关推荐

  1. springboot(2.2.4)全局异常处理(RestControllerAdvice,ExceptionHandler)

    当程序出现异常我们一般try,catch处理,这样代码结构不好看,我们希望程序员写的代码业务和框架是分离的,通过注解进行绑定使用.springboot里通过@RestControllerAdvice注 ...

  2. 【学习笔记】springboot中的全局异常处理 和@ControllerAdvice的使用

    文章目录 全局异常处理 例子 @ControllerAdvice的其他使用场景 全局异常处理 系统中异常包括:编译时异常和运行时异常RuntimeException ,前者通过捕获异常从而获取异常信息 ...

  3. SpringBoot+拦截器+自定义异常+自定义注解+全局异常处理简单实现接口权限管理...

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/weixin_44102992/article/ details/107335702 前言 提到权限管理这块肯定很多人第一想到的 ...

  4. Spring/SpringBoot系列之Spring中涉及的9种设计模式【七】

    1. 总览 Spring中涉及的设计模式: 简单工厂(非23种设计模式中的一种) 工厂方法 单例模式 适配器模式 装饰器模式 代理模式 观察者模式 策略模式 模版方法模式 2. 详细介绍 2.1 简单 ...

  5. 在.NET Core程序中设置全局异常处理

    以前我们想设置全局异常处理只需要这样的代码: 1 AppDomain currentDomain = AppDomain.CurrentDomain;2 currentDomain.Unhandled ...

  6. java异常统一处理_Java 代码中的全局异常处理

    最近接手一个新项目,写用例的时候去翻看代码,发现部分代码里缺少基本的异常处理,包括对参数异常以及业务异常的处理.对照之前负责过的异常处理做得比较好的项目,给开发提了几点建议,顺便又去翻看了之前项目的代 ...

  7. springboot怎么返回404_Spring Boot2 系列教程(十三)Spring Boot 中的全局异常处理

    在 Spring Boot 项目中 ,异常统一处理,可以使用 Spring 中 @ControllerAdvice 来统一处理,也可以自己来定义异常处理方案.Spring Boot 中,对异常的处理有 ...

  8. springboot获取静态图片路径_SpringBoot中的全局异常处理你确定你真的知道吗?

    本篇要点 介绍SpringBoot默认的异常处理机制. 如何定义错误页面. 如何自定义异常数据. 如何自定义视图解析. 介绍@ControllerAdvice注解处理异常. 一.SpringBoot默 ...

  9. 补习系列(10)-springboot 之配置读取

    目录 简介 一.配置样例 二.如何注入配置 1. 缺省配置文件 2. 使用注解 3. 启动参数 还有.. 三.如何读取配置 @Value 注解 Environment 接口 @Configuratio ...

  10. 【SpringBoot系列】 Spring中自定义Session管理,Spring Session源码解析

    系列文章:Spring Boot学习大纲,可以留言自己想了解的技术点 目录 系列文章:Spring Boot学习大纲,可以留言自己想了解的技术

最新文章

  1. 雨季来临 对车辆涉水说“NO”
  2. 网络服务-VSFTP
  3. model.train_on_batch介绍【TensorFlow2入门手册】
  4. 《像计算机科学家一样思考Python》——3.9 变量和形参是局部的
  5. RPL的故事 ——《x86汇编语言:从实模式到保护模式》读书笔记31
  6. hdu5279 YJC plays Minecraft 【分治NTT】
  7. JAVA设计模式 - 建造者模式
  8. APICloud的BUG 组件UIActionSelector数据格式引起的安卓手机显示不出
  9. 一些Euclid空间上的定义
  10. bg、jobs、fg
  11. web安全之逻辑漏洞
  12. 计算机网络实验-----常用网络命令操作
  13. linux根据关键字查询日志的方法
  14. 系统管理服务器名,服务器管理系统排名
  15. 服务器U盘安装安装centos
  16. java抠图人物背景图片_如何进行人物抠图?让你快速完成复杂背景人像的在线抠图...
  17. 小韩详解 Iptables -- 简单使用
  18. Java状态码枚举类
  19. 面向小白的OC快速无脑配置-基于OpenCore-0.5.8-04-23编译版
  20. 【疑难总结】float文字环绕的坑

热门文章

  1. 枚举根节点、安全点、安全区域、OopMap
  2. Netty之Channel、NioEventLoopGroup、客户端connect方法总结
  3. POI合并单元格时CellRangeAddress类提示过时之解决
  4. Linux系统Ubuntu下部署Tomcat
  5. 《高性能javascript》随笔
  6. hadoop发行版本之间的区别
  7. 对js运算符“||”和“”的总结
  8. SQL Server 2008 R2 事务与隔离级别实例讲解
  9. 智慧城市热度不减 产业资本进军智能汽车相关领域
  10. 互联网产品需求管理思考1——统一需求管理