一尘不染

使用消息存储拦截器进行struts2验证

jsp

  1. 用户刷新页面
  2. 错误消失了
    如何保存页面刷新错误?

这就是MessageStoreInterceptor的工作方式。它实际上是一个功能,而不是错误。

页面刷新是用户触发的操作,这意味着可以假定他已经阅读了上一个操作(登录尝试)的结果,除非他闭着眼睛按F5键。

您应该希望消息在第一次读取后过期。

考虑具有很多非ajax操作的页面,例如,组合框取决于其他操作,等等。…如果错误消息持续存在,则它将在每次不涉及进入另一个页面的提交操作之后弹出。

你不要那样 您应该希望收到一条消息,指出在 该
操作之后一个操作出了错(或正确)。如果用户随后继续执行其他操作(如刷新),并且这些操作没有出错(或处于特定的成功状态),则不会显示任何消息。

在那之后,也有不少世界问题 时,从会话持久性消息删除,否则你会与下一个动作得到该消息RETRIEVEAUTOMATIC一个operationMode。然后,您可以(但不应该)自定义MessageStore拦截器,或自行在会话之间写入/读取/删除消息,从而从根本上重新发明轮子。甚至放置两个MessageStore拦截器,一个RETRIEVE和一个STORE用于displayLoginPageAction,得到刚才提到的陷阱。

您还使用PRG模式(发布/重定向/获取),以避免刷新页面时重新发送数据。同样,您应该避免重复读取相同的消息两次。

要查看它是如何工作的,可以看一下MessageStore
Interceptor源代码
,它很简单:

  • 在调用之前,如果Action是 ValidationAwareand operationModeRETRIEVEor AUTOMATIC
    1. 阅读 actionMessagesactionErrorsfieldErrors从会议;
    2. 合并 与当前行动的他们actionMessagesactionErrorsfieldErrors
    3. 除去 actionMessagesactionErrorsfieldErrors从会议。
    /**
     * Handle the retrieving of field errors / action messages / field errors, which is
     * done before action invocation, and the <code>operationMode</code> is 'RETRIEVE'.
     *
     * @param invocation
     * @throws Exception
     */
    protected void before(ActionInvocation invocation) throws Exception {
        String reqOperationMode = getRequestOperationMode(invocation);

        if (RETRIEVE_MODE.equalsIgnoreCase(reqOperationMode) ||
                RETRIEVE_MODE.equalsIgnoreCase(operationMode) ||
                AUTOMATIC_MODE.equalsIgnoreCase(operationMode)) {

            Object action = invocation.getAction();
            if (action instanceof ValidationAware) {
                // retrieve error / message from session
                Map session = (Map) invocation.getInvocationContext().get(ActionContext.SESSION);

                if (session == null) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("Session is not open, no errors / messages could be retrieve for action ["+action+"]");
                    }
                    return;
                }

                ValidationAware validationAwareAction = (ValidationAware) action;

                if (LOG.isDebugEnabled()) {
                    LOG.debug("retrieve error / message from session to populate into action ["+action+"]");
                }

                Collection actionErrors = (Collection) session.get(actionErrorsSessionKey);
                Collection actionMessages = (Collection) session.get(actionMessagesSessionKey);
                Map fieldErrors = (Map) session.get(fieldErrorsSessionKey);

                if (actionErrors != null && actionErrors.size() > 0) {
                    Collection mergedActionErrors = mergeCollection(validationAwareAction.getActionErrors(), actionErrors);
                    validationAwareAction.setActionErrors(mergedActionErrors);
                }

                if (actionMessages != null && actionMessages.size() > 0) {
                    Collection mergedActionMessages = mergeCollection(validationAwareAction.getActionMessages(), actionMessages);
                    validationAwareAction.setActionMessages(mergedActionMessages);
                }

                if (fieldErrors != null && fieldErrors.size() > 0) {
                    Map mergedFieldErrors = mergeMap(validationAwareAction.getFieldErrors(), fieldErrors);
                    validationAwareAction.setFieldErrors(mergedFieldErrors);
                }
                session.remove(actionErrorsSessionKey);
                session.remove(actionMessagesSessionKey);
                session.remove(fieldErrorsSessionKey);
            }
        }
    }
  • 调用后,如果Action是 ValidationAwareand operationModeSTOREor(或operationModeis是AUTOMATICResult的类型redirectAction):
    1. 阅读 actionMessagesactionErrorsfieldErrors从行动;
    2. 存储 actionMessagesactionErrorsfieldErrors在会话中。
    /**
     * Handle the storing of field errors / action messages / field errors, which is
     * done after action invocation, and the <code>operationMode</code> is in 'STORE'.
     *
     * @param invocation
     * @param result
     * @throws Exception
     */
    protected void after(ActionInvocation invocation, String result) throws Exception {

        String reqOperationMode = getRequestOperationMode(invocation);
        boolean isRedirect = invocation.getResult() instanceof ServletRedirectResult;
        if (STORE_MODE.equalsIgnoreCase(reqOperationMode) ||
                STORE_MODE.equalsIgnoreCase(operationMode) ||
                (AUTOMATIC_MODE.equalsIgnoreCase(operationMode) && isRedirect)) {

            Object action = invocation.getAction();
            if (action instanceof ValidationAware) {
                // store error / messages into session
                Map session = (Map) invocation.getInvocationContext().get(ActionContext.SESSION);

                if (session == null) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("Could not store action ["+action+"] error/messages into session, because session hasn't been opened yet.");
                    }
                    return;
                }

                if (LOG.isDebugEnabled()) {
                    LOG.debug("store action ["+action+"] error/messages into session ");
                }

                ValidationAware validationAwareAction = (ValidationAware) action;
                session.put(actionErrorsSessionKey, validationAwareAction.getActionErrors());
                session.put(actionMessagesSessionKey, validationAwareAction.getActionMessages());
                session.put(fieldErrorsSessionKey, validationAwareAction.getFieldErrors());
            }
            else if(LOG.isDebugEnabled()) {
            LOG.debug("Action ["+action+"] is not ValidationAware, no message / error that are storeable");
            }
        }
    }

