热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

详解使用SpringMVC统一异常处理实战

1 描述 在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预

1 描述

在J2EE项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,系统的代码耦合度高,工作量大且不好统一,维护的工作量也很大。

那么,能不能将所有类型的异常处理从各处理过程解耦出来,这样既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护?答案是肯定的。下面将介绍使用Spring MVC统一处理异常的解决和实现过程。

2 分析

Spring MVC处理异常有3种方式:

(1)使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver;

(2)实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器;

(3)使用@ExceptionHandler注解实现异常处理;

3 实战

3.1 引言

为了验证Spring MVC的3种异常处理方式的实际效果,我们需要开发一个测试项目,从Dao层、Service层、Controller层分别抛出不同的异常,然后分别集成3种方式进行异常处理,从而比较3种方式的优缺点。

3.2 实战项目

3.2.1 项目结构 

 

3.2.2 Dao层代码

@Repository("testDao") 
public class TestDao { 
  public void exception(Integer id) throws Exception { 
    switch(id) { 
    case 1: 
      throw new BusinessException("12", "dao12"); 
    case 2: 
      throw new BusinessException("22", "dao22"); 
    case 3: 
      throw new BusinessException("32", "dao32"); 
    case 4: 
      throw new BusinessException("42", "dao42"); 
    case 5: 
      throw new BusinessException("52", "dao52"); 
    default: 
      throw new ParameterException("Dao Parameter Error"); 
    } 
  } 
} 

3.2.3 Service层代码

public interface TestService { 
  public void exception(Integer id) throws Exception; 
   
  public void dao(Integer id) throws Exception; 
} 
 
@Service("testService") 
public class TestServiceImpl implements TestService { 
  @Resource 
  private TestDao testDao; 
   
  public void exception(Integer id) throws Exception { 
    switch(id) { 
    case 1: 
      throw new BusinessException("11", "service11"); 
    case 2: 
      throw new BusinessException("21", "service21"); 
    case 3: 
      throw new BusinessException("31", "service31"); 
    case 4: 
      throw new BusinessException("41", "service41"); 
    case 5: 
      throw new BusinessException("51", "service51"); 
    default: 
      throw new ParameterException("Service Parameter Error"); 
    } 
  } 
 
  @Override 
  public void dao(Integer id) throws Exception { 
    testDao.exception(id); 
  } 
} 

3.2.4 Controller层代码

@Controller 
public class TestController { 
  @Resource 
  private TestService testService; 
   
  @RequestMapping(value = "/controller.do", method = RequestMethod.GET) 
  public void controller(HttpServletResponse response, Integer id) throws Exception { 
    switch(id) { 
    case 1: 
      throw new BusinessException("10", "controller10"); 
    case 2: 
      throw new BusinessException("20", "controller20"); 
    case 3: 
      throw new BusinessException("30", "controller30"); 
    case 4: 
      throw new BusinessException("40", "controller40"); 
    case 5: 
      throw new BusinessException("50", "controller50"); 
    default: 
      throw new ParameterException("Controller Parameter Error"); 
    } 
  } 
   
  @RequestMapping(value = "/service.do", method = RequestMethod.GET) 
  public void service(HttpServletResponse response, Integer id) throws Exception { 
    testService.exception(id); 
  } 
   
  @RequestMapping(value = "/dao.do", method = RequestMethod.GET) 
  public void dao(HttpServletResponse response, Integer id) throws Exception { 
    testService.dao(id); 
  } 
} 

3.2.5 JSP页面代码 

<%@ page cOntentType="text/html; charset=UTF-8"%> 
 
 
 
 
 

所有的演示例子

