3. Form Processing by the Controller
We will now focus on how the controller processes the form values when the user clicks the [Submit] button on the form.
3.1. The struts-config.xml file
The new struts-config.xml configuration file for the Struts controller looks like this:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<form-beans>
<form-bean
name="frmPersonne"
type="istia.st.struts.person.FormBean"
/>
</form-beans>
<action-mappings>
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/errors.do"
parameter="/views/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
<action
path="/errors"
parameter="/views/errors.person.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
<action
path="/response"
parameter="/views/response.person.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
<action
path="/form"
parameter="/views/person-form.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
</action-mappings>
<message-resources parameter="resources.personresources"/>
</struts-config>
We have highlighted the changes:
- a <form-beans> section appears. It is used to define the classes associated with each of the application's forms. There must be as many <form-bean> tags as there are different forms in the application. Here, we have only one form, so there is only one <form-bean> section. For each form, we must define:
- its name (name attribute)
- the name of the class derived from ActionForm responsible for storing the form’s values (type attribute)
These two attributes cannot be arbitrary. They must match those used in the <html:form> tag in the form’s HTML code. Recall the code for the (name, age) form:
The form must be declared in the same way in the struts-config.html file. This is what is done here:
- The configuration of the /main action has changed. This action is responsible for processing the form values. Therefore, we must provide the information it needs about the form:
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/errors.do"
parameter="/views/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
The /main servlet will process a form, which must be given a name. The name attribute handles this. This name must refer to the name attribute of one of the <form-bean> sections, in this case frmPersonne.
The scope="session" attribute indicates that the form values must be stored in the session. This is not always necessary. Here, it is. In fact, in the /reponse.do and /erreurs.do views, we find links that return to the form. In both cases, we want to display the form with the values entered by the user during a previous client-server exchange. Hence the need to store the form in the session.
The validate attribute indicates whether or not the validate method of the frmPersonne object should be called. This method is used to verify the validity of the form data. Here, we specify that the data must be verified, which means we will need to write a validate method in the FormulaireBean class. The form’s validate method is called by the Struts controller before the /main servlet is invoked. It returns an ActionErrors object, which is analogous to an error list. If this list exists and is not empty, the Struts controller will stop there and send the view specified by the input attribute as the response. The view will receive the ActionErrors list in the request, which it can display using the <html:errors> tag. Above, we specify that in case of errors, the /main servlet must send the /errors.do view. Recall that this view is associated with the following URL: /views/errors.response.jsp:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html>
<head>
<title>Person</title>
</head>
<body>
<h2>The following errors occurred</h2>
<html:errors/>
<html:link page="/form.do">
Back to form
</html:link>
</body>
</html>
The view correctly uses the <html:errors> tag, which will display the list of errors. In this error list, you will find not error messages but message identifiers present in the file referenced by the <message-resources> tag (note: resources with a single "s"):
The tag below indicates that the file containing the messages used by the application is located in the file WEB-INF/classes/ressources/personneressources.properties:

