Spring MVC 中,处理异常的 6种方式

异常处理是每个 Java程序员需要面对的一个问题,在Spring中,提供了多种机制来处理控制器抛出的异常,确保应用程序在面对各种错误情况时能够优雅地响应。这篇文章,我们来详细分析Spring MVC中,几种优雅处理异常的方式。

1. 使用@ExceptionHandler注解

@ExceptionHandler注解允许在单个Controller中定义处理特定异常的方法。当 Controller的方法抛出指定的异常时,Spring会调用相应的处理方法。

如下示例,展示了如何在 Controller层优雅处理异常:

@Controller
public class MyController {@RequestMapping("/example")public String example() {// 可能抛出异常的业务逻辑if (1/0) {throw new CustomException("自定义异常发生");}return "success";}@ExceptionHandler(CustomException.class)public ModelAndView handleCustomException(CustomException ex) {ModelAndView mav = new ModelAndView();mav.addObject("message", ex.getMessage());mav.setViewName("errorPage");return mav;}
}

优点: 简单直观,适用于单个控制器的异常处理。

缺点: 如果多个控制器需要相同的异常处理逻辑,需要在每个控制器中重复定义。

2. 使用@ControllerAdvice注解

@ControllerAdvice是一种全局的异常处理方式,可以应用于所有 Controller。通过将异常处理逻辑集中在一个地方,可以避免代码重复,提高维护性。

如下示例,展示了如何使用 @ControllerAdvice 优雅处理全局异常:

@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(CustomException.class)public ModelAndView handleCustomException(CustomException ex) {ModelAndView mav = new ModelAndView();mav.addObject("message", ex.getMessage());mav.setViewName("errorPage");return mav;}@ExceptionHandler(Exception.class)public ModelAndView handleGeneralException(Exception ex) {ModelAndView mav = new ModelAndView();mav.addObject("message", "发生了一个错误: " + ex.getMessage());mav.setViewName("errorPage");return mav;}
}

优点:

  • 全局统一管理异常处理逻辑。
  • 代码更清晰,易于维护。

缺点:

  • 全局处理不适用于需要针对某些控制器有特殊处理需求的情况,需结合其他方法使用。

3. 实现HandlerExceptionResolver接口

HandlerExceptionResolver 是一种更底层的异常处理机制,通过实现该接口,开发者可以自定义异常解析逻辑。

如下示例,展示了如何实现 HandlerExceptionResolver接口优雅处理异常:

public class MyExceptionResolver implements HandlerExceptionResolver {@Overridepublic ModelAndView resolveException(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex) {ModelAndView mav = new ModelAndView();if (ex instanceof CustomException) {mav.addObject("message", ex.getMessage());mav.setViewName("customErrorPage");} else {mav.addObject("message", "未知错误");mav.setViewName("errorPage");}return mav;}
}

配置
在 Spring 配置文件中注册自定义异常解析器:

<bean class="com.example.MyExceptionResolver"/>

优点

  • 高度灵活,可以处理各种复杂的异常情景。

缺点

  • 需要更多的配置和实现工作。
  • 不如注解方式直观,适用性较低。

4. 使用@ResponseStatus注解

@ResponseStatus注解可以用于自定义异常对应的 HTTP 状态码和错误信息,当抛出带有该注解的异常时,Spring会自动设置相应的状态码。

如下示例,展示了如何使用 @ResponseStatus注解优雅处理异常:

@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "资源未找到")
public class ResourceNotFoundException extends RuntimeException {public ResourceNotFoundException(String message) {super(message);}
}

使用:


@Controller
public class MyController {@RequestMapping("/resource")public String getResource() {// 假设资源未找到throw new ResourceNotFoundException("资源ID不存在");}
}

优点:

  • 简单快捷,适用于直接映射到特定 HTTP 状态码的异常情况。

缺点:

  • 无法返回自定义的错误页面或更复杂的错误信息。

5. 使用ResponseEntity和@RestControllerAdvice

在构建 RESTful API时,常用ResponseEntity来返回自定义的错误响应,并结合 @RestControllerAdvice可以全局处理异常并返回 JSON 格式的错误信息。

如下示例,展示了如何使用ResponseEntity和*@RestControllerAdvice*来处理 RESTful API的异常:

@RestControllerAdvice
public class RestExceptionHandler {@ExceptionHandler(CustomException.class)public ResponseEntity<ErrorResponse> handleCustomException(CustomException ex) {ErrorResponse error = new ErrorResponse("CUSTOM_ERROR", ex.getMessage());return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);}@ExceptionHandler(Exception.class)public ResponseEntity<ErrorResponse> handleGeneralException(Exception ex) {ErrorResponse error = new ErrorResponse("GENERAL_ERROR", "内部服务器错误");return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);}
}public class ErrorResponse {private String errorCode;private String errorMessage;// 构造方法、getter 和 setter
}

优点

  • 适用于 RESTful 服务,能够返回结构化的错误信息(如 JSON)。
  • 全局统一管理,易于维护。

