【Spring Boot】异常处理

异常处理

  • 1.认识异常处理
    • 1.1 异常处理的必要性
    • 1.2 异常的分类
    • 1.3 如何处理异常
      • 1.3.1 捕获异常
      • 1.3.2 抛出异常
      • 1.3.4 自定义异常
    • 1.4 Spring Boot 默认的异常处理
  • 2.使用控制器通知
  • 3.自定义错误处理控制器
    • 3.1 自定义一个错误的处理控制器
    • 3.2 自定义业务异常类
      • 3.2.1 自定义异常类
      • 3.2.2 自定义全局捕获异常
      • 3.2.3 测试自定义异常类

1.认识异常处理

异常处理 是编程语言的机制,用来处理软件系统中出现的异常情况,增强代码的可读性。

1.1 异常处理的必要性

异常处理用于解决一些程序无法掌控,但又必须面对的情况。例如,程序需要读取文件、连接网络、使用数据库等,但可能文件不存在、网络不畅通、数据库无效等情况。为了程序能继续运行此时就需要把这些情况进行异常处理。异常处理的方法通常有以下几种:

  • 将异常通知给开发人员、运维人员或用户。
  • 使因为异常中断的程序以适当的方式继续运行,或者退出。
  • 保存用户的当前操作,或者进行数据回滚。
  • 释放资源。

1.2 异常的分类

  • Error:代表编译和系统的错误,不允许捕获。
  • Exception:标准 Java 库的方法所激发的异常,包含运行异常 Runtime_Exception 和非运行异常 Non_RuntimeException 的子类。
  • Runtime Exception:运行时异常。
  • Non RuntimeException:非运行时可检测的异常,Java 编译器利用分析方法或构造方法中可能产生的结果来检测程序中是否含有检测异常的处理程序,每个可能的可检测异常、方法或构造方法的 throws 子句必须列出该异常对应的类。
  • Throw:用户自定义异常。

1.3 如何处理异常

1.3.1 捕获异常

捕获异常的格式,见以下代码:

try{//......
}
catch(//......
)
finally{//......
}
  • try:在 try 语句中编写可能发生异常的代码,即正常的业务功能代码。如果执行完 try 语句不发生异常,则执行 finally 语句(如果有的话)和 finally 后面的代码;如果发生异常,则尝试去匹配 catch 语句。
  • catch:捕捉错误并处理。
  • finallyfinally 语句是可选的,无论异常是否发生、是否匹配、是否被处理,finally 都会执行。

一个 try 至少要有一个 catch 语句,或至少要有 1 1 1finally 语句。finally 不是用来处理异常的,也不会捕获异常,是为了做一些清理工作,如流的关闭、数据库连接的关闭等。

1.3.2 抛出异常

除用 try 语句处理异常外,还可以用 throwthrows 抛出异常。

执行 throw 语句的地方是一个异常抛出点,后面必须是一个异常对象,且必须写在函数中。

throwthrows 的用法见以下代码。

  • throw 语法:
throw(异常对象);
  • throws 语法:
[(修饰符)](返回值类型)(方法名)([参数列表])[throws(异常类)]{...}

1.3.4 自定义异常

在应用程序的开发过程中,经常会自定义异常类,以避免使用 try 产生重复代码。自定义异常类一般是通过扩展 Exception 类来实现的。这样的自定义异常属于 检查异常checked exception)。如果要自定义非检查异常,则需要继承 RuntimeException。

1.4 Spring Boot 默认的异常处理

Spring Boot 提供了一个默认处理异常的映射。在 Spring Boot 的 Web 项目中,尝试访问一个不存在的 URL(http://localhost:8080/pipi),会得到 Spring Boot 中内置的异常处理如下提示:

This application has no explicit mapping for /error, so you are seeing this as a fallback.
Sat May 18 22:49:20 CST 2019
There was an unexpected error (type=Not Found, status=404).
No message available.

同样的地址,如果发送的请求带有 Content-Type→application/json;charset=UTF-8 则返回的是 JSON 格式的错误结果,见以下输出结果:

{"timestamp":"2019-05-18T14:47:46.722+0000","status": 404,"error": "Not Found","message": "No message available","path": "/pipi"
}

从上面结果可以看出,Spring Boot 会根据消费者发送的 Content-Type 来返回相应的异常内容,如果 Content-Typeapplicaton/json,则返回 JSON 文件;如果 Content-Type,是 text/html,则返回 HTML 文件。

2.使用控制器通知

在编写代码时,需要对异常进行处理。进行异常处理的普通的代码是 try...catch 结构。但在开发业务时,只想关注业务正常的代码,对于 catch 语句中的捕获异常,希望交给异常捕获来处理,不单独在每个方法中编写。这样不仅可以减少冗余代码,还可以减少因忘记写 catch 而出现错误的概率。

Spring 正好提供了一个非常方便的异常处理方案:控制器通知@ControllerAdvice@RestcontrollerAdvice),它将所有控制器作为一个切面,利用切面技术来实现。

