[ Team LiB ] Previous Section Next Section

Using Model-View-Controller in Your Web Applications

The Model-View-Controller (MVC) paradigm is a way of dividing an application into three distinct areas:

  • The controller, which is really the input that changes the system

  • The model, which is the data that describes the system

  • The view, which is the display of the data, whether it is graphical, textual, or even just information written out to a file

To put MVC into real-world terms, think of your application as a car. The gas pedal, brake, and steering wheel are controllers. They send input signals to the model, which is the engine, suspension, transmission, and so on. Your speedometer, tachometer, fuel gauge, and idiot lights are all examples of views. They give you some representation of what is happening in the model.

Most developers think of MVC in terms of a graphical user interface, because MVC is used extensively in GUI development. With a little imagination, though, you can extend the MVC paradigm to Web development, in terms of servlets and JSPs. The idea is that you split your application into three sections. A servlet handles any requests from the client and acts as a controller. You put your business logic (the model) in Java classes that are neither servlets nor JavaServer Pages. Finally, you use JavaServer Pages to display the view, which is a representation of the model. This is illustrated in Figure 20.3.

Figure 20.3. MVC can be used with servlets and JSPs.

graphics/20fig03.gif

When applying MVC to a Web application, you have to make some concessions toward the way the Web works. When you use MVC in a GUI application, changes to the model can result in immediate feedback to the user.

Because the client and the Web server spend most of their time disconnected from each other, you can't have that kind of dynamic view in a Web application. The important thing is that you concentrate on splitting the model, view, and controller into separate pieces.

How Does Model-View-Controller Help?

Unfortunately, many applications are developed in a piecemeal fashion. Someone comes to a developer and says, "Hey, can you write a JSP to display X on a browser?" A little while later, that person comes back and says, "Great, now can you put X over here, compute Y, and display Z over here?" After a few rounds of this, the JSP might look beautiful to the user, but the source code probably looks hideous to the developer.

The sequence of tasks in the JSP can end up looking something like this:

  1. Display some static content using HTML.

  2. Go get the user's profile information from the security server.

  3. If the user is a manager, go to the part of the JSP that displays the page using the manager's special format.

  4. Go get some information from the database.

  5. If there's an error in the database, display error information.

  6. Display the database information in HTML.

No one ever intends things to be so convoluted; they just get that way sometimes. By applying MVC to this same sequence of events, you get a cleaner picture. The sequence goes something like this:

  1. The controller servlet connects to the security server and obtains the user profile.

  2. The controller servlet grabs some information from the database and stores it in the request object.

  3. If there is an error fetching data from the database, the controller servlet forwards to an error JSP.

  4. If the user is a manager, the controller servlet forwards to a JSP that displays the manager's view of the data.

  5. If the user is not a manager, the controller servlet forwards to the regular display JSP.

  6. The display JavaServer Pages grab the information from the request object and display it.

An Example Controller

Listing 20.1 shows you an example controller that queries a database and then calls a view JSP to show the results. For the sake of brevity, the code is not as robust as it should be.

Listing 20.1 Source Code for ControllerServlet.java
package examples;

import java.io.*;
import java.util.*;
import javax.servlet.*;

public class ControllerServlet extends GenericServlet
{
    private static Person[] people = new Person[]
        { new Person("Samantha Tippin", 9, "770-123-4567"),
          new Person("Kaitlyn Tippin", 6, "770-123-4567"),
          new Person("Edward Alexander", 3, "No phone"),
          new Person("Star Alexander", 3, "Phone off hook"),
          new Person("Norton Alexander", 12, "No phone")
        };

    public synchronized void service(ServletRequest request,
        ServletResponse response)
        throws java.io.IOException, ServletException
    {
// Parse the minimum and maximum ages and go to an error page if they
// are invalid.
        String minimumAgeStr = request.getParameter("minAge");
        int minimumAge = 0;

        try
        {
            minimumAge = Integer.parseInt(minimumAgeStr);
        }
        catch (Exception exc)
        {
            gotoPage("/BadAge.jsp?"+
                "reason=Invalid+minimum+age",
                request, response);
        }

        String maximumAgeStr = request.getParameter("maxAge");
        int maximumAge = 0;

        try
        {
            maximumAge = Integer.parseInt(maximumAgeStr);
        }
        catch (Exception exc)
        {
            gotoPage("/BadAge.jsp?"+
                "reason=Invalid+maximum+age",
                request, response);
            return;
        }

// Get all the people matching the criteria.
        Vector v = new Vector();

        for (int i=0; i < people.length; i++) {
            if ((people[i].age >= minimumAge) &&
                (people[i].age <= maximumAge)) {
                v.addElement(people[i]);
            }
        }

// Store the vector of person objects so the JSP can access it.
        request.setAttribute("people", v);

        gotoPage("/ShowPeople.jsp",
            request, response);
        return;
    }

// This method comes in handy as a one-liner for forwarding. It should really
// check to make sure it can get the dispatcher and do something
// predictable if it can't.

    public void gotoPage(String pageName,
        ServletRequest request, ServletResponse response)
        throws IOException, ServletException
    {
        RequestDispatcher d = getServletContext().
            getRequestDispatcher(pageName);

        d.forward(request, response);
    }
}

An Example View

The controller does most of the work. The view will just display the results. We'll reuse the TableServlet class from Hour 10 to display the names in a table. Listing 20.2 shows the example view.

Listing 20.2 Source Code for ShowPeople.jsp
<html>
<body bgcolor="#ffffff">

The following people matched your search criteria:
<P>
<%-- Invoke the Table servlet, tell it the name of the attribute
     where the data is stored (data=people), set the border size to 4
     on the <table> tag, and describe each column to display.

     The "people" attribute was sent from the controller servlet
     and contains a vector of people objects. --%>

<jsp:include page="/TableServlet" flush="true">
    <jsp:param name="data" value="people"/>

    <jsp:param name="tableOptions" value="BORDER=4"/>

    <jsp:param name="column" value="name"/>
    <jsp:param name="columnType" value="data"/>
    <jsp:param name="columnHeader" value="Name"/>

    <jsp:param name="column" value="age"/>
    <jsp:param name="columnType" value="data"/>
    <jsp:param name="columnHeader" value="Age"/>

    <jsp:param name="column" value="phone"/>
    <jsp:param name="columnType" value="data"/>
    <jsp:param name="columnHeader" value="Phone"/>

</jsp:include>
</body>
</html>

Using Custom Tags in This Example

graphics/bytheway_icon.gif

By now it should be easy for you to imagine the use of custom tags as an alternative way to construct the table.


The front end to this controller-view pairing is a very small HTML page that prompts for the minimum and maximum ages for the query. Listing 20.3 shows the source for the HTML page.

Listing 20.3 Source Code for PeopleQuery.html
<html>
<body>

Please enter the minimum and maximum ages to view:
<P>
<form action="/ControllerServlet" method="post">
Minimum Age: <input type="text" name="minAge"><br>
Maximum Age: <input type="text" name="maxAge"><br>
<P>
<input type="submit" value="Perform Query!">
</form>
</body>
</html>

Finally, Figure 20.4 shows the output of the view class. Most of the view is actually generated by the TableServlet class.

Figure 20.4. The View page is responsible for displaying the data retrieved from the model.

graphics/20fig04.gif

    [ Team LiB ] Previous Section Next Section