2. A First Example
Most of our examples will be limited to the web layer implemented with Struts 2:
![]() |
Once the basics are covered, we will examine a more complex example with a multi-layer architecture.
2.1. Generating the example
We’re building our first application.
![]() |
- In [1], we create a new project
- In [2], select the Java Web / Web Application type
- In [3], name the project
- In [4], specify the project location.
- In [5], we make the new project the main project.
![]() |
- In [6], select the Tomcat server. When NetBeans 7.01 was installed, two servers were installed: Apache Tomcat and GlassFish 3.1.
- In [7], specify that you will be working with the Struts 2 framework. This option is available because the Struts 2 plugin has been installed. Without the plugin, the Struts 2 framework is not offered.
- In [8], we request the creation of the sample project we will be studying.
- In [9], you can verify which Struts 2 libraries will be used.
![]() |
- In [10], the generated project. We will return to this later.
- In [11], the project libraries. They were integrated by the Struts 2 plugin. If you do not have the plugin, you can find these libraries in the [lib] folder of the downloaded Struts 2 distribution. You will then follow steps 12 and 13.
2.2. The generated project in the file system
![]() |
- In [1], the [Projects] tab displays a "developer" view of the project
- In [2], the [Files] tab displays the project folder in the file system
- In [2A], the [Web Pages] branch is represented in [2] by the [web] folder [2B]
- In [3A], the [Source Packages] branch is represented in [2] by the [java] folder [3B]
2.3. The configuration file [META-INF/context.xml]
![]() |
This file is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/example-01"/>
Line 2 indicates that the web application context is /example-01. All URLs of the type [http://machine:port/exemple-01/...] will be handled by this application. This context can be found in the project properties [2]: right-click on the project / Properties / Run.
2.4. The configuration file [WEB-INF/web.xml]
![]() |
Every web application is configured by the [web.xml] file in the application’s [WEB-INF] folder. The one that was generated is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>example/HelloWorld.jsp</welcome-file>
</welcome-file-list>
</web-app>
- Lines 3–6 define a filter implemented by the Struts 2 class [org.apache.struts2.dispatcher.FilterDispatcher]. This class acts as the Controller (C) in the MVC model.
- Lines 7–10: define a mapping between a URL pattern and the filter that must handle URLs matching that pattern. Here, it is specified that any URL (pattern /*) must be handled by the filter named struts2. This is the filter defined in lines 3–6. Therefore, all URLs will pass through the Struts 2 controller.
- Lines 11–15: define the duration of a user session, here set to 30 minutes. During various requests, a user is tracked by a session token assigned to them upon their first request, which they then systematically send with each new request. This allows the web server to recognize the user and manage a "memory" for them, known as the session. If more than 30 minutes elapse between two requests, a new session token is generated for the user, who thereby loses their "memory" and starts a new one.
- Lines 16–18: define the file to display when the user accesses the web application without requesting a document. Thus, when the requested URL is [http://machine:port/exemple-01], the served URL will be [http://machine:port/exemple-01/example/HelloWord.jsp].
2.5. The [struts.xml] configuration file
![]() |
The [struts.xml] file is the Struts 2 configuration file. It can be located anywhere in the project’s ClassPath. In the NetBeans project above, the project’s ClassPath consists of two branches:
- Source Packages
- Libraries
Any folder or library located in these two branches is therefore part of the project's ClassPath. It is common practice to place [struts.xml] in the <default package>. Here, its content is as follows:
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<include file="example.xml"/>
<!-- Configuration for the default package. -->
<package name="default" extends="struts-default">
</package>
</struts>
- Lines 5 and 10: The root tag of the document is the <struts> tag
- line 6: the [example.xml] file is inserted here. It therefore brings its own configuration. We will come back to this later.
- Lines 8–9: define a package named "default" here. A package allows you to configure a group of Struts 2 actions that share the same URL. For example, [/path/Action1] and [/path/Action2]. You can then define a package for these actions:
<package name="employees" namespace="/employees" extends="struts-default">
... configuration
</package>
The package above is called "employees" and configures actions with the URL /employees/Action. A package can inherit from another package using the "extends" keyword. In the example above, the "employees" package inherits from the "struts-default" package. This package is located in the [struts-default.xml] file within the struts2-core.jar library:
![]() |
The "struts-default" package defined in the [struts-default.xml] file configures various elements, including a list of interceptors executed when an action is called. Let’s return to the MVC structure of a Struts 2 application:
![]() |
To process a URL of the form [http://machine:port/.../Action], the [FilterDispatcher] controller will instantiate the class that implements the requested action and execute one of its methods—by default, a method called execute. The call to this execute method will pass through a series of interceptors:
![]() |
The interceptors and the action all process the same request. The list of interceptors defined in the struts-default package is sufficient most of the time. Therefore, our Struts packages will always extend the struts-default package. To learn what the various interceptors do, refer to Chapter 4 of [ref2].
Let’s return to the struts.xml configuration file:
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<include file="example.xml"/>
<!-- Configuration for the default package. -->
<package name="default" extends="struts-default">
</package>
</struts>
- Line 8: The package named "default" has a special role. It handles actions that have not been configured in the other packages. Here, in lines 8–9, no configuration is specified for the "default" package. We could therefore remove the definition of this package.
Now let’s look at the [example.xml] file included on line 6 of the [struts.xml] file:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="HelloWorld" class="example.HelloWorld">
<result>/example/HelloWorld.jsp</result>
</action>
</package>
</struts>
- Line 8: defines a package named example that extends the struts-default package. This package handles URLs of the type /example/Action (namespace /example).
- lines 9–11: define an action named HelloWorld (name attribute) that corresponds to the URL /example/HelloWorld. This action is handled by an instance of the example.HelloWorld class (class attribute).
- The [FilterDispatcher] controller will execute the execute method of this class.
- This method will return a string called the navigation key.
- The various navigation keys must be defined using <result name="key"/> tags (line 10). If the name attribute is omitted, the success key is used by default. This is the case above. Therefore, the execute method of the example.HelloWorld class must return the success key to the [FilterDispatcher] controller.
- The [FilterDispatcher] controller then displays the page [/example/HelloWorld.jsp] (line 10).
If we merge the two files [struts.xml] and [example.xml] and remove the default package, which seems unnecessary, it’s as if we had reduced the [struts.xml] file to just the [example.xml] file.
2.6. The HelloWorld Action
![]() |
According to the [struts.xml] file we examined, the HelloWorld action is triggered when the URL requested by the client is /example/HelloWorld. Its execute method is then executed. It must return a navigation key. We saw that there was only one: success, and that the page /example/HelloWorld.jsp was sent in response to the user.
The code for the HelloWorld action is as follows:
package example;
import com.opensymphony.xwork2.ActionSupport;
public class HelloWorld extends ActionSupport {
public String execute() throws Exception {
setMessage(getText(MESSAGE));
return SUCCESS;
}
public static final String MESSAGE = "HelloWorld.message";
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
- Line 5: The HelloWorld class extends the Struts 2 ActionSupport class. This is almost always the case. This allows us to use certain methods, such as the getText method on line 8.
- Lines 7–10: The `execute` method, which is executed when the Struts controller is invoked. We know it must return a string, hence its signature on line 7. Here, it returns the `SUCCESS` constant, which is also defined in `ActionSupport`. Other constants are defined in the same way for the result of the `execute` method:
SUCCESS | "success" |
ERROR | "error" |
INPUT | "input" |
LOGIN | "login" |
So here, the execute method returns the string "success". Referring to the [struts.xml] file, this means that the page /example/HelloWorld.jsp will be returned to the user.
- Line 8: The execute method initializes the message field on line 14 with the value of getText("HelloWorld.message"). The getText method belongs to the parent class ActionSupport. It retrieves text from a file based on the language being used. By default, the package.properties file located in the same package as the action will be used here. This file comes in two versions:
The [package.properties] file is as follows:
It consists of a series of text lines in the key=value format. If this file is used, getText("HelloWorld.message") will return the value Struts is up and running ...
The [package_es.properties] file is as follows:
If the language used by the client browser is Spanish (the "es" attribute in package_es.properties), getText("HelloWorld.message") will return the value ¡Struts está bien! ... In all other cases, the [package.properties] file will be used.
2.7. The HelloWorld.jsp view
![]() |
This is the final piece of the Struts puzzle. It is the view that is displayed when the URL /example/HelloWorld is requested. We have seen the path the initial request took to finally display this response. The page code is as follows:
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title><s:text name="HelloWorld.message"/></title>
</head>
<body>
<h2><s:property value="message"/></h2>
<h3>Languages</h3>
<ul>
<li>
<s:url id="url" action="HelloWorld">
<s:param name="request_locale">en</s:param>
</s:url>
<s:a href="%{url}">English</s:a>
</li>
<li>
<s:url id="url" action="HelloWorld">
<s:param name="request_locale">es</s:param>
</s:url>
<s:a href="%{url}">Spanish</s:a>
</li>
</ul>
</body>
</html>
- The page uses HTML tags (lines 5, 6, ...) and tags from a library defined on line 3. All <s:xx> tags belong to this library.
- Line 7: The <s:text> tag allows you to display different text depending on the client browser’s language. The name attribute specifies the key to look for in the message files. Here, too, the package_xx.properties files will be used. Recall that they contain only a single message with the key HelloWorld.message.
- Line 11: The <s:property name="property"> tag is used to write the value of a property of an object called ActionContext. This object contains:
- the properties of the action that was executed. name="message" will display the value of the message field of the current action. The get and set methods associated with the field are used to retrieve its value or initialize it. These methods must therefore exist.
- the attributes of the current request denoted as <s:property name="#request['key']">
- the attributes of the user's session, denoted as <s:property name="#session['key']">
- attributes of the application itself, denoted as <s:property name="#application['key']">
- parameters sent by the client browser, denoted as <s:property name="#parameters['key']">
- The notation <s:property name="#attr['key']"> displays the value of an object searched for in the page, request, session, and application, in that order.
- Lines 16–18: The <s:url> tag is used to define a URL. The id attribute gives a name to the URL that will be created. This name is then used on line 19. The action attribute specifies which action the URL should point to.
- Line 17: The <s:param ..> tag allows you to add parameters to the URL in the form ?param1=value1¶m2=value2&... Here, the parameter added will be ?request_locale=es.
Ultimately, the generated URL will be as follows:
To understand this URL, remember that the [HelloWorld.jsp] page is displayed in two cases:
- upon direct request of the URL [/example-01/example/HelloWorld.jsp]
- when the action [/example-01/example/HelloWorld.action] is requested
In both cases, the URL path is /example-01/example. The <s:url action= "... "> tag appends the action defined by the action attribute to this path. This results in /example-01/example/HelloWorld. It then appends the .action suffix to the previous URL, along with any URL parameters if present. The resulting URL /example-01/example/HelloWorld.action?request_locale=en will call the HelloWorld action defined in the [struts.xml] file while passing the parameter request_locale=en. This parameter will not be processed by the HelloWorld action but by one of Struts’ interceptors, specifically the one that handles page internationalization. The request_locale parameter will be recognized and processed. The page language will change to English (en).
- Line 19: defines an HTML link. The href attribute of the <a> tag expects a string. Here, we want to use the value of the URL defined on line 16 with the id "url". To do this, we write href="%{url}". The url variable is evaluated, and its value is assigned to the href attribute. In most cases, variable evaluation is implicit. For example, when we write
<s:property name="message"/>
the value of the message property is displayed, not the string "message". But in other cases, you must force the evaluation of variables or properties. If we had written href="url", the string "url" would have been assigned to the href attribute.
- Lines 23–27: create an HTML link to change the page language to Spanish.
2.8. Running the application
We launch the project:
![]() |
- In [1], we run the [example-01] project. The Tomcat web server is then automatically started if it wasn’t already. The URL [/example-01] is requested [3]. The [web.xml] file is then used:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>example/HelloWorld.jsp</welcome-file>
</welcome-file-list>
</web-app>
- Because the requested URL [/example-01] does not specify a page, Tomcat will use the <welcome_file-list> tag on lines 16 and 18. Therefore, the URL /example-01/example/HelloWorld.jsp will be served.
- Because Struts 2 processes all URLs (lines 8 and 9), this URL will be filtered by Struts. Since it does not correspond to an action but to a JSP page, the latter will be displayed.
- What we see in [2] is therefore the HelloWorld.jsp page we studied.
- In [4], we see that the tag <title><s:text name="HelloWorld.message"/></title> did not take effect, nor did the tag <h2><s:property value="message"/></h2>. The reason is that no action was called. The list of interceptors that run before the action was therefore not executed, notably the one that handles internationalization. The internationalization tag <s:text ...> could not be processed correctly. Furthermore, the message property, which references the message field of the Action1 class, does not exist. Hence the lack of display.
Now, let’s follow the [English] link. We get the following page:
![]() |
- in [1], the requested URL. We have explained how this URL is formed. This time, a Struts action is requested: the HelloWorld action defined in [example.xml].
<struts>
<package name="example" namespace="/example" extends="struts-default">
<action name="HelloWorld" class="example.HelloWorld">
<result>/example/HelloWorld.jsp</result>
</action>
</package>
</struts>
- The execute method of this action has been executed. We saw that it returned the key "success." From line 4 above, we can deduce that the page /example/HelloWorld.jsp is returned to the client. This is what we see in [3].
- In [1], we see that the requested URL is set by the parameter `request_locale=en`. The language of the pages will now be English. In fact, this language choice is stored in the user’s session, which will retain this choice until the user changes it.
- In [2] and [3], we see internationalization in action. The tags <title><s:text name="HelloWorld.message"/></title> and <h2><s:property value="message"/></h2> have taken effect this time.
If we now select the [Espanol] link, we get the page in Spanish:
![]() |
2.9. Conclusion
We have examined an example automatically generated by the Struts 2 plugin for NetBeans. We found that it was quite difficult to follow the processing of a request. The following elements are involved:
- the configuration [web.xml], [struts.xml]
- the executed action: interceptors and the execute method.
At first, the mechanics of Struts 2 may seem complex. It takes a little time to get used to it. We will now present a series of examples, each illustrating a specific aspect of Struts.















