PSJay Blog

#FIXME, seriously

Struts2的validate错误跳转与chain配合使用的要点

| Comments

本文基于struts2.1.8.1 按照struts2的官方文档,chain类型默认的目标Action跳转方法是execute(),摘录xwork的doc: method - used to specify another method on target action to be invoked. * If null, this defaults to execute method * * 在一般情况下,这没有问题。在使用validate拦截器拦截到错误,希望转到目标Action的特定方法时,却发现根本不执行。 为了描述方便清晰,先定义以上使用场景: FooAction有触发validate拦截器的相关验证代码,验证不通过触发workflow的跳转功能,默认转入FooAction的input结果指定的去向,即BarAction的某个方法,定义为someMethod()。网上有一则相关文章提到:如果在定向到input视图前有错误(如action的hasError方法返回true)和异常发生,且返回的input视图的type为"chain"(即返回到另一个action)时,这个action的方法必须为input,否则这个方法不会执行,而是会直接定位到物理视图。按照这个做法,的确可以进入指定input方法并且执行,可是并没有官方文档有类似说明,这是为什么呢?经过对validate、workflow拦截器的调试分析,终于揭秘了真相。 FooAction的validate拦截器执行相关的验证方法并得到了errors,通过workflow再chain到BarAction时,会过一遍BarAction的拦截器栈,也就是说,workflow拦截器会再次被执行,只不过此次是针对BarAction。看workflow的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
    Object action = invocation.getAction();

    if (action instanceof ValidationAware) {
        ValidationAware validationAwareAction = (ValidationAware) action;

        if (validationAwareAction.hasErrors()) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Errors on action " + validationAwareAction + ", returning result name 'input'");
            }

            String resultName = inputResultName;

            if (action instanceof ValidationWorkflowAware) {
                resultName = ((ValidationWorkflowAware) action).getInputResultName();
            }

            InputConfig annotation = action.getClass().getMethod(invocation.getProxy().getMethod(), new Class[0]).getAnnotation(InputConfig.class);
            if (annotation != null) {
                if (!annotation.methodName().equals("")) {
                    Method method = action.getClass().getMethod(annotation.methodName());
                    resultName = (String) method.invoke(action);
                } else {
                    resultName = annotation.resultName();
                }
            }

            return resultName;
        }
    }

    return invocation.invoke();
}

在本场景中,由于FooAction验证的结果会通过chain传过来,validationAwareAction.hasErrors()的结果就是true,最终会走return resultName;也就是直接走了return “input",而不会进入action的someMethod方法。那为什么方法更名为input就可以了呢?原来,我们的配置文件里,对validate及workflow配置了

1
<param name="excludeMethods">input,back,cancel,browse</param>

input恰好就名列其中。也就是说,转向BarAction的input时,workflow是不进行拦截的,所以能进入BarAction的input方法。实际上,按照struts2的设计思想,input等方法就是用于错误处理的,不直接对前端提供服务,所以应该排除在validate和workflow之外。 这样,解决问题的方法就是: 1,利用struts2现有的机制,更改someMethod方法名为excludeMethods中现有的,最好是input,同时,chain的配置里,明确指定method参数为input,而不是默认的executed 2,把someMethod加入到validate和workflow的excludeMethods配置中 推荐第一种方法,不破坏struts2的设计思想。 出处:http://fan.javaeye.com/blog/553977

Comments