jsp - 使用消息存储拦截器的Struts2 验证

  显示原文与译文双语对照的内容
0 0

设想一下:

  1. 用户单击链接
  2. 请求转到 DisplayLoginAction
  3. 显示 Login.jsp
  4. 用户输入凭据
  5. 窗体映射到 ValidateLoginAction
  6. 验证在ValidateLoginAction中失败
  7. ValidateLoginAction存储错误并返回"输入""
  8. 转到 DisplayLoginAction 。
  9. DisplayLoginAction从截取程序检索错误并将它们显示给登录表单上方的用户
  10. 用户刷新页面
  11. 错误消失了

我应该如何保存页面刷新中的错误?


<action name="displayLoginPage" class="DisplayLoginAction">
 <interceptor-ref name="store">
 <param name="operationMode">RETRIEVE</param>
 </interceptor-ref> 
 <interceptor-ref name="customStack"/> 
 <result name="success">Login.jsp</result>
 <result name="input">Login.jsp</result> 
</action> 

<action name="validateloginForm" class="ValidateLoginAction">
 <interceptor-ref name="store">
 <param name="operationMode">STORE</param>
 </interceptor-ref>
 <interceptor-ref name="customStack"/> 
 <result name="input" type="redirectAction">displayLoginPage</result>
 <result name="success">LoginConfirmation.jsp</result>
</action>

时间: 原作者:

0 0
  1. 用户刷新页面

  2. 错误消失了

我应该如何保存页面刷新中的错误?

这就是 MessageStoreInterceptor的工作方式。 它实际上是一个特性,而不是一个 Bug 。

页刷新是由用户触发的操作,这意味着它已经读取了前一个操作( 登录尝试)的结果。

你应该希望邮件在第一次读取后过期。

考虑一个带有很多非ajax操作的页面,比如组合框依赖于其他的,等等 。 如果错误消息是持久的,在每次提交操作不涉及到另一个页面之后,它将弹出。

,你不希望收到消息说一个操作出错了,那就是在运行。 如果用户继续执行其他操作,如刷新,如果这些操作不出现错误( 或者以特定的成功状态),则不应显示消息。

之后,当你从会话中删除持久消息时,也存在问题,否则你就会在下一个动作中得到消息,或者使用 RETRIEVE 或者 AUTOMATIC operationMode 。 然后,你可以自定义( 但是应该',或者自己从会话中自定义MessageStore拦截器,基本上重复轮。 或者甚至将两个MessageStore拦截器。一个 RETRIEVE 和一个 STORE 放在 displayLoginPage 操作中,得到了刚刚提到的陷阱。

你还在使用 PRG Pattern (Post/Redirect/Get),,以避免在刷新页面时发送数据。 同样,你应该避免读同样的消息两次。

要了解具体工作原理,可以查看 MessageStore拦截器源代码,这非常简单:

  • 调用前,如果操作为 ValidationAwareoperationModeRETRIEVE 或者 AUTOMATIC:
    1. 从会话中读取 actionErrorsfieldErrors
    2. 用当前的动作,actionErrorsfieldErrors,将它们合并为
    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);
 }
 }
}

  • 调用后,如果操作为 ValidationAware 并且 operationModeSTORE 或者( operationModeAUTOMATIC,结果的类型为 redirectAction ):
    1. 从动作中读取 actionErrorsfieldErrors
    2. 在会话中存储 actionErrorsfieldErrors

/**
 * 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");
 }
 }
}

英镑笔记: 登录操作也可以自我说明: 如果在登录页面上再次登录,它只能表示登录失败。"。 上说明适用于每个页面/功能
注意:在X 秒后,有些网站会自动生成过期的信息,而不关心用户是否已经阅读。 这违背了可用性。

原作者:
...