当结果类型是Struts2中的重定向操作时,prepare()方法被调用两次

时间:2014-01-07 15:41:59

标签: java configuration struts2 interceptor prepare

我有以下动作类:

@Namespace("/admin_side")
@ResultPath("/WEB-INF/content")
@ParentPackage(value="struts-default")
public final class FabricAction extends ActionSupport implements Serializable, ValidationAware, Preparable, ModelDriven<Fabric>
{
    @Autowired
    private final transient FabricService fabricService=null;
    private static final long serialVersionUID = 1L;

    private int pageSize=5;
    private Long id;
    private Boolean deleteOneRow;
    private Boolean deleteMultipleRows;
    private String message;
    private List<Long>chk;
    private Long deleteId;

    private Long begin;
    private Long end;
    private Long currentPage=1L;
    private Long rowCount;
    private Long totalPages;
    private Integer status;

    private Fabric entity=new Fabric();
    private List<Fabric>fabrics=new ArrayList<Fabric>();

    //Getters & Setters.

    @Action(value = "Fabric",
            results = {
                @Result(name=ActionSupport.SUCCESS, location="Fabric.jsp"),
                @Result(name = ActionSupport.INPUT, location = "Fabric.jsp")},
            interceptorRefs={
                @InterceptorRef(value="paramsPrepareParamsStack", params={"params.acceptParamNames", "id, currentPage, rowCount, totalPages, message, status", "validation.validateAnnotatedMethodOnly", "true", "validation.excludeMethods", "load"})})
    public String load() throws Exception
    {
        //Invokes, when the page is loaded.
        return ActionSupport.SUCCESS;
    }

    @Action(value = "FabricPage",
        results = {@Result(name=ActionSupport.SUCCESS, location="Fabric.jsp", params={"namespace", "/admin_side", "actionName", "Fabric", "currentPage", "${currentPage}"}),
        @Result(name = ActionSupport.INPUT, location = "Fabric.jsp")},
        interceptorRefs={
            @InterceptorRef(value="conversionError"),
            @InterceptorRef(value="paramsPrepareParamsStack", params={"params.acceptParamNames", "currentPage", "validation.validateAnnotatedMethodOnly", "true"})})
    public String page()
    {
        //Invokes, when a page link is clicked.
        return ActionSupport.SUCCESS;
    }

    @Validations(
            requiredStrings={
                @RequiredStringValidator(fieldName="fabricName", type= ValidatorType.FIELD, key = "fabric.name.required")},
            stringLengthFields={
                @StringLengthFieldValidator(fieldName="fabricName", type= ValidatorType.FIELD, minLength="2", maxLength="45", key="fabric.name.length", messageParams={"2", "45"})})
    @Action(value = "AddFabric",
        results = {
            @Result(name=ActionSupport.SUCCESS, type="redirectAction", location="Fabric.jsp", params={"namespace", "/admin_side", "actionName", "Fabric", "currentPage", "${currentPage}", "message", "${message}", "id", "${id}", "status", "${status}"}),
            @Result(name = ActionSupport.INPUT, location = "Fabric.jsp")},
        interceptorRefs={
            @InterceptorRef(value="conversionError"),
            @InterceptorRef(value="paramsPrepareParamsStack", params={"params.acceptParamNames", "id, fabricId, fabricName, currentPage, rowCount, totalPages, status", "validation.validateAnnotatedMethodOnly", "true"})
        })
    public String insert()
    {
        //Handles insert and update operations.
        return ActionSupport.SUCCESS;
    }

    @Action(value = "EditFabric",
            results = {
                @Result(name=ActionSupport.SUCCESS, location="Fabric.jsp"),
                @Result(name = ActionSupport.INPUT, location = "Fabric.jsp")},
            interceptorRefs={
                @InterceptorRef(value="paramsPrepareParamsStack", params={"params.acceptParamNames", "id, fabricId, fabricName, currentPage", "validation.validateAnnotatedMethodOnly", "true"}),
                @InterceptorRef(value="conversionError")})
    public String edit()
    {
        //Invokes, when an edit link is clicked.
        return ActionSupport.SUCCESS;
    }

    @Validations(
            fieldExpressions={@FieldExpressionValidator(fieldName="deleteOneRow", expression="deleteOneRow==true", shortCircuit=true, key="delete.row.reject")})
    @Action(value = "DeleteFabric",
            results = {
                @Result(name=ActionSupport.SUCCESS, type="redirectAction", location="Fabric.action", params={"currentPage", "${currentPage}", "message", "${message}", "status", "${status}"}),
                @Result(name = ActionSupport.INPUT, location = "Fabric.jsp")},
            interceptorRefs={
                @InterceptorRef(value="paramsPrepareParamsStack", params={"params.acceptParamNames", "deleteId, deleteOneRow, currentPage, status", "validation.validateAnnotatedMethodOnly", "true"}),
                @InterceptorRef(value="conversionError")})
    public String deleteSingleRow()
    {
        //Handles deletion of a single row.
        return ActionSupport.SUCCESS;
    }

