【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 中的异常处理:全局异常与自定义异常

 <前文回顾>

点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshare=blogcolumn&sharetype=blogcolumn&sharerId=12907601&sharerefer=PC&sharesource=FoyoDesigner&sharefrom=from_link

<今日更新>

一、开篇整活儿

今儿个咱唠唠 Spring Boot 里头的异常处理。这玩意儿吧,说大不大,说小不小,整好了是锦上添花,整不好就是火上浇油。你要是刚入门,那可得悠着点儿,别一上来就整得自己“翻车”了。

二、Java 中的异常是啥构型?

Java 里头的异常,说白了就是程序运行时出的岔子。Java 的异常体系是“树形结构”,最顶上是 Throwable,往下分成 Error 和 Exception。Error 是那种严重的、没法儿处理的错误,比如说内存溢出啥的。Exception 是那种可以处理的异常,比如说空指针、数组越界啥的。

1. Exception 的分类

Exception 又分成两种:受检异常非受检异常

  • 受检异常:这种异常你得在代码里头显式处理,要么 try-catch,要么 throws。比如说 IOException,你要是读写文件,那得处理这个异常。
  • 非受检异常:这种异常不用显式处理,比如说 NullPointerException、ArrayIndexOutOfBoundsException,这些异常通常是代码写得不严谨导致的。

Java Code

// 受检异常示例

try {

    FileInputStream fis = new FileInputStream("file.txt");

} catch (IOException e) {

    e.printStackTrace();

}

// 非受检异常示例

String str = null;

System.out.println(str.length()); // 这里会抛出 NullPointerException

2. 异常之间的关系

Java 里头的异常是“继承关系”,子类异常可以捕获父类异常。比如说,IOException 是 Exception 的子类,你要是 catch 了 Exception,那 IOException 也能被捕获。

Java Code

try {

    // 一些可能抛出异常的代码

} catch (IOException e) {

    // 处理 IOException

} catch (Exception e) {

    // 处理其他 Exception

}

这段代码里头,IOException 会被第一个 catch 捕获,其他的 Exception 会被第二个 catch 捕获。

三、Spring Boot 中的全局异常处理

Spring Boot 里头有个 @ControllerAdvice 注解,专门用来做全局异常处理。你可以把它想象成一个“兜底的”,Controller 里头没处理的异常,它都能接住。

1. 全局异常处理示例

Java Code

@ControllerAdvice

public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)

    public ResponseEntity<String> handleException(Exception e) {

        return new ResponseEntity<>("出错了:" + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);

    }

}

这段代码里头,@ControllerAdvice 是用来定义一个全局的异常处理类,@ExceptionHandler 是用来处理特定类型的异常的。ResponseEntity 是用来返回 HTTP 响应的,里头可以带上状态码和响应体。

2. 处理特定异常

你可以针对不同的异常,写不同的处理方法。比如说,处理 NullPointerException 和 IllegalArgumentException。

Java Code

@ControllerAdvice

public class GlobalExceptionHandler {

    @ExceptionHandler(NullPointerException.class)

    public ResponseEntity<String> handleNullPointerException(NullPointerException e) {

        return new ResponseEntity<>("空指针异常:" + e.getMessage(), HttpStatus.BAD_REQUEST);

    }

    @ExceptionHandler(IllegalArgumentException.class)

    public ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException e) {

        return new ResponseEntity<>("参数不合法:" + e.getMessage(), HttpStatus.BAD_REQUEST);

    }

}

这段代码里头,NullPointerException 和 IllegalArgumentException 会被分别处理,返回不同的错误信息。

四、自定义异常

有时候,Java 自带的异常不够用,你得自己整一个。自定义异常很简单,继承 Exception 或者 RuntimeException 就行。

1. 自定义异常示例

Java Code

public class MyCustomException extends RuntimeException {

    public MyCustomException(String message) {

        super(message);

    }

}

这段代码里头,MyCustomException 是自定义异常,继承自 RuntimeException,所以它是非受检异常。

2. 使用自定义异常

你可以在代码里头抛出这个自定义异常。