注1 :登录操作也是不言自明的:如果登录后再次进入登录页面,则仅表示登录失败…顺便说一句,以上说明适用于每个页面/功能
注2 :网站产生的消息会在X秒钟后自动过期,而不关心用户是否已阅读这些消息…… 与可用性恕我直言。


阅读 289

收藏
2020-06-08

共1个答案

一尘不染

  1. 用户刷新页面

  2. 错误消失了

如何保存页面刷新错误?

这就是MessageStoreInterceptor的工作方式。它实际上是一个功能,而不是错误。

页面刷新是用户触发的操作,这意味着可以假定他已经阅读了上一个操作(登录尝试)的结果,除非他闭着眼睛按F5键。

您应该希望消息在第一次读取后过期。

考虑具有很多非ajax操作的页面,例如,组合框取决于其他操作,等等。…如果错误消息持续存在,则它将在每次不涉及进入另一个页面的提交操作之后弹出。

你不要那样 您应该希望收到一条消息,指出在
操作之后一个操作出了错(或正确)。如果用户随后继续执行其他操作(如刷新),并且这些操作没有出错(或处于特定的成功状态),则不会显示任何消息。

在那之后,也有不少世界问题 时,
从会话持久性消息删除,否则你会与下一个动作得到该消息RETRIEVEAUTOMATIC一个operationMode。然后,您可以(但不应该)自定义MessageStore拦截器,或自行在会话之间写入/读取/删除消息,从而从根本上重新发明轮子。甚至放置两个MessageStore拦截器,一个RETRIEVE和一个STORE用于displayLoginPageAction,得到刚才提到的陷阱。

您还使用PRG模式(发布/重定向/获取),以避免刷新页面时重新发送数据。同样,您应该避免重复读取相同的消息两次。

