Spring Boot 使用断言抛出自定义异常,优化异常处理机制

2023-11-02 21:15

本文主要是介绍Spring Boot 使用断言抛出自定义异常,优化异常处理机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 什么是断言?
    • 什么是异常?
    • 基于断言实现的异常处理机制
      • 创建自定义异常类
      • 创建全局异常处理器
      • 创建自定义断言类
      • 创建响应码类
      • 创建工具类
      • 测试效果

什么是断言?

实际上,断言(Assertion)是在Java 1.4 版本引入的特性,它为开发人员提供了一种简单的机制来进行代码预期条件的验证和调试。

Java 1.4 版本于2002年发布,它引入了许多新功能和改进,其中之一就是断言。断言的目的是在程序中进行可验证的内部检查,以确保代码的正确性和可靠性。

断言最早是在1989年由美国计算机科学家C.A.R. Hoare提出的概念,称为"断言语句"。然后,在Java 1.4版本中,Sun Microsystems将其引入到Java编程语言中,并添加了关键字assert用于表示断言。

使用assert关键字,开发人员可以在代码中编写断言语句,以检查程序的状态或条件是否满足预期。如果断言失败,会抛出一个AssertionError异常,提示开发人员该断言点存在问题。

例如org.springframework.util.Assert是Spring Framework中的一个工具类,用于进行参数校验和断言判断。它是一个包含静态方法的最终类。

org.springframework.util.Assert类中,提供了一系列静态方法用于进行断言操作,例如notNull()isTrue()hasText()等。这些方法主要用于验证方法参数或对象状态是否满足预期条件,如果不满足,则会抛出IllegalArgumentExceptionIllegalStateException等运行时异常。

常用的Assert方法源码如下:

//判断传入的表达式是否为true,如果为false,则抛出`IllegalArgumentException`异常,并使用指定的错误信息
public static void isTrue(boolean expression, String message) {if (!expression) {throw new IllegalArgumentException(message);}
}//判断传入的对象是否为null,如果为null,则抛出`IllegalArgumentException`异常,并使用指定的错误信息
public static void isNull(@Nullable Object object, String message) {if (object != null) {throw new IllegalArgumentException(message);}
}

org.springframework.util.Assert类中提供的方法可以帮助我们在编码过程中进行快速的参数校验,避免使用繁琐的if语句或手动抛出异常。同时,这些方法也提供了可自定义的错误信息,有助于更好地理解校验失败的原因。

什么是异常?

异常(Exception)是程序运行时出现的错误或异常情况,它会打断程序正常的执行流程,并且可能导致程序崩溃或产生不可预期的结果。在Java中,异常通常被表示为一个继承自Throwable类的对象,例如RuntimeException、IllegalArgumentException等。

而自定义异常是指开发人员基于Java中的Exception或其子类,定义自己的异常类。通常情况下,自定义异常类用于表示特定的异常情况,以便更好地对程序的异常情况进行分类处理和管理。自定义异常类可以包含自己的属性和方法,以提供更详细的异常信息和处理方式。

需要自定义异常的原因有以下几点:

  1. 更细粒度的异常控制:Java标准库中的异常类型比较全面,但是在实际应用中,我们可能需要更具体的异常类型来描述某种特定场景下的异常情况。例如,我们可以自定义一个PayErrorException来表示支付异常,这样可以更好地区分不同类型的异常情况,并进行不同的处理。

  2. 信息更丰富:Java标准库中的异常类型通常只包含错误信息,如果需要传递更多的相关信息,就需要自定义异常类。例如,我们可以在自定义异常类中添加一些额外的属性,如异常码、请求参数等,以便更好地记录和跟踪异常信息。

  3. 更友好的异常提示:Java标准库中的异常信息通常比较晦涩难懂,如果需要更加友好和易于理解的提示信息,就需要自定义异常类。通过自定义异常类,开发人员可以提供更加直观和易懂的异常提示信息,以便用户或其他开发人员更好地理解异常情况。

在实际业务中,我们往往需要设置一个全局的异常处理器对异常进行统一的处理和管理,并返回相应的错误信息,确保应用程序的稳定性和可靠性。

基于断言实现的异常处理机制

创建自定义异常类

首先,需要创建一个自定义的异常类,继承自RuntimeException或其子类:

/*** 自定义通用异常类*/
public class CommonException extends RuntimeException {/*** 无参构造方法*/public CommonException() {}/*** 构造方法,传入异常信息* @param message 异常信息*/public CommonException(String message) {super(message);}/*** 构造方法,传入异常信息和原始异常对象* @param message 异常信息* @param cause 原始异常对象*/public CommonException(String message, Throwable cause) {super(message, cause);}/*** 构造方法,传入原始异常对象* @param cause 原始异常对象*/public CommonException(Throwable cause) {super(cause);}
}

