2014-01-07 3 views
1

У меня есть следующий класс действия:Метод подготовки() вызывается дважды, когда тип результата является перенаправление действия в Struts2

@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() дважды, когда type из @Result установлено в redirectAction?

+0

Не можете ли вы напечатать имя действия в 'prepare()'? –

+0

Как отобразить имя действия? – Tiny

+0

Что-то вроде 'System.out.println (" actionName = "+ ActionContext.getContext(). GetName())' –

ответ

1

Вы ошиблись, выбрав результат type или location. Потому что "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 перехватчик.

+0

Я сделал эти много изменений, но ничто не мешает тому, чтобы метод 'prepare()' выполнялся дважды в случае 'type =" redirectAction "', который необходим для предотвращения повторной отправки формы после создания почтового запроса и 'ActionSupport. SUCCESS' оценивается в ответ на запрос. – Tiny

+0

* Метод подготовки не называется дважды *, как я сказал в своем ответе. –

+0

При использовании 'paramsPrepareParamsStack', а в случае' type = "redirectAction" 'сначала запускается действие 'AddFabric', а затем выполняется действие' Fabric', как в вопросе, заставляя 'prepare()' выполняться еще раз, что, в свою очередь, вызывает дорогостоящие запросы на базу данных, которая не должна произойти. В противном случае нет смысла использовать метод 'prepare()' вообще. – Tiny

1

У меня была такая же проблема, и в конечном итоге я обнаружил, что я ссылался на стек перехватчика в нескольких местах. В вашем случае, похоже, у вас есть на уровне класса:

@ParentPackage(value="struts-default"), который, как я считаю, использует стек по умолчанию.

А затем на уровне @Action, у вас есть ссылка на 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 { 
... 
} 

Тогда в классе действий, я имел перехватчик реф («myCustomStack») еще раз. Удаление стека reflex перехватчика в моем классе 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, у которого есть значение по умолчанию.пакет установлен на «по умолчанию»:

<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>