热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

javaweb项目发生异常依然能运行

由于JavaWeb应用业务逻辑的复杂性,容易发生一些意想不到的错误和异常,给系统的调试带来不必要的麻烦,不友好的提示信息使编程者对错误和异常无从下手。特别是当发生异常时,Java异

由于JavaWeb应用业务逻辑的复杂性,容易发生一些意想不到的错误和异常,给系统的调试带来不必要的麻烦,不友好的提示信息使编程者对错误和异常无从下手。特别是当发生异常时,Java异常栈输出的信息只能给程序员来看,是绝对不能展示给用户的。而且一旦项目发布成最终版本运行时,也十分有必要跟踪和记录所发生的错误和异常的详细信息,并返回一个特定的友好界面给用户。 在传统的JavaWeb应用中,应用程序通常是采用硬编码的方式来避免将要发生的错误和异常,对应用程序中的异常经常使用try…catch语句进行处理,哪 里可能会抛出异常,就在哪里进行捕获,这些语句似乎成了应对编译器而不得已的手段。为了简化,往往在catch代码块中什么也不写,try…catch语句成了一种摆设。甚至干脆就用关键字throws声明抛出异常,不对异常进行处理。这样不但会使写出来的程序杂乱无序,到处都是一些无用的try…catch语句,程序的可读性、可修改性大大降低,而且还会增加程序员的工作量。

      针对以上问题,考虑到JavaWeb应用开发、日后运行、升级和维护,在Java异常机制的基础上构建了一个在JavaWeb环境中的错误处理和异常处理的框架模型。该模型对异常和错误进行统一管理,并在一个集中的位置统一处理,程序的可读性、可维护性、可修改性、鲁棒性等都得到了提高。本文使用Struts、spring、hibernate架构三层JavaWeb应用。Struts作为表示层,Spring作为业务逻辑层,Hibernate作为持久层。

 

 

2.1错误和异常处理原则

      本文对错误的处理方式是采用抛出自定义类型的异常,这样便于对异常和错误进行统一管理,提高JavaWeb应用程序的健壮性。JavaWeb应用开发中产生的异常都应该继承Exception(属于checkedexcpetion类型)。而且JavaWeb应用一般采用三层或多层架构,程序员没有必要在各个层中对错误和异常进行处理,应用中的每一层在包装并传递异常时要过滤掉Runtime-Exception,从责任这个角度看uncheckedexception是程序应该负担的责任;checkedexception是具体应用负担的责任。无论如何我们都不应该将uncheckedexception这样的异常暴露给客户的,因为他们没有解决这个问题的责任,应该将这种异常封装成checkedexception类型的异常,由具体的应用程序来负担这个责任。

 

 

2.2错误处理策略

       程序中可能会发生很多的错误,例如当执行删除记录、插入记录、修改记录和复杂的业务逻辑等错误,当出现了错误应该如何处理呢?
      传统的处理方法是采用编程的方式来提高应用程序的健壮性。当发生错误时,由程序来控制给用户提示友好信息或者显示一个错误提示界面。很显然这种处理方式的实质就是增加程序的代码量来弥补程序中的不足,治标没有治本,不能从根本上解决问题。
本文采用的错误处理策略是当发生错误时,将错误和发生错误时转向的页面封装成一个异常对象将其抛出,然后将异常集中到一个统一的位置进行处理。显而易见,采用这种错误处理的方式的优点在于:当运行中的程序发生错误时就抛出一个详细的异常对象,根据发生的异常信息来决定转向到不同的页。避免因采用编程而被忽略的一些错误(由于代码量的增加而导致的错误)。

 

2.3异常处理策略

       程序中可能会发生很多的异常,例如业务逻辑、未找到指定的文件、类型转换失败等异常时,Web应用程序应该将异常和发生异常时转向的页面封装成一个新的异常对象将其抛出,然后将异常集中到一个统一的位置进行处理。显然,采用这种异常处理的方式的优点在于Java中的异常栈信息没有展现给用户,而是将异常信息和友好的页面展现给用户。
       使用异常对应用程序错误和异常进行统一管理的好处在于:由于Java的异常机制允许调用者可以不对异常进行处理,而用关键字throws抛出异常,这将会使异常向上一级传递,即当前环境没有足够的信息和能力来解决这个异常时,就可以把这个异常交到一个更高级的有能力处理的环境中,在这里将做出对异常的处理,形成一个异常的传递链。这样可以将所有的异常通过这样的传递链集中到一个统一的位置进行统一处理。
      它能使错误代码变得更有条理,与采用硬编码的方式来处理错误方式相比,代码量会明显减少,并且通过这种错误报告机制,只需在一个地方处理错误,即在所谓的“异常处理程序”中处理,这种方式节省了代码,而且把“描述做什么事”的代码和“出了问题怎么办”的代码相分离。总之,与采用硬编码的方式来处理错误的方法相比,异常机制使代码的阅读、编写和调试工作更加井井有条。

 