缺点

  • 需要定义额外的错误响应类。

6. 使用@ControllerAdvice和@ExceptionHandler

如果使用 Spring Boot,可以更便捷地使用 @ControllerAdvice 结合自动配置实现异常处理。

如下示例,展示了如何使用 @ControllerAdvice@ExceptionHandler来处理异常:

@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(MethodArgumentNotValidException.class)public ResponseEntity<ValidationErrorResponse> handleValidationExceptions(MethodArgumentNotValidException ex) {ValidationErrorResponse errors = new ValidationErrorResponse();ex.getBindingResult().getAllErrors().forEach((error) -> {errors.addError(((FieldError) error).getField(), error.getDefaultMessage());});return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);}// 其它异常处理方法
}

优点

  • 与 Spring Boot 无缝集成,减少配置。
  • 提供了诸多便利的功能,如自动处理验证错误等。

7. 总结

本文,我们分析了 Spring MVC优雅处理异常的几种方法以及代码示例,我们可以根据具体需求选择合适的方法:

  • 局部控制器处理:使用 @ExceptionHandler 注解,适用于单个控制器的特定异常处理。
  • 全局处理:使用 @ControllerAdvice@RestControllerAdvice,适用于跨多个控制器的统一异常处理。
  • 自定义解析:实现 HandlerExceptionResolver 接口,适用于需要高度自定义的异常处理逻辑。
  • 状态码注解:使用 @ResponseStatus 注解,适用于简单的异常状态码映射。
  • RESTful API:结合 ResponseEntity 和全局异常处理,返回结构化的错误响应。

从实际工作来看,@ControllerAdvice@RestControllerAdvice是使用频率最高的一种方式。

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

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

相关文章

量子通信学习路径(一)

量子通信是一门融合量子力学和通信技术的交叉学科&#xff0c;其核心目标是利用量子力学的特性&#xff08;如叠加态和纠缠&#xff09;实现信息传递和安全通信。以下是一个系统学习量子通信的完整大纲&#xff0c;从基础知识到实际应用逐步深入&#xff0c;帮助建立全面的知识…

QGIS修行记-如何使用QGIS进行换行标注

问题描述 QGIS根据指定的文字进行换行标注 项目的需要先描述一下&#xff1a; 需要标注的字段太长&#xff0c;需要进行换行标注需要换行的数据不确定有多少&#xff08;适用于批量数据的操作&#xff09;我需要根据指定文字进行换行 如&#xff1a;成山头海洋生态自然保护区…

指针的深入讲解

本章重点&#xff1a; 字符指针数组指针指针数组数组传参和指针传参函数指针函数指针数组指向函数指针数组的指针回调函数 我们在指针的初阶的时候主要讲了&#xff1a; 1.指针就是变量&#xff0c;用来存放地址&#xff0c;地址唯一标识一块内存空间 2.指针的大小是固定4个…

LWIP协议:三次握手和四次挥手、TCP/IP模型

一、三次握手&#xff1a;是客户端与服务器建立连接的方式&#xff1b; 1、客户端发送建立TCP连接的请求。seq序列号是由发送端随机生成的&#xff0c;SYN字段置为1表示需要建立TCP连接。&#xff08;SYN1&#xff0c;seqx&#xff0c;x为随机生成数值&#xff09;&#xff1b;…

WEB开发: 全栈工程师起步 - Python Flask +SQLite的管理系统实现

一、前言 罗马不是一天建成的。 每个全栈工程师都是从HELLO WORLD 起步的。 之前我们分别用NODE.JS 、ASP.NET Core 这两个框架实现过基于WebServer的全栈工程师入门教程。 今天我们用更简单的来实现&#xff1a; Python。 我们将用Python来实现一个学生管理应用&#xff0…

WatchAlert - 开源多数据源告警引擎

概述 在现代 IT 环境中&#xff0c;监控和告警是确保系统稳定性和可靠性的关键环节。然而&#xff0c;随着业务规模的扩大和数据源的多样化&#xff0c;传统的单一数据源告警系统已经无法满足复杂的需求。为了解决这一问题&#xff0c;我开发了一个开源的多数据源告警引擎——…

ABAP SQL 取日期+时间最新的一条数据

我们在系统对接的时候&#xff0c;外部系统可能会推送多个数据给到我们。 我们 SAP 系统的表数据中日期和时间是作为主键的&#xff0c;那么如果通过 ABAP SQL 取到最新日期的最新时间呢。 解决方案&#xff1a; 方式 1&#xff1a;SELECT MAX 可以通过两个 SELECT MAX 来取…

Vue3 + Element-Plus + vue-draggable-plus 实现图片拖拽排序和图片上传到阿里云 OSS 父组件实现真正上传(最新保姆级)

Vue3 Element-Plus vue-draggable-plus 实现图片拖拽排序和图片上传到阿里云 OSS&#xff08;最新保姆级&#xff09;父组件实现真正上传 1、效果展示2、UploadImage.vue 组件封装3、相关请求封装4、SwiperConfig.vue 调用组件5、后端接口 1、效果展示 如果没有安装插件&…

