As I understand it, Struts2 action class instances can (unlike Struts1) be stateful, because each GET or POST to an action creates a new instance of the backing action class.
I also see that there's a standard(?) idiom (Pattern?) to provide input forms: the same .jsp is used as the View component of two different actions, like this:
<action name="showForm" class="defaultActionThatDoesNothingExceptReturnSuccess">
<result name="success">inputForm.jsp</result>
</action>
<action name="validateAndProcessForm" class="realAction">
<result name="input">inputForm.jsp</result>
<result name="success">formProcessed.jsp</result>
</action>
The first action just displays the form, without validating the input or processing it. The form in the .jsp posts to the second action:
<s:form action="validateAndProcessForm" method="post">
and that second action validates the posted fields/parameters, returning "input" if the form's inputs are incomplete or invalid, or actually calling the action class's execute
if the inputs are complete and valid, thus processing the form and returning the (e.g.) formProcessed.jsp
that displays something like "thanks for your input!".
So we have this sort of "picket fence" idiom:
defaultAction- -> realAction-
| | | |
-> input.jsp- <--- -> success.jsp
This is done so that the first time input.jsp
is displayed, validations aren't called (and so validation errors are not shown), but that after the submit button on that jsp is clicked, the "real" action will validate the input, possibly passing back errors calling out invalid input which the input.jsp
will display.
Which brings us back to stateful, non-singleton actions; because the action is stateful and thus not shared across GETs or POSTs, and each instance is instantiated just for that GET or POST, the action has no way to know if a particular session has "GETted" the same page multiple times. So GETting showForm.action
will never validate, and GETing validateAndProcessForm
will always validate (and show errors if the parameters are invalid), even if that GET is the first time a particular session has "GETted" that URL.
Which is why we need the "fence post": the first action just to display the form, the second to capture the input.
Is my understanding correct? Is there a less verbose way to do this, to not validate input on the initial GET, but to validate on the POST, without having to have two actions for every form?
When the user presses the submit button, Struts 2 will automatically execute the validate method and if any of the “if” statements listed inside the method are true, Struts 2 will call its addFieldError method. If any errors have been added, then Struts 2 will not proceed to call the execute method.
Interceptor is an object that is invoked at the preprocessing and postprocessing of a request. In Struts 2, interceptor is used to perform operations such as validation, exception handling, internationalization, displaying intermediate result etc.
Timer. This simple interceptor merely records the duration of an execution.
There is another way to perform what you want without the picket fence. The validation interceptor, by default, does not fire for the input method. You can therefore update your struts.xml to the following:
<action name="*MyForm" method="{1}" class="realAction">
<result name="input">inputForm.jsp</result>
<result name="success">formProcessed.jsp</result>
</action>
With this setup, you do not need the empty action at all. When you first go to the form, you would go to the url "inputMyForm", and have your form action just point to "MyForm". The {1} in the method block just means that the framework will call whatever method matches the * from the action name. If the * match is empty, it defaults to the execute method. So you get the following kinds of actions:
Since the validator interceptor excludes any actions going to the input method, you can set up whatever validation you want for this action, and it will only look for it when you submit the form. Since every time you submit the form, it is going to the execute method, the validation will occur every time you submit the form.
Also, if you are extending the ActionSupport class, that class already defines the input() method, so you would not even need to change your action class to accomplish this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With