2.4异常抛出策略和捕获位置

       在图1所示的JavaWeb三层架构模型中,我们可以利用Java的多态机制,只捕获自定义的基类异常(例如BasicException),它包含了所有应用程序异常的默认行为,但是具体业务逻辑抛出的异常可以是BasicEx-ception类的任何子类异常,使用多态来隐藏异常的具体的实现类。这意味着BasicException异常(仅仅是这个异常)可以放到抛出checked异常的每个方法的throws子句中,不能包含其他任何应用程序异常。当应用程序发生了某个具体的异常(BasicException的派生类)时,应用程序应该做出在哪一界面上显示哪条错误消息的决策,即在什么位置捕获异常。本文选择的位置是控制器(Struts的Action),它恰恰有根据不同的异常来设置不同的错误信息和跳转到不同的错误页面的能力,而且Action的位置是最接近客户端表示层的,所以这个位置是最恰当的。

       这样所有的异常会在一个集中的公共位置得到处理,使用模板方法(TemplateMethod)设计模式并结合Struts的DispatchAction编写一个模板方法,并在该模板方法中捕获BasicException异常,这将会捕获到所有的子类异常。因此我们采用的策略是:持久层中的所有方法都抛出BasicException异常,不对其处理;业务逻辑层中的所有方法采用像持久层中的策略,同样不对异常进行处理,即抛出BasicEx-ception异常。利用这种传播异常的通用机制,将异常以一种普适的方式集中到距离客户端最近的控制器中处理。这样处理有很多优点:不需要在throws子句中放入大量的checked异常;throws子句中只需要有一个异常,不需要再对应用程序异常使用混乱的catch块;如果需要处理它们,一个catch块(用于BasicException)就足够了,程序员也不需要亲自进行异常处理(日志记录以及获取错误代码),使编程者更加专注于业务逻辑的处理,而错误和异常的处理与记录可以使用后文提到的Facade接口完成。

3.错误与异常处理模型实现

3.1错误与异常层次结构

       本文仅以两类错误和两类异常为例展开讨论,但本文构建的错误和异常处理框架模型是适合任意多的错误和异常种类,只要它们间接继承BasicException类,例如数据没有找到类型的错误,例如DataNot-FoundExceptionextendsBasicException。逻辑异常:LogicaExceptionextendsBasicException数据查找错误:DataExceptionextendsBasicExcep-tion权限异常:RightExceptionextendsBasicException登录错误:LoginExceptionextendsBasicException在具体工程项目实现时,可以根据需要增加错误和异常的种类。

3.2应用与模型交互

       本框架模型是在StrutsAction层负责决定对错误与异常采取什么操作。这种决策涉及到识别抛出异常的代码。此外还需要知道在处理错误与异常之后应该把错误消息重定向到哪一界面。我们需要对基于异常类型获得错误代码这个过程进行抽象,同时还应该执行日志记录。我们把这些工作抽象成一个接口,该接口基于外观设计模式也叫总管模式(Facade模式)[10~11],该模式为子系统中的一组接口提供一个统一外部访问入口。
       外观定义了一个更高级别的接口,使子系统变得更加易于访问,是用于处理所有派生自BasicException的异常的整个异常处理系统的外观。也就是说该接口是连接应用程序与框架模型的一个桥梁,为复杂的异常处理框架模型提供一个统一的操作门面。采用这种设计模式的优点在于:
       它为应用逻辑屏蔽了异常框架模型子系统的复杂性,使得异常框架模型系统更加容易使用。实现了子系统与应用逻辑之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。方便在子系统中添加新功能,只需要在Facade里添加新的方法,然后调用拥有新功能的类或方法就可以了,原来实际执行任务的类不需改变。如图2所示,给出了异常处理模型的时序图。

       从图2可以看出采用这种Facade模式使得业务逻辑控制器只与异常处理门面打交道,简化了业务逻辑关于异常处理的编程,使程序员更加专注于业务逻辑的编程。如图3所示,给出了异常处理模型的时序图。

 java web项目发生异常依然能运行                                     

 

java web项目发生异常依然能运行                                                        



       从图3可以看出异常处理系统通过异常处理门面,调用异常工具类将发生的所有可能的错误和异常统一封装成ExDTO对象返回给控制器,同时也将异常的详细信息记录到日志文件中有助于日后的调试以及查找错误。
      下面给出一个在StrutsAction方法中进行异常处理的例子。

