Spring 框架——利用HandlerExceptionResolver实现全局异常捕获

2023-11-03

一、需求描述

        因为在项目中,我们不可否认的会出现异常,而且这些异常并没有进行捕获。经常出现的bug如空指针异常等等。在之前的项目中,如果我们没有进行任何配置,那么容器会自动打印错误的信息,如果tomcat的404页面,400页面等等。如果我们在web.xml中进行如下配置,就会拦截错误,然后跳转到指定的错误页面。

<error-page>
    <error-code>500</error-code>
    <location>/500.jsp</location>
</error-page>

但是这已经落后了,现在我们通过实现spring的HandlerExceptionResolver接口来捕获所有的异常。

二、基本应用

        首先我们新建GlobalExceptionResolver如下:

public class GlobalExceptionResolver implements HandlerExceptionResolver{
​
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception exception) {
        //--------------------------------------------
        return null;
    }
}

然后在spring配置文件中配置刚才新建的类,或者加上@Component注解。

<!--全局异常捕捉 -->
<bean class="com.ssm.exception.GlobalExceptionResolver" />

现在就可以根据自己的需求修改GlobalExceptionResolver的横线部分了,在你在开发的时候,请返回null,这样这个类就如同不起作用,之前该怎么样就怎么样。当开发完成之后,根据错误的信息来返回需要的东西了。首先我们可以做的是打印错误日志,当然也是必须的。

System.err.println("访问" + request.getRequestURI() + " 发生错误, 错误信息:" + exception.getMessage());

这里我只是用控制台举例,你当然可以用日志框架打印。打印信息主要是包括是访问那个地址出现了什么错误。之后如果你需要返回错误页面,那么就直接在ModelAndView里面写就行了,这里就不多举例了,ModelAndView写过MVC的Controller应该都熟悉。

ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
return modelAndView;

 以上其实就已经实现了全局捕获异常的功能,你可以自己抛出一个不捕获的异常测试一下是否成功。

三、其他说明

注意不同类型和来源的请求

        因为在实际项目中,可能遇到各种请求类型,如正常的get,post。也可能是来自ajax的请求。所以如果均返回同一个ModelAndView显然可能有点不合适,对于ajax可能需要特别处理。

        还有就是如果有手机端和PC在同一个项目中的情况,那么来源不同,返回的页面也可能不同。虽然可以交给前端去做自适应处理,但是我们还是得做好考虑。

        总之,要考虑到各种不同的请求,单一返回可能并不适用所有项目。

GlobalExceptionResolver这个类推荐放在exception包下,属于一种自定义异常

        这个配置推荐放在和web相关的spring配置下,因为和类似一个controller

spring是怎么做到的?handler参数又是什么?

        首先spring官方文档536页说明了HandlerExceptionResolve,而官方推荐的是使用@ExceptionHandler注解去捕获固定的异常。然后我查了源码,spring源码中:

/**
     * Resolve the exception by iterating over the list of configured exception resolvers.
     * The first one to return a ModelAndView instance wins. Otherwise {@code null} is returned.
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response,
                                         Object handler,
                                         Exception ex) {
        if (resolvers != null) {
            for (HandlerExceptionResolver handlerExceptionResolver : resolvers) {
                ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
                if (mav != null) {
                    return mav;
                }
            }
        }
        return null;
    }

这是spring默认实现,也就是说,我们没有重写的话,spring是这样执行的,从命名来瞎说就是。如果出现异常(private List<HandlerExceptionResolver> resolvers;),处理异常解析器就会非空,通过循环异常解析器处理resolvers中的异常,然后处理。最后返回null也就是我们之前所说的不做任何错误页面的那种处理。然后处理异常打印异常信息是在抽象类里面完成的:

/**
     * Check whether this resolver is supposed to apply (i.e. if the supplied handler
     * matches any of the configured {@linkplain #setMappedHandlers handlers} or
     * {@linkplain #setMappedHandlerClasses handler classes}), and then delegate
     * to the {@link #doResolveException} template method.
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
            Object handler, Exception ex) {
​
        if (shouldApplyTo(request, handler)) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Resolving exception from handler [" + handler + "]: " + ex);
            }
            prepareResponse(ex, response);
            ModelAndView result = doResolveException(request, response, handler, ex);
            if (result != null) {
                logException(ex, request);
            }
            return result;
        }
        else {
            return null;
        }
    }

就是打印错误信息,这里我们看到handler被打印了。打印的意思是从哪一个handler解析出什么异常。最后如果有结果依旧返回。总之我们可以知道的是,spring的handle在处理时发现异常后,HandlerExceptionResolver的列表会被赋值,然后进行处理。

四、项目运用

        这里我们可以参考《异常处理》一节阅读,首先我们的全局异常拦截器实现如下:

/**
 * 
 * 类名称 : SgccExceptionResolver. <br>
 * 功能描述 : 全局异常拦截器,可在此做异常信息的判断及输出. <br>
 * <p>
 * 创建人: Administrator <br>
 * 创建时间 : 2017年7月3日 下午15:12:36. <br>
 * </p>
 * 修改历史:  <br>
 * 修改人  修改日期   修改描述<br>
 * -----------------------------------<br>
 */
