You are on page 1of 31

Struts

Best Practices

1
Sang Shin
sang.shin@sun.com
www.javapassion.com
Java™ Technology Evangelist
Sun Microsystems, Inc.
2
Disclaimer & Acknowledgments
● Even though Sang Shin is a full-time employees of Sun
Microsystems, the contents here are created as their own personal
endeavor and thus does not reflect any official stance of Sun
Microsystems.
● Sun Microsystems is not responsible for any inaccuracies in the
contents.
● Acknowledgments:
– Some slides are created from "Jakarta Struts: Seven lessons from trenches"
article written by Chuck Cavaness
– Some slides are created from "Struts Best Practices” article written by Brijesh
Deb

3
Revision History
● July 2nd, 2005: version 1: created by Sang Shin
● Things to do

4
Extend Only When Needed
● Make sure extending the framework is the
last resort
– Add maintenance cost

5
Use Declarative Exception Handling
● Struts framework includes a class called
ExceptionHandler that by default is
responsible for processing any exceptions
that occur during action execution
● The default Struts exception handler class
creates an ActionError object and stores it in
the appropriate scope object

6
Use Application Modules
● In a multi-developer environment, a single
struts-config.xml is a bottleneck
● Allows parallel development
● Necessary for large scale applications

7
Protect JSP Pages
● Protect your JSP pages from unauthorized
access or viewing
● Front your JSP pages with Struts Actions
● Two options
– Store your pages in a directory that is below the
Web application's WEB-INF directory
– Use security feature of Web application

8
Protect JSP's Behind WEB-INF
● Suppose we had an Action mapping in
Struts configuration file for a logoff action,
the path must include /WEB-INF
<action
path="/logoff"
type="org.apache.struts.webapp.example.LogoffAction">
<forward name="success" path="/WEB-INF/jsp/index.jsp"/>
</action>

9
Protect JSP's using Security
Features of Web application
● Nobody can access JSP pages directly
<web-app>
...
<security-constraint>
<web-resource-collection>
<web-resource-name>no_access</web-resource-name>
<url-pattern>*.jsp</url-pattern>
</web-resource-collection>
<auth-constraint/>
</security-constraint>
...
</web-app>

10
Use the Prebuilt Actions
● Struts framework comes with several prebuilt
Action classes that can save a tremendous
amount of development time and reduce the
number of files to manage
– org.apache.struts.actions.ForwardAction
– org.apache.struts.actions.DispatchAction

11
Use DynaActionForm's
● Allow you to configure an ActionForm
completely through the Struts configuration
file; there's no longer a need to create actual
concrete ActionForm classes in your
application
● Helps to facilitate automatic presentation-
layer validation

12
Use Struts Tools
● Adalon (Commercial)
● Easy Struts (Open source)
● Struts Console (Free)
● JForms (Commercial)
● Camino (Commercial)
● Struts Builder (Open source)
● StrutsGUI (Free)

13
Categorize Errors
● To display the error messages of different
categories, define these categories such as
FATAL, ERROR, WARNING, or INFO, in an
interface
● In the Action or form-bean class, you can
then use the following
– errors.add("fatal", new ActionError("....")); or
– errors.add("error", new ActionError("....")); or
– errors.add("warning", new ActionError("....")); or
– errors.add("information", new ActionError("...."));
– saveErrors(request,errors);
14
Categorize Errors
● To display them according to those categories, use
the following code:
<logic:messagePresent property="error">
<html:messages property="error" id="errMsg" >
<bean:write name="errMsg"/>
</html:messages>
</logic:messagePresent >

Or use:

<logic:messagePresent property="error">
<html:messages property="error" id="errMsg" >
showError('<bean:write name="errMsg"/>'); // JavaScript
Function
</html:messages>
</logic:messagePresent > 15
Create Common Action Class
● When common operations need to be
included in all the actions, create common
Action class
– An example of such a requirement in an Online
Shopping application would be to perform user
authorization before processing all user requests
● Make all other Action classes extend the
common action class to centralize the
handling of common operations and
reduce code redundancy

