This article explains my hardships which trying to get the example work. It is still not fully working solution but a solution which takes you through steps any new guys goes through while trying to configure struts2 using annotation. With introduction of annotation concept in Java5 , many framework’s tried to exploit it very well to make themselves developer friendly. With respect to Web Framework’s Spring MVC is the leader as well as frontrunner in using this. Struts2 has tried to implement the same concepts but for any new developer it be little hard to get it to work as there are not many working articles over the web. I never suggest using any fremawork tags in building UI elements which these framework’s profess ( It would be difficult to reuse/migrate if at all we have migrate in future). I never support people/framework’s who push UI development in hands of developers rather then to designer’s.
Saying this here is example of a sample struts2 application where i have a html named index.jsp which call a Struts2 Action in back-end to get data and presentation is defined in HTML
First of all i’ll define by build structure and dependencies. As i’m planning to use Maven my build structure is default maven build structure here is my pom.xml
<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.linkwithweb.struts2</groupId> <artifactId>Struts2Example</artifactId> <packaging>war</packaging> <version>1.0</version> <name>Struts2Example Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <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> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-json-plugin</artifactId> <version>2.1.8</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>Struts2Example</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.1</version> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>tomcat-maven-plugin</artifactId> <version>1.0</version> <configuration></configuration> </plugin> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>7.1.4.v20100610</version> <configuration> <webApp>${basedir}/target/medihits-admin</webApp> </configuration> </plugin> </plugins> </build> </project>
The struts2-convention-plugin-version jar file is needed if your are using annotations.
Struts2 has made life little simple by avoiding all the Configuration files it needed before this version by providing configuration by annotation if we just see our web.xml , it’s pretty straightforward where we configure Struts2 Filter to route all requests to corresponding actions
<!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 Sample 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>/struts/*</url-pattern> </filter-mapping> </web-app>
If you observer web.xml i’m filtering all requests that are starting with /struts/* using struts filter. This is entry point of struts application. Now let me describe how we define an Action in Struts2
package com.linkwithweb.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; /** *Example : http://localhost:8080/struts/User */ @Namespace("/struts/User") @ResultPath(value="/") public class WelcomeUserAction extends ActionSupport{ private String username; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } // Example URL : http://localhost:8080/struts/User/Welcome @Action(value="Welcome", results={ @Result(name="success",location="pages/welcome_user.jsp") }) public String execute() { return SUCCESS; } }
Looking at above code by now you might have understood how URL are mapped in Struts2.
Now let me describe my effort to add JSON-Plugin. If you have previously observed my pom i have added JSON plugin depdendency
<dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-json-plugin</artifactId> <version>2.1.8</version> </dependency>
Here is some background how struts2 works
The Convention plug-in is the one which does everything in the background. The Convention plug-in does the following things.
- By default the Convention plug-in looks for the action classes inside the following packagesstrut, struts2, action or actions. Here our package name is com.vaannila.action. Any package that matches these names will be considered as the root package for the Convention plug-in.
- The action class should either implement com.opensymphony.xwork2.Action interface or the name of the action class should end with Action. Here we extend our WelcomeUser class from com.opensymphony.xwork2.ActionSupport which inturn implements com.opensymphony.xwork2.Action.
- The Convention plug-in uses the action class name to map the action URL. Here our action class name is WelcomeUser and the URL is welcome-user. The plug-in converts the camel case class name to dashes to get the request URL.
- Now the Convention plug-in knows which Action class to call for a particular request. The next step is to find which result to forward based on the return value of the execute method. By default the Convention plug-in will look for result pages in WEB-INF/contentdirectory.
- Now the Convention plug-in knows where to look for results, but it doesn’t know which file to display inside the content directory. The Convention plug-in finds this with the help of the result code returned by the Action class. If “success” is returned then the Convention plug-in will look for a file name welcome-user-success.jsp or welcome-user.jsp . It need not be a jsp file it can be even a velocity or freemaker files. If the result value is “input” it will look for a file name welcome-user-input.jsp or welcome-user-input.vm or welcome-user-input.ftl.
package com.linkwithweb.ajax.action; import java.util.ArrayList; import java.util.List; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Namespace; import org.apache.struts2.convention.annotation.ParentPackage; import org.apache.struts2.convention.annotation.Result; import com.opensymphony.xwork2.ActionSupport; /** * @author Ashwin Kumar * */ @Namespace("/struts/Ajax") @Result(name = "success", type = "json") @ParentPackage("json-default") public class AjaxAction extends ActionSupport { @Action( value = "grid", results = { @Result(name = "success", type = "json") }) public String execute() { return "success"; } /** * To Directly write to response and skip all Struts process flows use the below 2 methofs */ /* public HttpServletResponse getResponse() { return ServletActionContext.getResponse(); }*/ /** * Rename to execute to override * * @return * @throws Exception *//* public String executeToOverrride() throws Exception { PrintWriter printWriter = null; getResponse().setContentType("text / xml;charset = UTF-8"); getResponse().setHeader("Cache - Control", "no - cache"); StringBuffer sb = new StringBuffer("<movie>"); // let's say you have A Movie object "movie" that needs to be represented as XML try { printWriter = getResponse().getWriter(); sb.append("<director>dir</director>"); sb.append("<language>lang</language>"); sb.append("<year>year</year>"); sb.append("</movie>"); printWriter.print(sb.toString()); } catch (IOException e) { e.printStackTrace(); throw e; } finally { printWriter.close(); printWriter = null; } return NONE; }*/ /** * @return */ public String getPage() { return "1"; } public int getTotal() { return 2; } public String getRecords() { return "13"; } public List<String> getRows() { List<String> arrayList = new ArrayList<String>(); arrayList.add("{'id':'13','cell':['13','2007-10-06','Client 3','1000.00','0.00','1000.00',null]}"); arrayList.add("{'id':'12','cell':['12','2007-10-06','Client 2','700.00','140.00','840.00',null]}"); arrayList.add("{'id':'11','cell':['11','2007-10-06','Client 1','600.00','120.00','720.00',null]}"); arrayList.add("{'id':'10','cell':['10','2007-10-06','Client 2','100.00','20.00','120.00',null]}"); arrayList.add("{'id':'9','cell':['9','2007-10-06','Client 1','200.00','40.00','240.00',null]}"); arrayList.add("{'id':'8','cell':['8','2007-10-06','Client 3','200.00','0.00','200.00',null]}"); arrayList.add("{'id':'7','cell':['7','2007-10-05','Client 2','120.00','12.00','134.00',null]}"); arrayList.add("{'id':'6','cell':['6','2007-10-05','Client 1','50.00','10.00','60.00','']}"); arrayList.add("{'id':'5','cell':['5','2007-10-05','Client 3','100.00','0.00','100.00','no tax at all']}"); arrayList.add("{'id':'4','cell':['4','2007-10-04','Client 3','150.00','0.00','150.00','no tax']}"); return arrayList; } }
{"page":"1","records":"13","rows":["{'id':'13','cell':['13','2007-10-06','Client 3','1000.00','0.00','1000.00',null]}","{'id':'12','cell':['12','2007-10-06','Client 2','700.00','140.00','840.00',null]}","{'id':'11','cell':['11','2007-10-06','Client 1','600.00','120.00','720.00',null]}","{'id':'10','cell':['10','2007-10-06','Client 2','100.00','20.00','120.00',null]}","{'id':'9','cell':['9','2007-10-06','Client 1','200.00','40.00','240.00',null]}","{'id':'8','cell':['8','2007-10-06','Client 3','200.00','0.00','200.00',null]}","{'id':'7','cell':['7','2007-10-05','Client 2','120.00','12.00','134.00',null]}","{'id':'6','cell':['6','2007-10-05','Client 1','50.00','10.00','60.00','']}","{'id':'5','cell':['5','2007-10-05','Client 3','100.00','0.00','100.00','no tax at all']}","{'id':'4','cell':['4','2007-10-04','Client 3','150.00','0.00','150.00','no tax']}"],"total":2}
jQuery("#list9").jqGrid({ url:'response.jsp?time='+new Date().getTime(), datatype: "json", colNames:['Inv No','Date', 'Client', 'Amount','Tax','Total','Notes'], colModel:[ {name:'id',index:'id', width:55}, {name:'invdate',index:'invdate', width:90}, {name:'name',index:'name', width:100}, {name:'amount',index:'amount', width:80, align:"right"}, {name:'tax',index:'tax', width:80, align:"right"}, {name:'total',index:'total', width:80,align:"right"}, {name:'note',index:'note', width:150, sortable:false} ], rowNum:10, rowList:[10,20,30], pager: '#pager9', sortname: 'id', recordpos: 'left', viewrecords: true, sortorder: "desc", multiselect: true, caption: "Multi Select Example" }); jQuery("#list9").jqGrid('navGrid','#pager9',{add:false,del:false,edit:false,position:'right'}); jQuery("#m1").click( function() { var s; s = jQuery("#list9").jqGrid('getGridParam','selarrrow'); alert(s); }); jQuery("#m1s").click( function() { jQuery("#list9").jqGrid('setSelection',"13"); });
Nice Tutorial…… Keep it up Ashwin …..
Hi,
checkout
into this forder :
C:\maj\practices\struts2\
Struts2Example
Please can you show me what to do with this folder Struts2Example to have it as a project in eclipse ?
Thanks
It’s already an eclipse project. You can directly import into eclipse by usin gimport existign projects option in eclipse. Incase you want to regenerate eclipse configuration files
use this command
mvn eclipse:eclipse
hi Aswin its very good tutorial .. Can I have This same pagination using display tag including checkboxes Or SAME THIS TUTORIAL WITH OUT MABEN AND ANNOTATIONS AS I AM NOT AWARE OF THEM hThank you very much for your effort
Getting Ognl:NoConversationPossible Error
I’m Facing some Issue, Can you please Look here, I posted in detail..,
http://stackoverflow.com/questions/21474295/getting-ognlnoconversationpossible-error
Getting Ognl:NoConversationPossible Error
I’m Facing some Issue, Can you please Look here, I posted in detail..,
http://stackoverflow.com/questions/21474295/getting-ognlnoconversationpossible-error
The link for the SVN repo 404’s
Unfortunately i didnt migrate my code from google code.. and google stopped hosting service