Best practices for Struts development
http://www-128.ibm.com/developerworks/web/library/wa-struts/
Best practices for Struts development Optimize the Struts framework in your Web application development
Level: Introductory Palaniyappan Thiagarajan (
[email protected]), Software Engineer, IBM Global Services India Pagadala Suresh (
[email protected]), Software Engineer, IBM Global Services India 16 Jun 2004 Leverage your Web application development using the flexible Struts framework. Here, the authors explore best practices that you can follow to optimize this open source and mature framework. Learn to use standard, yet valuable, Struts components, including ActionForm, Action class, and ActionErrors. Struts: A brief introduction
Struts, an open source framework you can use to build Web applications, is based on the popular Model-View-Controller (MVC2) design paradigm. The framework is built upon standard technologies like Java Servlets, JavaBeans, ResourceBundles, and XML, and it provides flexible and extensible components. Struts implements the Controller layer in the form of ActionServlet and recommends building the View layer using JSP tag libraries. Struts also provides a wrapper around the Model layer through Action classes. Figure 1 illustrates the Struts framework based on the Model-View-Controller design. Figure 1. Struts and MVC
Overview of Struts components
First, we'll explain the Struts components in the context of best practices and the role each one plays in your Web application development. Action
Every Action of your application extends Struts' org.apache.struts.action.Action. These Action classes provide an interface to the application's Model layer, acting as a wrapper around the business logic. Each Action class must provide its case-specific implementation to the perform() method. The perform() method always returns a value of type ActionForward. ActionForm
Every ActionForm of your application extends Struts' org.apache.struts.action.ActionForm. ActionForms are simple JavaBeans that encapsulate and validate request parameters. To validate your request data, your ActionForm's validate() method must give a case-specific implementation. ActionForms serve as a carrier of request data to the Action class. A JSP object combines with a respective ActionForm to form your application's View layer, where almost every form field of the JSP object maps to an attribute of the corresponding ActionForm.
1 of 6
5/17/2006 5:57 AM
Best practices for Struts development
http://www-128.ibm.com/developerworks/web/library/wa-struts/
JSP custom tag libraries
The JSP custom tag libraries are a collection of actions presented as tags. This is a powerful feature of the JSP Specification 1.1; it allows you to separate presentation from other application tiers. The libraries are easy to use and you can read them in XML-like fashion. You can easily maintain the JSP components by minimizing the use of Java scriptlets in them. The JSP tags that Struts provides include HTML, logic, and bean tags. ActionErrors
You use ActionErrors to support exception handling. An ActionError traps and propagates an application exception to the View layer. Each one is a collection of ActionError instances. ActionErrors encapsulate error messages, while the in the Presentation layer renders all error messages in the ActionError collection.
Best Practice 1. Reuse data across multiple ActionForms
Now that you are familiar with the Struts components, we will continue by showing you ways to get the most out of the framework. First, Struts recommends that you associate every JSP object with an ActionForm, which encapsulates data represented in the screen. You access the form data in the JSP object using accessory methods found in ActionForm. Listing 1 shows the conventional use of ActionForm tag in the View layer. Listing 1. Using ActionForm in JSP
property="attrib1" />
The ActionForm called "BP1AForm" includes the attribute attrib1, as well as its getter and setter methods. In the configuration file struts-config.xml, the action "/bp1" maps to bp1AForm using the name attribute. This facilitates data display in the JSP. To implement this best practice, Struts recommends you do two things: 1. Create a JavaBean (BP1BForm) with attributes that form an attribute subset in BP1AForm, along with the attributes' getter and setter methods. 2. Replace the attributes in BP1AForm with the bean BP1BForm by associating the bean with BP1AForm. Now you can access this attribute subset in BP1AForm through BP1BForm. Listing 2 shows you how. Listing 2. Accessing form attributes in JSP
name="bp1B" property="subsetAtt1" />
Points to remember
2 of 6
5/17/2006 5:57 AM
Best practices for Struts development
http://www-128.ibm.com/developerworks/web/library/wa-struts/
This practice's main advantage is that you can use it when you need multiple ActionForms to access a set of attributes. When following this best practice, you'll want to keep in mind the following: Struts implements the
tag. When the code <%@ taglib uri="struts-bean.tld" prefix="bean" %> points to struts-bean.tld, the
tag starts to work in the JSP components. BP1AForm's validation framework, which extends ActionForm, must validate BP1BForm's data. When creating Action classes in your application, instead of directly extending org.apache.struts.action.Action, create an Action class (IntermediateAction) by extending org.apache.struts.action.Action to handle common things in your application. All other Action classes extend this IntermediateAction class.
Best Practice 2. Use Action class to handle requests
Typically when using the Struts framework, for every action the JSP component requests your application to execute, the application must extend Struts' org.apache.struts.action.Action to create an Action class. This individual Action class interfaces with the application's Model layer while processing the request. To implement this practice, Struts recommends you follow these steps: 1. Create an Action class, say BP2Action, by extending org.apache.struts.action.Action. 2. Create all other Action classes in your Web application by extending BP2Action. 3. In BP2Action, create a method performTask(), as in public abstract ActionForward performTask(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException. 4. In BP2Action add one or more generic methods to the application, for example serverSideValidate(). You can decide on the method's access modifier by considering the following factors: If all Action classes must implement this method, make it abstract. If some Action classes will provide a case-specific implementation, declare the method protected and give it a default implementation. 5. In BP2Action, declare method perform() as final. Invoke the above generic method, which must always be called before processing the request. Now call the method performTask() created in step 3. 6. In every Action class extending BP2Action, add method performTask() with a case-specific implementation. Advantages
This practice has two main advantages. First, it helps you avoid redundant code in every Action class of your Web application. Second, it gives the application more control over generic tasks by centralizing the behavior in one Action class.
Best Practice 3. Use ActionForm to work on session data
In a Struts-based Web application, each ActionForm extends org.apache.struts.action.ActionForm. These ActionForms encapsulate page data and provide a validation framework to validate request parameters.
3 of 6
5/17/2006 5:57 AM
Best practices for Struts development
http://www-128.ibm.com/developerworks/web/library/wa-struts/
Most Web applications maintain data in session to make them available throughout the application. This best practice addresses this Web application feature. It allows methods toSession() and fromSession() to move session data to and from the form data. Thus, it addresses session data maintenance in a Web application. To adhere to this practice, follow these steps: 1. Create an abstract class named BP3Form by extending org.apache.struts.action.ActionForm. 2. In BP3Form, add methods with access modifiers as in public abstract void toSession(SessionData sessionData) and void fromSession(SessionData sessionData). 3. In every ActionForm, extend BP3Form and implement the abstract methods in which the form data is transported to and from the session. 4. The corresponding Action class may determine the order in which these methods are called. For example, you could invoke method toSession() on the ActionForm just before actionForward is determined. When to use this practice
This practice is most useful when session data is maintained as a single object and/or every page manipulates or uses session data.
Best Practice 4. Handle exceptions effectively
Conventionally, when an application exception occurs in an Action class, the exception is first logged. Then the class creates an ActionError and stores it in the appropriate scope. This Action class then forwards control to the appropriate ActionForward. Listing 3 shows how Action class handles exceptions. Listing 3. Exception handling in an Action class try { //Code in Action class } catch (ApplicationException e) { //log exception ActionErrors actionErrors = new ActionErrors(); ActionError actionError = new ActionError(e.getErrorCode()); actionErrors.add(ActionErrors.GLOBAL_ERROR, actionError); saveErrors(request, actionErrors); }
While conventional exception handling procedures save exception information in every Action class, best practice 4 aims to avoid redundant code while handling exceptions. To use this practice, Struts recommends following these steps: 1. Create an Action class, say BP4Action, by extending org.apache.struts.action.Action. 2. Create all other Action classes in your Web application by extending BP4Action. 3. In BP4Action, declare variable ActionErrors actionErrors = new ActionErrors();. 4. In BP4Action, create a method performTask() as in public abstract ActionForward performTask(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, ActionErrors actionErrors) throws IOException, ServletException.
4 of 6
5/17/2006 5:57 AM
Best practices for Struts development
http://www-128.ibm.com/developerworks/web/library/wa-struts/
5. In BP4Action, declare method perform() as final. Then invoke generic methods, which must always be called before processing the request. Now you can call the method performTask() created in the previous step. 6. While implementing method performTask() in every Action class (by extending BP4Action), handle application exceptions as shown in Listing 4. Listing 4. Using ActionErrors effectively try { //Code in Action class } catch(ApplicationException appException) { //Log exception //Add error to actionErrors actionErrors.add(ActionErrors.GLOBAL_ERROR, new ActionError(appException.getErrorCode())); }
In BP4Action, after invoking the method performTask(), save the ActionErrors using saveErrors(request, errors). Advantages
This practice's main advantage is that it avoids code redundancy in every Action class that handles ActionErrors.
In conclusion
Building an easily maintainable Web application can be one of the most challenging tasks for a development team. Using a mature framework like Struts helps you implement the infrastructure code normally associated with building an application. The Struts framework provides a set of standard interfaces for plugging business logic into the application, a consistent mechanism across development teams for performing tasks such as user data validation, screen navigation, and so forth, as well as a set of custom tag libraries to simplify developing screens. These four best practices are important for you to extract more from the framework's features. You, as a developer, can benefit from these lessons to increase your code modularity and application reusability, plus minimize code redundancy. These are all critical to building an extensible Web application.
Resources
Find out more about Struts at the Jakarta Struts Home page. Download the Struts source code. Read "Struts, An Open-Source MVC Implementation" for an introduction to Struts (developerWorks, February 2001). Discover the "Struts Adoption" discussion of pertinent Struts issues. Explore a useful reference on Struts, Mastering Jakarta Struts by James Goodwill (Wiley Publishers, 2002).
5 of 6
5/17/2006 5:57 AM
Best practices for Struts development
http://www-128.ibm.com/developerworks/web/library/wa-struts/
Read about changes to Struts, including the Tiles library in "Struts and tiles aid component-based development" (developerWorks, June 2002). Browse for books on these and other technical topics. Visit developerWorks Web Architecture and Java technology zones for a range of articles on the topics of Web architecture, usability, and Java.
About the authors
Palaniyappan Thiagarajan specializes in Web application development using Struts framework and IBM JADE framework. He has presented topics on the Struts framework in technical forums, and holds professional certifications from IBM in IBM WebSphere Application Server 3.5, IBM DB2 Family Fundamentals and IBM Certification for OOAD and UML. He has also written articles for IBM developerWorks, Java zone.
Pagadala Suresh specializes in Java technology, WebSphere Application Server, and WebSphere Studio Application Developer (WSAD), Ariba Buyer. He has participated in the IBM Redbook program on WebSphere, and has professional experience in WebSphere Business Components Composer and IBM JADE Framework.
6 of 6
5/17/2006 5:57 AM