Applying MVC to Web-Based Applications with Generic Views
The business world is heavily investing into the evolution of their services and product lines; both presentation and customer interaction are becoming Internet centric. Corporations are establishing a Web presence to attract new customers, diversify, and simplify its interaction with its existing customer base, ease business-to-business communications, or to simply put a new face on an old service. Today, practically every bank offers online banking; every financial institution, brokerage house, and hedge fund is rewriting their trading systems to allow global access and trading from any internet-enabled location. Airline, defense, pharmaceutical, document management, and other industries are all adding Web interfaces to their business models.
This rapid emergence of Web-based services and applications caused a tremendous growth in the Web application development area. Existing programming methodologies, design patterns, and code libraries have been reapplied (or rewritten) to make them pertinent to Web-based applications. Even entire frameworks have been created to decrease development time, ease maintenance cycles, and simplify coding of online applications. Because the Model-View-Controller (MVC) design paradigm's main purpose is to separate business logic from presentation and because it's flexible enough to be incorporated into any type of application, it was a prime candidate for adaptation in Web-based applications and services. Apache's software foundation project Struts is actually a framework implementation of MVC in Java, and the FuseBox project is another implementation of MVC in multiple Web technologies: ColdFusion, PHP, Java, ASP, and Lasso.
In my last article (Creating Dynamic Swing Views with Reflection by Extending MVC), I described how to apply MVC to a Java Swing application to dynamically generate JTabbedPane views by using Reflection and briefly described the history of the Model-View-Controller; in this article, I'll show how to use MVC in a Web-based project. My controller will rely on Reflection API to dynamically call action methods, redirect to proper views, and coordinate data flow between presentation and model layers.
Because it will be a Web-based project, I will use Servlets for server-side processing and controller implementation, Java Beans for the model layer, and JSPs as a presentation layer. If you are not familiar at all with Servlets, JSPs, and J2EE component development, please first read the referenced tutorials at the end of this article.
In order to test my project or if you want to use it as a backbone for a larger program, you will need to configure the J2EE compliant application server. I use the freely available Tomcat, but in an enterprise environment you will probably use IBM WebSphere or BEA WebLogic as commercial J2EE application servers with EJB and JSP containers. The setup of application server is beyond the scope of this article, but project's source is packaged as a J2EE—compliant application WAR (Web archive) file with all necessary XML deployment descriptor files; so, to run it on a configured server, all you'll need to do is drop it in an appropriate place. Also, if you feel like investing a bit more time and not writing your own Controller layer, you may want to look at the Apache Struts framework, which also comes with a huge JSP tag library for all sorts of functionalities you may need.
To show how to use MVC in a Web-based application, I've created a simple project consisting of several JSP Views—viewable in any web browser—several helper bean and action classes, and a Servlet controller class. The business objective will be to display weather information based on the user's ZIP code or city name. The project's structure is generic enough to make it easily modifiable for any type of larger online application. Enterprise-level applications usually have a database in the back end, to fetch dynamic data for the views, comprising a so-called three-tier architecture—client application, server processes, and enterprise data services; in my case, hoverer, all data info will be stored in a HashMap object.
The main controller of any MVC design is responsible for the coordination of data flow between the model and view layers, respond to user requests, and management of data in models with actions. This is why the Model-View-Controller can by applied to a Web-based application; if the controller is properly written, it will channel request data and invoke action calls for any type and number of views; therefore, you can easily apply the same controller to any project and add as many views as you need.
I called my controller Servlet "MainServlet" and added its definition into an XML deployment descriptor file under new Web application (webapp), called WeatherAppWeb in my application server.
The Servlet has standard doGet and doPost methods; but in addition, it has HashMap to store Action objects dynamically created based on keys passed from JSP views.
Instead of having a property file to match key with what action to perform or JSP to display, I put action keys into JSPs themselves as hidden variables indicating to the controller what to do next.
The main magic happens in the doPost method, when JSP submits its data to the Controller. I use Reflection API to instantiate the Action class (first I check whether it yet exists), and then call a method indicated by a parameter key. Action classes are used by the Controller to perform any sort of action on the user's behalf. All action classes implement an empty ActionInterface, so that they can be instantiated, using Reflection, based on parameter key passed from the JSP form. Action classes are used to populate helper Java beans or do any other task. After the Action call returns, I redirect to another view—based on the second key parameter in a finally clause.
Note: the Key notation is <Action Class name>.<action method name>—for example, WeatherAction.viewByZip—where WeatherAction is a class implementing ActionInterface and viewByZip is its method taking two objects (request and response) as parameters. See Listing 1.
The views are simply HTML pages that the user can see in any Web browser. They are generated by the Application Server from JSPs. Post views have an HTML form with a submit action pointing to the Controller Servlet.
<FORM action="../MainServlet" method="post">
and two key parameters indicating to the controller what to do and where to redirect.
<input type="hidden" name="ACTIONKEY" value="WeatherAction.viewByZip">
<input type="hidden" name="REDIRECTKEY" value="weather_data">
In my case, one view of JSP gets the ZIP code and submits it to the controller, which instantiates an Action class based on the first key—WeatherAction—and calls the viewByZip method, passing to it a request object. From the request object, I get all parameters and do a lookup by ZIP code in a Data Store WeatherData object. The reference to the result bean is put back into the request object. See Listing 1. After the method finishes, the Controller Servlet redirects to "weather_data.jsp", specified by the second key. The JSP that uses the data bean only has to call the proper methods in the right places in HTML to show dynamic data. See Listing 2.
As you can see from the architecture overview diagram above, I have two JSP views (one taking a ZIP code and another taking a City string), both having a second redirect key pointing to the third JSP (weather_data) were I show results. By following this pattern, you can add any number of Views and models with the correct key values, and the Controller will effortlessly coordinate data flow between them, without knowing anything about views or corresponding models.
One last thing to mention about JSP views is that I validate the ZIP and City fields by using JSP Tag library on the server-side added by:
<%@ taglib uri="/WEB-INF/validtag.tld" prefix="valTags" %>
If you are not familiar with JSP Tags, don't worry; I'll describe in detail how to use them for data verification in my next article, "Verifying User Input in MVC Views Using JSP Tag Libraries".
Page 1 of 2