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

news2024/12/20 14:00:16

异常处理是每个 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 {

    @Override
    public 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.coloradmin.cn/o/2262748.html

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

相关文章

初学stm32 --- 时钟配置

目录 stm32时钟系统 时钟源 &#xff08;1&#xff09; 2 个外部时钟源&#xff1a; &#xff08;2&#xff09;2 个内部时钟源&#xff1a; 锁相环 PLL PLLXTPRE&#xff1a; HSE 分频器作为 PLL 输入 (HSE divider for PLL entry) PLLSRC&#xff1a; PLL 输入时钟源 (PL…

[机器学习]XGBoost(3)——确定树的结构

XGBoost的目标函数详见[机器学习]XGBoost&#xff08;2&#xff09;——目标函数&#xff08;公式详解&#xff09; 确定树的结构 之前在关于目标函数的计算中&#xff0c;均假设树的结构是确定的&#xff0c;但实际上&#xff0c;当划分条件不同时&#xff0c;叶子节点包含的…

常用命名总结

命名在编程中是非常重要的&#xff0c;它直接影响到代码的可读性、可维护性和开发效率。一个好的命名能够让代码更加直观、易于理解和修改&#xff0c;反之&#xff0c;不恰当的命名可能导致混乱、错误和难以调试的问题。以下是一些关于命名的最佳实践和原则&#xff1a; 1. 简…

AutoMQ 流表一体新特性 Table Topic 发布: 无缝集成 AWS S3 Table 和 Iceberg

超越共享存储&#xff1a;使用 Apache Iceberg 中的 AutoMQ Table Topic 实现流处理与分析的统一 自 2023 年底官宣以来&#xff0c;AutoMQ 成功地将 Apache Kafka 从“Shared Nothing architecture”转变为“Shared Storage architecture”&#xff0c;这为京东、知乎、小红书…

maven使用Dependency-Check来扫描安全漏洞

在现代软件开发中&#xff0c;使用开源库和第三方依赖项已成为常态。然而&#xff0c;这些依赖项可能包含已知的安全漏洞&#xff0c;给应用程序带来潜在的风险。为了解决这个问题&#xff0c;OWASP Dependency-Check 应运而生。本文将介绍 OWASP Dependency-Check 的功能、安装…

#渗透测试#红队全栈 powshell基础使用

声明&#xff01; 学习视频来自B站up主 泷羽sec&#xff0c;任何违法事件与本人以及泷羽sec团队无关&#xff0c;切勿触碰法律底线&#xff0c;否则后果自负&#xff01;&#xff01;&#xff01;&#xff01; 目录标题 认识powsehll打开方式 使用方式美化自己的powershell简单…

Qt:QMetaObject::connectSlotsByName实现信号槽自动关联

简介 在Qt中&#xff0c;QMetaObject::connectSlotsByName 是一个便利的方法&#xff0c;它可以根据对象的对象名&#xff08;objectName&#xff09;自动将信号和槽连接起来。但是&#xff0c;要使用这个方法&#xff0c;必须确保&#xff1a; 1 控件&#xff08;如按钮&…

《算法ZUC》题目

判断题 ZUC算法LFSR部分产生的二元序列具有很低的线性复杂度。 A.正确 B.错误 正确答案A 单项选择题 ZUC算法驱动部分LFSR的抽头位置不包括&#xff08; &#xff09;。 A.s15 B.s10 C.s7 D.s0 正确答案C 单项选择题 ZUC算法比特重组BR层主要使用了软件实现友好的…

maven项目中对不同目录下的同包同名类的引用情况整理

说明 maven项目&#xff0c;允许在不同目录中出现相同包名和相同类名&#xff0c;不会出现冲突&#xff0c;包括&#xff1a; java目录test目录依赖中目录 这里就用Hutool.class类中的一个常量做测试&#xff0c;如图 好奇同包同名类同时存在时&#xff0c;会加载哪个类 Syst…

【UE5 C++课程系列笔记】10——动态单播/多播的基本使用

目录 概念 申明动态委托 一、DECLARE_DYNAMIC_DELEGATE 二、DECLARE_DYNAMIC_MULTICAST_DELEGATE 绑定动态委托 一、BindDynamic 二、AddDynamic 三、RemoveDynamic 执行动态委托 ​一、Execute 二、ExecuteIfBound 三、IsBound 四、Broadcast 动态单播使用示…

Redis篇-19--运维篇1-主从复制(主从复制,读写分离,配置实现,实战案例)

1、概述 Redis的主从复制&#xff08;Master-Slave Replication&#xff09;是一种数据冗余机制&#xff0c;它允许将一台Redis服务器的数据复制到其他Redis服务器。在主从复制中&#xff0c;有一台主服务器&#xff08;Master&#xff09;和一个或多个从服务器&#xff08;Sl…

【ORACLE】一个允许关键字作为别名所引起的语法歧义场景

前言 最近在看SQL语法解析器&#xff0c;发现了antlr4提供的PlSql语法树存在一个BUG&#xff0c;然后我顺着这个BUG&#xff0c;构造了一条SQL&#xff0c;在ORACLE执行&#xff0c;如下 然后神奇的事情出现了&#xff0c;这个查询竟然没有返回行&#xff01;t1表左关联t2&…

【前端】Jquery拍照,通过PHP将base64编码数据转换成PNG格式,并保存图像到本地

目录 一、需求 二、开发语言 三、效果 四、业务逻辑&#xff1a; 五、web端调用摄像头 六、示例代码 1、前端 2、后端 一、需求 web端使用jquery调用摄像头拍照&#xff0c;并使用PHP把base64编码转换成png格式图片&#xff0c;下载到本地。 由于js不能指定图片存储的…

本地摄像头视频流在html中打开

1.准备ffmpeg 和(rtsp-simple-server srs搭建流媒体服务器)视频服务器. 2.解压视频流服务器修改配置文件mediamtx.yml ,hlsAlwaysRemux: yes 3.双击运行服务器。 4&#xff0c;安装ffmpeg ,添加到环境变量。 5.查询本机设备列表 ffmpeg -list_devices true -f dshow -i d…

机器情绪及抑郁症识别算法(六)

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

34. Three.js案例-创建球体与模糊阴影

34. Three.js案例-创建球体与模糊阴影 实现效果 知识点 WebGLRenderer WebGLRenderer 是 Three.js 中用于渲染 3D 场景的核心类。它负责将场景中的对象绘制到画布上。 构造器 new THREE.WebGLRenderer(parameters)参数类型描述parametersObject可选参数对象&#xff0c;包…

服务器数据恢复—RAIDZ离线硬盘数超过热备盘数导致阵列崩溃的数据恢复案例

服务器存储数据恢复环境&#xff1a; ZFS Storage 7320存储阵列中有32块硬盘。32块硬盘分为4组&#xff0c;每组8块硬盘&#xff0c;共组建了3组RAIDZ&#xff0c;每组raid都配置了热备盘。 服务器存储故障&#xff1a; 服务器存储运行过程中突然崩溃&#xff0c;排除人为误操…

108. 将有序数组转换为二叉搜索树(java)

题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#xff1a;[0,-10,5,null,-3,…

电子应用设计方案-60:智能床垫系统方案设计

智能床垫系统方案设计 一、引言 智能床垫作为智能家居的一部分&#xff0c;旨在为用户提供更舒适的睡眠体验和健康监测功能。本方案将详细描述智能床垫系统的设计理念、功能模块及技术实现。 二、系统概述 1. 系统目标 - 实时监测睡眠状态&#xff0c;包括心率、呼吸、体动等…

YOLOv8目标检测(六)_封装API接口

YOLOv8目标检测(一)_检测流程梳理&#xff1a;YOLOv8目标检测(一)_检测流程梳理_yolo检测流程-CSDN博客 YOLOv8目标检测(二)_准备数据集&#xff1a;YOLOv8目标检测(二)_准备数据集_yolov8 数据集准备-CSDN博客 YOLOv8目标检测(三)_训练模型&#xff1a;YOLOv8目标检测(三)_训…