Java Code

@RestController

@RequestMapping("/api")

public class MyController {

    @GetMapping("/test")

    public String test() {

        throw new MyCustomException("这是我的自定义异常");

    }

}

这段代码里头,test 方法会抛出 MyCustomException,然后被全局异常处理器捕获。

3. 处理自定义异常

你可以在全局异常处理器里头,专门处理这个自定义异常。

Java Code

@ControllerAdvice

public class GlobalExceptionHandler {

    @ExceptionHandler(MyCustomException.class)

    public ResponseEntity<String> handleMyCustomException(MyCustomException e) {

        return new ResponseEntity<>("自定义异常:" + e.getMessage(), HttpStatus.BAD_REQUEST);

    }

}

这段代码里头,MyCustomException 会被专门处理,返回自定义的错误信息。

五、异常的 AOP 处理

AOP(面向切面编程)是 Spring 里头的一个高级特性,可以用来在方法执行前后做一些额外的事情。异常处理也可以用 AOP 来做。

1. AOP 处理异常示例

Java Code

@Aspect

@Component

public class ExceptionAspect {

    @AfterThrowing(pointcut = "execution(* com.example.demo.controller.*.*(..))", throwing = "e")

    public void handleException(Exception e) {

        System.out.println("捕获到异常:" + e.getMessage());

    }

}

这段代码里头,@Aspect 是用来定义一个切面,@AfterThrowing 是用来在方法抛出异常后执行的。pointcut 是指定哪些方法需要被切面处理,throwing 是指定异常对象的变量名。

2. AOP 和全局异常处理的区别

AOP 和全局异常处理都可以用来处理异常,但它们的应用场景不一样。全局异常处理是用来处理 Controller 里头的异常,而 AOP 可以用来处理任何地方的异常,比如说 Service 层、DAO 层啥的。

六、Spring Boot 里头的异常处理坑点

1. 异常处理的顺序

Spring Boot 里头,异常处理的顺序很重要。你要是先 catch 了 Exception,那后面的 catch 就不起作用了。

Java Code

@ControllerAdvice

public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)

    public ResponseEntity<String> handleException(Exception e) {

        return new ResponseEntity<>("出错了:" + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);

    }

    @ExceptionHandler(NullPointerException.class)

    public ResponseEntity<String> handleNullPointerException(NullPointerException e) {

        return new ResponseEntity<>("空指针异常:" + e.getMessage(), HttpStatus.BAD_REQUEST);

    }

}

这段代码里头,NullPointerException 会被 handleException 捕获,handleNullPointerException 就不起作用了。

2. 异常信息的暴露

Spring Boot 里头,默认会把异常信息返回给客户端。你要是觉得这样不安全,可以把异常信息隐藏掉。

Java Code

@ControllerAdvice

public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)

    public ResponseEntity<String> handleException(Exception e) {

        return new ResponseEntity<>("出错了", HttpStatus.INTERNAL_SERVER_ERROR);

    }

}

这段代码里头,异常信息被隐藏了,客户端只能看到“出错了”。

3. 日志记录

异常处理里头,日志记录是个大事儿。你要是没记日志,那出了问题就抓瞎了。

Java Code

@ControllerAdvice

public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(Exception.class)

    public ResponseEntity<String> handleException(Exception e) {

        logger.error("捕获到异常:", e);

        return new ResponseEntity<>("出错了", HttpStatus.INTERNAL_SERVER_ERROR);

    }

}

这段代码里头,异常信息被记录到日志里头了,方便以后排查问题。

专有名词解释

  1. Throwable:Java 中所有错误和异常的基类。
  2. Error:Java 中表示严重错误的类,通常无法恢复。
  3. Exception:Java 中表示可恢复异常的类。
  4. 受检异常:必须在代码中显式处理的异常。
  5. 非受检异常:不需要显式处理的异常。
  6. ControllerAdvice:Spring 中用于定义全局异常处理类的注解。
  7. ExceptionHandler:Spring 中用于处理特定类型异常的注解。
  8. ResponseEntity:Spring 中用于封装 HTTP 响应的类。
  9. AOP:面向切面编程,一种编程范式,用于在方法执行前后做一些额外的事情。
  10. Aspect:Spring 中用于定义切面的注解。
  11. AfterThrowing:Spring 中用于在方法抛出异常后执行的注解。
  12. Logger:用于记录日志的工具类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/74164.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

