代码之家  ›  专栏  ›  技术社区  ›  Alfredo Osorio

struts 2 s:如果存在操作错误,则操作标记不会呈现操作错误

  •  1
  • Alfredo Osorio  · 技术社区  · 15 年前

    例如,我有以下内容:

    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>
    

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

    国家: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..
    }
    

    当我提交表单时,出现了一个验证错误,例如,假设我们没有填写任何数据,因此输入字段“firstname”和“lastname”将在它们旁边显示相应的消息。但国家选择列表并非如此,即使存在无法显示的操作错误。

    我认为发生这种情况是因为父操作savePerson是添加错误(addFieldErrors)的操作,但是当调用其他操作国家(填充列表的国家)时,这些错误在该上下文中不可用,因为如果在该操作中调用hasErrors(),它将是“false”,因此当呈现输入时并检查是否有任何错误以便呈现消息,将调用hasErrors并返回false,因此不会呈现任何错误消息。

    这种调用另一个操作只是为了呈现另一个输入控件的方法是Struts2常见问题解答告诉您这样做的方法之一: http://struts.apache.org/2.2.1/docs/how-do-we-repopulate-controls-when-validation-fails.html

    因此,如何使这些操作上的控件呈现其父操作中的操作错误。

    有什么想法吗?

    提前谢谢你

    1 回复  |  直到 15 年前
        1
  •  2
  •   Alfredo Osorio    15 年前

    我通过设置从调用者操作到被调用操作的错误引用来解决这个问题。这是作为拦截器实现的:

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

    必须声明自己的堆栈,该堆栈扩展Struts默认值:

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

    对于将被其他操作(在本例中是通过操作标签)阻止的操作,必须引用这个新的拦截器堆栈。例子:

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

    希望这有帮助,

    阿尔弗雷多o