Since Struts 2.1, the framework provides the Convention Plugin that allows developers writing action classes and wiring them with result views without any configuration (no struts.xml required). Indeed, this can be done by following some standard naming conventions and defaults specified by the Convention Plugin.
In this article, we’d like to show you how to implement a simple Struts application using naming conventions instead of XML or annotations configuration.
Table of contents:
First, let’s take a look at the Convention plugin.
This plugin enables zero-configuration for Struts application by enforcing the standard naming conventions. It comes with Struts distribution since version 2.1 and replaces the old CodebehindPlugin and Zero Config plugins. To use this plugin, simply put its jar file under WEB-INF\lib directory of your web application:
struts2-convention-plugin-VERSION.jar
Or if you are using Maven, put the following entry in the pom.xml file:
<dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-convention-plugin</artifactId> <version>VERSION</version> </dependency>
Now let’s explore some primary conventions.
For example, the following classes will be found by the Convention plugin:
Classes | Reasons |
net.codejava.struts.HelloWorldAction | Package name has “struts” and class name ends with “Action”. |
net.codejava.actions.LoginAction | Package name has “actions” and class name ends with “Action”. |
net.codejava.struts2.services.FileDownload | Package name has “struts2” and class implements the com.opensymphony.xwork2.Action interface. |
Action Classes | URLs |
net.codejava.struts.HelloWorldAction | /hello-world |
net.codejava.actions.LoginAction | /login |
net.codejava.struts2.services.FileDownload | /services/file-download |
The default location where the plugin looks for JSP pages corresponding to result codes returned from the action’s execute() method is WEB-INF/content directory. The following table shows how the plugin searches for the JSP pages based on the result codes:
URLs | Result codes | Matching JSP pages |
/hello-world | success | /WEB-INF/content/hello-world.jsp |
/hello-world | success | /WEB-INF/content/hello-world-success.jsp |
/login | success | /WEB-INF/content/login.jsp |
/login | error | /WEB-INF/content/login-error.jsp |
/login | input | /WEB-INF/content/login-input.jsp |
/services/file-download | success | /WEB-INF/content/services/file-download.jsp |
/services/file-download | error | /WEB-INF/content/services/file-download-error.jsp |
NOTE:
Now let’s dive into a complete sample Struts application which applies the above conventions. The sample application shows a form that allows users entering two numbers X and Y. When the users submit the form, an action is called to calculate division of the two numbers and return result. If the dividing number is zero, an error page is returned.
Create an Eclipse project with the following structure:
Here is source code of the input.jsp file under WEB-INF/content directory:
<%@ taglib prefix="s" uri="/struts-tags" %> <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Input Form</title> </head> <body> <center> <h2>Calculate Division of X/Y</h2> <s:form action="calculate" method="post"> <s:textfield name="x" label="Enter X" /> <s:textfield name="y" label="Enter Y" /> <s:submit /> </s:form> </center> </body> </html>
The form contains two text fields and it will call the action /calculate when submitted.
Source code of the CalculateAction.java under the package net.codejava.struts:
package net.codejava.struts; import com.opensymphony.xwork2.ActionSupport; public class CalculateAction extends ActionSupport { private int x; private int y; private float division; public String execute() { // calculates division if (y == 0) { return ERROR; } division = x / y; return SUCCESS; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public float getDivision() { return division; } public void setDivision(float division) { this.division = division; } }
The action class declares two variables x, y and division with corresponding getters and setters. Its execute() method returns ERROR code if y equals to zero, otherwise returns SUCCESS code. That means we should create two JSP pages corresponding to these two result codes.
Source code of the calculate-success.jsp (for SUCCESS result code) under WEB-INF/content directory:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Division Result</title> </head> <body> <h3> Result of ${x} / ${y} is ${division} </h3> </body> </html>
And source code of the calculate-error.jsp (for ERROR result code) under WEB-INF/content directory:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Division Error</title> </head> <body> <h3> Cannot divide by zero! </h3> </body> </html>
Enable Struts' dispatcher filter in the web.xml as follows:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>Struts2ZeroConfig</display-name> <filter> <filter-name>struts2</filter-name> <filter-class> org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter </filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
Add the following jar files into WEB-INF\lib directory (including the Convention Plugin’s jar file):
These jar files come from Struts download page.
Now let’s test the application we have built. Deploy it on Tomcat and type the following URL into browsers’ address bar:
http://localhost:8080/Struts2ZeroConfig/input
The input form is displayed. Enter two numbers as follows:
Then hit Submit, the result page is displayed:
If we enter 0 for Y, the error page is displayed:
Wow! The application is working perfectly, as we can notice: there is no configuration at all (except the configuration of Struts framework in the web.xml file). So using standard naming conventions would be an alternative way to XML configuration as it helps reducing the amount of code to write.