public class SgccExceptionResolver implements HandlerExceptionResolver {
​
    private Logger logger = Logger.getLogger(this.getClass());
​
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
            Exception ex) {
        logger.info("==============Exception Start 000000=============");
        if (ex instanceof BaseException) {
            logger.debug(ex, ex);
        }else {
            logger.error(ex, ex);
        }
        logger.info("==============Exception End 000000=============");
        if (NetworkUtil.isAjax(request)) {
            String msg = null;
            String code = null;
            String detail = null;
            if (ex instanceof BaseException) {
                msg = ((BaseException) ex).getErrorMsg();
                code = ((BaseException) ex).getErrorCode();
                detail = ((BaseException) ex).getMsgDetail();
            }else {
                FSTErrorCode fc = FSTErrorCode.SYS_ERROR_000000;
                msg = fc.getErrorMsg();
                code = fc.getErrorCode();
                detail = fc.getMsgDetail();
            }
            try {
                Map<String, Object> map = new HashMap<String, Object>();
                map.put("msg", msg);
                map.put("code", code);
                map.put("detail", detail);
                JSONObject json = JSONObject.fromObject(map);
                response.setContentType("text/html;charset=utf-8");
                response.getWriter().print(json);
            }catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }else {
            ModelAndView mv = new ModelAndView();
            mv.setViewName("error/error");
            mv.addObject("exception", ex.toString().replaceAll("\n", "<br/>"));
            return mv;
        }
    }    
    
}

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring 框架——利用HandlerExceptionResolver实现全局异常捕获 的相关文章

  • 我的应用程序中的 google+ 集成

    我是 Android 开发新手 正在创建一个带有 Google 集成的 Android 应用程序 我看到了一个教程并开始遵循它 但自教程以来 Google 已经更新了 Google 集成 例如 在本教程中您曾经单击 获取配置文件 按钮htt
  • Java无法读取字体

    好的 我在使用自定义字体时遇到问题 基本上我得到了从互联网上下载的自定义字体并在我的程序中使用它 当我在 Eclipse 我使用的编辑器 中运行该程序时 一切正常 没有问题 但是 每当我将它从 eclipse 导出到 jar 时 或者尝试从
  • 如何选择主题与队列

    当我们设计应用程序时如何选择Topic Queue类型实现 我知道 a 如果有多个消费者使用该消息 则使用 Topicb 如果只有一个消费者则使用Queue 请提供更多需要考虑的点 比如并发 消息持久化 负载均衡等等 Thanks Rw 如
  • RSA Java 加密和 Node.js 解密不起作用

    我有一个系统 需要在 javascript 中生成 RSA 密钥对 然后将公钥存储在服务器端的数据库中 作为字符串 然后 Java 中的服务器端将使用存储的公钥对字符串进行加密密钥并将其发送到客户端 客户端将使用私钥解密该字符串 我在客户端
  • uniVocity 不会将第一列解析为 beans

    我试图在 uniVocity parsers 的帮助下从 GTFS zip 读取 CSV 文件 但遇到了一个我无法解决的问题 由于某种原因 某些 CSV 文件的第一列似乎无法正确解析 例如 在 stops txt 文件中 如下所示 stop
  • 在java中将HTML转换为RTF?

    我需要将 HTML 转换为 RTF 我正在使用以下代码 private static String convertToRTF String htmlStr OutputStream os new ByteArrayOutputStream
  • 问题:将大数据传递给第二个 Activity

    我有一个奇怪的问题 我在网上浏览但没有找到答案 我仍然是android编程的初学者 那么让我们开始吧 我想做的就是用一些数据调用第二个活动 它适用于小数据 但如果数据变大 第二个 Activity 将不会显示 第一个 Activity 将完
  • Linux 上的 JavaFX

    Linux x86 和 x64 上的 JavaFX 情况如何 JavaFX 应用程序可以在 Linux 操作系统上顺利执行吗 我发现了 2011 年和 2012 年的一些问题 当时应用程序不稳定 目前发布的 JFX 版本是 2 2 4 在
  • JFreeChart 更改现有条形图中的数据

    我想循环更改条形图数据 但我不知道该怎么做 我的代码 DefaultCategoryDataset barChartData new DefaultCategoryDataset barChartData setValue 0 Values
  • 如何从 ByteBuffer 转换为 Integer 和 String?

    我转换了一个int使用 ByteBuffer 的字节数组putInt 方法 我该如何做相反的事情 那么将这些字节转换为 int 吗 此外 我使用 String 的将字符串转换为字节数组getBytes 方法 我如何将其反过来转换 这byte
  • Apache HttpClient 4.x 在上传较大文件时表现奇怪?

    我正在使用 java 和 scala 开发和测试一个简单的客户端 服务器应用程序 The server是基于com sun net httpserver HttpServer并允许使用 POST 和 PUT 操作通过基本的 RESTful
  • 自动装箱是否调用 valueOf()?

    我试图确定以下陈述是否保证为真 Boolean true Boolean TRUE Boolean true Boolean valueOf true Integer 1 Integer valueOf 1 我一直认为自动装箱相当于调用va
  • Java 1.8 和 tomcat 6.0.53 引起:java.io.EOFException:SSL 对等点错误关闭

    java cp catalina jar org apache catalina util ServerInfo Server version Apache Tomcat 6 0 53 Server built Apr 19 2017 22
  • Selenium 和 xpath:查找带有类/id 的 div 并验证其中的文本

    我正在努力拥有xpath find a div并验证div有一个特定的string里面的文字 这是HTML div class Caption Model saved div and div class gwt HTML sfnStanda
  • Java 多态性中的字段如何工作? [复制]

    这个问题在这里已经有答案了 我正在读书面试问题 http javabypatel blogspot in 2016 04 java interview questions html关于java 发现了很好的例子 但感到困惑 因为没有很好 更
  • Java Reflection:为什么这么慢?

    我一直避免使用 Java 反射 因为它速度缓慢 我在当前项目的设计中达到了一个点 能够使用它将使我的代码更具可读性和优雅性 所以我决定尝试一下 我只是对这种差异感到惊讶 我注意到有时运行时间几乎延长了 100 倍 即使在这个简单的例子中 它
  • JRuby调用了错误的方法

    我在调用 Java 方法时遇到了一个奇怪的问题JRuby http en wikipedia org wiki JRuby 在我的 Java 类中 这些方法定义了两次 看来 JRuby 调用了错误的方法 所以我尝试使用java method
  • 在同步子句中抛出异常的副作用?

    从同步子句中抛出异常是否有任何不清楚的副作用 锁会发生什么情况 private void doSomething throws Exception synchronized lock doSomething 我没有看到任何副作用 The 锁
  • 使用 ProGuard 混淆代码后如何保持 javadoc 可见?

    我使用 progured 4 7 混淆了我的代码 并保留了 A 类 其中包含描述该类功能的 javadoc keep public class com mysite ClassA public keepattributes InnerCla
  • Scala 不可变 Map 速度慢

    当我创建地图时 我有一段代码 val map gtfLineArr 8 split map split collect case Array k v gt k v toMap 然后我使用这张地图来创建我的对象 case class MyOb

