views:

49

answers:

1

If I have the following struts.xml config:

<action name="input">
   <result>/jsp/input.jsp</result>
</action>

<action name="result">
    <result>/jsp/result.jsp</result>
    <result name="input">/jsp/input.jsp</result>
</action>

And a simple form with only one field:

<s:form action="result">
    <s:textfield name="firstName" label="First Name"/>
    <s:submit/>
</s:form>

When validation fails, let's say that every time I submit the action (result) validates that firstName length is longer than 3. When it fails it will return to the input page, in this case input.jsp but with the field firstName already populated (with the incorrect value I just submitted. How does Struts 2 do this? I wonder because as I understand when I submit the default method is to POST the input data to the action and those request parameters names that match the validation will be validated. In case it fails the validation it will return to the input page (as a response of the POST) with only those request parameters available. So the only think that comes to my mind is that the input field gets populated with those request parameters but for example if I do the following test. Let's say I will simulate that with the following:

http://domain/myApp/input.action?firstName=alfredo The input field firstName won't be populate.

But when the result comes from a validation it will be populated. I wonder if Struts 2 in order to get those values that should be on the request parameters, push the request parameter object (#parameters) and this way it gets populated.

Could someone explain that to me? How does Struts 2 achieve that repopulation?

Thank you.

+1  A: 

I think you are misunderstanding some Struts2 concepts and terms. Why are you calling your actions "input" and "result" ? That's bad practice, and introduce confusion -specially since "input" is the name of a standard Struts2 "result".

Actions should be called according to the action they perform.

The basic pattern is simple. A URL (http request, GET or POST) corresponds to the user (browser, client) asking the server (webapp, with struts2 in top) to perform some action. The action can give several results, each result will return some info (view) (typically a HTML generated via JSP page) to the user.

A simple example. Lets assume I want to add 2 numbers and display the result. (I recycle my answer from here.

URL : http://...../addnumbers.action

Here the name of the action is "addnumbers" - this request will perform the addition (dont get tricked and think it will show also an input form - it will not, for now - it just performs the addition, as its name implies)

A typical implementation. In struts.xml you specify the mapping:

   <action name="addnumbers" class="example.AddNumbersAction">
     <result name="success">/AddNumbersResult.jsp</result> <!-- 'success' can be omitted here -->
   </action>

Your Java action:

   public class AddNumbersAction extends ActionSupport { 
       private int x;
       private int x;
       private int z;
       public String execute() {
           z = x + y; 
           return SUCCESS;
       }
       // getters and setters ommited
   }

And your AddNumbersResult.jsp :

<div>
Result of addition:
<s:property value="x"> + <s:property value="y"> = <s:property value="z">
</div>

You can (you should!) check that typing the url http://.../mywebapp/addnumbers.action?x=10&amp;y=20 works as expected.

Under the scenes, Struts2 (with the default configuration, default stack of interceptors) is creating an instance of AddNumbersAction and calling by reflection the setters corresponding to the http parameters (doing a best effort to make type conversions - from string to integer here). Then the default method of the action ("execute") is called, the result is "success", and the AddNumbersResult.jsp is used to generate the html page ; in this stage, the Action object is in the "value Stack" (sort of scope) so that the tags invoke its getters.

Once you get clear this, there remain two issues: how to display a previous html page for the user to enter the numbers (the "input form"), and how to deal with invalid or incomplete arguments. These issues are related.

There are several (few) approaches. One possiblity: add another action mapping:

   <action name="addnumbersForm"> <!-- no action specified - will use ActionSupport -->
     <result>/AddNumbersInputForm.jsp</result>
   </action>

And your /AddNumbersInputForm.jsp:

<div>
Please type two integer numbers to be added<p>
<s:actionerrors />       <!-- see below -->
<s:form action="addnumbers">
  <s:textfield name="x" label="X value" />
  <s:textfield name="y" label="Y value" />
  <s:submit />
</s:form>
</div>

As we do not specify a Action class, a dummy default will be used (and "success" will be returned). Kind of a "do nothing" action.

Actually, a plain html page would habe been enough here, but using the struts2 tags we attain a "binding" of the input elements with the action fields, and so we can deal with errors and retries. By (mere) convention, an Struts2 action will return "input" (instead of "success") when the arguments are unsufficient or invalid (the idea is that the action is saying "you instructed me to perfom this action X but I was not succesfull, I need that you give me a proper input, please - perhaps you want to retry?"). So, in our case we get this complete struts.xml mapping for the scenario:

   <action name="addnumbersForm"> 
      <result>/AddNumbersInputForm.jsp</result>
   </action>

   <action name="addnumbers" class="example.AddNumbersAction">
     <result name="input">/AddNumbersInputForm.jsp</result>
     <result name="success">/AddNumbersResult.jsp</result>
   </action>

And in our AddNumbersInputForm.jsp we can add a tag to show validation errors (generated by the Struts2 inside, or by our code).

Then, if we press the submit button with invalid arguments Struts will detect this in its parameter intercetor (plus validation if you configure it) and return "input" before calling the execute() method. Then, the AddNumbersInputForm.jsp will be rendered, but now the text inputs will be repopulated with the previous values. From where? From the action, if the field could be set, or from the request itself. This little magic is essential for any user-friendly html input form (and it's essential to understand it).

There are some other ways, but the essential point is to distinguish: the "use case" is just one here (add two numbers), but the actions are (conceptually) two: the first just presents the user with a input form, the second actually does the addition. This concept should be reflected in the name of the actions/urls.

leonbloy
Thank you great answer. I did an example with your code and it worked as expected. If the setter couldn't be set the input field populates from the request but if it could be set and it fails a validation the input field will be repopulated with those field set in the action. However I found there is an exception to this if the value attribute of the input tag is set the input value (in case repopulation) won't be neither from the request parameter nor the action fields. It will be that value you set in that tag.
Alfredo O