在自定义异常类CommonException中我们提供了几个不同的构造方法,方便在不同场景下创建异常对象。每个构造方法都调用了父类的构造方法super,以便初始化异常对象。

创建全局异常处理器

我们还需要创建一个全局异常处理器GlobalExceptionHandler,用于统一处理我们抛出的自定义异常类:

/*** 全局异常处理器*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {/*** 处理CommonException异常* @param e 异常对象* @return 异常信息*/@ExceptionHandler(CommonException.class)public String handleCommonException(CommonException e) {log.error("错误信息:{}", e.getMessage());return e.getMessage();}
}

在全局异常处理器GlobalExceptionHandler类上我们使用了@RestControllerAdvice注解标识该类为全局异常处理器。在该类中,定义了一个方法handleCommonException,用于处理异常捕获后的逻辑,在方法上添加了@ExceptionHandler()注解表示该方法处理指定自定义异常CommonException

创建自定义断言类

对于断言类,我们可以模仿org.springframework.util.Assert类,借鉴其中的方法,自定义一个抽象类MyAssert

/*** 断言类*/
public abstract class MyAssert {/*** 判断对象是否为空,如果不为空则抛出CommonException异常** @param object 要进行判断的对象*/public void assertIsNull(@Nullable Object object) {// 如果对象不为空,则抛出CommonException异常,并将当前对象序列化为JSON字符串作为异常信息if (object != null) {throw new CommonException(JSON.toJSONString(this));}}}

如上,我们创建了一个assertIsNull方法,参数object用于接收要进行判断的对象,如果object为空,则抛出CommonException异常,并将当前对象序列化为JSON字符串作为异常信息。

创建响应码类

创建自定义的响应码类,同时继承断言类MyAssert,这样我们可以通过响应码直接调用断言类中的方法进行判断:

/*** 响应码类,继承自断言类MyAssert*/
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ResCode extends MyAssert {/*** 响应码*/private int code;/*** 响应消息*/private String message;}

上述代码中,使用了Lombok库的注解来简化代码编写。具体注解的含义如下:

  • @Getter: 自动生成属性的getter方法。
  • @NoArgsConstructor: 自动生成无参构造方法。
  • @AllArgsConstructor: 自动生成包含所有参数的构造方法。

创建工具类

ResCodeUtils工具类用于调用响应码进行校验,抛出自定义异常并返回指定错误信息:

/*** 响应码工具类,继承自响应码类ResCode*/
public class ResCodeUtils extends ResCode {/*** 响应码naa,表示错误*/public static ResCode naa = new ResCode(300, "错误");/*** 响应码naa1,表示naa1错误*/public static ResCode naa1 = new ResCode(4044, "naa1错误");}

ResCodeUtils类中提供了两个静态属性naanaa1,分别表示响应码为300和4044的错误类型,方便通过类名.的方式直接调用。

测试效果

  1. 编写TestController类,添加@RestController注解表明该类是一个控制器类,用于处理HTTP请求并返回响应:

    @RestController
    public class TestController {@RequestMapping("/send1")public String send1() {ResCodeUtils.naa.assertIsNull(null);return "success";}@RequestMapping("/send2")public String send2() {ResCodeUtils.naa1.assertIsNull(new ResCode());return "success";}}
    

    TestController类中,定义了两个请求处理方法send1()send2()。这两个方法使用了@RequestMapping注解来指定它们对应的URL路径。

    • send1()方法中调用了ResCodeUtils.naa.assertIsNull(null),这表示对naa响应码进行断言,判断传入的参数是否为null。如果参数为null,断言通过,否则会抛出异常。

    • send2()方法中调用了ResCodeUtils.naa1.assertIsNull(new ResCode()),这表示对naa1响应码进行断言,判断传入的参数是否为null。由于参数new ResCode()不为null,所以这里会抛出异常。

    无论是send1()还是send2()方法,最终都会返回字符串"success"作为处理结果。

  2. 启动项目,使用 ApiFox 访问对应接口。

    • 访问send1(),由于参数为null,断言通过,返回字符串"success":

      image-20231101211357371

    • 访问send2(),由于参数为new ResCode(),不为null,断言未通过,抛出自定义异常之后被全局异常处理器GlobalExceptionHandler捕获,返回对应错误信息:

      image-20231101211431765

      同时,可以在控制台看到打印的日志信息

      image-20231101211511456


本文到此结束,感谢您的阅读,希望对您有所帮助!!!

这篇关于Spring Boot 使用断言抛出自定义异常,优化异常处理机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/333359

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关