WanTii, Inc. Tech Blog

Discussion of Java on the Web Server…

Getting Started with Struts2 (Part 1)

July 1st, 2007 by Wes Wannemacher

To start a Struts2-based project, it is as easy as downloading the appropriate WAR file from the Struts website (http://struts.apache.org) and importing it into the chosen development environment. The choice of developer platform is strictly a matter of preference. Personally, I enjoy using Eclipse Webtools combined with the Websphere AppServer Community Edition. Eclipse Webtools has a nifty ‘Import WAR’ utility that will setup the Struts2 template WAR files rather nicely.

Struts2 is a vast and encompassing framework which includes many different technologies and languages (Freemarker, JavaScript, Java, CSS, HTML, OGNL, and XML to name a few) so it is hard to pick any one point to start because there are dependencies that may seem circular and it almost seems to require an inherent knowledge just to start. Therefore, it may be best to dive right in and briefly skim some of the important details just so that we can start covering topics one by one. The following section will move fast and may seem confusing, but these topics will receive much more expanded coverage in later entries. The point here is to get a glimpse of what will come.

The most basic of the Struts2 example applications is called struts2-blank-2.x.y.war. This WAR file contains the basic requirements to use Struts2 without any plug-ins. Here is a listing of the important files and directories contained in the GA release of struts2-blank as of the writing of this article:

example
example/HelloWorld.jsp
example/Login.jsp
example/Menu.jsp
example/Missing.jsp
example/Register.jsp
example/Welcome.jsp
index.html
WEB-INF
WEB-INF/classes
WEB-INF/classes/example
WEB-INF/classes/example/ExampleSupport.class
WEB-INF/classes/example/HelloWorld.class
WEB-INF/classes/example/Login-validation.xml
WEB-INF/classes/example/Login.class
WEB-INF/classes/example/package.properties
WEB-INF/classes/example/package_es.properties
WEB-INF/classes/example.xml
WEB-INF/classes/LICENSE.txt
WEB-INF/classes/NOTICE.txt
WEB-INF/classes/struts.xml
WEB-INF/lib
WEB-INF/lib/commons-logging-1.1.jar
WEB-INF/lib/freemarker-2.3.8.jar
WEB-INF/lib/ognl-2.6.11.jar
WEB-INF/lib/struts2-core-2.0.6.jar
WEB-INF/lib/xwork-2.0.1.jar
WEB-INF/src
WEB-INF/src/java
WEB-INF/src/java/example
WEB-INF/src/java/example/build.bat
WEB-INF/src/java/example/ExampleSupport.java
WEB-INF/src/java/example/HelloWorld.java
WEB-INF/src/java/example/Login-validation.xml
WEB-INF/src/java/example/Login.java
WEB-INF/src/java/example/package.properties
WEB-INF/src/java/example/package_es.properties
WEB-INF/src/java/example.xml
WEB-INF/src/java/LICENSE.txt
WEB-INF/src/java/NOTICE.txt
WEB-INF/src/java/struts.xml
WEB-INF/web.xml

To make a Struts2-based web application, the first step is configuring the Struts2 servlet filter. Previous versions of Struts were invoked as a Servlet that would pick the appropriate action based on the configuration. The FilterDispatcher filter will be covered in another entry, but for now, it is important to note that the url-pattern is mapped to /*. Servlet filters are configured in the application’s web.xml file. Here are the contents of the struts2-blank web.xml -
web.xml ->

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9"
  version="2.4"
  xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/webapp_2_4.xsd">
    <display-name>Struts Blank</display-name>
    <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>
    <welcome-file-list>
      <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

Within the WEB-INF/lib directory there are five jar files that makeup the basic Struts2 requirements. Each of these jar files has a distinct purpose, commons-logging-1.1.jar allows Struts2 components to log messages in a configurable manner. The Apache commons-logging library provides an abstraction so that developers can write log messages without adding dependencies (such as log4j). The commons-logging library can use other logging frameworks such as log4j, but how commons-logging operates is controlled through run-time configuration. Check the Apache commons-logging web site for more details. freemarker-2.3.8.jar is used within Struts2 to generate the output for the majority of the Struts2 tags. Freemarker is a template language and library that is preferred by many web developers. We will cover Freemarker in another entry when we discuss customizing the Struts2 tags. ognl-2.6.11.jar is also used by Struts2 tags. OGNL stands for Object Graph Notation Language and more information can be found at http://www.ognl.org. OGNL provides a programming language that the Struts2 tags can evaluate when reading attributes. The OGNL is very handy and can easily refer to many of the built-in objects in a JSP. We will cover OGNL and the objects accessible within the tag attributes in another entry as well. struts2-core-2.0.6.jar and xwork-2.0.1.jar contain the core components and resources of the Struts2 framework.

The starting place for understanding the code in struts2-blank is WEB-INF/classes/struts.xml. There are most likely going to be two or more configuration files within your Struts2-based web application. The first or “base” configuration file is called struts-default.xml and will be located in the struts2-core-2.x.jar file. This configuration file although editable, is best left untouched. Often I will refer to it to find out what interceptor stack will be executed by default, or to see which interceptor stacks can be chosen, we will delve a little further into interceptors and interceptor stacks later. After the struts-default.xml is read and parsed, the web application will look for a ’struts.xml’ file in WEB-INF/classes.
The example struts.xml file included with struts2-blank -
struts.xml ->

<?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>
  <constant name="struts.enable.DynamicMethodInvocation" value="false" />
  <constant name="struts.devMode" value="true" />
  <include file="example.xml"/>
  <!-- Add packages here -->
</struts>

Right away, it is clear that there is very little configuration done in this example. The purpose is to demonstrate the ability to break configuration into multiple files. When working with Struts2, I have found it best to set application-wide defaults within struts.xml and then to inherit those defaults in the included xml files. This allows the developer to create sub-web-apps or modules within the larger project. Although JSP and Servlet development is well-organized and lends to good design, managing a large project is often problematic which leads architects to want to break projects into multiple web applications. Although this can be done, individual web applications can not easily communicate with other web applications. Breaking the web application up within Struts2 is easy and allows components to communicate easily and even hide information if necessary. One recent project I worked on contained ’shopping cart,’ ‘registration,’ and ‘check out’ modules that were easily separated in the codebase, but was capable of using a single API for business object interaction and persistence to the database.

The meaningful configuration is set forth in the example.xml file. Here are the contents of example.xml -
example.xml ->

<?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>
    <action name="Login_*" method="{1}" class="example.Login">
      <result name="input">/example/Login.jsp</result>
      <result type="redirect-action">Menu</result>
    </action>
    <action name="*" class="example.ExampleSupport">
      <result>/example/{1}.jsp</result>
    </action>
    <!-- Add actions here -->
  </package>
</struts>

The schema of the included file(s) is identical to the schema the struts.xml and struts-default.xml files. The example.xml file contains a few examples of the helpful features of Struts2. Within the tags there will be one or more tags. A ‘package’ delineates a module within your Struts2-based web-app. The actions defined within a ‘package’ inherit the package’s configuration (which may itself be inherited from the package’s “extends” attribute as is done in example.xml). A package is also assigned a namespace which is appended to the web-app’s context root and prepended to the action. In the example.xml file the action named ‘HelloWorld’ is defined within the example package which is configured with a namespace of “/example.” If the war file is configured in a context called ’struts2-blank,’ then the URL to reach this action would be – http://yourhost/struts2-blank/example/HelloWorld.action. Also present in example.xml are examples of the new “intelligent defaults.” Each action has one or more configured ‘results’ which tell the server how to generate a response. Each result will have a “name” and a “type.” The result’s name matches the String returned from the method executed in the action. The default name is “success.” If you are configuring the “success” result for an action, you can skip the ‘name=’ attribute since “success” is the default. The result’s “type” indicates how the application server should generate the response. By default, the result is dispatched, so the ‘type=’ attribute is only needed when a result needs to be generated by redirecting (such as if you are trying to
implement the redirect-after-post pattern to eliminate browser “Back” button problems). When you combine these defaults with the Wildcard feature, you can easily and quickly configure a basic action such as is done here –

<action name="*" class="example.ExampleSupport">
  <result>/example/{1}.jsp</result>
</action>

This is the ‘catch-all’ action in the “example” package. By specifying a * as the action name, but using a backreference in the result, when a request comes in that does not match any other configured actions, the response should be dispatched to a JSP matching the request if such a JSP exists. For instance, following the example previously, if a request comes in to – http://yourhost/struts2-blank/example/Foo.action , the filesystem will be searched for a file called /example/Foo.jsp and the result of executing /example/Foo.jsp will be dispatched as the result.

One question that developers ask when first adopting Struts is whether or not it is necessary to have all requests processed by a Struts action. The answer to this question is most definitely yes. This seems like extra work, but there are a few benefits. One benefit is that for Struts2 tags to work appropriately, the JSP must have the Struts2 filter invoked. There are a few useful Struts2 tags that are helpful to adopt whether the page performs a typical CRUD operation or not. One such tag is the ‘<s:url>’ tag. <s:url> helps create URLs that can be placed in links without hardcoding assumptions like the name of the web-app into your JSP code. An example of using <s:url> -

<s:url id="add2cart" action="AddInvoiceToCart" namespace="/customer/ajax">
<s:param name="invoiceId"><s:property value="invoiceNumber"/></s:param>
</s:url>
<s:a theme="ajax" errorText="unable to add invoice to cart"
     href="%{add2cart}" targets="shopCartDiv" executeScripts="true" >

This particular snippet generates a link which invokes an AJAX request to move an item into the user’s shopping cart. Although the page was not a typical Struts2 view or result, by invoking the JSP via a wildcard-mapped action, I was able to take advantage of OGNL and Struts2 tags to simplify what would otherwise be a complex combination of HTML and JavaScript. Wildcard mappings allow developers to easily leverage the Struts2 framework for their UI code with minimal configuration and Java code.

The next set of files to note in struts2-blank are package.properties and package_es.properties. These files provide an easy route to externalize the Strings in your UI and Struts2 can automatically present the proper translation to the web application’s visitors. package.properties is the default “resource bundle” for the struts2-blank web application, but if the web application is configured to do so, the locale will be pushed into the context so that when resources are retrieved from the bundle, Struts2 will find the resource in the appropriate bundle for the browser’s locale and present the appropriate translation. So, internationalizing a web application is as simple as externalizing your Strings into resource bundles and adding appropriate translations as necessary.

The rest of the files in struts2-blank are code examples. The concepts behind the code examples in struts2-blank will each be covered in subsequent entries. To start building a Struts2-based web application a developer can import the struts2-blank WAR file or create the following directory structure -

WEB-INF/lib/commons-logging-1.1.jar
WEB-INF/lib/freemarker-2.3.8.jar
WEB-INF/lib/ognl-2.6.11.jar
WEB-INF/lib/struts2-core-2.0.6.jar
WEB-INF/lib/xwork-2.0.1.jar
WEB-INF/classes/struts.xml
WEB-INF/classes/your.java.package/package.properties (optional, but suggested)
WEB-INF/web.xml

Another interesting WAR file to look at is the struts2-showcase-2.x.x.war. Many developers will deploy the showcase war file somewhere accessible so that the advanced examples can be viewed quickly. Before moving further, take the time to download the Struts2 WAR files and install them in the development platform that will be used. If the base WAR files do not install appropriately, then further development will not be fruitful. When attempting to deploy and run the Struts2 WAR files, developers can check the struts website or the struts-user mailing list archives if any errors are encountered.



This entry was posted on Sunday, July 1st, 2007 at 11:34 pm and is filed under Java, Struts 2. You can follow any responses to this entry through the RSS 2.0 feed.

Spread the Word

del.icio.us Digg Furl Reddit StumbleUpon Technorati


You can leave a response, or trackback from your own site.



19 responses about “Getting Started with Struts2 (Part 1)”

  1. eusto said:

    Great intro, cleared a few questions for me :)

  2. Elson Bezerra said:

    Directly. After read I start easy my app.

  3. waspdigger said:

    im just seeing the tip of the iceberg hehheehehe. I hope i can make my first struts2 web application.

  4. Fred said:

    Good luck!

    I try find a tutorial … but i find a good article.

    Thanks

  5. Fred said:

    This article is Cool!

  6. Mahesh.A said:

    This is very good article. Explains clearly the basics of struts framework. Very helpful for those who does not know the framework

    Thanks… :-)

  7. simon said:

    great tutorial, Thanks for the good work

  8. Bizancio Spirit said:

    Very good explanation :)

  9. GIRAUDON said:

    Hello! first of all Happy new year 2008 !
    Now the stupid question :
    What if you want to run this tutorial strust2 app with an existins Strust 1 app ..
    How can you set up web.xml to correctly redirect *.do to struts-config.xml and *.action to struts.xml ?
    Is it possible ? Even if they are not in the same subfolder ??

  10. rohit said:

    hey.
    really great article. simple and direct.
    cleared quite a few things for me. now gonna read the second part. hope tht one helps too.
    thanks!!

  11. RuthraMoorthy.P from cbe said:

    In this article describing ths struts2 is very simple for beginners…

  12. Boobalan said:

    Nice but we expect much explore

  13. sl said:

    I tired to run this configuration in IBM Websphere RAD, but i cannot run it. If i install my WAR file AS-IS, it RUN. But if i extract out the contents of the WAR file, to make some code changes, it WebSphere RAD complains of not finding the Action Classes

    Any Ideas??

  14. Praveen said:

    can u please eloborate on URL concept in this perticular posting

  15. talip said:

    great!
    Thank you so much

  16. Ghufran said:

    Very helpful article.

    I have imported the the war file in RAD initially it didn’t work due to the location of Java files those were not compiled. I have moved the Java files to the source folder and it worked perfectly.

  17. Anoop said:

    Really good. Best intro to Struts2 I’ve seen yet.

  18. Prasad K said:

    Very nice article. Important thing is that it is explained Struts 2 in required details without referring Maven’s repository Strut’s examples.
    Thanks for giving essential dependency’s details too.

  19. Nancy Wang said:

    I have two questions:
    1. Should “example.xml” be located in
    /WEB-INF/classes?

    2. Does web.xml include any information about “example.xml”?

    Thanks.

Leave a Reply