java平台统一异常框架的设计与实现

  在一个framework的设计中,异常框架的设计占据着很重要的位置,因为它会直接影响到整个应用的健壮性、稳定性和易用性,因此笔者结合自己在产品开发中的经验给出了一个异常框架的设计及实现与大家共享,有考虑不周或欠妥的地方还望大家一起讨论,共同提高。

 
1.1  Java 异常框架 总体设计
异常框架的总体结构图

 11.1异常框架总体结构图

如上图所示, java 平台框架的异常机制包括程序异常及业务异常。对于程序异常和业务异常我们设计一个 BaseException 基类, BaseException 是一个 unchecked exception (即继承于 RuntimeException ), javaeye 上有一篇关于 checked exception unchecked exception 的讨论长达几十页,偶在此就不多做解释了,基于此平台框架进行开发的应用可以对 BaseException 进行派生,例如 BizFocus-workflow 封装了 PersistenceException ServiceException 来对应于持久层异常和业务层异常。持久层和业务层的异常在捕获之后通过 log4j 输出到了程序日志,然后继续向外抛给展现层的 Action 控制类, Action 不需要对异常进行捕获,因为 BizFocus-workflow 提供了一个基于 webwork 的异常拦截器( ExceptionInterceptor )对所有的 Action 的异常进行拦截。拦截后不同的异常在异常的国际化文件中取得异常提示信息展示给最终用户。
1.2.1 异常信息的国际化封装
如图 1.1 所示,异常信息的国际化封装主要由 Messages 接口及其实现类 MessageImpl Message_CN.properties Message.properties 两个国际化文件组成。
Messages 接口如下:
public interface Messages {
 
    public static final int ERROR_UNKNOWN = 0;
    public static final int ERROR_SYSTEM = 1;
    public static final int ERROR_WORKFLOW = 2;
    public static final int NO_DECISIONVALUE_SET = 3;
………// 其它的异常代码
}
MessageImpl 实现类的代码如下:
public class MessageImpl implements Messages {
 
    public MessageImpl() {
    }
 
    public static String getFormattedMessage(int i, Object aobj[]) {
        String s;
        try {
            s = bundle.getString(String.valueOf(i));
            if (aobj != null)
                s = MessageFormat.format(s, aobj);
        }
        catch (MissingResourceException missingresourceexception) {
            s = missingresourceexception.getMessage();
        }
        return s;
    }
 
private static ResourceBundle bundle = ResourceBundle.getBundle("com.xxx.common.MessagesCN");
Message.properties 国际化文件如下:
0 = Unknown error
1 = System error
2 = Workflow error
3 = No decision vlaue was set
…… 其它异常信息
Message_CN.properties 文件内容如下:
0 = 未知的错误
1 = 系统错误
2 = 工作流错误
3 = 您没有设置工作流分支节点的决策值
…… 其它异常信息
1.2.2 业务层和持久层异常的国际化处理
对于业务层和持久层异常的处理可以按照如下方式进行:
        try {
            // 业务逻辑代码 ……
        } catch (XXXException  ex) {
            if (log.isDebugEnabled())// 如果是 debug 状态,直接输出异常的堆栈调用顺序
                ex.printStackTrace();
            else// 不是 debug 状态,则只输出异常信息到日志文件
                log.error(BaseException.getLocalizedMessage(Messages.ERROR_WORKFLOWENGINE, null), ex);
              throw new ServiceException(ex);// 最后将异常抛给外层
        }
 
1.2.3 展现层异常的国际化处理
持久层和业务层的异常首先抛给了展现层的 Action ,在 Action 中对 Exception 不做任何处理直接抛出,例如 Action 的代码如下:
public String execute() throws Exception {// Exception 直接抛出
       // 控制逻辑的代码 ……
}
1.2.4 通过 webwork 拦截器实现异常信息在界面的展示
在上一节中, Action Exception 直接抛出,因此在 webwork 拦截器中,对 Exception 进行拦截,将拦截的 Exception 进行分类,根据分类取得相关的异常提示信息,然后传给统一的异常显示页面,用户在异常页面上就会看到不同的异常信息。 ExceptionInterceptor 代码示例如下:
public class ExceptionInterceptor implements Interceptor {
    private static final Log log = LogFactory.getLog(ExceptionInterceptor.class);
    public static final String EXCEPTION = "exception";
 
    public void destroy() {
        //To change body of implemented methods use File | Settings | File Templates.
    }
 
    public void init() {
        //To change body of implemented methods use File | Settings | File Templates.
    }
 
    public String intercept(ActionInvocation invocation) throws Exception {
      String tipMessge = null;// 中文提示信息
      String detailMessage = null;// 详细的错误信息
try {
            return invocation.invoke();
        } catch (Exception e) {
            if (e instanceof PersistenceException){// 判断程序异常的类型
              // 从国际化文件中取得相应的错误提示信息
 tipMessge = ErrorMessage.getLocalizedMessage(Messages.ERROR_PERSISTENCELAYER);
            }else if(e instanceof ServiceException){// 判断程序异常的类型
tipMessge = ErrorMessage.getLocalizedMessage(Messages.ERROR_SERVICELAYER);
}
            // 详细的错误信息栈
detailMessage  =  invocation.getAction();
            return EXCEPTION;//webwork 将导向 EXCEPTION 对应的错误信息页面, common/exception.ftl
        }
    }
}
上述代码是一个比较详细的异常拦截器的代码,业务端可以基于此拦截器进行继承,然后就可以很详细地定制自己在开发过程中的异常。
common/exception.ftl 页面的代码如下:
<table align="left" class="common_input_table" style="width:100%;height:100%">
        <tr>
            <td align="center" class="common_td_lable">${action.getText('bizfocus.ui.errorPageTitle')}</td>
        </tr>
        <tr>
        <td align="center" class="common_td_text" >
            <div align="center">
                <br><br><br><br>
                <@ww.if test="errorMessage==null">
                `   <font color="red">${action.getText('bizfocus.ui.errormessage')}</font>
                </@ww.if>
                <@ww.else>
                   <a href=”detailMessage.action?detailMessage=<@ww.property value=’detailMessage’/>”> <font color="red"><@ww.property value="tipMessage"/></font>
                </@ww.else>
            </div>
        </td>
        </tr>
    </table>
 
1.3  业务异常的扩展
1.3.1Exception 的继承机制
业务异常的处理,是在开发过程中经常遇到的问题,例如工作流引擎提供的根据业务数据自动决策分支节点的路由功能中,如果业务数据没有传递给工作流引擎,则应该抛出一个没有设置决策数据的业务异常 (NoDecisionValueSetException) ,因此在开发业务的过程中,开发者可以根据实际的业务情况进行异常类的定制开发,最后这些业务异常同样被开发者自己扩展的异常拦截器进行拦截,最后根据业务异常的种类将不同的业务异常提示信息展示给最终用户(例如: 您没有设置决策数据给工作流引擎 )。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值