要查看它是如何工作的,可以看一下MessageStore
Interceptor源代码
,它很简单:

  • 在调用之前,如果Action是 ValidationAwareand operationModeRETRIEVEor AUTOMATIC

    1. 阅读 actionMessagesactionErrorsfieldErrors从会议;
    2. 合并 与当前行动的他们actionMessagesactionErrorsfieldErrors
    3. 除去 actionMessagesactionErrorsfieldErrors从会议。

    /*
    * Handle the retrieving of field errors / action messages / field errors, which is
    * done before action invocation, and the operationMode is ‘RETRIEVE’.
    * * @param invocation
    * @throws Exception
    /
    protected void before(ActionInvocation invocation) throws Exception {
    String reqOperationMode = getRequestOperationMode(invocation);

    if (RETRIEVE_MODE.equalsIgnoreCase(reqOperationMode) ||
            RETRIEVE_MODE.equalsIgnoreCase(operationMode) ||
            AUTOMATIC_MODE.equalsIgnoreCase(operationMode)) {
    
        Object action = invocation.getAction();
        if (action instanceof ValidationAware) {
            // retrieve error / message from session
            Map session = (Map) invocation.getInvocationContext().get(ActionContext.SESSION);
    
            if (session == null) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Session is not open, no errors / messages could be retrieve for action ["+action+"]");
                }
                return;
            }
    
            ValidationAware validationAwareAction = (ValidationAware) action;
    
            if (LOG.isDebugEnabled()) {
                LOG.debug("retrieve error / message from session to populate into action ["+action+"]");
            }
    
            Collection actionErrors = (Collection) session.get(actionErrorsSessionKey);
            Collection actionMessages = (Collection) session.get(actionMessagesSessionKey);
            Map fieldErrors = (Map) session.get(fieldErrorsSessionKey);
    
            if (actionErrors != null && actionErrors.size() > 0) {
                Collection mergedActionErrors = mergeCollection(validationAwareAction.getActionErrors(), actionErrors);
                validationAwareAction.setActionErrors(mergedActionErrors);
            }
    
            if (actionMessages != null && actionMessages.size() > 0) {
                Collection mergedActionMessages = mergeCollection(validationAwareAction.getActionMessages(), actionMessages);
                validationAwareAction.setActionMessages(mergedActionMessages);
            }
    
            if (fieldErrors != null && fieldErrors.size() > 0) {
                Map mergedFieldErrors = mergeMap(validationAwareAction.getFieldErrors(), fieldErrors);
                validationAwareAction.setFieldErrors(mergedFieldErrors);
            }
            session.remove(actionErrorsSessionKey);
            session.remove(actionMessagesSessionKey);
            session.remove(fieldErrorsSessionKey);
        }
    }
    

    }

  • 调用后,如果Action是 ValidationAwareand operationModeSTOREor(或operationModeis是AUTOMATICResult的类型redirectAction):

    1. 阅读 actionMessagesactionErrorsfieldErrors从行动;
    2. 存储 actionMessagesactionErrorsfieldErrors在会话中。

    /*
    * Handle the storing of field errors / action messages / field errors, which is
    * done after action invocation, and the operationMode is in ‘STORE’.
    * * @param invocation
    * @param result
    * @throws Exception
    /
    protected void after(ActionInvocation invocation, String result) throws Exception {

    String reqOperationMode = getRequestOperationMode(invocation);
    boolean isRedirect = invocation.getResult() instanceof ServletRedirectResult;
    if (STORE_MODE.equalsIgnoreCase(reqOperationMode) ||
            STORE_MODE.equalsIgnoreCase(operationMode) ||
            (AUTOMATIC_MODE.equalsIgnoreCase(operationMode) && isRedirect)) {
    
        Object action = invocation.getAction();
        if (action instanceof ValidationAware) {
            // store error / messages into session
            Map session = (Map) invocation.getInvocationContext().get(ActionContext.SESSION);
    
            if (session == null) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Could not store action ["+action+"] error/messages into session, because session hasn't been opened yet.");
                }
                return;
            }
    
            if (LOG.isDebugEnabled()) {
                LOG.debug("store action ["+action+"] error/messages into session ");
            }
    
            ValidationAware validationAwareAction = (ValidationAware) action;
            session.put(actionErrorsSessionKey, validationAwareAction.getActionErrors());
            session.put(actionMessagesSessionKey, validationAwareAction.getActionMessages());
            session.put(fieldErrorsSessionKey, validationAwareAction.getFieldErrors());
        }
        else if(LOG.isDebugEnabled()) {
        LOG.debug("Action ["+action+"] is not ValidationAware, no message / error that are storeable");
        }
    }
    

    }

注1 :登录操作也是不言自明的:如果登录后再次进入登录页面,则仅表示登录失败…顺便说一句,以上说明适用于每个页面/功能
注2 :网站产生的消息会在X秒钟后自动过期,而不关心用户是否已阅读这些消息…… 与可用性恕我直言。

2020-06-08