Thursday, May 5, 2011

Struts 2 and Annotations

Googling around i saw there wasnt any concise article explaining how to integrate Struts 2 with annotations. I will keep this as simple as possible because,well the struts developers have done some awesome work to make it as simple as they can. I will create a sample maven project showing you how to integrate struts 2.

Ok first off lets go ahead and create our maven project.Im going with a maven project because its just easier to create a war and dependencies required for struts as well. So below is my project root pom;

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">



 <modelVersion>4.0.0</modelVersion>

 <groupId>com.myexamples</groupId>

 <artifactId>my-struts-sample</artifactId>

 <packaging>war</packaging>

 <version>1.0-SNAPSHOT</version>

 <name>My Struts Example</name>

 <dependencies>



  





  <dependency>

   <groupId>javax</groupId>

   <artifactId>javaee-api</artifactId>

   <version>6.0</version>

   <scope>provided</scope>

  </dependency>





  



  <dependency>

   <groupId>commons-collections</groupId>

   <artifactId>commons-collections</artifactId>

   <version>3.2.1</version>

  </dependency>



  <dependency>

   <groupId>commons-logging</groupId>

   <artifactId>commons-logging</artifactId>

   <version>1.1.1</version>

  </dependency>



  <dependency>

   <groupId>commons-configuration</groupId>

   <artifactId>commons-configuration</artifactId>

   <version>1.6</version>

  </dependency>



  <dependency>

   <groupId>commons-lang</groupId>

   <artifactId>commons-lang</artifactId>

   <version>2.5</version>

  </dependency>









  <dependency>

   <groupId>org.slf4j</groupId>

   <artifactId>slf4j-log4j12</artifactId>

   <version>1.5.2</version>

   <scope>provided</scope>

  </dependency>

  <dependency>

   <groupId>log4j</groupId>

   <artifactId>log4j</artifactId>

   <version>1.2.16</version>

   <scope>provided</scope>

  </dependency>



  

  <dependency>

   <groupId>junit</groupId>

   <artifactId>junit</artifactId>

   <version>4.8.1</version>

   <scope>test</scope>

  </dependency>

  







  <dependency>

   <groupId>com.sun</groupId>

   <artifactId>tools</artifactId>

   <version>1.4.2</version>

   <scope>system</scope>

   <systemPath>${java.home}/../lib/tools.jar

   </systemPath>

  </dependency>



  <dependency>

   <groupId>org.apache.struts</groupId>

   <artifactId>struts2-core</artifactId>

   <version>2.0.6</version>

  </dependency>





  



  

  <!-- standard.jar -->

  <dependency>

   <groupId>taglibs</groupId>

   <artifactId>standard</artifactId>

   <version>1.1.2</version>

  </dependency>



  <!-- JSTL -->

  <dependency>

   <groupId>javax.servlet</groupId>

   <artifactId>jstl</artifactId>

   <version>1.1.2</version>

  </dependency>

  

 



 </dependencies>



 <build>

  <plugins>

   <plugin>

    <groupId>org.apache.maven.plugins</groupId>

    <artifactId>maven-war-plugin</artifactId>

    <version>2.0</version>

    <configuration>



     <archive>

      <manifest>

       <addClasspath>true</addClasspath>

       <classpathPrefix>lib/</classpathPrefix>

      </manifest>

     </archive>

     <webResources>

      <resource>

       <!-- this is relative to the pom.xml directory -->

       <directory>${project.basedir}/resources

       </directory>



      </resource>

     </webResources>

     <outputDirectory>${env.JBOSS_HOME}/server/default/deploy</outputDirectory>

     <warName>my-struts-sample</warName>

    </configuration>

   </plugin>

  </plugins>

 </build>



</project>


The structure of the project will be as follows;

    my-struts-sample
            |
            |
            --------->pom.xml
            |
            |
            ----->resources
            |        |
            |        |
            |        ----->js
            |
            ----->src
                   |
                   |
                   ------->main
                             |
                             |
                             ----->webapp
                                     |
                                     |
                                     ------->index.html
                                     |
                                     |
                                     ------->WEB-INF
                                                |
                                                |
                                                ------>web.xml
                                                |
                                                |
                                                ------>jsp
                                                        |
                                                        |
                                                        ------>test
                                                                |
                                                                |
                                                                ---->test.html

That is the normal structure of any maven project. This will create the war file and deploy it within your jboss as i have mentioned to get it from JBOSS_HOME in my pom.xml. You can change it as you need depending on your server.

Afterwards lets create our first action class given below;

package com.test..myexample;
import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.config.Result;
import org.apache.struts2.config.Results;
import org.apache.struts2.interceptor.ServletRequestAware;

@Results({
    @Result(name="success", value="/public/showTest")
})

public class ShowTestAction implements ServletRequestAware{
 
 private HttpServletRequest request;
 
 public void setServletRequest(HttpServletRequest request) {
  this.request = request;
 }
 
 public String  execute(){
  return "success";
 }
}


This is a simple action class. Few things to note here. Always your Action class name should end with the name Action, else it wont get recognized as an action class during package scan phase which i will explain later. For now i am only returning success. You can add more Results as you deem appropriate to handle error situations and others. I have injected the HttpServletRequest instance here as well because almost always you will require this to read your parameters or attributes. Now that you have your action class lets see how we can map out our web.xml and configure struts 2.



<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

 


 <filter>
  <filter-name>struts2</filter-name>
  <filter-class>
   org.apache.struts2.dispatcher.FilterDispatcher
  </filter-class>
  <init-param>
   <param-name>actionPackages</param-name>
   <param-value>
      com.test..myexample
          </param-value>
  </init-param>
 </filter>

 

 <filter-mapping>
  <filter-name>struts2</filter-name>
  <url-pattern>*.action</url-pattern>
 </filter-mapping>

 <servlet>
  <servlet-name>mytest</servlet-name>
  <jsp-file>/WEB-INF/jsp/test/test.html</jsp-file>
 </servlet>

 <servlet-mapping>
  <servlet-name>mytest</servlet-name>
  <url-pattern>/public/showTest</url-pattern>
 </servlet-mapping>

</web-app>

There are a few things to note here. One is that we have defined a filter called struts 2. Within that we have specified an attribute called actionPackages. This is the place where we define the package name in which our action classes reside in. If you have many packages then you can have comma separated package names specified within the param-value attribute.

Next we have specified a filter-mapping attribute. This says that all urls ending with .action should go through the org.apache.struts2.dispatcher.FilterDispatcher which in turn will search in all packages defined to see which action should be called. Hope that is clear to you guys. The rest is just normal servlet mapping which all of you should be familiar with.

Now i will show you the index.html which just does a simple redirect calling our action class which in turn will display our test.html according the success mapping name defined within the action class.


<html>
<head>My Home Page</head>
<body>


<script type="text/javascript">
location.replace('showTest.action');
</script>
</body>
</html>

Here we are saying to redirect to showTest.action. Note that your action name was ShowTestAction. But when you call it you should always make sure the name starts with a simple letter and ends with .action or else it would not be recognized by the struts Filter Dispatcher.

Thats about it guys. I did not give the implementation of the test.html because that can be anything you want. Please feel free to leave a comment if you have any doubts or clarification regarding the tutorial provided. mvn clean install and your good to go with struts 2 with annotations :)

Cheers guys