struts2-自定义异常的捕捉

背景环境:1)框架:ssm(struts2.3.16+spring3.2.5+mybatis3.2.6)
2)自定义异常类,必要时刻抛出,我的情况是,在每个页面判断权限(防止有人直接输入页面进入),无权限的话直接抛出无权限异常(自定义的)
3)struts.xml中配置如下:
<global-results>
<result name="login">/login.jsp</result>
<result name="error">/error.jsp</result>
<result name="prompt">/prompt-page.jsp</result>
<result name="no-permission-exception">/no-permission-exception.jsp</result>
</global-results>
<global-exception-mappings>
   <!-- 当系统抛出Exception异常时,转入名为exception的结果。 --> 
   <exception-mapping exception="XX.XX.XX.NoPermissionException" result="no-permission-exception" />//自定义异常
   <exception-mapping exception="java.lang.Exception" result="error" />
</global-exception-mappings>
现象描述:每次跳转页面都是error.jsp,说明没有匹配自定义异常。
解决过程:
1)debug跟踪,跟踪到了struts的拦截器ExceptionMappingInterceptor(位置:xwork-core\src\main\java\com\opensymphony\xwork2\interceptor),大体看了一下变量,发现会取出我global中列出的两个异常列表,然后抛出的异常进行比较(JasperException,由servlet异常引起的,detaiMessage中有我的自定义异常,cause中也有我的自定义异常)。当我debug结束的时候发现并没有匹配我的自定义异常。纠结中。。。只能看看到底是如何比较的,为啥把自己定义的没匹配到。

2)下载Struts2.3.16的开源包,关联继续调试,终于真相大白:截取一下ExceptionMappingInterceptor中的部分源码如下:

 @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        String result;

        try {
            result = invocation.invoke();
        } catch (Exception e) {
            if (isLogEnabled()) {
                handleLogging(e);
            }
            List<ExceptionMappingConfig> exceptionMappings = invocation.getProxy().getConfig().getExceptionMappings();
            ExceptionMappingConfig mappingConfig = this.findMappingFromExceptions(exceptionMappings, e);
            if (mappingConfig != null && mappingConfig.getResult()!=null) {
                Map parameterMap = mappingConfig.getParams();
                // create a mutable HashMap since some interceptors will remove parameters, and parameterMap is immutable
                invocation.getInvocationContext().setParameters(new HashMap<String, Object>(parameterMap));
                result = mappingConfig.getResult();
                publishException(invocation, new ExceptionHolder(e));
            } else {
                throw e;
            }
        }

        return result;
    }
    protected ExceptionMappingConfig findMappingFromExceptions(List<ExceptionMappingConfig> exceptionMappings, Throwable t) {
    <span style="white-space:pre">	</span>ExceptionMappingConfig config = null;
        // Check for specific exception mappings.
        if (exceptionMappings != null) {
            int deepest = Integer.MAX_VALUE;
            for (Object exceptionMapping : exceptionMappings) {
                ExceptionMappingConfig exceptionMappingConfig = (ExceptionMappingConfig) exceptionMapping;
                int depth = getDepth(exceptionMappingConfig.getExceptionClassName(), t);
                if (depth >= 0 && depth < deepest) {
                    deepest = depth;
                    config = exceptionMappingConfig;
                }
            }
        }
        return config;
    }
    public int getDepth(String exceptionMapping, Throwable t) {
        return getDepth(exceptionMapping, t.getClass(), 0);
    }

    private int getDepth(String exceptionMapping, Class exceptionClass, int depth) {
        if (exceptionClass.getName().contains(exceptionMapping)) {
            // Found it!
            return depth;
        }
        // If we've gone as far as we can go and haven't found it...
        if (exceptionClass.equals(Throwable.class)) {
            return -1;
        }
        return getDepth(exceptionMapping, exceptionClass.getSuperclass(), depth + 1);
    }
从这个拦截器的源码中可以看到整个流程:先取到配置文件中的异常列表,然后把抛出的异常跟这个列表中的异常作比较,这个逻辑在上一次的debug已经认证了,主要是是匹配的这个段代码
<span style="white-space:pre">	</span>if (exceptionClass.getName().contains(exceptionMapping)) {
            // Found it!
            return depth;
        }

 首先判断异常类的名字跟我们配置文件中取到的类名是否一致,如果一致ok,如果不一致继续判断 

return getDepth(exceptionMapping, exceptionClass.getSuperclass(), depth + 1);
这段代码告诉了我们如何判断,直接取我们抛出的异常的上级进行判断,这样循环,直接到最顶级的父级进行判断。显然我们抛出的jasperException不可能出现在这里,从

return getDepth(exceptionMapping, t.getClass(), 0);
这段代码已经注定了不能匹配成功了,直接把我们抛出的异常转化为了class,使得我们的其它信息已经丢失。

解决思路:

1.我的第一印象修改源代码- -!后来一想,这个属于下策,可能其它地方我们有注意到,导致我自己的失误,所以想其他方法

2.网络是个好东西,看了一下网上的这方面的资料,倾向于自定义的拦截器,毕竟我调试的源码也是自带的拦截器,为何不自己也定义一个拦截器进行修正呢。

