Struts 2 Hello World Annotation Example

In this tutorials, it will reuse the previous Strust 2 Hello World (XML version) example, and convert it into annotation version.

Struts 2 Annotation Concept

The Struts 2 annotation is supported by Struts 2 convention plugin, So, you have to understand the magic behind its “Scanning Methodology” and “Naming Converter” mechanism.

1. Scanning Methodology

Many Struts 2 articles or books stated that you can configure the filter’s “init-param” or “struts.convention.action.packages” to tell Struts 2 where to scan the annotated classes. For example,

web.xml

<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.mkyong.common</param-value>
  </init-param>
</filter>

From my testing (Struts2 version 2.1.6 and 2.1.8), this is not true, no matter what you put in the “param-value” or “struts.convention.action.packages“, Struts 2 will just ignore it and scan the specified folders named struts, struts2, action or actions only.

Here’s how the scanning work

  1. Scan the annotated classes which located at the packaged named “struts, struts2, action or actions“.
  2. Next, scan the file which match either of the following criteria :
    • Implemented the com.opensymphony.xwork2.Action interface.
    • Extends the com.opensymphony.xwork2.ActionSupport class.
    • File name ends with Action (e.g UserAction, LoginAction).

See this Struts 2 convention plugin documentation.

2. Naming Converter

Struts 2 convention plugin will convert all the annotated action file name to a specified format.

For example : LoginAction.java

  1. First, remove the “Action” word at the end of the file name, if present.
  2. Second, convert the first letter of the file name to lowercase.

So, After removing the ending and converting the case of the first letter, the LoginAction.action will change to login.action.

The Struts 2 convention plugin’s “scanning methodology” and “naming converter” features are really bring a lot of conveniences and benefits, only if your Struts 2 project is following the naming convention properly; otherwise it will be a total disaster.

Struts 2 Annotation example

It’s time to start the conversion process.

Final project structure

Struts2 hello world annotation

1. Update pom.xml

To use the Struts 2 annotation feature, you need to download the struts2-convention-plugin.jar.
pom.xml

...
    <dependency>
          <groupId>org.apache.struts</groupId>
	  <artifactId>struts2-core</artifactId>
	  <version>2.1.8</version>
    </dependency>
 
    <dependency>
          <groupId>org.apache.struts</groupId>
	  <artifactId>struts2-convention-plugin</artifactId>
	  <version>2.1.8</version>
    </dependency>
...

2. LoginAction

Create a LoginAction extends ActionSupport and do nothing, the ActionSupport default return a “success” string, which will match the @Result and redirect to “pages/login.jsp“.

Annotation version

package com.mkyong.user.action;
 
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.ResultPath;
 
import com.opensymphony.xwork2.ActionSupport;
 
@Namespace("/User")
@ResultPath(value="/")
@Result(name="success",location="pages/login.jsp")
public class LoginAction extends ActionSupport{
 
}

XML equivalent

<package name="user" namespace="/User" extends="struts-default">
	<action name="Login">
		<result>pages/login.jsp</result>
	</action>
</package>

3. WelcomeUserAction

Override the execute() method and specified the @Action and @Result annotation.

Annotation version

package com.mkyong.user.action;
 
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.ResultPath;
 
import com.opensymphony.xwork2.ActionSupport;
 
@Namespace("/User")
@ResultPath(value="/")
public class WelcomeUserAction extends ActionSupport{
 
	private String username;
 
	public String getUsername() {
		return username;
	}
 
	public void setUsername(String username) {
		this.username = username;
	}
 
	@Action(value="Welcome", results={
		@Result(name="success",location="pages/welcome_user.jsp")
	})
	public String execute() {
 
		return SUCCESS;
 
	}
}

XML equivalent

<package name="user" namespace="/User" extends="struts-default">
   <action name="Welcome" class="com.mkyong.user.action.WelcomeUserAction">
	<result name="SUCCESS">pages/welcome_user.jsp</result>
   </action>
</package>
The Struts 2 annotations – @Action, @Result and @Namespace are self-explanatory, you can always compare it with the XML equivalent. The @ResultPath may need a bit explanation, see this @ResultPath example.

4. JSP view pages

