2010-10-28 6 views
1

Par exemple, je donne les résultats suivants:Struts 2 s: balise d'action ne rend pas d'erreurs d'action le cas échéant sont présents

struts.xml:

<action name="personForm"> 
    <result>/jsp/personForm.jsp</result> 
</action> 
<action name="savePerson"> 
    <result>/jsp/successSave.jsp</result> 
    <result name="input">/jsp/personForm.jsp</result> 
</action> 
<action name="countries"> 
    <result>/jsp/countries.jsp</result> 
</action> 

personForm.jsp:

<%@ taglib prefix="s" uri="/struts-tags" %> 
<s:form action="savePerson"> 
     <s:textfield name="firstName" label="First Name" /> 
     <s:textfield name="lastName" label="Last Name" /> 
     <s:action name="countries" executeResult="true" /> 
     <s:submit /> 
</s:form> 

CountriesAction.java:

public class CountriesAction extends ActionSupport { 
    public String execute() { 
     countries = getCountries(); 
     return SUCCESS; 
    } 

    private Map<String, String> getCountries() { 
      ... 
    } 

    private Map<String, String> countries; 
} 

countries.jsp:

<%@ taglib prefix="s" uri="/struts-tags" %> 
    <s:select name="countryId" label="Countries" list="countries" 
     headerKey="-1" headerValue="Please select the country ..."/> 

SavePerson.action

public class SavePerson extends ActionSupport { 

    public void validate() { 
     if (firstName == "") { 
      addFieldError(firstName, "First Name is required."); 
     } 

     if (lastName == "") { 
      addFieldError(lastName, "Last Name is required."); 
     } 

     if (countryId == "-1") { 
      addFieldError(countryId, "Country is required."); 
     } 

    } 

    public String execute() { 
     //get the properties and save the person... 
     return SUCCESS; 
    } 

    private String firstName; 
    private String lastName; 
    private String countryId; 

    //corresponding setters and getters.. 
} 

Quand je soumets le formulaire et une erreur de validation se produit par exemple, disons que nous ne remplissons toutes les données de sorte que les champs d'entrée de la prenom 'et' lastName 'auront leur message correspondant à côté d'eux. Mais ce n'est pas le cas pour la liste de sélection du pays, même s'il y a des erreurs d'action qui ne s'afficheront pas.

Je crois que cela arrive parce que l'action parente qui est SavePerson est celle qui a ajouté les erreurs (addFieldErrors) mais quand l'autre action Pays (celle qui remplit la liste) est appelée alors ces erreurs ne sont pas disponibles dans ce contexte car si j'appelle hasErrors() dans cette Action, il sera "false" donc quand l'entrée sera affichée et vérifiera s'il y a des erreurs pour rendre le message appellera hasErrors et retournera false donc aucun message d'erreur ne sera rendu.

Cette approche d'appeler une autre action juste pour rendre un autre contrôle d'entrée est l'un des moyens que Struts 2 FAQS dire de le faire: http://struts.apache.org/2.2.1/docs/how-do-we-repopulate-controls-when-validation-fails.html

Alors, comment puis-je faire de ces contrôles sur ces actions rendent les erreurs d'action de son action parentale.

Des pensées?

Nous vous remercions à l'avance

Répondre

2

Je résolus en réglant la référence des erreurs de l'action de l'appelant à l'action invoquée. Cela a été mis en œuvre comme un intercepteur:

public class CopyErrorsInterceptor extends AbstractInterceptor { 


    public String intercept(ActionInvocation invocation) throws Exception { 
     ValueStack stack = invocation.getStack(); 
     CompoundRoot root = stack.getRoot(); 
     Action currentAction = (Action) invocation.getAction(); 
     if (root.size() > 1 && isValidationAware(currentAction)) { 
      Action callerAction = getFirstActionBelow(root, currentAction); 
      if (callerAction != null && isValidationAware(callerAction)) { 
       ValidationAware currentActionVal = (ValidationAware) currentAction; 
       ValidationAware callerActionVal = (ValidationAware) callerAction; 

       //Copy the errors to the chained action. 
       currentActionVal.setActionErrors(callerActionVal.getActionErrors()); 
       currentActionVal.setFieldErrors(callerActionVal.getFieldErrors()); 
      } 
     } 

     return invocation.invoke(); 
    } 

    /** 
    * Gets the first action below the passed action. 
    * @param root the stack to find the action 
    * @param current is the current action. 
    * @return 
    */ 
    private Action getFirstActionBelow(CompoundRoot root, Action current) { 
     boolean foundCurrentAction = false; 
     for(Object obj : root) { 
      if (obj == current) { 
       foundCurrentAction = true; 
      } else { 
       if (obj instanceof Action && foundCurrentAction) { 
        return (Action) obj; 
       } 
      } 
     } 
     return null; 
    } 

    private boolean isValidationAware(Action action) { 
     return action instanceof ValidationAware; 
    } 

} 

dû déclarer ma propre pile qui étend des entretoises par défaut:

<interceptors> 
      <interceptor name="copyErrors" class="com.afirme.casa.interceptor.CopyErrorsInterceptor"/> 

      <interceptor-stack name="defaultPlusErrors"> 
       <interceptor-ref name="copyErrors"/> 
       <interceptor-ref name="defaultStack"> 
        <param name="workflow.excludeMethods"> 
         input,back,cancel,execute 
        </param> 
       </interceptor-ref> 
      </interceptor-stack> 
     </interceptors> 

Et les actions qui vont être inovked par d'autres actions (dans ce cas à travers les balises d'action) doivent faire référence à cette nouvelle pile d'intercepteurs. Exemple:

<action name="example" class="ExampleAction"> 
      <interceptor-ref name="defaultPlusErrors"/> 
      <result>/jsp/example.jsp</result> 
     </action> 

Hope this helps,

Alfredo O

Questions connexes