[java] view plain copy
 
  1. try{  
  2. /* 
  3. 处理应用程序的业务逻辑 
  4. 调用业务逻辑层的业务逻辑方法,该业务方法声明抛出Ba- 
  5. sicException 
  6. */}  
  7. catch(BasicExceptione){  
  8. //定义错误和异常处理者  
  9. ExceptiOnHandlereh=newExceptionHandler();ExDTOexDto=eh.handleException(“context”,user,ex);ActiOnMessagesmessages=newActionMessages();messages.add(ActionMessages.GLOBALMESSAGE,newActionMessage(exDTO.getMessageCode()));  
  10. saveMessages(request,messages);//转到用户有好界面  
  11. returnmapping.findForward("errorAndExceptionOccur");}  

3.3精简Struts的Action的代码

      从上面编写Action的方法可以看出,每个方法都必须书写捕获异常的模板代码,应该避免这样的编码方式,解决方式是利用Struts的DispatchAction的工作机制(这里不对该类的工作方式进行介绍,可以查看帮助文档),并结合模板方法模式(TemplateMethod)[10,11]重写模板方法execute,并将不变的处理错误和异常模板的代码写在execute方法中,把具体的可变的业务逻辑控制方法留给子类来实现。下面给出一个自定义的

[java] view plain copy
 
  1. StrutsDispatchAction中的execute方法的具体实现例子。  
  2. try{  
  3. ActiOnForwardfoward=  
  4. dispatchMethod(mapping,form,request,response,name);returnfoward;}  
  5. //处理用户定义错误和异常catch(BaseAppExceptione){  
  6. //定义错误和异常处理者  
  7. ExceptiOnHandlereh=newExceptionHandler();ExDTOexDto=eh.handleException(expDTO.getContext(),userId,e);  
  8. ActiOnMessagesmessages=newActionMessages();messages.add(ActionMessages.GLOBAL_MESSAGE,newActionMessage(exDTO.getMessageCode()));saveMessages(request,messages);//转到用户有好界面  
  9. returnmapping.findForward("errorAndExceptionOccur");}  
  10. //处理非用户定义错误和异常catch(Exceptionex){  
  11. //对错误和异常进行记录  
  12. ExceptionUtil.logException(this.getClass(),ex,userId);throwex;  
  13. }finally  
  14. {exDisplay.set(null);}  


经过这样的处理,每个Structs的Action只要继承DispatchAction类就可以自动继承错误和异常处理代码,节省大量代码的编写。

4.结语

       本文提出了一种关于错误处理和异常处理的框架模型,并利用三层架构思想实现了该模型,解决了JavaWeb应用中错误处理和异常处理普遍存在的问题。当应用发生错误和异常时,该模型能将错误和异常详细信息记录到日志文件中,同时控制器能够根据该信息将页面跳转到指定的网页上。
       由于本文重点介绍错误与异常处理模型,故可以选用不同的工具加以实现。例如表示层可以选用JSF、Struts2;业务逻辑层可以选用Jdon;持久层可以选用其他的ORM框架,例如KylinORM、MyBatis等。


推荐阅读
  • 2018年人工智能大数据的爆发,学Java还是Python?
    本文介绍了2018年人工智能大数据的爆发以及学习Java和Python的相关知识。在人工智能和大数据时代,Java和Python这两门编程语言都很优秀且火爆。选择学习哪门语言要根据个人兴趣爱好来决定。Python是一门拥有简洁语法的高级编程语言,容易上手。其特色之一是强制使用空白符作为语句缩进,使得新手可以快速上手。目前,Python在人工智能领域有着广泛的应用。如果对Java、Python或大数据感兴趣,欢迎加入qq群458345782。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • Week04面向对象设计与继承学习总结及作业要求
    本文总结了Week04面向对象设计与继承的重要知识点,包括对象、类、封装性、静态属性、静态方法、重载、继承和多态等。同时,还介绍了私有构造函数在类外部无法被调用、static不能访问非静态属性以及该类实例可以共享类里的static属性等内容。此外,还提到了作业要求,包括讲述一个在网上商城购物或在班级博客进行学习的故事,并使用Markdown的加粗标记和语句块标记标注关键名词和动词。最后,还提到了参考资料中关于UML类图如何绘制的范例。 ... [详细]
  • Java 11相对于Java 8,OptaPlanner性能提升有多大?
    本文通过基准测试比较了Java 11和Java 8对OptaPlanner的性能提升。测试结果表明,在相同的硬件环境下,Java 11相对于Java 8在垃圾回收方面表现更好,从而提升了OptaPlanner的性能。 ... [详细]
  • Java和JavaScript是什么关系?java跟javaScript都是编程语言,只是java跟javaScript没有什么太大关系,一个是脚本语言(前端语言),一个是面向对象 ... [详细]
author-avatar
万熊卡拉梦
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有