备注:Struts1中出现的类似checkbox问题可以通过ActionForm的reset方法解决。
问题: 用户没有选中任何checkbox时,提交不生效。
原因: load和edit操作共用同一个Action类的prepare()方法; params interceptor对checkbox处理方式比较特殊。
使用标签<s:checkboxlist>时,如果页面上所有的checkbox都没被选中,Struts2的parameter interceptor不会对相应属性赋值,从而造成程序bug。例如,
页面timeframe.page:
<s:form id="tform" method="post" action="edit">
<s:checkboxlist id="seltimeframes" name="seltimeframes" key="lbl.timeframe" list="timeframeList" listKey="id" listValue="name" />
</s:form>
正常情况下,如果使用defaultStack,调用interceptors的先后顺序是先prepare,然后modelDriven,最后params。如果使用paramsPrepareParamsStack,则在调用prepare之前要先调用一次params,将输入参数传给prepare()使用。但是问题是: 如果没有任何checkbox被勾选,params根本不给seltimeframes属性赋值。
产生问题的具体场景(scenario)是这样的:
在装载(load)页面timeframe.page的时候,需要通过prepare()方法给seltimeframes属性设置初始值:
public void prepare() {
....
seltimeframes.add(...);
}
然后用户将所有的checkboxes取消勾选,在提交表单调用edit这个action的时候(load和edit操作共用同一个Action类), 由于struts2 interceptor stack仍然会调用prepare()方法,但是在执行edit时我们不希望seltimeframes.add(...);这条语句生效。在正常的情况下, 我们希望params这个interceptor能将属性seltimeframes重新设置为用户提交的值,即seltimeframes为空,从而覆盖prepare()中的设置。但是在没有任何checkbox被选中的情况下,params interceptor并没这样做。从而edit操作得到的结果仍然是用户取消勾选之前的状态,出现bug!
如果要改正过来,有一个做法是在调用seltimeframes.add(...);这条语句时判断是load操作还是edit操作的prepare(),因此可以在<s:form>中加一个hidden属性:
<s:form id="tform" method="post" action="edit">
<s:hidden id="submitflag" name="submitflag" value="1"/>
<s:checkboxlist id="seltimeframes" name="seltimeframes" key="lbl.timeframe" list="timeframeList" listKey="id" listValue="textName" />
</s:form>
然后将edit的action改为:
@Component
@Scope("prototype")
@InterceptorRefs({
@InterceptorRef(value="paramsPrepareParamsStack")
})
public class EditAction implements Preparable,ModelDriven<Item>{
private List<Integer> seltimeframes = new ArrayList<Integer>();
private Integer submitflag;
public void prepare() {
....
if(submitflag == null || submitflag.intValue() != 1){
seltimeframes.add(...);
}
}
....
}
这样保证了用户提交的数据能够生效。