Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 4 of 5
Now that you have a cursory understanding of Struts, let's dive in deeper by examining the simple Web application shown in Figure 6.



Figure 6. Use Struts actions
Figure 6's Web application consists of two JSPs: test.jsp, shown in the top picture and forwardPage.jsp, shown in the bottom two pictures. When you click on the link in test.jsp, an HTML anchor element sends an HTTP request to the Struts action servlet. The action servlet maps that request to an application-specific
action that increments a counter stored in a file, and subsequently forwards to forwordPage.jsp. That JSP displays the counter's
value and includes test.jsp so that you can initiate the request/action cycle again if you desire.
To implement Figure 6's Web application, first configure the application in the deployment descriptor, as seen in Example 2:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<web-app>
<!-- Action Servlet Configuration -->
<servlet>
<servlet-name>
action
</servlet-name>
<servlet-class>
org.apache.struts.action.ActionServlet
</servlet-class>
...
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/action.xml</param-value>
</init-param>
...
</servlet>
<!-- Action Servlet Mapping -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
...
</web-app>
The preceding deployment descriptor does three things:
org.apache.struts.action.ActionServlet)
/WEB-INF/action.xml)
Example 3 lists test.jsp, the JSP shown in Figure 6's top picture:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Struts Actions</title>
</head>
<body>
<a href='simple.do'>
Click Here to Perform a Simple Action
</a>
</body>
</html>
The preceding JSP creates an HTML anchor element that references the /simple.do URL. If you click on that link, the Struts action servlet is invoked because the mapping in the deployment descriptor maps
all URLs that end in .do to the action servlet (see Example 2). So what does the action servlet do when it receives the /simple.do URL? The answer resides in the Struts configuration file, which is specified in the deployment descriptor (see Example 2)
and listed in Example 4:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd">
<struts-config>
<action-mappings>
<action path="/simple"
type="actions.SimpleAction">
<forward name="fwd-page" path="/forwardPage.jsp"/>
</action>
</action-mappings>
</struts-config>
The preceding configuration file maps the /simple URL to the actions.SimpleAction class. When the action servlet receives the /simple.do URL, it strips off the .do suffix and maps the URL to the actions.SimpleAction class. If an instance of that class does not exist, the action servlet creates one and invokes its execute() method. Example 5 lists the actions.SimpleAction class:
package actions;
import javax.servlet.ServletContext;
import javax.servlet.http.*;
import org.apache.struts.action.*;
import beans.CounterBean;
public class SimpleAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws java.io.IOException,
javax.servlet.ServletException {
ActionServlet servlet = getServlet();
ServletContext application = servlet.getServletContext();
CounterBean counterBean = (CounterBean)application.
getAttribute("counterBean");
if(counterBean == null) {
counterBean = new CounterBean();
application.setAttribute("counterBean", counterBean);
}
counterBean.updateCount(request, ".simpleActionCount");
return mapping.findForward("fwd-page");
}
}
The preceding action checks to see if a counter bean exists in the application scope; if not, it creates one and stores it
there. Subsequently, the action invokes the counter bean's updateCount() method, which updates a counter stored in a file named .simpleActionCount. Then the action returns an ActionForward instance that points to a JSP mapped to the string fwd-page. That mapping, also defined in the Struts configuration file (see Example 4), resolves the string fwd-page to the forwardPage.jsp JSP. The action servlet subsequently forwards control to that JSP, listed in Example 6:
<%@ taglib uri='/WEB-INF/tlds/struts-bean.tld' prefix='struts'%>
<%@ taglib uri='http://java.sun.com/jstl/core' prefix='c'%>
<%@ page import='beans.CounterBean' %>
This simple action has been accessed
<c:out value='${counterBean.count}'/>
<c:choose>
<c:when test='${counterBean.count == 1}'>
time.
</c:when>
<c:otherwise>
times.
</c:otherwise>
</c:choose>
<p><c:import url='test.jsp'/>
The preceding JSP uses the JSTL <c:out>, <c:choose>, <c:when>, and <c:otherwise> actions to display information about how many times the counter bean, and therefore the simple action, has been accessed.
JSTL defines an expression language that will be incorporated into the upcoming JSP 2.0. The preceding JSP, for example, uses
that expression language to access the counter bean in application scope. (You can download JSTL from Resources.)
Finally, Example 7 lists the counter bean class—beans.CounterBean:
package beans;
import java.io.*;
import javax.servlet.http.*;
public class CounterBean {
private int count = 0;
private File file = null;
public synchronized void updateCount(HttpServletRequest request,
String filename)
throws java.io.IOException {
checkFile(filename);
readCount();
count++;
saveCount();
}
public int getCount() {
return count;
}
private void checkFile(String filename) throws IOException {
if(file == null) {
file = new File(filename);
count = 0;
}
if(!file.exists()) {
file.createNewFile();
saveCount();
}
}
private void saveCount() throws java.io.IOException {
FileWriter writer = new FileWriter(file);
writer.write(count);
writer.close();
}
private void readCount() throws java.io.IOException {
FileReader reader = new FileReader(file);
count = reader.read();
reader.close();
}
}
The CounterBean class updates the count associated with a particular action. That class serves as a receiver, as I discussed at this article's
beginning, by implementing application-specific behavior.