struts 2.2.1 中ActionChainResult的修改[CSDN迁移文章]

如果你因struts2暴露的安全漏洞 而希望升级到struts 2.2.1,那么你需要仔细测试你的程序是否能在2.2.1的环境下顺利运行。因为struts 2.2.1版本升级了OGNL、freemarker,以及对我们代码影响很大的xwork。

其中xwork的一个bug编号为"WW-2869 "的修订,对我们熟悉的chain result type做了重要的修改。这个bug的出发点是在一个Action a执行后,跳转到执行result。假设这个result是一张jsp页面,而这张jsp页面中调用了<s:action name="bar"/>标签。假设在执行a Action时,执行了类似代码"addActionError("an error from FooAction");",那么会停止对Action bar的正确调用,而执行Action bar的input。

这个问题的归结原因是在ChainingInterceptor中,在调用Action bar前,会将上一个Action(面假设中的Action a)的一些属性值拷贝到bar中。以下是在strtus 2.2.1前的xwork中的ChainingInterceptor代码

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        ValueStack stack = invocation.getStack();
        CompoundRoot root = stack.getRoot();
        if (root.size() > 1) {
            List<CompoundRoot> list = new ArrayList<CompoundRoot>(root);
            list.remove(0);
            Collections.reverse(list);
            Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
            Iterator<CompoundRoot> iterator = list.iterator();
            int index = 1; // starts with 1, 0 has been removed
            while (iterator.hasNext()) {
            	index = index + 1;
                Object o = iterator.next();
                if (o != null) {
                	if (!(o instanceof Unchainable)) {
						//拷贝属性值到将要执行的Action中
                		reflectionProvider.copy(o, invocation.getAction(), ctxMap, excludes, includes);
                	}
                }
                else {
                	LOG.warn("compound root element at index "+index+" is null");
                }
            }
        }
 

