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

<servlet>

  <servlet-name>EAIActionServlet</servlet-name>
  <servlet-class>org.apache.struts.action.ActionServlet
  </servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>EAIActionServlet</servlet-name>
  <url-pattern>/*.do</URL-pattern>
</servlet-mapping>

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 :

<action path="/Register"

   type="oracle.otnsamples.jintdemo.marvel.web.actions.RegisterAction"
   scope="request"
name="registerForm"> <forward name="success" path="/jsps/Message.jsp"/> <forward name="failure" path="/jsps/Register.jsp"/> <forward name="addCart" path="/AddToCart.do"/> </action>

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:

<form-beans>
  <form-bean  name="registerForm"     
     type="oracle.otnsamples.jintdemo.marvel.web.forms.RegisterForm"/>
</form-beans>

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 :

http://myhost.com/MarvelSystem/GetProfile?method=update

Action Mapping Configuration

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 :

<servlet>
   ....  
   <init-param>
	 <param-name>config</param-name>
	 <param-value>/WEB-INF/struts-config.xml</param-value>
   </init-param>
</servlet>

Following are the important elements of struts-config.xml file :

<struts-config>
  <form-beans>
    <form-bean name="registerForm"
      type="oracle.otnsamples.jintdemo.marvel.RegisterForm"/>
  </form-beans>

  <global-forwards>
    <forward name="Login" path="/Login"/>
  </global-forwards>
  

  <action-mappings>
    <action path="/Profile"
      type="oracle.otnsamples.jintdemo.marvel.ProfileAction"
      scope="request"
      name="registerForm"
      validate="true"
      parameter="method" >
      <forward name="success" path="/jsps/Profile.jsp"/>
      <forward name="failure" path="/jsps/Login.jsp"/>
    </action> 
  </action-mappings>
</struts-config>

<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. /SignUp
 type      : 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 :

<global-exceptions>
<exception key="exception.key" type="java.lang.NullPointerException" handler="app.mypackage.ExceptionHandler"/>
</global-exceptions>
<action path=/Profile ... <exception key="exception.key" type="java.lang.NullPointerException" handler="app.mypackage.ExceptionHandler"/> </action>

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 :

<action path=/Profile
        ... 
  <exception key="exception.key" type="java.lang.NullPointerException" 
             path="/root/Message.jsp"/>
 </action>

Resources

For more information, refer

JInt Demo application
http://jakarta.apache.org/struts/
E-mail this page
Printer View Printer View
Oracle Is The Information Company About Oracle | Oracle RSS Feeds | Careers | Contact Us | Site Maps | Legal Notices | Terms of Use | Privacy