    @Validations(
            requiredFields={
                @RequiredFieldValidator(type= ValidatorType.FIELD, fieldName="chk", key="delete.multiple.alert"),
                @RequiredFieldValidator(type= ValidatorType.FIELD, fieldName="deleteMultipleRows", key="delete.multiple.confirm")})
    @Action(value = "DeleteFabrics",
            results = {
                @Result(name=ActionSupport.SUCCESS, type="redirectAction", location="Fabric.jsp", params={"namespace", "/admin_side", "actionName", "Fabric", "currentPage", "${currentPage}", "message", "${message}", "status", "${status}"}),
                @Result(name = ActionSupport.INPUT, location = "Fabric.jsp")},
            interceptorRefs={
                @InterceptorRef(value="paramsPrepareParamsStack", params={"params.acceptParamNames", "deleteMultipleRows, chk, currentPage, rowCount, totalPages", "validation.validateAnnotatedMethodOnly", "true"}),
                @InterceptorRef(value="conversionError")})
    public String deleteMultipleRows()
    {
        //Handles deletion of multiple rows.
        return ActionSupport.SUCCESS;
    }

    public Fabric getEntity() {
        return entity;
    }

    public void setEntity(Fabric entity) {
        this.entity = entity;
    }

    public List<Fabric> getFabrics()
    {
        return fabrics;
    }

    @Override
    public Fabric getModel()
    {
        return entity;
    }

    @Override
    public void prepare() throws Exception
    {
        fabrics= fabricService.getList((int)(currentPage-1)*pageSize, pageSize);
    }
}

执行除insert()方法关联的插入和更新之外的所有操作(两者都与映射到insert()操作的<s:submit>相关联), prepare()方法只执行一次。

执行插入或更新时,可以看到prepare()方法被调用两次。为什么会这样?

如果type="redirectAction"@Result(),则prepare()方法执行两次。当prepare()的{​​{1}}设置为type时,有没有办法阻止@Result方法执行两次?

2 个答案:

答案 0 :(得分:1)

选择结果typelocation时出错。因为"Fabric.jsp""Fabric.action"不是有效的操作名称。

@Result(name=ActionSupport.SUCCESS, type="redirectAction", location="Fabric.jsp",

应该是dispatcher结果

@Result(name=ActionSupport.SUCCESS, location="Fabric.jsp",

redirectAction结果

@Result(name=ActionSupport.SUCCESS, type="redirectAction", location="Fabric"

如果使用redirectAction结果类型,则默认情况下会创建新的操作类实例,其中在操作之前执行prepare方法。如果打印hashCode(),即使不同的操作名称,您也可以检查此项。因此,没有prepare方法调用两次,因为每个操作的堆栈中只有prepare拦截器。另一方面,如果使用paramsPrepareParamsStack,则params拦截器被调用两次:prepare拦截器之前和之后。

答案 1 :(得分:1)

我遇到了同样的问题,我最终发现的是我在多个地方引用了一个拦截器堆栈。在您的情况下,您似乎在班级:

@ParentPackage(value="struts-default"),我认为它使用默认堆栈。

然后在@Act​​ion级别,您可以引用paramsPrepareParamsStack

interceptorRefs={
            @InterceptorRef(value="paramsPrepareParamsStack"...)})

在我的特定情况下,我的Action类扩展了一个BaseAction类。我在两个地方宣布了@InterceptorRef注释。 BaseAction(引用的第一个拦截器堆栈):

@Namespace("/")
@InterceptorRef("myCustomStack")
@Results({ @Result(name = "cancel", location = "${previousPageLink}", type = "redirectAction", params = {
 }) })
public class BaseAction extends ActionSupport implements ServletRequestAware, ParameterAware,
SessionAware { 
...
}

然后,在动作类中,我再次使用了拦截器ref(&#34; myCustomStack&#34;)。在我的HomeAction类中删除拦截器引用堆栈为我解决了这个问题。

@Namespace("/")
@InterceptorRefs({
@InterceptorRef(value = "store", params = {"operationMode", "RETRIEVE"}) })
/*@InterceptorRef("myCustomStack") })*/
@Results({ @Result(name = "success", location = "home.def", type = "tiles")
})
public class HomeAction extends BaseAction implements Preparable {
...
}

最后,这是我的struts.xml,其default.parent.package设置为&#39;默认&#39;:

<struts>
  <constant name="struts.convention.action.packages" value="com.myapp.action" />
  <constant name="struts.convention.default.parent.package" value="default" />
  <constant name="struts.action.extension" value="action" />
  <constant name="struts.enable.DynamicMethodInvocation" value="false" />
  <constant name="struts.ognl.allowStaticMethodAccess" value="true" />
  <package name="default" namespace="/" extends="tiles-default,json-default">
    <interceptors>
      <interceptor-stack name="myCustomStack">
        <interceptor-ref name="basicStack" />
        <interceptor-ref name="staticParams" />
        <interceptor-ref name="validation">
          <param name="excludeMethods">input,back,cancel,browse</param>
        </interceptor-ref>
        <interceptor-ref name="workflow">
          <param name="excludeMethods">input,back,cancel,browse</param>
        </interceptor-ref>
      </interceptor-stack>
    </interceptors>
  </package>
</struts>