通过基于 @ControllerAdvice 或 @RestControllerAdvice 的注解可以对异常进行全局统一处理,默认对所有的 Controller 有效。如果要限定生效范围,则可以使用 ControllerAdvice 支持的限定范围方式。

  • 按注解@ControllerAdvice(annotations=RestController.class)
  • 按包名@ControllerAdvice("org.example.controller")
  • 按类型@ControllerAdvice(assignableTypes={Controllerlnterface.class, AbstractController.class})

这是 ControllerAdvice 进行统一异常处理的优点,它能够细粒度地控制该异常处理器针对哪些 Controller、包或类型有效。

可以利用这一特性在一个系统实现多个异常处理器,然后 Controller 可以有选择地决定使用哪个,使得异常处理更加灵活、降低侵入性。

异常处理类会包含以下一个或多个方法:

  • @InitBinder:对表单数据进行绑定,用于定义控制器参数绑定规则。如转换规则、格式化等。可以通过这个注解的方法得到 WebDataBinder 对象,它在参数转换之前被执行。
  • @ModelAttribute:在控制器方法被执行前,对所有 Controller 的 Model 添加属性进行操作。
  • @ExceptionHandler:定义控制器发生异常后的操作,可以拦载所有控制器发生的异常。
  • @ControllerAdvice:统一异常处理,通过 @ExceptionHandler(value=Exception.class) 来指定捕获的异常。@ControllerAdvice + @ExceptionHandle 可以处理除 404 以外的运行异常。

3.自定义错误处理控制器

3.1 自定义一个错误的处理控制器

以下代码演示如何自定义一个错误的处理控制器。

package com.example.demo.Controller;import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;import java.util.HashMap;
import java.util.Map;@RestController
/*springboot提供了默认的错误映射地址error
@RequestMapping("${server.error.path:${error.path:/error}}")
@RequestMapping("/error")
上面2种写法都可以
*/
@RequestMapping("/error")
//继承springboot提供的ErrorController
public class TestErrorController implements ErrorController {//一定要重写方法,默认返回null就可以,不然报错,因为getErrorPath为空@Overridepublic String getErrorPath() {return null;}//一定要添加url映射,指向error@RequestMappingpublic Map<String, Object> handleError() {//用Map容器返回信息Map<String, Object> map = new HashMap<String, Object>();map.put("code", 404);map.put("msg", "不存在");return map;}/*这里加一个能正常访问的页面,作为比较因为写在一个控制器所以它的访问路径是http://localhost:8080/error/ok*/@RequestMapping("/ok")@ResponseBodypublic Map<String, Object> noError() {//用Map容器返回信息Map<String, Object> map = new HashMap<String, Object>();map.put("code ", 200);map.put("msg", "正常,这是测试页面");return map;}
}

启动项目,访问一个不存在的网址,则返回下方信息:

在这里插入图片描述
访问正确定义的映射,则返回下方正确信息:

在这里插入图片描述

3.2 自定义业务异常类

3.2.1 自定义异常类

自定义异常类需要继承 Exception(异常)类。这里继承 RuntimeException,代码如下:

package com.example.demo.exception;public class BusinessException extends RuntimeException{//自定义错误码private Integer code;//自定义构造器,必须输入错误码及内容public BusinessException(int code, String msg) {super(msg);this.code = code;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}
}

RuntimeException 和 Error 是非检查异常,其他的都是检查异常。所有方法都可以在不声明 throws 方法的情况下抛出 RuntimeException 及其子类,不可以在不声明的情况下抛出非 RuntimeException,即:非 RuntimeException 要自己写 catch 语句处理,如果 RuntimeException 不使用 try...catch 进行捕捉,则会导致程序运行中断。