[url=./dao.do&#63;id=1]Dao正常错误[/url]

[url=./dao.do&#63;id=10]Dao参数错误[/url]

[url=./dao.do&#63;id=]Dao未知错误[/url]

[url=./service.do&#63;id=1]Service正常错误[/url]

[url=./service.do&#63;id=10]Service参数错误[/url]

[url=./service.do&#63;id=]Service未知错误[/url]

[url=./controller.do&#63;id=1]Controller正常错误[/url]

[url=./controller.do&#63;id=10]Controller参数错误[/url]

[url=./controller.do&#63;id=]Controller未知错误[/url]

[url=./404.do&#63;id=1]404错误[/url]

3.3 集成异常处理

3.3.1 使用SimpleMappingExceptionResolver实现异常处理

1、在Spring的配置文件applicationContext.xml中增加以下内容:

 
   
   
   
   
   
   
     
      error-business 
      error-parameter 
 
       
     
   
 

2、启动测试项目,经验证,Dao层、Service层、Controller层抛出的异常(业务异常BusinessException、参数异常ParameterException和其它的异常Exception)都能准确显示定义的异常处理页面,达到了统一异常处理的目标。

3、从上面的集成过程可知,使用SimpleMappingExceptionResolver进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,但该方法仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适用。

3.3.2 实现HandlerExceptionResolver 接口自定义异常处理器

1、增加HandlerExceptionResolver 接口的实现类MyExceptionHandler,代码如下:

public class MyExceptionHandler implements HandlerExceptionResolver { 
 
  public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, 
      Exception ex) { 
    Map model = new HashMap(); 
    model.put("ex", ex); 
     
    // 根据不同错误转向不同页面 
    if(ex instanceof BusinessException) { 
      return new ModelAndView("error-business", model); 
    }else if(ex instanceof ParameterException) { 
      return new ModelAndView("error-parameter", model); 
    } else { 
      return new ModelAndView("error", model); 
    } 
  } 
} 

2、在Spring的配置文件applicationContext.xml中增加以下内容:

代码如下:

 

3、启动测试项目,经验证,Dao层、Service层、Controller层抛出的异常(业务异常BusinessException、参数异常ParameterException和其它的异常Exception)都能准确显示定义的异常处理页面,达到了统一异常处理的目标。

4、从上面的集成过程可知,使用实现HandlerExceptionResolver接口的异常处理器进行异常处理,具有集成简单、有良好的扩展性、对已有代码没有入侵性等优点,同时,在异常处理时能获取导致出现异常的对象,有利于提供更详细的异常处理信息。

3.3.3 使用@ExceptionHandler注解实现异常处理

1、增加BaseController类,并在类中使用@ExceptionHandler注解声明异常处理,代码如下:

public class BaseController { 
  /** 基于@ExceptionHandler异常处理 */ 
  @ExceptionHandler 
  public String exp(HttpServletRequest request, Exception ex) { 
     
    request.setAttribute("ex", ex); 
     
    // 根据不同错误转向不同页面 
    if(ex instanceof BusinessException) { 
      return "error-business"; 
    }else if(ex instanceof ParameterException) { 
      return "error-parameter"; 
    } else { 
      return "error"; 
    } 
  } 
} 

2、修改代码,使所有需要异常处理的Controller都继承该类,如下所示,修改后的TestController类继承于BaseController: 

public class TestController extends BaseController 

3、启动测试项目,经验证,Dao层、Service层、Controller层抛出的异常(业务异常BusinessException、参数异常ParameterException和其它的异常Exception)都能准确显示定义的异常处理页面,达到了统一异常处理的目标。

4、从上面的集成过程可知,使用@ExceptionHandler注解实现异常处理,具有集成简单、有扩展性好(只需要将要异常处理的Controller类继承于BaseController即可)、不需要附加Spring配置等优点,但该方法对已有代码存在入侵性(需要修改已有代码,使相关类继承于BaseController),在异常处理时不能获取除异常以外的数据。

3.4 未捕获异常的处理

对于Unchecked Exception而言,由于代码不强制捕获,往往被忽略,如果运行期产生了Unchecked Exception,而代码中又没有进行相应的捕获和处理,则我们可能不得不面对尴尬的404、500……等服务器内部错误提示页面。

我们需要一个全面而有效的异常处理机制。目前大多数服务器也都支持在Web.xml中通过(Websphere/Weblogic)或者(Tomcat)节点配置特定异常情况的显示页面。修改web.xml文件,增加以下内容:

 
 
  java.lang.Throwable 
  /500.jsp 
 
 
  500 
  /500.jsp 
 
 
  404 
  /404.jsp 
 
 
 

4 解决结果

1、运行测试项目显示的首页,如下图所示: 

2、业务错误显示的页面,如下图所示: 

3、参数错误显示的页面,如下图所示: 

4、未知错误显示的页面,如下图所示: 

5、服务器内部错误页面,如下图所示: 

5 总结

综合上述可知,Spring MVC集成异常处理3种方式都可以达到统一异常处理的目标。从3种方式的优缺点比较,若只需要简单的集成异常处理,推荐使用SimpleMappingExceptionResolver即可;若需要集成的异常处理能够更具个性化,提供给用户更详细的异常信息,推荐自定义实现HandlerExceptionResolver接口的方式;若不喜欢Spring配置文件或要实现“零配置”,且能接受对原有代码的适当入侵,则建议使用@ExceptionHandler注解方式。

6 源代码

源代码项目如下所示,为Maven项目,若需运行,请自行获取相关的依赖包。

点击这里获取源代码 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • iOS超签签名服务器搭建及其优劣势
    本文介绍了搭建iOS超签签名服务器的原因和优势,包括不掉签、用户可以直接安装不需要信任、体验好等。同时也提到了超签的劣势,即一个证书只能安装100个,成本较高。文章还详细介绍了超签的实现原理,包括用户请求服务器安装mobileconfig文件、服务器调用苹果接口添加udid等步骤。最后,还提到了生成mobileconfig文件和导出AppleWorldwideDeveloperRelationsCertificationAuthority证书的方法。 ... [详细]
  • SpringMVC工作流程概述
    SpringMVC工作流程概述 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 本文介绍了使用cacti监控mssql 2005运行资源情况的操作步骤,包括安装必要的工具和驱动,测试mssql的连接,配置监控脚本等。通过php连接mssql来获取SQL 2005性能计算器的值,实现对mssql的监控。详细的操作步骤和代码请参考附件。 ... [详细]
  • MySQL中的MVVC多版本并发控制机制的应用及实现
    本文介绍了MySQL中MVCC的应用及实现机制。MVCC是一种提高并发性能的技术,通过对事务内读取的内存进行处理,避免写操作堵塞读操作的并发问题。与其他数据库系统的MVCC实现机制不尽相同,MySQL的MVCC是在undolog中实现的。通过undolog可以找回数据的历史版本,提供给用户读取或在回滚时覆盖数据页上的数据。MySQL的大多数事务型存储引擎都实现了MVCC,但各自的实现机制有所不同。 ... [详细]
  • 本文介绍了Android中的assets目录和raw目录的共同点和区别,包括获取资源的方法、目录结构的限制以及列出资源的能力。同时,还解释了raw目录中资源文件生成的ID,并说明了这些目录的使用方法。 ... [详细]
  • 分享css中提升优先级属性!important的用法总结
    web前端|css教程css!importantweb前端-css教程本文分享css中提升优先级属性!important的用法总结微信门店展示源码,vscode如何管理站点,ubu ... [详细]
author-avatar
H丨uAn9-伟安
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有