思源配置阿里云 OSS 踩坑记

按照正常的配置IAM&#xff0c;赋予OSS权限&#xff0c;思源笔记还是无法使用&#xff0c;缺少ListBuckets权限。 正常配置权限&#xff0c;又无法覆盖&#xff0c;因此需要手动配置权限。 {"Version": "1","Statement": [{"Effect":…

Debezium日常分享系列之:Debezium Charts

Debezium日常分享系列之&#xff1a;Debezium Charts 最近&#xff0c;围绕 Debezium 图表发生了一些变化&#xff0c;所以我在这里解释这些变化是什么以及背后的理由。正如您从我们的最新公告中了解到的&#xff0c;我们将发布 Debezium 管理平台的第一个版本。 Debezium 管理…

moveit2基础教程上手-使用xarm6演示

0、前置信息 开发环境&#xff1a;wsl。 ros版本&#xff1a;jazzy&#xff0c;ubuntu版本&#xff1a;24.04 xarm-ros2地址 1、启动Rviz&#xff0c;加载 Motion Planning Plugin&#xff0c;实现演示功能 Getting Started — MoveIt Documentation: Rolling documentation…

第十六届蓝桥杯模拟二

由硬件框图可以知道我们要配置LED 和按键 一.LED 先配置LED的八个引脚为GPIO_OutPut,锁存器PD2也是,然后都设置为起始高电平,生成代码时还要去解决引脚冲突问题 二.按键 按键配置,由原理图按键所对引脚要GPIO_Input 生成代码,在文件夹中添加code文件夹,code中添加fun.…

在OpenGL ES中将值传入shader的方法总结

在OpenGL ES中&#xff0c;将值传入Shader的方式主要有以下几种&#xff1a; 1. Uniform变量 用途&#xff1a;用于传递在绘制过程中不变的常量数据&#xff0c;如变换矩阵、颜色等。步骤&#xff1a; 在Shader中声明Uniform变量&#xff1a;uniform mat4 uMVPMatrix; // 例如…

华为总部-华为东莞松山湖基地参观游学攻略

你有听说过全球科技巨头-华为吗&#xff1f;今天带你深入了解这一世界标杆工厂的秘密基地。跟随华研标杆游学服务商一窥华为的强大实力。 在东莞松山湖&#xff0c;这里不仅仅是华为的终端总部&#xff0c;更是研发、销售和增值业务的核心区域。我们一行人抵达后&#xff0c;立…

Linux小知识

1. /etc目录 我们在配置文件中一直会调用 /etc目录 cd /etc/xxxx.conf etc的全称是editable configuration&#xff08;其中一种说法&#xff09;意为可编辑的配置&#xff1b;此目录主要用来存放系统的配置文件和初始化文件的&#xff1b;像网络配置 用户信息 各种服务的配置…

晶鑫股份迈向敏捷BI之路,永洪科技助力启程

数据驱动的时代&#xff0c;每一次技术的创新和突破都在为企业的发展注入新的动力。而敏捷性也不再是选择&#xff0c;是企业生存与发展的必要条件。作为连续5年获得中国敏捷BI第一名的永洪科技&#xff0c;通过不断地在数据技术领域深耕细作&#xff0c;再次迎来了行业内的关注…

基于CAMEL 的Workforce 实现多智能体协同工作系统

文章目录 一、workforce 简介1.架构设计2.通信机制 二、workforce 工作流程图示例1.用户角色2.工作流程 三、workforce 中重要函数说明1.__init__函数2.add_single_agent_worker 函数3.add_role_playing_worker 函数4.add_workforce 函数 四、基于workforce实现多智能体协调&am…

每日一题力扣2974.最小数字游戏c++