3.2.2 自定义全局捕获异常

package com.example.demo.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;@ControllerAdvice
public class CustomerBusinessExceptionHandler {@ResponseBody@ExceptionHandler(BusinessException.class)public Map<String, Object> businessExceptionHandler(BusinessException e) {Map<String, Object> map = new HashMap<String, Object>();map.put("code", e.getCode());map.put("message", e.getMessage());//发生异常进行日志记录,此处省略return map;}
}

3.2.3 测试自定义异常类

创建控制器。以抛出 BusinessException 的自定义异常。

package com.example.demo.controller;import com.example.demo.exception.BusinessException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class TestController {@RequestMapping("/BusinessException")public String testResponseStatusExceptionResolver(@RequestParam("i") int i) {if (i == 0) {throw new BusinessException(600, "自定义业务错误");}return "success";}}

启动项目,访问 http://localhost:8080/BusinessException?i=0 测试异常处理情况,则抛出下方错误信息:

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

树莓派 5 AI 套件(Hailo-8L)使用教程

系列文章目录 前言 The Raspberry Pi AI Kit Raspberry Pi AI 套件将 Raspberry Pi M.2 HAT 与 Hailo AI 加速模块捆绑在一起&#xff0c;供 Raspberry Pi 5 使用。套件包含以下内容&#xff1a; 包含神经处理单元&#xff08;NPU&#xff09;的 Hailo AI 模块Raspberry Pi M.…

STM32 proteus + STM32Cubemx仿真教程(第二课按键教程)

文章目录 前言一、STM32按键的原理二、STM32Cubemx创建工程三、proteus仿真电路图四、程序代码编写4.1函数介绍4.2使用按键点亮LED灯 总结 前言 本篇文章开始带大家学习如何使用proteus和STM32Cubemx来完成STM32的学习&#xff0c;第二节课我们先来学习按键的用法。 proteus使…

[docker] docker-compose-mysql.yml

引言&#xff1a;作为一名专业的资深开发&#xff0c;本地一定拥有了不少开源项目以供学习&#xff0c;每次都要去启动 mysql 数据库跟 redis 服务器&#xff0c;这种操作1.挺烦的&#xff0c;挺费时间&#xff0c;每次都要启动命令来一次&#xff1b;2.占用自己电脑的资源&…

五款软件推荐:U盘数据不小心删除了?帮你快速找回!

U盘数据不小心删除了怎么恢复&#xff1f;U盘是一种便携式存储设备&#xff0c;因其小巧轻便而广受欢迎。但是&#xff0c;U盘也常常会遇到数据丢失的问题。当U盘数据丢失时&#xff0c;需要找到一款可靠的数据恢复软件来恢复数据。 接下来为大家推荐5款好用的免费U盘数据恢复软…

Python 使用scrapy框架

1、安装scrapy 2、使用scrapy创建项目,在终端命令行 执行如下命令&#xff0c;会创建一个myproject项目 scrapy startproject myproject 3、创建完成后&#xff0c;目录结构如下 4、cd myproject进入项目 ,执行scrapy genspider weather ******&#xff0c;会在spiders下创建…

Incredibuild for Mac 来了!

Mac 开发者在寻找适合自己需求的工具时可能会遇到一些困难&#xff0c;因为 Mac 操作系统相对封闭&#xff0c;不像其他系统那样开放和灵活。尽管如此&#xff0c;Mac 开发者在开发应用程序时的需求&#xff08;比如功能、效率等&#xff09;和使用其他操作系统的开发者是类似的…

Linux中安装Docker,并使用Docker安装MySQL和Redis

1、安装docker 1卸载系统之前的docker yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine2、安装Docker-CE #安装必须的依赖 sudo yum install -y yum-utils \device-map…

LINUX----进程替换,exec族函数

execl族函数的作用 exel族函数用于调用一个已经存在的可执行程序,将该程序的运行需要的代码区和数据区的数据覆盖原进程,这样就可以实现在一个进程中调度另一个进程. 简单实现一个小功能来看一看 mytest.c #include <stdio.h> #include <unistd.h>int main(){print…

开源VS闭源

当我们谈论大模型时&#xff0c;往往会涉及到开源和闭源两种不同的模型类型&#xff0c;开源和闭源的主要区别在于源代码的访问权限和修改能力。开源意味着软件的源代码对公众开放&#xff0c;任何人都可以查看、修改和分发源代码&#xff0c;这促进了技术的透明性、合作和创新…

抽象的java入门1.3.0

前言&#xff1a; 在1.2.0版本中我们介绍了public class hello {}并从中提取出两个新概 修饰符和作用域 public class hello {public static void main(String[] args) {System.out.println("Hello World");} } 正片&#xff1a; 这一期把剩余的内容刨析出来 pub…

【Redis学习笔记04】Jedis客户端(上)

Java客户端操作Redis Java生态丰富&#xff0c;自定义的客户端非常多&#xff0c;常见的有Jedis、Lettuce、以及Spring整合后的RedisTemplate&#xff0c;但是对于初学者而言&#xff0c;从Jedis开始入门学习是非常容易上手的&#xff0c;因为Jedis中的API与原生Redis命令高度…

Android Bugreport分析工具:ChkBugReport教程

安装&#xff1a; 如果下载地址过期请看原仓库地址的wiki&#xff0c;或许会有更新&#xff1a;https://github.com/sonyxperiadev/ChkBugReport/wiki 提前下载好如下文件&#xff1a; ​​​​​​http://sonyxperiadev.github.io/ChkBugReport/download/chkbugreport (Lau…

Python中的上下文管理器(contextlib)模块

Python中的contextlib模块提供了一些用于创建和管理上下文管理器&#xff08;context managers&#xff09;的工具。上下文管理器是实现了__enter__()和__exit__()方法的对象&#xff0c;它们通常用于确保在代码块执行前后执行某些操作&#xff0c;比如资源获取与释放、设置和重…

一分钟有60秒,这个有趣的原因你知道吗?

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

string类的模拟实现的一些改进

上回我们完成了string类的模拟实现&#xff0c;不过之前写的传统写法本篇&#xff0c;我们将要对其进行一些改进&#xff0c;写成参考的是现代写法&#xff0c;这样写可以提高可读性。 上回我们写好的string类 //string.h #pragma once#define _CRT_SECURE_NO_WARNINGS 1 #p…

常见汇编指令

下面是一些包含汇编指令 MOV、PUSH、POP、LEA、LDS、ADD、ADC、INC、SUB、SBB、DEC、CMP、MUL、DIV、AND、OR、XOR、NOT、TEST、SHL、SAL、SHR、SAR、ROL、ROR、RCL、RCR、LODS、MOVS 的例题。这些例题展示了每条指令的用法及其作用。 1. MOV 指令 MOV AX, BX ; 将寄存器 B…

github stylesmile fastboot介绍

**Fastboot是一个极速的Java Web框架&#xff0c;旨在提供高效的启动速度和低内存占用**。 Fastboot的设计理念是为了让Java应用能够以极短的时间启动&#xff0c;并且占用非常少的内存资源。项目的定位是成为Java领域内最佳的云原生解决方案&#xff0c;为开发者提供一个高效…

像素坐标系与图像坐标系

前言 在数字图像处理中&#xff0c;经常会看到使用 (x, y) 表示图像中的某个像素点。 在一些图像处理库&#xff0c;例如 Pillow 、OpenCV 、Numpy 中也会使用到坐标系处理图像的像素点。 介绍 无论是像素坐标系还是图像坐标系&#xff0c;其原理都是一样的&#xff1a; 以…

[AIGC] BFS算法详解以及实例应用

BFS&#xff08;Breadth-First Search&#xff0c;广度优先搜索&#xff09;是一种用于图的查找算法&#xff0c;可以用来解决许多问题&#xff0c;比如寻找最短路径&#xff0c;检查图是否连通&#xff0c;检查图中是否存在环等。 文章目录 BFS算法的概念BFS算法的步骤BFS示例…

UI学习(二)

UI学习&#xff08;二&#xff09; 文章目录 UI学习&#xff08;二&#xff09;布局子视图手动布局自动布局 导航控制器导航控制器基础导航控制器的切换导航栏工具栏 分栏控制器分栏控制器协议部分的内容UITableView基础部分相关的协议函数高级协议与单元格 多界面传值 布局子视…