16
Create Common Action Class
Public abstract class BaseApplicationAction extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
try {
//Call all common methods
performAuthorization();
return executeSpecificTask(mapping,form,request,response);
} catch(Exception ex){//exception}
}

// Authorization is an operation common through all the application actions


private void performAuthorization() {
//Code for user authorization
}

//Provide implementation of this method in sub-classes


public abstract ActionForward executeSpecificTask(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception
} 17
Handle Duplicate Form Submission
● The problem of duplicate form submission
arises when a user clicks the Submit button
more than once before the response is sent
back or when a client accesses a view by
returning to a previously bookmarked page.
● Handle it by using the saveToken() and
isTokenValid() methods of Action class
– saveToken() method creates a token (a unique string)
and saves that in the user's current session
– isTokenValid() checks if the token stored in the user's
current session is the same as that was passed as
the request parameter.
18
Handle Duplicate Form Submission
public class PurchaseOrderAction extends DispatchAction {
public ActionForward load(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception {

try {
//save the token
saveToken(request)

// rest of the code for loading the form


} catch(Exception ex){//exception}

19
Handle Duplicate Form Submission
public ActionForward submitOrder(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception {

try {
// check the token. Proceed only if token is valid
if (isTokenValid(request,true)) {
//implement order submit functionality here
} else {
return mapping.findForward("failure");
}
} catch(Exception ex){
}

}
}
20
Use Single ActionForm for
Similar Forms
● For similar forms, use a single ActionForm
that includes all possible fields instead of
having several ActionForms
● This is generally applicable to different forms
required to implement the same use case
● It leads to easy maintenance, though all the
fields will be not be used for all the Actions

21
Use Single ActionForm for
Similar Forms
● For example, in the Online Shopping
application we can use a single ActionForm
(CustomerProfileForm) for different forms
related to customer profile management (like
DisplayCustomerProfile.jsp,
EditCustomerProfile.jsp, etc.)

22
Use intermediate Action class for
common operations
● When a common operation needs to be
performed for all actions
– ex) authorization
● All action classes then extend the
intermediate action class
● Centralize the common operato

23
Use global-forwards to Avoid
Redundant forwards
● Helps to avoid mentioning for all the actions
● The Online Shopping application should
display the login page in case of session
timeout. Instead of including for all the
actions, add a single entry in the struts-
config.xml to throw the login.jsp to the user in
case of session timeout encountered in any
Action, like this:

24
Remove ActionFrom From
Session
● If ActionForm is set to session scope, it
should be removed from session whenever
it's utility is over
● In the sample online shopping application, in
case of the multi-screen customer
registration, if the RegistrationForm is set to
session scope, it should be removed form the
session once the user clicks Cancel

25
Use Business Delegate
● Action should not implement complex
business functionalities, rather delegate
these to the Model
● Use Business Delegate to talk to the
Business tier and the Data Tier

26
Avoid instance/static Variable in
Action Class
● Instance and static variables should not be
used in an Action class to store information
related to the state of a particular request.
The same instance of an Action class can be
shared among multiple simultaneous
requests through multi-threading
● Instance/static variable may however be
used to share global resources across
requests for the same action.

27
Do Not Include Business Logic in
ActionForm
● ActionForm represents HTML form(s) and it
is used by Struts to transfer data between
View and Controller
– They should not be treated as part of the Model
– Do not include any business functionality in the
reset() or validate() method of ActionForms as
this would lead to tight coupling of application
business functionality with the presentation tier
(implemented through the Struts framework).

28
Use html:messages (instead of
html:errors
● For displaying error messages to the end
user, use html:messages instead of
html:errors
● html:messages allows to get the markup
language out of the resource bundle.

29
Use StrutsTestCase For Unit
Testing
● Because StrutsTestCase uses the ActionServlet
controller to test the code, you can test not only
the implementation of your Action objects, but
also the mappings, form beans, and forwards
declarations.
● StrutsTestCase provides both container testing
and simulated container testing to actually run
the Struts ActionServlet, allowing you to test
Struts code with or without a running servlet
engine.

30
Passion!

31

You might also like