容器化技术全面解析:Docker 与 Containerd 的深入解读

目录 Docker 简介 1. 什么是 Docker&#xff1f; 2. Docker 的核心组件 3. Docker 的主要功能 4. Docker 的优点 5. Docker 的使用场景 Containerd 简介 1. 什么是 Containerd&#xff1f; 2. Containerd 的核心特性 3. Containerd 的架构 4. Containerd 与 Docker 的…

LNMP+discuz论坛

0.准备 文章目录 0.准备1.nginx2.mysql2.1 mysql82.2 mysql5.7 3.php4.测试php访问mysql5.部署 Discuz6.其他 yum源&#xff1a; # 没有wget&#xff0c;用这个 # curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo[rootlocalhost ~]#…

Android Studio的笔记--BusyBox相关

BusyBox 相关 BusyBoxandroid上安装busybox和使用示例一、下载二、移动三、安装和设置环境变量四、使用 busybox源码下载和查看 BusyBox BUSYBOX BUSYBOX链接https://busybox.net/ 点击链接后如图 点击左边菜单栏的Get BusyBix中的Download Source 跳转到busybox 的下载源码…

LabVIEW与PLC点位控制及OPC通讯

在工业自动化中&#xff0c;PLC通过标准协议&#xff08;如Modbus、Ethernet/IP等&#xff09;与OPC Server进行数据交换&#xff0c;LabVIEW作为上位机通过OPC客户端读取PLC的数据并进行监控、控制与处理。通过这种方式&#xff0c;LabVIEW能够实现与PLC的实时通信&#xff0c…

C++ OpenGL学习笔记(1、Hello World空窗口程序)

终于抽出时间系统学习OpenGL 教程&#xff0c;同时也一步一步记录怎样利用openGL进行加速计算。 目录 1、环境准备1.1、库的下载1.2、库的选择及安装 2、OpenGL第一个项目&#xff0c;Hello World!2.1、新建hello world控制台项目2.2、配置openGL环境2.2.1 包含目录配置2.2.2 …

系统移植——Linux 内核顶层 Makefile 详解

一、概述 Linux Kernel网上下载的版本很多NXP等有自己对应的版本。需要从网上直接下载就可以。 二、Linux内核初次编译 编译内核之前需要先在 ubuntu 上安装 lzop 库 sudo apt-get install lzop 在 Ubuntu 中 新 建 名 为 “ alientek_linux ” 的 文 件夹 &#xff0c; …

ubuntu16.04ros-用海龟机器人仿真循线系统

下载安装sudo apt-get install ros-kinetic-turtlebot ros-kinetic-turtlebot-apps ros-kinetic-turtlebot-interactions ros-kinetic-turtlebot-simulator ros-kinetic-kobuki-ftdi sudo apt-get install ros-kinetic-rocon-*echo "source /opt/ros/kinetic/setup.bash…

Connection lease request time out 问题分析

Connection lease request time out 问题分析 问题背景 使用apache的HttpClient&#xff0c;我们知道可以通过setConnectionRequestTimeout()配置从连接池获取链接的超时时间&#xff0c;而Connection lease request time out正是从连接池获取链接超时的报错&#xff0c;这通常…

【文档搜索引擎】在内存中构造出索引结构(上)

文章目录 主要思路正排索引和倒排索引的表示1. 正排索引查询文档详细信息2. 倒排索引中查找关联词3. 新增文档正排索引倒排索引实现词频统计 主要思路 通过 Index 类&#xff0c;在内存中构造出索引结构。这个类要提供的方法&#xff1a; 给定一个 docId&#xff0c;在正排索…

单节点calico性能优化

在单节点上部署calicov3273后&#xff0c;发现资源占用 修改calico以下配置是资源消耗降低 1、因为是单节点&#xff0c;没有跨节点pod网段组网需要&#xff0c;禁用overlay方式网络(ipip&#xff0c;vxlan),使用route方式网络 配置calico-node的环境变量 CALICO_IPV4POOL_I…

tryhackme-Pre Security-HTTP in Detail(HTTP的详细内容)

任务一&#xff1a;What is HTTP(S)?&#xff08;什么是http&#xff08;s&#xff09;&#xff09; 1.What is HTTP? (HyperText Transfer Protocol)&#xff08;什么是 HTTP&#xff1f;&#xff08;超文本传输协议&#xff09;&#xff09; http是你查看网站的时候遵循的…

Javascript面试手撕常见题目(回顾一)

1.JS查找文章中出现频率最高的单词? 要在JavaScript中查找文章中出现频率最高的单词&#xff0c;你可以按照以下步骤进行操作&#xff1a; 将文章转换为小写&#xff1a;这可以确保单词的比较是大小写不敏感的。移除标点符号&#xff1a;标点符号会干扰单词的计数。将文章拆…