consider this:
- user clicks on a link
- request goes to DisplayLoginAction
- Login.jsp is displayed
- user enters his credentials
- form is mapped to ValidateLoginAction
- validation fails in ValidateLoginAction
- ValidateLoginAction stores the errors and returns "input"
- redirecting to DisplayLoginAction..
- DisplayLoginAction retrieves the errors from the interceptor and shows them to the user above the login form
- user refreshes the page
- The errors are gone
How should I save the errors on page refresh?
<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>
That is the way MessageStoreInterceptor works. It is actually a feature, not a bug.
Page refresh is an action triggered by the user, that means it can be assumed he has already read the result of the previous operation (the login attempt), unless he is pressing F5 with the eyes closed.
You should WANT a message to expire after the first read.
Consider a page with a lot of non-ajax operations, like combobox depending on others, etc... If the error message is persistent, it would popup after each submit operation that does not involve going to another page.
You don't want that. You should want to get the message saying that one operation has gone wrong (or right) just after that operation. If the user then proceed with other operations, like a refresh, if those operations aren't going in error (or in a specific success state), no message should be shown.
After that, there's also the problem of when deleting from session a persistent message, because otherwise you would get that message in the next action with a
RETRIEVE
orAUTOMATIC
operationMode. Then you could (but shouldn't) customize the MessageStore Interceptor, or writing / reading / deleting messages from and to the session on your own, basically reinventing the wheel. Or even put two MessageStore Interceptors, oneRETRIEVE
and oneSTORE
fordisplayLoginPage
Action, getting the pitfalls just mentioned.You are also using the PRG pattern (Post/Redirect/Get), to avoid re-sending the data when refreshing the page. At the same way, you should avoid re-reading the same messages twice.
To see how this specifically works, you can take a look at the MessageStore Interceptor source code, that is quite simple:
ValidationAware
andoperationMode
isRETRIEVE
orAUTOMATIC
:actionMessages
,actionErrors
,fieldErrors
from session;actionMessages
,actionErrors
,fieldErrors
;actionMessages
,actionErrors
,fieldErrors
from session.ValidationAware
andoperationMode
isSTORE
or (operationMode
isAUTOMATIC
and Result is of typeredirectAction
):actionMessages
,actionErrors
,fieldErrors
from action;actionMessages
,actionErrors
,fieldErrors
in the session.Note 1: The login operation is also self-explanatory: if after logging in you land on the login page again, it can only mean that the login failed... BTW the above explanation applies to every page/functionality
Note 2: There are sites producing messages that expire automatically after X seconds, not caring about the user having read them or not... and that is against the usability, IMHO.