JInt Demo: Implementing MVC Architecture using Struts
Introduction
Struts is an open source framework from Apache Jakarta for building applications
using Model View Controller (MVC) design pattern. Struts provide the basic infrastructure
for implementing MVC allowing developers to concentrate on the business logic.
The framework is also flexible and can be extended to meet the requirements
specific to a project.
The objective of this article is to help users quickly get started with using
Struts in their applications. It also shows how JInt Demo uses Struts to implement
(MVC) architecture in its Web applications.
MVC Architecture
The aim of MVC architecture is to separate the business logic and data of the
application from the presentation of data to the user. Following is the small
description of each of the components in MVC architecture:
Model : The model represents the data of an application. Anything that
an application will persist becomes a part of model. The model also defines
the way of accessing this data ( the business logic of application) for manipulation.
It knows nothing about the way the data will be displayed by the application.
It just provides service to access the data and modify it.
View : The view represents the presentation of the application. The
view queries the model for its content and renders it. The way the model will
be rendered is defined by the view. The view is not dependent on data or application
logic changes and remains same even if the business logic undergoes modification.
Controller : All the user requests to the application go through the
controller. The controller intercepts the requests from view and passes it to
the model for appropriate action. Based on the result of the action on data,
the controller directs the user to the subsequent view.
Getting Started with Struts
Struts provides the controller in the form of an
ActionServlet class. The framework uses this class for handling all the
requests. To enable your application to use this controller servlet, include
the following in the deployment descriptor i.e. web.xml
In web.xml, we also need to specify the mapping of application URLs to this
servlet. In the above code any URL with .do
extension calls the ActionServlet to handle the request.
To carry out an appropriate action for a particular request, the ActionServlet
is configured using Action Mappings in the struts-config.xml file. An Action
Mapping specifies a fully qualified Action class name that should be invoked
when a URL matching its path is requested. Following is a sample action mapping
:
When a URL for the application ending with Register.do is called, the ActionServlet
searches for a mapping with path as /Register. It then instantiates the class
defined by the type attribute to perform the required action. Any form parameters
in the request object are passed to the Action class using the form bean defined
by the name attribute. The name attribute defines a logical name for the form
bean, the mapping for which done is using <form-bean> tag in sturts-config.xml
file as shown below:
Using this input the Action class performs operations to serve the request.
Depending on the result of operation, the user is directed to the next view
using the ActionForward object (which represents the <forward> tag in Action Mappings).
Writing an Action Class
An Action class is an adapter between an incoming HTTP request and the corresponding
business logic that should be executed to process this request. It should define
a perform method which will be automatically invoked to serve the request. For
each request, the controller ( ActionServlet class) will select an appropriate
Action class, create an instance (if one does not exist), and call the perform
method. The perform method should be implemented to execute the business logic
for serving the request, handle errors and navigate to appropriate view based
on outcome of the action. Usually it is a good practice to delegate the business
logic part of implementation to Enterprise Java Beans(EJB) or simple vanilla
Java Beans. Here is a sample implementation of action class taken from JInt
demo.
... //class imports ....
public class MainAction extends Action { /** * function: perform() * @param mapping The ActionMapping used to select
* this instance * @param actionForm The optional ActionForm bean
* for this request (if any) * @param request The HTTP request we are processing * @param response The HTTP response we are creating * @throws IOException if an input/output error occurs * @throws ServletException if a servlet exception occurs * @return where control will be forwarded to after
* this request is processed * @description :This is the main action called from
* the struts framework. */
public ActionForward perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException,
ServletException {
// define variable to forward control to next view ActionForward actionForward=null;
SLSBProductManagementHome home = null; SLSBProductManagement bean=null;
try{ home = lookUpProductManagementHome(); bean= home.create(); ...... // execute business logic ......
//on success forward the control to main jsp page actionForward = mapping.findForward("success");
}
catch(CreateException e){ actionForward = mapping.findForward("failure"); } return actionForward; }
Many times it is required to use the same action class for related a set of
operations, say, for example, retrieving the user's profile from the database
and then updating it after modification. In such cases, the action class should
extend org.apache.struts.actions.DispatchAction
class. Different methods are defined for each action with methods having the
same signature as the perform method above.
For invoking a particular method, the name of method is passed as the value
of parameter with the invoking URL. The name of this parameter is defined in
Action Mapping for the URL. For example, a URL to invoke update function in
action class with parameter name as method in Action Mapping would look as follows
:
For mapping a request URL to a particular Action class, the
ActionServlet class is to be provided with suitable information using
ActionMapping interface. Struts provides
a declarative way in the form of XML configuration file to pass this information
to the controller servlet. The controller servlet parses this file and gets
the required information to handle the incoming request. The configuration file
usually named as struts-config.xml file should
be defined and placed in the WEB-INF folder
of the application Web Archive (WAR file). The controller servlet knows the
configuration file from the web.xml where
it is declared as follows :
<form-beans> :
Contains definition of the beans used by the application. A <form-bean>
describes an instance of ActionForm class that will be used to pass the form
data to the action class. Important attributes of <form-bean> are as follows:
name : A unique identifier for the bean that will be used as reference
in action mappings.
type : Fully qualified class name of the ActionForm subclass used to
defined this bean.
<global-forwards>:
This elements define the forwards that can be used by all action mappings. A
Forward is an instance of ActionForward
class that maps a resource name to the actual resource in the application. These
forward names are used in application to forward the control to the next view
based on the outcome of execution of a request. Important attributes of a
<forward> element are as follows :
name : The logical name of the forward. This will be used in the application
to forward the request to the resource referenced by this forward.
path : The relative path to the resource (typically jsp page).
redirect : true or false. If true, a redirect is carried out to the resource
instead of forward.
<action-mappings>:
This element is used for defining mapping for various actions using <action>
tags. An <action> tag is used to map
a request URL to a particular action and pass associated information. Here are
important attributes of <action> element
:
path : The application context-relative path to the action e.g. /SignUptype : Fully qualified name of Java class that will be used to
execute this action.
name : The logical name of form bean used to pass the form data to
action class.
parameter : The name of parameter whose values is used to call a particular
method in action class.
validate : Set to true if the validate() method of the action associated
with this mapping should be called.
forward : The request URI to which the control should be passed for this
action mapping.
Handling Form Data
Your form may contain lot of information as an input from the user when a request
is made. This data can be passed as an instance of ActionForm class to the serving
Action class for processing. The ActionForm class is subclassed to create a
Java bean that defines getter and setter method for the fields defined in the
input form. The action mapping for a particular request defines which ActionForm
class is to be used to pass the form data to Action class. Here is a simple
definition of a class used when the user tries to register with the Web application
in JIntDemo.
import org.apache.struts.action.ActionForm;
public class RegisterForm extends ActionForm {
private String firstName = null;
private String lastName = null;
/**
* Get the first name
*/
public String getFirstName(){
return (firstName);
}
/**
* Set the last name
*/
public void setfirstName(String firstName ){
this.firstName =firstName ;
}
/**
* Get the last name
*/
public String getLastName(){
return (lastName);
}
/**
* Set the last name
*/
public void setLastName(String lastName ) {
this.lastName =lastName ;
}
}
The ActionForm subclass follows standard Java Beans convention to name the
methods for a property.
This mechanism of Struts proves to be a better alternative to
<jsp: useBean> tag to capture form data. It helps to avoid calling
Java Beans in the JSP page(the view) avoiding tight coupling between the two
and provides a declarative way to do the same.
ActionForward Configuration
A forward is defined using <global-forward>
or a <forward> element in the
<action> tag as explained earlier. A forward maps a resource to
a logical name which can be referenced in the Action class to forward the control
of the application as and when required. Struts provides a convenient method
viz. ActionForward.findForward(forwardName)
to locate a forward using logical name defined in the config file. This instance
of ActionForward is returned to the
RequestProcessor which forward the control to the next view identified
by the selected forward.
Global forward defined in the config file using
<global-forward> tag can be used by all the action classes to
forward the control. For example an application that requires a user to login
before performing any operations, can define a global forward to direct the
user to a login page when he/she requests any URL of the application. In addition,
an action mapping can define forward specific to its requirements using a
<forward> tag in the action mapping.
ActionForward provides a convenient way to declare the forward path without
having to hard code it in the Action class. The path is referred by a logical
name in the code and hence can be changed anytime in the config file based on
the requirement without modifying the code.
Handling Exceptions
Exceptions thrown by perform method in the Action class can be handled by defining
an exception handler class derived from org.org.apache.struts.action.ExceptionHandler
. The execute method in this class should be overridden to contain the code
that should be executed in case of exception. This method should return an
ActionForward class instance defining an appropriate forward to the
next view. The exception handler class is configured in the config file using
<global-exception> tag or by using
<exception> tag specific to an action
mapping as follows :
When the above configuration is done, the execute
method of ExceptionHandler is invoked whenever
a NullPointerException is thrown during
processing of corresponding request. The execute
method can forward control to a page displaying the message defined by the
key attribute in message resource properties. Instead of a
handler attribute, you could directly give a
path attribute to redirect the user to a page specified by the path in
case no operation needs to be performed on exception. Such a configuration will
look as follows :