What is in this file? It is a properties file corresponding to the Java Properties class, i.e., a set of key=value lines:
errors.header=<ul>
errors.footer=</ul>
person.form.name.empty=<li>You must enter a name</li>
person.form.age.incorrect=<li>The age [{0}] is incorrect</li>
This message file has at least two functions:
- it allows you to change the application's messages without having to recompile it
- it enables the internationalization of Struts applications. You can create multiple resource files, one per language. Struts will automatically use the correct message file provided certain naming conventions are followed.
- If the form’s validate method returns an empty error list, then the Struts controller calls the execute method of the ForwardAction servlet. It is important to understand here that when the servlet’s execute method runs, it means the form data has been deemed valid (provided, of course, that it was validated via validate="true"). It is within the execute method of the servlet associated with the action that the developer actually processes the form. This is where the core of the processing takes place (application logic, use of business classes and data access classes). Ultimately, the method returns an ActionForward object that tells the renderer which view to send back to the client. Here we have used Struts’ predefined ForwardAction action. Its execute method simply returns an ActionForward pointing to the URL specified by the parameter attribute:
<action
path="/main"
name="frmPersonne"
validate="true"
input="/errors.do"
parameter="/views/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
So, if the form data is valid, the /main action will return the /vues/main.html view that we have already used.
3.2. The new FormBean class
We have already created an initial version of the FormBean class responsible for storing the data (name, age) from the formulaire.personne.jsp form. This version did not validate the data. Now, we must do so since we specified in the struts-config.xml file that the form data must be validated (validate="true") before being passed to the ForwardAction servlet. The class code becomes as follows:
package istia.st.struts.personne;
import javax.servlet.http.*;
import org.apache.struts.action.*;
public class FormBean
extends ActionForm {
// name
private String name = null;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// age
private String age = null;
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
// validation
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
// error handling
ActionErrors errors = new ActionErrors();
// the name must not be empty
if (name == null || name.trim().equals("")) {
errors.add("emptyName", new ActionError("person.form.name.empty"));
// age must be a positive integer
}
if (age == null || age.trim().equals("")) {
errors.add("ageisempty", new ActionError("person.form.age.empty"));
}
else {
// age must be a positive integer
if (!age.matches("^\\s*\\d+\\s*$")) {
errors.add("ageincorrect", new ActionError("person.form.age.incorrect", age));
// return the list of errors
}
} //if
// return the list of errors
return errors;
}
}
The new feature lies in the implementation of the validate method. This method is called by the Struts controller after it has populated the name and age attributes of the class with the values from the form fields of the same name. It must verify the validity of the name and age attributes. The code above is fairly straightforward:
- an empty error list (ActionErrors errors) is created
- the name field is checked. If it is empty, an error is added to the errors list using the ActionErrors.add("key", ActionError) method.
- The same is done if the age field is not an integer.
- the validate method returns the error list (ActionErrors errors) to the Struts controller. If errors is null or if errors.size() is 0, the controller considers that there were no errors. It will then execute the execute method of the Action class associated with the action (type="org.apache.struts.actions.ForwardAction"). Otherwise, it will return the view associated with form errors (input="/errors.do").
An error is added to the ActionErrors list using ActionErrors.add("errorKey", new ActionError("messageKey"[,param0, param1, param2, param3])). The first parameter, "errorKey", is used to uniquely identify an ActionError element in the ActionErrors list, much like in a dictionary. It can be any string. ActionError is an object associated with an error message using its constructor ActionError(String errorKey[,String param0, String param1, String param2, String param3]), where errorKey is the identifier of the message associated with the error and up to 4 optional parameters. The keyMessage identifier is not arbitrary. It is one of the identifiers found in the file specified by the <message-resources> tag in the struts-config.xml file:
Note that this file (actually WEB-INF/classes/resources/personneressources.properties) contains the following keys:
errors.header=<ul>
errors.footer=</ul>
person.form.name.empty=<li>You must enter a name</li>
person.form.age.incorrect=<li>The age [{0}] is incorrect</li>
We can verify that the message keys used by the validate method of the FormBean class do indeed exist in the file above. We used the HTML tag <li> for each error message so that the <html:errors> tag displays them as an HTML list. We have seen that the ActionError object can be constructed not only with a message key but also with additional parameters:
If an ActionError has been constructed with additional parameters (up to a maximum of four), these are accessible in the message text via the notation {0} to {3}. Thus, the validate method of FormulaireBean constructs an ActionError with the key personne.formulaire.age.incorrect and the additional parameter param0 age:
The message associated with the key **person.form.age.incorrect** in the .properties file is
The {0} will be replaced by the age value. Finally, the messages with the keys errors.header and errors.footer will be written before and after the list of errors, respectively. Here, these two keys will be used to include the HTML tags <ul> and </ul>, which must surround the <li> tags.
3.3. Form validation tests
We are ready to test the form's validity. Below is a reminder of where the various components of the application should be placed:
![]() | |
![]() | |
![]() | |
![]() |
3.3.1. Test 1
Restart Tomcat so that it reads the new configuration files, then enter the URL http://localhost:8080/strutspersonne/formulaire.do:

Explanations:
- In struts-config.html, the following section was used:
<action
path="/form"
parameter="/vues/formulaire.personne.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
If we view the HTML code of the received page, we see that the <form> tag on the page is as follows:
The [Submit] button, which is of type submit, will therefore send the form data to the URL /strutspersonne/main.do.
3.3.2. Test 2
Let’s use the [Submit] button while leaving the input fields blank. We get the following response:

