【问题标题】:Prevent form resubmit on refresh in struts2 (with action messages and fields messages preservation)防止在struts2中刷新时重新提交表单(保留操作消息和字段消息)
【发布时间】:2012-01-17 21:57:18
【问题描述】:

我得到了一个简单的表单验证和提交,效果很好

这是我的 struts.xml:

    <action name="register" class="registerAction">
        <interceptor-ref name="defaultWithoutAuthenticationStack"/>
        <result type="tiles" name="input">
            <param name="titleKey">global.title.register</param>
            <param name="location">register</param>
        </result>
        <result type="tiles" name="success">register.success</result>
    </action>

我的jsp表单:

<s:form method="post" action="register.action" validate="true">
    <s:textfield name="usernameRegister" id="usernameRegister" key="global.username" labelposition="left" />
    <s:password name="passwordRegister" id="passwordRegister" key="global.password" labelposition="left" />
    <s:password name="passwordConfirmRegister" id="passwordConfirmRegister" key="global.password.confirm" labelposition="left" />
    <s:textfield name="emailRegister" id="emailRegister" key="global.email" labelposition="left" />
    <s:submit key="global.register" name="submitRegister" method="goRegister"></s:submit>
</s:form>

还有我的提交功能:

public String goRegister(){
    user.setUsername(getUsernameRegister());
    user.setPassword(getPasswordRegister());
    user.setEmail(getEmailRegister());
    userService.addUser(user);

    ArrayList<String> successMessageUsername = new ArrayList<String>();

    successMessageUsername.add(getUsernameRegister());
    this.addActionSuccess(getText("global.register.success", successMessageUsername));
    return SUCCESS;
}

没什么花哨的!

问题是当我在成功页面或表单页面上刷新页面时(验证失败时),我有一个窗口要求重新提交表单信息

我怎样才能防止这种情况发生?

谢谢

编辑:我将操作消息和字段消息保存添加到我的问题中 如何通过重定向保留操作消息和字段消息(验证)?

【问题讨论】:

  • 我现在不能回答,但我会尽快发布

标签: forms struts2 refresh form-submit


【解决方案1】:

使用post-redirect-get pattern

成功后,重定向到“您已注册”页面。这样,如果用户刷新,他们就会再次获得相同的页面。

【讨论】:

  • 谢谢,我会试试这个:) 我也可以将它用于失败的验证表单吗?我的意思是重定向到带有字段值/错误的表单?你如何在 struts.xml 上设置这个
  • 由于我一开始没有要求保留消息,所以我接受您的回答(这是一个开始搜索的好地方),如果您对消息,字段消息保存感兴趣,请看下面:)
  • @Fluckysan 如果注册失败,我不明白你为什么要麻烦重定向;再次显示输入页面。如果您想保留操作状态,请使用范围拦截器,或者只是将消息保存在会话中并自行删除。
  • 我想重定向以防止在验证失败后刷新浏览器弹出“你想重新提交值”,我可以用我自己的 MessageStoreInterceptor 这样做(不知道它存在所以我开发了我的 >_
  • @Fluckysan 是的,scopestore 拦截器。就个人而言,我认为它们都有点笨重,通常使用小型闪存式拦截器,但功能是相同的。
【解决方案2】:

Oki 在 Dave Newton 的建议之后,我挖掘了一点以完成正确的方法:)

到目前为止,这是我的回答,不再刷新、向后或向前重新提交表单并保留 ValidationAware 消息(错误和消息)

我的 struts.xml :

    <action name="register" class="registerAction">
        <interceptor-ref name="defaultWithoutAuthenticationStack"/>
        <result type="tiles" name="input">
            <param name="titleKey">global.title.register</param>
            <param name="location">register</param>
        </result>
        <result name="success" type="redirectAction">index</result>
    </action>

    <action name="goRegister" class="registerAction">
        <interceptor-ref name="defaultWithoutAuthenticationStack"/>
        <result name="input" type="redirectAction">register</result>
        <result name="success" type="redirectAction">index</result>
    </action>

还有我的jsp:

    <s:form method="post" action="goRegister" validate="true">
    <s:textfield name="usernameRegister" id="usernameRegister" key="global.username" labelposition="left" />
    <s:password name="passwordRegister" id="passwordRegister" key="global.password" labelposition="left" />
    <s:password name="passwordConfirmRegister" id="passwordConfirmRegister" key="global.password.confirm" labelposition="left" />
    <s:textfield name="emailRegister" id="emailRegister" key="global.email" labelposition="left" />
    <s:submit key="global.register" name="submitRegister" method="goRegister"></s:submit>