随机推荐

  • MacOS Xcode与Swift版本对应关系

    Swift4 Xcode9 0 or later macOS 10 12 6 Xcode 9 4 1 macOS 10 13 2 Swift4 2 Xcode10 or later macOS 10 13 4 Swift5 0 ABI 现在
  • 解决某网站无法调试的问题(function anonymous( ) { debugger })

    Ctrl F8
  • Add Addtional Series with fitlers of Stacked Column Charts or Bar Charts in MS CRM 2011

    Aggregate Total on top of Stacked Column Charts or Bar Charts in MS CRM 2011 Adding an aggregated total to the top of a
  • Oracle面试题整理

    目录 Oracle面试题整理 1 MySQL和Oracle的区别 2 Oracle中function和procedure的区别 3 比较truncate和delete命令 4 oralce中 rowid rownum的定义 5 事务的特性
  • K8S系列一:概念入门

    写在前面 本文组织方式 K8S的架构 作用和目的 需要首先对K8S整体有所了解 K8S是什么 为什么是K8S K8S怎么做 K8S的重要概念 即K8S的API对象 要学习和使用K8S必须知道和掌握的几个对象 Pod 实例 Volume 数据
  • 【目标检测】9、Feature Selective Anchor-Free Module for Single-Shot Object Detection

    文章目录 摘要 1 引言 2 相关工作 3 Anchor free特征选择模型 3 1 网络结构 3 2 Ground truth 和 loss 3 3 在线特征选择 3 4 Joint 推断和训练 4 实验 4 1 消融学习 4 2 与目
  • 生成payload木1马 攻击 linux

    需要 1 生成payload 木马 2 开启httpd 3 启动msfdb run 监听 4 目标机下载payload 并执行 5 6 开始 1 生成payload 木马 把他存放到httpd服务的 var www html 下 msfve
  • 【Vue/element】 el-table实现表格动态新增/插入/删除 表格行,可编辑单元格

    el table实现表格动态新增 插入 删除 表格行 可编辑单元格 效果如下 点击 新增一行 可以在表格最后新增一行 单元格内容可编辑 点击绿色 按钮 可在指定行的后面插入一行 点击红色 按钮 可以删除指定行 原理 表格el table是通
  • 值得收藏的30道Python练手题(附详解)

    今天给大家分享30道Python练习题 建议大家先独立思考一下解题思路 再查看答案 文末附python学习资料 1 已知一个字符串为 hello world yoyo 如何得到一个队列 hello world yoyo 使用 split 函
  • 指针数组与数组指针、函数指针与函数指针数组

    一 指针数组 是一个存放指针的数组 eg int arr 优先级高 所以arr首先是一个数组 里面存放的是一个个指针 int arr 数组中放入二级指针 二 数组指针 是一个指向数组的指针 eg int arr 10 指向int 10 的指
  • Mybatis:in在where查询条件中的写法(mysql和pgsql)

    在mybatis使用过程中 有时需要传递一个包含多个值的参数 用in来查询这些值范围内的数据 如fid是一个Int类型字段 现在需要查询1 2 3 这三个fid的记录 直接将 1 2 3作为一个入参传递进来时 需要做些修改才能正确实现In的
  • 哪些行业需要重点防御ddos攻击

    DDoS攻击是网络安全领域最为常见 危害性十分庞大的攻击方式之一 各大行业都很容 易遭受DDoS攻击 因此受到了各个企业的广泛关注 那么到底什么是DDoS攻击 哪些行业最 需要预防DDoS攻击 我们一起来看看吧 到底什么是DDoS攻击 DD
  • 类什么时候被加载

    在Java中 类会在第一次使用时被加载 而加载类的时机取决于类的加载触发条件 Java类的加载过程是按需加载的 这意味着只有在需要使用类的时候 类才会被加载到内存中 类加载的触发条件包括以下情况 创建类的实例 当你使用 new 关键字创建一
  • 组合优化

    组合优化 MATLAB实现GA BP和PSO BP多输入单输出预测 目录 组合优化 MATLAB实现GA BP和PSO BP多输入单输出预测 基本介绍 程序设计 GA BP PSO BP 参考资料 基本介绍 MATLAB实现GA BP和PS
  • Android混合开发详解

    1 Android加载HTML页面 1 1 WebView简介与使用 Webview的应用场景 WebView控件功能强大 除了具有一般View的属性和设置外 还可以对url请求 页面加载 渲染 页面交互进行强大的处理 主要用于html页面
  • 淘宝购物车测试用例

    功能 购物车界面的所有跳转链接都可以点的动 点击店铺名可以跳转到店铺界面 点击商品可以跳转到商品界面 如果店铺的 table 区域中有 凑单 字样 跳转到凑单界面 如果店铺有 领券 字样 可以弹出领券界面 如果不选择任何商品就进行结算 则显
  • C语言可以开发哪些项目?

    C语言是我们大多数人的编程入门语言 对其也再熟悉不过了 不过很多初学者在学习的过程中难免会出现迷茫 比如 不知道C语言可以开发哪些项目 可以应用在哪些实际的开发中 这些迷茫也导致了我们在学习的过程中不知道如何学 学什么 所以 总结这个列表
  • 第147篇 笔记-预言机(Oracle)

    定义 区块链预言机是将区块链连接到外部系统的实体 从而使智能合约能够基于现实世界的输入和输出执行 预言机为分散的 Web3 生态系统提供了一种访问现有数据源 遗留系统和高级计算的方式 去中心化预言机网络 DON 支持创建混合智能合约 其中链
  • Sentinel服务熔断和流控

    简介 Sentinel 随着微服务的流行 服务和服务之间的稳定性变得越来越重要 Sentinel 是面向分布式服务架构的流量控制组件 主要以流量为切入点 从限流 流量整形 熔断降级 系统负载保护 热点防护等多个维度来帮助开发者保障微服务的稳
  • Spring 框架——利用HandlerExceptionResolver实现全局异常捕获

    一 需求描述 因为在项目中 我们不可否认的会出现异常 而且这些异常并没有进行捕获 经常出现的bug如空指针异常等等 在之前的项目中 如果我们没有进行任何配置 那么容器会自动打印错误的信息 如果tomcat的404页面 400页面等等 如果我