2974. 最小数字游戏 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:vector<int> numberGame(vector<int>& nums) {vector<int> arr(nums.size());sort(nums.begin(),nums.end());for(size_t i0;i<nums.size();i2){arr[i]nums[i1]…

对接马来西亚、印度、韩国、越南等全球金融数据示例

Python对接StockTV全球金融数据API的封装实现及使用教程&#xff1a; import requests import websockets import asyncio from typing import Dict, List, Optional, Union from datetime import datetimeclass StockTVClient:"""StockTV全球金融数据API客户端…

Adobe After Effects 操作

Adobe After Effects &#xff08;AE&#xff09;可以实现将多个元素进行合成&#xff0c;实现特殊效果。AE的项目文件是aep&#xff0c;可以将素材、层、效果等一切信息&#xff0c;保存在这个项目文件中。 AE的原理&#xff0c;和PS的原理非常类似。 操作界面 操作界面如…

【React】基于自定义Hook提取公共逻辑

目录 自定义Hook自定义Hook 1自定义Hook 2使用 注意事项 自定义Hook 作用&#xff1a;提取封装一些公共的处理逻辑 玩法&#xff1a;创建一个函数&#xff0c;名字需要是 useXxx &#xff0c;后期就可以在组件中调用这个方法&#xff01; 自定义Hook 1 页面加载的时候修改浏…

AUTOSAR与arxml的文档解析

如下是文档脑图 一、文档概述 该文档是 AUTOSAR 经典平台的应用接口用户指南&#xff0c;主要解释 **Al Table&#xff08;应用接口表&#xff09;** 的结构、方法论及相关技术细节&#xff0c;帮助开发者理解如何通过标准化接口实现软件组件的互操作性。 关键内容 目的&#…

油候插件、idea、VsCode插件推荐(自用)

开发软件&#xff1a; 之前的文章&#xff1a; 开发必装最实用工具软件与网站 推荐一下我使用的开发工具 目前在用的 油候插件 AC-baidu-重定向优化百度搜狗谷歌必应搜索_favicon_双列 让查询变成多列&#xff0c;而且可以流式翻页 Github 增强 - 高速下载 github下载 TimerHo…

阿里云平台服务器操作以及发布静态项目

目录&#xff1a; 1、云服务器介绍2、云服务器界面3、发布静态项目1、启动nginx2、ngixn访问3、外网访问测试4、拷贝静态资源到nginx目录下并重启nginx 1、云服务器介绍 2、云服务器界面 实例详情&#xff1a;里面主要显示云服务的内外网地址以及一些启动/停止的操作。监控&…

Spring Cache 实战指南

redis中常见的问题 前言 在本文中&#xff0c;我们将探讨 Redis 在缓存中的应用&#xff0c;并解决一些常见的缓存问题。为了简化理解&#xff0c;本文中的一些配置是直接写死的&#xff0c;实际项目中建议将这些配置写入配置文件&#xff0c;并通过配置文件读取。 一、为什…

区块链开发技术公司:引领数字经济的创新力量

在数字化浪潮席卷全球的今天&#xff0c;区块链技术作为新兴技术的代表&#xff0c;正以其独特的去中心化、不可篡改和透明性等特点&#xff0c;深刻改变着各行各业的发展格局。区块链开发技术公司&#xff0c;作为这一领域的先锋和推动者&#xff0c;正不断研发创新&#xff0…

EJS缓存解决多页面相同闪动问题

基于 EJS 的模板引擎特性及其缓存机制&#xff0c;以下是关于缓存相同模块的详细解答&#xff1a; 一、EJS 缓存机制的核心能力 模板编译缓存 EJS 默认会将编译后的模板函数缓存在内存中&#xff0c;当相同模板文件被多次渲染时&#xff0c;会直接复用已编译的模板函数&#x…

多条件排序(C# and Lua)

C# 升序排序 OrderBy 按升序对序列的元素进行排序 ThenBy 按升序对序列中的元素执行后续排序 降序排序 OrderByDescending 按降序对序列的元素排序 ThenByDescending 按降序对序列中的元素执行后续排序 public class Fruit {public int id;public string name;publi…