</s:form>

我找到了消息保存here 的答案,当我们处于重定向情况时,他将不同的操作消息(消息、错误、字段错误)存储在会话中,否则将它们推送到操作消息

这是我的实现(你会发现我在默认消息和错误消息中添加了成功消息):

public class MessagesInterceptor extends AbstractInterceptor {
/**
 * 
 */
private static final long serialVersionUID = -6230422534075664728L;
private Map<String, Object> session;

@Override
public String intercept(ActionInvocation invocation) throws Exception {
    session = invocation.getInvocationContext().getSession();
    MyAction action = (MyAction) invocation.getAction();

    this.addSessionMessagesInActionMessages(action);

    String output = invocation.invoke();
    Result result = invocation.getResult();

    // If it's a redirection, store the messages in session
    if(result instanceof ServletRedirectResult || result instanceof ServletActionRedirectResult)
        this.addActionMessagesInSessionMessages(action);

    return output;
}

@SuppressWarnings("unchecked")
private void addSessionMessagesInActionMessages(MyAction action) {
    Object messagesObject = getSession().remove(SESSION_ACTION_MESSAGES);
    if (messagesObject != null) {
        List<String> sessionMessages = (List<String>)messagesObject;
        for (String sessionMessage : sessionMessages) {
            action.addActionMessage(sessionMessage);
        }
    }

    Object errorsObject = getSession().remove(SESSION_ACTION_ERRORS);
    if (errorsObject != null) {
        List<String> sessionErrors = (List<String>)errorsObject;
        for (String sessionError : sessionErrors) {
            action.addActionError(sessionError);
        }
    }

    Object successObject = getSession().remove(SESSION_ACTION_SUCCESS);
    if (successObject != null) {
        List<String> sessionSuccessList = (List<String>)successObject;
        for (String sessionSuccess : sessionSuccessList) {
            action.addActionSuccess(sessionSuccess);
        }
    }

    @SuppressWarnings("rawtypes")
    Map<String, List<String>> fieldErrors = (Map) session.remove(SESSION_FIELD_ERRORS);
    if (fieldErrors != null && fieldErrors.size() > 0){
        for (Map.Entry<String, List<String>> fieldError : fieldErrors.entrySet()){
            for (String message : fieldError.getValue()){
                action.addFieldError(fieldError.getKey(), message);
            }
        }
    }
}

protected void addActionMessagesInSessionMessages(MyAction action) throws Exception{
    Collection<String> actionErrors = action.getActionErrors();

    if (actionErrors != null && actionErrors.size() > 0){
       session.put(SESSION_ACTION_ERRORS, actionErrors);
    }

    Collection<String> actionMessages = action.getActionMessages();

    if (actionMessages != null && actionMessages.size() > 0){
       session.put(SESSION_ACTION_MESSAGES, actionMessages);
    }

    Collection<String> actionSuccess = action.getActionSuccess();

    if (actionSuccess != null && actionSuccess.size() > 0){
       session.put(SESSION_ACTION_SUCCESS, actionSuccess);
    }

    Map<String, List<String>> fieldErrors = action.getFieldErrors();

    if (fieldErrors != null && fieldErrors.size() > 0){
       session.put(SESSION_FIELD_ERRORS, fieldErrors);
    }
}

public Map<String, Object> getSession() {
    return session;
}

public void setSession(Map<String, Object> session) {
    this.session = session;
}

}

MyAction 继承 ActionSupport

希望这会对某人有所帮助;)

现在可以保留操作消息和字段验证消息,没有刷新问题

但我的字段值现在是空白的,如何检索/存储它们以重新填充我的字段?

【讨论】:

  • defaultWithoutAuthenticationStack 这是你自己的拦截器,如果是的话,MessagesInterceptor 你在哪里使用它?
  • 你说得对,我好像忘了添加一些代码,defaultWithoutAuthenticationStack 是我自己的实现,更准确地说它是从我添加的 defaultStack (struts.apache.org/release/2.0.x/docs/…) 派生的拦截器堆栈我的MessagesInterceptor
猜你喜欢
  • 2019-07-20
  • 1970-01-01
  • 2015-03-05
  • 1970-01-01
  • 2011-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-06
相关资源
最近更新 更多