Most of JEE’s MVC frameworks nowadays, requires a bit of learning on their XML configurations. Some might get frustrated when seeing those long list of XMLs in a project. But for me, XML configuration is easier to maintain and learn if you know where to look. Now, Struts2 has taken the next step, and their goal is zero configuration. There are not actually there yet, but they have done tremendous job on reducing XML configs. But if you are a fan of XML like me, you can still stick to XML configs.
Struts2 took advantage of Annotation to move those configurations from XML to Action class itself. The only XML you need to set is your ol’ trusty web.xml. You need to set the heart of Struts2 component which is the FilterDispatcher like below.
<?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/web-app_2_4.xsd">
<display-name>Dhydrated's Fortune Teller Web</display-name>
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.FilterDispatcher
</filter-class>
<!-- Scanning for annotation packages -->
<init-param>
<param-name>actionPackages</param-name>
<param-value>org.dhydrated</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
There is nothing special about above settings but just note that within FilterDispatcher element, I’m declaring actionPackages with org.dhydrated value. Struts2 will scan through this java packages for Action classes.
Below is my first Action class called Index.java.
package org.dhydrated.sample;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.config.Result;
/**
* @author Dhydrated
*/
@Result( value="/pages/VisitorForm.jsp" )
public class Index extends ActionSupport{
}
Above will be the first Action class to be hit when entering the application. From the index.jsp, I will just redirect by calling response.sendRedirect(“sample/index.action”);. Index action class will do nothing except redirecting to the VisitorForm.jsp. Below is my VisitorForm.jsp code.
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Dhydrated's Fortune Teller</title>
</head>
<body>
<h4>Although I'm a fortune teller, please state your name</h4>
<s:form action="fortuneTeller">
<s:textfield name="name" label="Your name"/>
<s:submit/>
</s:form>
</body>
</html>
Below is the page being rendered.
On this page, I’m just trying to capture the user name and bind it to name property of FortuneTellerAction action class. When I submit this form, FortuneTellerAction action class will be executed. Below is my FortuneTellerAction action class.
package org.dhydrated.sample;
import org.apache.struts2.config.Result;
/**
* @author Dhydrated
*/
@Result(name="SUCCESS", value="/pages/FortuneTeller.jsp" )
public class FortuneTellerAction {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFortune(){
return "Howdy, " + name + ". Today's is your lucky day.";
}
public String execute() {
return "SUCCESS";
}
}
By now, above class already captured user’s data into name property. execute method will be called and redirect user to FortuneTeller.jsp page. This is set at the above code as @Result(name=”SUCCESS”, value=”/pages/FortuneTeller.jsp” ). FortuneTeller.jsp code is as below.
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<title>Dhydrated's Fortune Teller</title>
</head>
<body>
<h4><s:property value="fortune"/></h4>
</body>
</html>
Value fortune is referring to the getFortune() method from the FortuneTellerAction action class. The output of the page should be like below.
There are 2 points you should notice here. First, there are 2 ways of naming your Action class when using annotation. The Index action class extends Struts2 ActionSupport class, but the FortuneTellerAction action class does not. So, either you extends from ActionSupport class or end your action class with Action suffix, Struts2 will recognizes it as an Action class.
Second, if you recall, we set org.dhydrated as the annotation packages. My Index action class is under org.dhydrated.sample package. The value after org.dhydrated. will be treated as the URL namespace. So, the URL to call my Index action class is http://<host>:<port>/<servlet-contextpath>/sample/index.action. And of course, there will be .action suffix for every Action class.
Annotation really helps to slam down the number of XML config files. But when the project grew bigger, it could get complicated when you need to browse through all the Action classes to understand your project flow. For me, XML is still the best way to put all your Action declarations and project flows. Usually, XML files is group within a same folder so that it is easy to find. Some IDEs have great visual editor that works with XML to simplify the process in building the configs.