3.修改之后的struts.xml如下:

<interceptors>
<span style="white-space:pre">			</span><interceptor name="MyCustomInterceptor" class="cn.com.cottech.cotton.Interceptor.MyCustomInterceptor"></interceptor>
<span style="white-space:pre">			</span><!--这里可以配置多个interceptor-->
<span style="white-space:pre">			</span><!--拦截器栈-->
<span style="white-space:pre">			</span><interceptor-stack name="MyInterceptorStack">
<span style="white-space:pre">				</span><interceptor-ref name="defaultStack" /> 
<span style="white-space:pre">				</span><interceptor-ref name="MyCustomInterceptor"></interceptor-ref>
<span style="white-space:pre">				</span><!--这里也可以配置多个interceptor-ref-->
<span style="white-space:pre">			</span></interceptor-stack>
<span style="white-space:pre">		</span></interceptors>
<span style="white-space:pre">		</span><!-- 全局默认拦截器 ,一个系统中只能一个全局默认-->
<span style="white-space:pre">		</span><default-interceptor-ref name="MyInterceptorStack"></default-interceptor-ref>
<span style="white-space:pre">		</span><!-- 设置全局的返回结果 -->
<span style="white-space:pre">		</span><global-results>
<span style="white-space:pre">			</span><result name="login">/login.jsp</result>
<span style="white-space:pre">			</span><result name="error">/error.jsp</result>
<span style="white-space:pre">			</span><result name="prompt">/prompt-page.jsp</result>
<span style="white-space:pre">			</span><result name="no-permission-exception">/no-permission-exception.jsp</result>
<span style="white-space:pre">		</span></global-results>
里面的一些定义就不解释了,这里注意一下,拦截器的顺序,可以看到有两个拦截器,一个是系统默认的,还有一个自定义的,默认的必须有,它牵扯到struts整个路程的各种处理,比如赋值,request,session,form的值等等。

我的自定义的部分代码如下:

@Override
<span style="white-space:pre">	</span>public String intercept(ActionInvocation ac) throws Exception {
<span style="white-space:pre">		</span>String result = "error";
<span style="white-space:pre">		</span>try {
<span style="white-space:pre">			</span>result = ac.invoke();
<span style="white-space:pre">		</span>} catch (Exception e) {
<span style="white-space:pre">			</span>log.debug(e, e);
<span style="white-space:pre">			</span>e.printStackTrace();
<span style="white-space:pre">			</span>// 这里可以有多个catch,但要注意顺序问题,用于捕捉不同的异常,进行不同的处理
<span style="white-space:pre">			</span>List<String> exceptionList = new ArrayList<String>();
<span style="white-space:pre">			</span>exceptionList.add(NoPermissionException.class.getName()+",no-permission-exception");
<span style="white-space:pre">			</span>exceptionList.add(NullPointerException.class.getName()+",error");
<span style="white-space:pre">			</span>int deepest = Integer.MAX_VALUE;
<span style="white-space:pre">			</span>for(int i=0;i<exceptionList.size();i++){
<span style="white-space:pre">				</span>String[] exception_con = exceptionList.get(i).split(",");
<span style="white-space:pre">				</span>String exceptionName = exception_con[0];
<span style="white-space:pre">				</span>if(isContainException(exceptionName, e)){
<span style="white-space:pre">					</span>return exception_con[1];
<span style="white-space:pre">				</span>}
<span style="white-space:pre">			</span>}
<span style="white-space:pre">		</span>}
<span style="white-space:pre">		</span>return result;
<span style="white-space:pre">	</span>}
<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span> public boolean isContainException(String exceptionMapping, Throwable t) {
<span style="white-space:pre">	</span> <span style="white-space:pre">	</span>int depth = 1;
    <span style="white-space:pre">	</span>if(t.getClass().getName().contains(exceptionMapping)){//直接判断异常的名称是什么
    <span style="white-space:pre">		</span>return true;
    <span style="white-space:pre">	</span>}
    <span style="white-space:pre">	</span>Throwable tb = t.getCause();
    <span style="white-space:pre">	</span>while(tb!=null){//如果异常名称不符合,那就查看他的起因
<span style="white-space:pre">			</span>if(tb.getMessage().contains(exceptionMapping)){
<span style="white-space:pre">				</span>return true;//if the cause contains exceptionMapping,return depth,else invoke getDepth(String exceptionMapping, Class exceptionClass, int depth)
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>tb = tb.getCause();
<span style="white-space:pre">			</span>if(depth>=Integer.MAX_VALUE){//Prevent loop
<span style="white-space:pre">				</span>break;
<span style="white-space:pre">			</span>}
<span style="white-space:pre">			</span>++depth;
    <span style="white-space:pre">	</span>}
    <span style="white-space:pre">	</span>return false;
        //return getDepth(exceptionMapping, t.getClass(), 0);
    }
自定义的拦截器主要功能有两个:

1)打印异常,出现异常说明程序有问题,这个是需要程序员进行跟踪修改的。

2)主要处理我自定义的权限异常,将来可以添加系统的和自定义的其它异常。

备注:这里的异常是写死的,可以参考源码,直接从config配置中取。这里就不修改了

到此这个异常体系基本建立



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值