@Override public String intercept(ActionInvocation invocation) throws Exception { ValueStack stack = invocation.getStack(); CompoundRoot root = stack.getRoot(); if (root.size() > 1) { List<CompoundRoot> list = new ArrayList<CompoundRoot>(root); list.remove(0); Collections.reverse(list); Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); Iterator<CompoundRoot> iterator = list.iterator(); int index = 1; // starts with 1, 0 has been removed while (iterator.hasNext()) { index = index + 1; Object o = iterator.next(); if (o != null) { if (!(o instanceof Unchainable)) { //拷贝属性值到将要执行的Action中 reflectionProvider.copy(o, invocation.getAction(), ctxMap, excludes, includes); } } else { LOG.warn("compound root element at index "+index+" is null"); } } }

对于这种方式的好处,我们或许已经默默的在使用了。还是前面提到的Action a和Action bar,若Action a和Action bar都有一个共同的属性叫common,并且都有get、set方法。那么在Action a中的一些处理后,属性common有了值,经过chain resultType时,Action bar的common会自动被赋值。如果你在升级到struts2.2.1后,发现一些请求返回了NullPointerException,那么很有可 能是struts2.2.1对ChainingInterceptor的修改导致了这个问题。

以下是struts 2.2.1中的ChainingInterceptor源代码

    public String intercept(ActionInvocation invocation) throws Exception {
        ValueStack stack = invocation.getStack();
        CompoundRoot root = stack.getRoot();
        if (root.size() > 1 && isChainResult(invocation)) {
            List<CompoundRoot> list = new ArrayList<CompoundRoot>(root);
            list.remove(0);
            Collections.reverse(list);
            Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap();
            Iterator<CompoundRoot> iterator = list.iterator();
            int index = 1; // starts with 1, 0 has been removed
            while (iterator.hasNext()) {
                index = index + 1;
                Object o = iterator.next();
                if (o != null) {
                    if (!(o instanceof Unchainable)) {
                        reflectionProvider.copy(o, invocation.getAction(), ctxMap, excludes, includes);
                    }
                } else {
                    LOG.warn("compound root element at index " + index + " is null");
                }
            }
        }
        return invocation.invoke();
    }
 

public String intercept(ActionInvocation invocation) throws Exception { ValueStack stack = invocation.getStack(); CompoundRoot root = stack.getRoot(); if (root.size() > 1 && isChainResult(invocation)) { List<CompoundRoot> list = new ArrayList<CompoundRoot>(root); list.remove(0); Collections.reverse(list); Map<String, Object> ctxMap = invocation.getInvocationContext().getContextMap(); Iterator<CompoundRoot> iterator = list.iterator(); int index = 1; // starts with 1, 0 has been removed while (iterator.hasNext()) { index = index + 1; Object o = iterator.next(); if (o != null) { if (!(o instanceof Unchainable)) { reflectionProvider.copy(o, invocation.getAction(), ctxMap, excludes, includes); } } else { LOG.warn("compound root element at index " + index + " is null"); } } } return invocation.invoke(); }

和前面的相比,if (root.size() > 1) 中对了一个判断isChainResult(invocation)。这个判断让我有些纳闷,因为根据我的一些跟踪,在ActionInvocation 调用invoke()方法前,ActionInvocation中的result属性是null,所以这个if总是false。难道有什么其他设置能恢复 原来类似功能吗?希望有高人解答。正是因为这个问题,若你还希望使用原来chain的拷贝功能,你需要删除 isChainResult(invocation)这个判断。

以下是一个很有趣的实验,首先我们看核心的struts.xml配置信息:

    <package name="default" namespace="/" extends="struts-default">
        <!-- <default-action-ref name="index" /> -->
        <action name="index">
            <result>index.jsp</result>
        </action>
        
        <action name="chainSrc" class="ChainSrcAction">
        	<result type="chain">chainDest</result>
        </action>
         <action name="chainDest" class="ChainDestAction">
        	<result>chainDest.jsp</result>
        </action>
        
    </package>
 

<package name="default" namespace="/" extends="struts-default"> <!-- <default-action-ref name="index" /> --> <action name="index"> <result>index.jsp</result> </action> <action name="chainSrc" class="ChainSrcAction"> <result type="chain">chainDest</result> </action> <action name="chainDest" class="ChainDestAction"> <result>chainDest.jsp</result> </action> </package>

ChainSrcAction的源代码:

import com.opensymphony.xwork2.ActionSupport;
public class ChainSrcAction extends ActionSupport {
	
	private String p1;
	private String p2 = "chain";
	@Override
	public String execute() throws Exception {
		System.out.println(ChainSrcAction.class+"p1="+p1);
		System.out.println(ChainSrcAction.class+"p2="+p2);
		return SUCCESS;
	}
	
	public String getP1() {
		return p1;
	}
	public void setP1(String p1) {
		this.p1 = p1;
	}
	public String getP2() {
		return p2;
	}
}
 

import com.opensymphony.xwork2.ActionSupport; public class ChainSrcAction extends ActionSupport { private String p1; private String p2 = "chain"; @Override public String execute() throws Exception { System.out.println(ChainSrcAction.class+"p1="+p1); System.out.println(ChainSrcAction.class+"p2="+p2); return SUCCESS; } public String getP1() { return p1; } public void setP1(String p1) { this.p1 = p1; } public String getP2() { return p2; } }

ChainDestAction的源代码:

import com.opensymphony.xwork2.ActionSupport;
public class ChainDestAction extends ActionSupport {
	
	private String p1;
	private String p2 ;
	@Override
	public String execute() throws Exception {
		System.out.println(ChainDestAction.class+"p1="+p1);
		System.out.println(ChainDestAction.class+"p2="+p2);
		return SUCCESS;
	}
	
	public String getP1() {
		return p1;
	}
	public void setP1(String p1) {
		this.p1 = p1;
	}
	public String getP2() {
		return p2;
	}
	public void setP2(String p2) {
		this.p2 = p2;
	}
}
 

import com.opensymphony.xwork2.ActionSupport; public class ChainDestAction extends ActionSupport { private String p1; private String p2 ; @Override public String execute() throws Exception { System.out.println(ChainDestAction.class+"p1="+p1); System.out.println(ChainDestAction.class+"p2="+p2); return SUCCESS; } public String getP1() { return p1; } public void setP1(String p1) { this.p1 = p1; } public String getP2() { return p2; } public void setP2(String p2) { this.p2 = p2; } }

在struts 2.2.1的环境下,在地址栏上输入"http://127.0.0.1/s221/chainSrc.action?p1=struts2.2.1"你将会得到以下答案:

class ChainSrcActionp1=struts2.2.1
class ChainSrcActionp2=chain
class ChainDestActionp1=struts2.2.1
class ChainDestActionp2=null

在struts 2.1.8的环境下,相同的访问你会得到答案:

class ChainSrcActionp1=struts2.2.1
class ChainSrcActionp2=chain
class ChainDestActionp1=struts2.2.1
class ChainDestActionp2=chain

如果你将ChainingInterceptor中的if (root.size() > 1 && isChainResult(invocation))改为if (root.size() > 1 ),你也可以得到struts 2.1.8的结果。对于熟悉p1,它始终都得到了赋值是因为还有ParametersInterceptor对它赋值。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值