Normal JSP view pages to accept a username and password, and redirect to a welcome page once the submit button is clicked.

login.jsp

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head></head>
<body>
<h1>Struts 2 Hello World Annotation Example</h1>
 
<s:form action="Welcome">
	<s:textfield name="username" label="Username"/>
	<s:password name="password" label="Password"/>
	<s:submit/>
</s:form>
 
</body>
</html>

welcome_user.jsp

<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head></head>
<body>
<h1>Struts 2 Hello World Annotation Example</h1>
 
<h2>Hello <s:property value="username"/></h2>
 
</body>
</html>

5. struts.xml

No need to create struts.xml file, all classes are annotated.

6. web.xml

Just create a classic web.xml file and declared the FilterDispatcher filter as normal.

<!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>
  <display-name>Struts 2 Web Application</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>
 
</web-app>

7. Run it

The LoginAction.action is changed to login.action, see “Naming Converter” above.
http://localhost:8080/Struts2Example/User/login.action

Struts 2 annotation login screen

http://localhost:8080/Struts2Example/User/Welcome.action

Struts 2 annotation welcome screen

Reference

  1. Struts 2 convention plugin documentation
  2. Strust 2 Hello World (XML version)
Tags :

About the Author

mkyong
Founder of Mkyong.com and HostingCompass.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

  • Pingback: Blue Coaster33()

  • http://seffcon.com ravi

    Hi Mkyong

    How can I post a dynamic parameter with annotations?
    So in your example given above say I need ID=POSTEDVALUe

    @Namespace(“/User”)
    @ResultPath(value=”/”)
    @Result(name=”success”,location=”pages/login.jsp?id=DYNAMICVALUE”)
    public class LoginAction extends ActionSupport{

    }

  • Andrey

    Dear MKYONG,

    I’m sorry I have lost code snippets from the previous post.
    Below is the correct version.

    b) am I correct that whenever you want to WRITE smth into Action bean, you link jsp and bean via ‘name’ attrubuted of the form tags, like

    And whenever you READ smth out of Action bean on the jsp side you use

    Thank you in advance

  • Andrey

    Dear MKYONG,

    Firstly, I want to thank you for the efforts you put in your really useful site.
    My gratitude is immense.

    Secondly, let me ask two rather basic questions:
    a) when LoginAction is addressed (via url like /login.action) what is actually done behined the curtains? I mean what method probably inherited from ActionSupport gets performed which redirects page flow to login.jsp?

    b) am I correct that whenever you want to WRITE smth into Action bean, you link jsp and bean via ‘name’ attrubuted of the form tags, like

    And whenever you READ smth out of Action bean on the jsp side you use

    Thank you in advance

  • http://no sumi

    if i change the package name it throws NullPointerException .what is solution for it.

  • Chuck

    Hi,

    I was wondering is it possible to eliminate the need of web.xml all together? like in RESTEAsy.

    Thank you,
    Chuck

  • nam

    thanks so much, work great !

  • Fenil

    Thank you for your project. It helped me lot.
    Thank you again.

  • Keith

    Hmmmm,

    I just get the following:

    HTTP Status 404 – There is no Action mapped for namespace /User and action name Welcome

    When going to
    http://localhost/struts2App/User/Welcome.action

  • Jeegar

    Hi ,
    I have done exactly what you mentioned in the above steps but still not able to run the jsp file , please advise me what could be for the same .

    Regards,
    Jeegare

  • Jeegar

    I am not able to run your sample project , it says Cannot find the tag library descriptor for uri=”/struts-tags” %> in login.jsp

  • peterwkc

    Hi, I’m tried to develop an application in struts2 but still fail because of this warning

    WARN [org.apache.struts2.dispatcher.Dispatcher] (http-localhost-127.0.0.1-8080-1) Could not find action or result: No result defined for action com.peter.action.LoginAction and result success
    at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:376) [xwork-core-2.3.4.1.jar:2.3.4.1]

    when i click the submit button

  • Héctor

    Hello,

    First of all, thank you for the tutorial. It really helped me a lot to understand the basic concepts.

    However, I have a question… The url in wich you access at first time is:
    http://localhost:8080/Struts2Example/User/login.action
    I think this URL is not too friendly, it would be great if I could just delete the login.action and let the path / as default.
    How can you configure struts to execute the LoginAction as default each time the user access to the URL:
    http://localhost:8080/Struts2Example/User/

    Thank you in advance.

  • JeremyLee

    we can tell the convention plugin to scan specified package by

    &lt;constant name=&quot;struts.convention.package.locators&quot; value=&quot;myaction&quot; /&gt;

    The property “struts.convention.package.locators” ‘s default value is “action,actions,struts,struts2″, packages whose name end with one of these strings will be scanned for actions.

    I hope this will be helpful to understand where the plugin to scan the actions.

  • Nil

    Thanks! Very helpful content.

  • Alex

    When I put my action classes in a jar and deploy the application then after calling the action it shows following error…

    There is no Action mapped for namespace / and action name Login. – [unknown location]

    Same thing works fine if I put action .class files in WEB-INF/classes folder.

    Could you please help me on this…

    • JeremyLee

      configure your output folder in eclipse.

  • Mayank

    Hi Mkyong,

    Thanks for providing such important tutorial for begginers of struts2.
    I have tried your tutorials after downloading from from given link and add required jars.

    Thats is running fine on weblogic 10, but i am facing one issue when i deloyed that application as exploded way it was running fine but i want ot deploy the same as packahed way (as war file). it fails to find annoted action and gives me errors like no action mapped for give url.

    Please help me out .

    Thanks
    Mayank

  • Pingback: Maven – Convenciones – Estructura de carpetas | Lycka Bonita()

  • yy

    also got the exception “There is no Action mapped for namespace /User and action name”

    then moved the action class to package my.actions, and problem resolved

  • Pingback: Struts 2 Tutorials()

  • akki

    hi…i dont wanna use pom configuration file and want to implement it throungh struts2 annotation only….whn i did it myself i am getting an error as

    HTTP Status 404 – There is no Action mapped for namespace /User and action name login.
    plzz help me out

  • Tapio Niemela

    hey, and thanks for clear tutorial/example..

    Do you happen to know what should URL look like when calling “camel-case” action class. Like MyLoginAction instead of LoginAction. I tried to use URLs myLogin.action and MyLogin.action and either one didn’t work..

  • Cristiano

    Where is the complete pom.xml?
    Should I add library to it? It would be nice to have the list of jarS you are using!

    • http://www.mkyong.com mkyong

      you can download the full project source code with the download link above, the pom.xml is inside the project.

      • PengPang

        to bopa struts padeithial

  • momo

    the package name is actions not package sorry

  • momo

    until now i did’nt successe to do an exemple of annotation, i use eclips 3.4 gynamed an pache tomcat, i have a pcage that his name is package in the src and i have a foldr jsp in web content , where i have may jsp with form and action refer to my action ,
    my classe actio name is WelcomUser implement Action support,mau action name is actionUser.action in the form action, in the web xml i put
    in the web.xml

    actionPackages
    actions

    the jsp file

    ex-annotation

    the javas classe

    package actions;

    import org.apache.struts2.convention.annotation.Action;
    import org.apache.struts2.convention.annotation.Result;
    import org.apache.struts2.convention.annotation.Namespace;

    import com.opensymphony.xwork2.ActionSupport;

    @Result(name=”success”,location=”jsp/welcom-user-success.jsp”)

    public class WelcomUserAction extends ActionSupport {

    /**
    *
    */
    private static final long serialVersionUID = 1L;
    private String userAnot;
    private String message1;

    public String execute(){
    message1=”welcom”+””+userAnot;
    return “SUCCESS”;
    }

    public void setUserAnot(String userAnot){
    this.userAnot=userAnot;

    }
    public String getUserAnot(){

    return userAnot;
    }
    public void setMessage1(String message1){
    this.message1=message1;

    }
    public String getMessage1(){

    return message1;
    }
    }

    but i had alreday a fichier struts.xml
    and it s dont work problem
    There is no Action mapped for namespace / and action name welcomUser. – [unknown location]

    • http://www.mkyong.com mkyong

      zip your project and send it to me, see if i could help.