Explanations:
- As indicated above, the form data was sent to the URL /strutspersonne/main.do. The following sections of the struts-config.xml file were then used:
<form-bean
name="frmPersonne"
type="istia.st.struts.personne.FormulaireBean"
scope="session"
/>
....
<action
path="/main"
name="frmPersonne"
validate="true"
input="/errors.do"
parameter="/views/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
The /main action has been triggered. It uses the frmPersonne form (name="frmPersonne"). The Struts controller has therefore instantiated, if necessary, an object of the FormulaireBean class (type="istia.st.struts.personne.FormulaireBean" in the form-bean tag). It has populated the name and age attributes of this object with the fields of the same name in the HTML form:
<table>
<tr>
<td>Name</td>
<td><html:text property="nom" size="20"/></td>
</tr>
<tr>
<td>Age</td>
<td><html:text property="age" size="3"/></td>
</tr>
<tr>
</table>
Once this is done, the Struts controller calls the validate method of the FormBean object because the validate attribute of the /main action is set to true in the configuration file:
<action
path="/main"
name="frmPersonne"
validate="true"
input="/errors.do"
parameter="/views/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
The validate method of the FormBean class is as follows:
// validation
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
// error handling
ActionErrors errors = new ActionErrors();
// the name must not be empty
if (name == null || name.trim().equals("")) {
errors.add("emptyName", new ActionError("person.form.name.empty"));
// age must be a positive integer
}
if (age == null || age.trim().equals("")) {
errors.add("ageempty", new ActionError("person.form.age.empty"));
}
else {
// age must be a positive integer
if (!age.matches("^\\s*\\d+\\s*$")) {
errors.add("ageincorrect", new ActionError("person.form.age.incorrect", age));
// return the list of errors
}
} //if
// return the list of errors
return errors;
}
Since the [name] and [age] fields were empty, the validate method above generated a list of two errors, which it returned to the Struts controller. Because there were errors, the controller then returned the view associated with the input attribute to the client. To determine which view this was, it used the following section of its configuration file:
<action
path="/errors"
parameter="/views/errors.person.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
It therefore ultimately sent the view /views/errors.person.jsp. This view contains the following code:
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html>
<head>
<title>Person</title>
</head>
<body>
<h2>The following errors occurred</h2>
<html:errors/>
<html:link page="/form.do">
Back to form
</html:link>
</body>
</html>
The <html:errors> tag simply displays the list of messages sent to it by the Struts controller. It uses the message file specified by the <message-resources> tag:
It contains the following keys and messages:
person.form.name.empty=<li>You must enter a name</li>
person.form.age.empty=<li>You must specify an age</li>
person.form.age.incorrect=<li>The age [{0}] is incorrect</li>
errors.header=<ul>
errors.footer=</ul>
- The message associated with the errors.header key is written
- the messages associated with the various keys in the received ActionErrors list are written
- the message associated with the errors.footer key is written
3.3.3. Test 3
Let's use the [Back to form] link on the error page. We get the following page:

Explanations:
- The [Back to form] link has the following HTML code:
The Struts controller used the following section from its configuration file:
<action
path="/form"
parameter="/views/form.person.jsp"
type="org.apache.struts.actions.ForwardAction"
/>
It therefore returned the view /views/form.person.jsp.
3.3.4. Test 4
We fill out the following form and then click the [Submit] button:

We get the following response:

Explanations: These are the same as for Test 2.
3.3.5. Test 5
We click the [Back to Form] link above. We see the following page:

We see that the form is in the same state as when we submitted it.
Explanations: These are the same as for Test #3, with additional information:
- The displayed HTML form has the following tags:
<table>
<tr>
<td>Name</td>
<td><html:text property="name" size="20"/></td>
</tr>
<tr>
<td>Age</td>
<td><html:text property="age" size="3"/></td>
</tr>
<tr>
</table>
The <html:text> tags have two functions:
- When sending form values from the client to the server, the values of the form's input fields are assigned to the fields of the same name in the FormBean object
- when the server sends the HTML code for the form to be displayed back to the client, the value attributes of the input fields associated with the <html:text> tags are initialized with the values of the fields with the same name in the FormBean object.
Here we have two different client-server interactions:
- In the first, the user filled out the form and submitted it to the server
- in the second, the user clicked the [Back to Form] link to return to the form.
The only way for the form to be re-displayed with its original values in the second interaction is for those values to be stored in the client’s session. This is what was specified in the section configuring the /main action:
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/errors.do"
parameter="/views/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
If we had set scope="request", the form data would not have been stored in the session, and we would not have been able to retrieve its values in the second exchange.
3.3.6. Test 6
Let’s go back to the form and enter valid data this time:

Submit the form. We get the following result:

Explanations:
- Since the [Submit] button sends the form values to the URL /strutspersonne/main.do, the same explanations apply as in Test 2 until the Struts controller receives the ActionErrors result from the validate method of FormBean. But here, this list is empty. The controller then uses a new part of the /main action configuration:
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/errors.do"
parameter="/views/main.html"
type="org.apache.struts.actions.ForwardAction"
/>
The Struts controller creates, if necessary, an object of the type specified by the type attribute. The execute method of this class is executed and must return an ActionForward object indicating the view that the controller must send as a response to the client. Here, the type attribute refers to the predefined ForwardAction class. The execute method of this class does nothing and simply returns an ActionForward object pointing to the view defined by the parameter attribute, in this case the /vues/main.html view. This is indeed the view that the controller returned.
3.3.7. Test 7
We request the /form.do view again:

