企业管理及信息化解决方案;--因为专注,所以专业!
客服热线:028-86272612
成都蓝源 -> > EDP资讯 -> 详细内容
Lanyo EDP中的错误处理问题
时间: 2011-10-09    来源:

错误处理是一个比较细节的问题。在传统的SSH中,错误处理一般有以下几种方式:1,级别的错误使用error-page来处理;2,中小应用可以使用Strutsglobal-exception或者局部的exception来统一处理;3servicedao中的错误都简单包装后向上抛出,在包装类中记录一下root cause,用来追溯错误链,在spring中,即错误从HibernateException(PersistenceException)包装为SpringDataAccessException,这几个错误都是在DAO(或者某些service中)会出现的错误,接着这些错误在service1,可能会重新包装成checked错误,这些错误会被Action强制的使用try..catch来处理,在catch中处理后,返回给用户可以接受的提示页面。2service不管这些错误,action在执行的时候,如果遇到unchecked错误,使用global-exception,或者error-page处理。但是在控制的比较细节的应用中,RuntimeException也是会在Actiontry..catch,来个性化处理。另外,还可以采用配置AfterThrowing的增强来统一拦截错误,但基于性能,调试方便,等因素来考虑,这个个人不是很推荐使用。

错误处理涉及到的另一个问题是事务的回滚,在使用声明式事务配置中,被代理的service中一旦抛出了任何的RuntimeException,即回滚事务。在传统的SSH中,这点是没有任何问题的,完全符合SSH中错误的抛出原则。

错误处理,jweb中使用了一个错误处理链来统一处理错误。终,有一个叫DefaultExceptionHandle的错误处理器,这个错误处理器会拦截任何action中的错误,并统一返回一个提示页面。

这样处理没有问题,但是这样处理在和事务绑定在一起的时候,问题就出现了。从上面的时序图中,我们可以看到,事务是开在DefaultRequestProcessorprocess方法上的,但错误处理是包含在process方法里面的,意思就是说,默认情况下,在Action中抛出的任何错误,不可能被spring拦截。这是一个非常有趣的问题,就是说,无论抛出任何错误,事务都不会被自动回滚,除非在service上在重新开启一个传播级别为REQUIRESNEW的事务。为了避免这种问题的发生,我们的处理问题核心就在于,要将需要回滚事务的错误包装成任何的RuntimeException,并绕过DefaultExceptionHandle处理器抛出给spring。在EDP中,添加了一个com.lanyo.ria.exception.RiaExceptionHandler,该错误处理器会在DefaultExceptionHandle执行之前拦截PersistenceException,并直接抛出。或者实现自定义的RuntimeException,继承EDP中提供了CustomerException。该错误也会被抛出到spring中。

上面面已经提到了一些EDP中的错误处理,关键的核心问题还是在错误处理链上,如果抛开事务的问题,EDP中的错误处理总体来说还是很优雅的,至少提供了一个很简单的机制来统一处理错误,不管是基于JSPVelocity的传统页面,还是基于AJAX的请求,都能很好的处理,但是问题还是在于一旦绑定了事务,为了使事务正常回滚,必须要将错误抛出Actionspring中。可能会造成后台大量的错误日志产生。

下面来看看怎么解决这个问题的(该问题的解决,包括事务的解决,在EDP2.0中已经完成)。

EDP中提供了一个简单的CustomerException错误基类,但是这个基类并不能记录整个错误栈信息,下面就简单来完善一下整个错误处理。首先,需要明确一点,就是整个应用的错误级别和结构。可以这样来规划错误:DAO层的错误不管,就直接是使用spring提供的DataAccessException或者TranscationManager,由于这些错误又都是继承NestedRuntimeException,可以统一处理,service中的所有逻辑错误和checked异常都使用一个基类来处理:我们的错误结构可以像这样:

其中,ServiceLogicException是代表应用逻辑错误,CheckedWrapperException是对应用中遇到的checkedException拦截后的封装。基类是spring提供的NestedRuntimeException,该Exception是一个RuntimeException,并且能很好的记录错误栈信息。

接下来只需要在JWEBerrorHandler中统一处理这些错误即可。

public boolean handle(Throwable exception, Object arg1, Method arg2, Object[] arg3) throws Exception {

       if (exception instanceof NestedRuntimeException) {

           NestedRuntimeException e = (NestedRuntimeException) exception;

           log.error(e.getMessage());

           String msg = "";

           if (e instanceof ServiceLogicException) {

               msg = e.getMessage();

           }else if (e instanceof CheckedWrapperException) {

               msg = I18n.get("checked.wrapper.exception.info");

           }else{

               msg=I18n.get("default.service.exception.info");

           }

           HttpServletResponse response = ActionContext.getContext().getResponse();

           HttpServletRequest request = ActionContext.getContext().getRequest();

           String contentType = "application/x-json;charset=UTF-8";

           if (request.getContentType().indexOf("multipart/form-data") == 0) {

               contentType = "text/html";

           }

           response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

           response.setContentType(contentType);

           PrintWriter out = response.getWriter();

           Map<String, Object> map = new HashMap<String, Object>();

           map.put("err", msg);

           out.print("function(){");

           out.print(AjaxUtil.getJSON(map));

           out.print("}()");

           out.close();

           return false;

       }

    return true;

}

在这里面,可以单独的为每一种错误配置不同的处理方式,然后在mvc.xml中声明该bean即可。当然,也可以为每一种错误编写一个ExceptionHandler,然后通过在mvc.xml中为每一种错误分别配置exceptionHandler即可。



3.62K
上一篇:没有了
下一篇:Lanyo EDP系统结构