We see the form exactly as we submitted it. The explanation has already been given. By configuration (scope="session"), we specified that the form should remain in the session. Its values are therefore preserved throughout client-server exchanges.
We’re almost done. We still need to create a proper action for when the form data is valid. For now, we’ve used the predefined ForwardAction to simplify our demonstration.
3.4. New configuration for the /main action
We are not changing the current struts-config.xml configuration file, except to modify its /main section as follows:
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/errors.do"
type="istia.st.struts.personne.FormAction"
>
<forward name="response" path="/response.do"/>
</action>
The type attribute now refers to another class called FormAction, which we will need to implement. It is the execute method of this class that will be called if the data in the frmPersonne form is valid. We have specified that the execute method performs its task and returns an ActionForward object indicating the view that the controller should send back to the client. There are often several possible views depending on the result of the form processing. The list of possible views is specified within the <forward> tags included in the <action> tag. The syntax for such a tag is as follows:
any name that uniquely identifies a view | |
URL of the view associated with the key |
3.5. The FormAction class
Writing the FormAction class essentially consists of writing its execute method:
package istia.st.struts.personne;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import javax.servlet.ServletException;
public class FormAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// we have a valid form; otherwise, we wouldn't have gotten this far
FormBean form = (FormBean) form;
request.setAttribute("name", form.getName());
request.setAttribute("age", form.getAge());
return mapping.findForward("response");
}//execute
}
The execute method takes four parameters:
- ActionMapping mapping: an "image" object representing the configuration of the currently executing action; in this case, an image of the following configuration:
<action
path="/main"
name="frmPersonne"
validate="true"
input="/errors.do"
type="istia.st.struts.personne.FormAction"
>
<forward name="response" path="/response.do"/>
</action>
Thus, the action has access to the keys associated with the views that can be returned to the client at the end of the action. The execute method must return one of these keys.
- ActionForm form: the bean object containing the form values used by the current action. Here, it is the frmPersonne object of type FormBean. Thus, the action has access to the form values.
- HttpServletRequest request: the client request, which may have been enriched by various servlets. The action thus has access to all parameters of the initial request (request.getParameter) as well as all attributes added to that initial request (request.getAttribute). In our example, the execute method enriches the request by adding the name and age. This is completely unnecessary here since these two values are already present, but as parameters rather than attributes. The code is included here for illustrative purposes.
- HttpServletResponse response: the response that will be sent to the client. The action could enrich this response. Here, it does not.
Here, we are dealing with a special case. The execute method has almost nothing to do. It simply needs to indicate that the next view is /reponse.do and specify in the request that this view will receive the name and age information it needs to display. It does this using the findForward method of the ActionMapping class, which takes as a parameter one of the keys found in the forward tags of the action’s configuration. Here, there is only one such tag:
Our method therefore returns an ActionForward with "response" as the key to indicate that the /response.do view should be sent.
3.6. FormAction Tests
We compile the previous class with JBuilder and place the generated .class file in WEB-INF/classes:

We modify the view /vues/reponse.personne.jsp:
<%
// retrieve the name and age data
String name = (String) request.getAttribute("name");
String age = (String) request.getAttribute("age");
%>
<html>
<head>
<title>Person</title>
</head>
<body>
<h2>Person - response</h2>
<hr>
<table>
<tr>
<td>Name</td>
<td><%= name %>
</tr>
<tr>
<td>Age</td>
<td><%= age %>
</tr>
</table>
<html:link page="/form.do">
Back to form
</html:link>
</body>
</html>
The view retrieves the name and age information from the request attributes it receives. We request the form at the URL http://localhost:8080/strutspersonne/formulaire.do and then fill it out:

We click the [Submit] button and receive the following response:

Explanations:
- We will refer to the explanation given for Test #2 for the beginning of the process. Let’s review the configuration of the /main action:
<action
path="/main"
name="frmPersonne"
scope="session"
validate="true"
input="/errors.do"
type="istia.st.struts.personne.FormAction"
>
<forward name="response" path="/response.do"/>
</action>
- After the form was submitted to the controller at the URL /main.do, the controller created or reused a frmPersonne object of type FormBean and populated it with the form values
- The validate method of the frmPersonne object was called. Since the data was valid, the validate method returned an empty ActionErrors list.
- A FormAction object was created or recycled, and its execute method was called. This method returned an ActionForward object with the key "reponse".
- The controller then sent the view associated with the "reponse" key, i.e., /reponse.do, and thus /vues/reponse.personne.jsp.
- The view reponse.personne.jsp was displayed with the values set in the request by the execute method of the FormAction object.
3.7. Conclusion
We have built a comprehensive yet simple application. When actually implementing it with Struts, Tomcat, and JBuilder, there are many opportunities to make mistakes, particularly in the application’s XML configuration files. At first glance, it may seem simpler to build this application without Struts, using a servlet and JSP pages. For beginners, this is probably true. With experience, however, it becomes easier to develop with Struts. Many companies mandate the Struts methodology for their web development for the following reasons:
- Struts adheres to the MVC model
- When all developers work in the same way, application maintenance becomes easier because they have a standard architecture.



