devxlogo

Simplify Your Web App Development Using the Spring MVC Framework

Simplify Your Web App Development Using the Spring MVC Framework

n a previous article, I introduced you to the Spring framework, showed you how to use Spring’s basic functionality to create objects, and how to do some simple database interactions. In this follow-up article I will introduce you to the Spring model-view- controller (MVC) framework by walking you through the creation of a simple stock-trading Web application.

MVC is a pattern that helps separate presentation from business logic. In short, in an MVC application all Web requests are handled by controllers. A “controller” is responsible for interpreting the user’s request and interacting with the application’s business objects in order to fulfill the request. These business objects are represented as the “model” part of the MVC. Based on the outcome of the request execution, the controller decides which “view” to forward the model to. The view uses the data in the model to create the presentation that is returned to the user.

If you’ve ever worked on a Web application, chances are that you’ve worked with either a custom MVC framework or an existing framework, such as Struts. Struts is in fairly widespread use in the Java world, but the Spring MVC framework promises to provide a simpler alternative to Struts.

In this article I will walk you through the development of a Web-based stock-trading application. This application will have three primary workflows each of which will cover a different type of controller available in Spring. After reading this article, you should have enough technical and business knowledge to build a full-fledged stock-trading application and compete head-on with existing discount brokerage firms. … OK, not really, but you will at least have enough knowledge to get you started on your own Web projects using Spring.

You can download the Spring distribution from http://www.springframework.org/download.html. If you want to see the application in action, download the source code for this article, which includes a deployable war file.

Author’s Note: The code in this article has only been tested on Tomcat 5.5.

The Platform
There are many different Web application servers and development environments to choose from. I won’t describe any single environment here because I want to focus the discussion on the Spring framework and not the underlying tools. However, I developed this sample application using Tomcat 5.5, Java 1.5, Spring 1.1, and Eclipse 3.0 using the Sysdeo Tomcat plugin. I have used Spring with other application servers and with different versions of Java 1.4.x without any big surprises, so you should be safe if you have a slightly different environment.

Getting Started
Before diving into Spring, set up a mechanism for deploying your application code into your Web server and set up an application context if necessary. In Tomcat 5.5, the application context automatically takes on the name of the war file (or expanded war directory) that you deploy. My war file is called “tradingapp.war” and my context is consequently “/tradingapp.”

Here is the basic directory structure that you need to create for your Web app:

/WEB-INF          /src             (java classes will go in here)          /jsp             (application jsps will go in here)          /lib             (jar files that our app depends on will go in here)          /classes      (compiled class files will go in here)

In order to test out the application server setup, create a file called index.jsp (as follows) and put it in the root of your application directory:

/index.jspTrading App TestTrading App Test
Figure 1. Clear the Deck: Pull up the index.jsp page to make sure that you can retrieve a simple JSP page.

Try to pull up the page by going to http://localhost:8080/tradingapp/index.jsp (see Figure 1). (The port may vary depending on the application server you are using.)

On most application servers, users can access files in the root directory of the context. Hence, you were able to hit the index.jsp file directly. In an MVC architecture, you want the controller to handle all incoming requests. In order to do this, it is a good idea to keep your JSP files in a place where they are not directly accessible to the user. That is why we will put all of our application JSP files in the WEB-INF/jsp directory. We’ll come back to this soon, but for now let’s find out how to access a Spring controller.

Accessing a Controller
Like in other Web frameworks, Spring uses a servlet called DispatcherServlet to route all incoming requests (this pattern is sometimes called the Front Controller pattern). This servlet should be defined in the Web deployment descriptor as shown here:

/WEB-INF/web.xmlbr> 'http://java.sun.com/dtd/web-app_2_3.dtd'>               tradingapp                         org.springframework.web.servlet.DispatcherServlet                    1                         tradingapp          *.htm                         index.jsp          

In the web.xml file I’ve defined a servlet mapping that forces any URL that ends in .htm to reroute to the tradingapp Servlet (the DispatcherServlet). This servlet analyzes the request URL and determines which controller to pass control on to by using a URL mapping defined in a Spring XML file. This Spring XML file must exist in the /WEB-INF directory and it must have the same name as the servlet name that you defined in the web.xml with a “-servlet.xml” appended to it. Thus, we will create a file in the /WEB-INF directory called “tradingapp-servlet.xml.”

Here is the Spring XML file that the DispatcherServlet will use:

/WEB-INF/tradingapp-servlet.xml                                                                                                                                              

I called the bean urlMapping, but Spring should pick up the mapping regardless of what you name it. In fact, you can have multiple handler-mapping objects defined. The SimpleUrlHandlerMapping class has a map property called urlMap that maps URLs to objects that implement the Controller interface. When the DispatcherServlet looks in this bean definition file, it will load the mapping and use it to determine which controller to route to. I’ve created a reference to the PortfolioController.

There are several different types of controllers available in the Spring framework. In this article, I will show you three different types:

  1. For the portfolio page, I will create the simplest type of controller: one that implements the Controller interface directly.
  2. Next I’ll create a logon form that will use a SimpleFormController class.
  3. Last, I’ll create a trade wizard using the AbstractWizardFormController class.

The Portfolio Page
I first want to change the index.jsp page to redirect to my portfolio page by going through the PortfolioController. I’ll also create a JSP called include.jsp that all of my JSP files can include in order to inherit a common set of properties and tag library definitions.

/index.jsp/WEB-INF/jsp/include.jsp

Now I’ll create a simple portfolio view and have my controller route to it just to make sure everything is working.

/WEB-INF/jsp/portfolio.jspPortfolio PagePortfolio Page

Before writing the Controller, you should add a few jar files to your /WEB-INF/lib directory:

Jar Description Source
spring.jar Main spring jar file [spring-dist]/dist
log4j-1.2.8.jar log4j logging package [spring-dist]/lib/log4j
commons-logging.jar Jakarta Commons logging package [spring-dist]/lib/jakarta-commons
jstl.jar Java standard tag library [spring-dist]/lib/j2ee
standard.jar Jakarta standard tag library [spring-dist]/lib/jakarta-taglibs
taglibs-string.jar Jakarta tag library used for String manipulation http://jakarta.apache.org/taglibs/
commons-lang-2.0.jar Jakarta Commons language API http://jakarta.apache.org/commons
jfl.jar Financial library used to get stock-quotes online http://www.neuro-tech.net/archives/000032.html

Most of these jars are available in the Spring distribution. All of them are available with the downloadable code for this article.

Now create a class called PortfolioController:

/WEB-INF/src/com/devx/tradingapp/web/PortfolioController.javapackage com.devx.tradingapp.web;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.mvc.Controller;public class PortfolioController implements Controller {    public ModelAndView handleRequest(HttpServletRequest request,            HttpServletResponse response) {        return new ModelAndView("/WEB-INF/jsp/portfolio.jsp");    }}

The Controller interface defines a single method signature:

public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws java.lang.Exception;
Figure 2. Back to the Portfolio: The index.jsp page should now redirect you to the Portfolio Page.

The object that is returned by the handleRequest method is of the type ModelAndView. As you probably guessed, the ModelAndView object represents the Model and View in the MVC pattern. ModelAndView has several contructors. The one we’re using right now just takes a string that represents the view that we want to forward to. Because our portfolio.jsp page doesn’t have any dynamic content (yet), we don’t need to return a model object.

Compile the PortfolioController and make sure the compiled file is under the WEB-INF/classes directory structure (i.e. /WEB-INF/classes/com/devx/tradingapp/web/PortfolioController.class). Now you can deploy your application and pull up the index.jsp page again. Go to http://localhost:8080/tradingapp/index.jsp and you should see what is shown in Figure 2.

Now I’ll make it a little easier to specify views from within the Controller objects. The goal is to avoid having to type out the full path to a JSP inside of my Controller code. I can achieve this through use of a ViewResolver that I’ll define in my tradingapp-servlet.xml file. The ViewResolver appends a prefix and suffix to the view that the Controller returns.

/WEB-INF/tradingapp-servlet.xml            org.springframework.web.servlet.view.JstlView        /WEB-INF/jsp/        .jsp    

Now I can simplify my PortfolioController:

/WEB-INF/src/com/devx/tradingapp/web/PortfolioController.java package com.devx.tradingapp.web;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.mvc.Controller;public class PortfolioController implements Controller {    public ModelAndView handleRequest(HttpServletRequest request,            HttpServletResponse response) {        return new ModelAndView("portfolio");    }}

Just to make sure that the Portfolio Page still loads after this change, reload the page in your Web browser (you may have to reload the application context or restart your application server if your application server does not support hot-deploy functionality).

Now I want to make the portfolio page more interesting! First, I’ll add some custom-tag library definitions to the include.jsp file. Using custom tags helps me keep my presentation logic separate from the presentation itself.

/WEB-INF/jsp/include.jsp

Next, update your PortfolioController (see the code in Listing 1).

In the new version of the Controller, I’ve added a model. I use the three-argument constructor for ModelAndView that takes the view, the string name that the JSPs will use to refer to the model, and the model object itself. In Spring, a model is usually just a java.util.Map object. I put two elements on the model, a cash amount, and a list of portfolio line items. Each line item is of type PortfolioItemBean, a JavaBean that I created. This bean is primarily for View purposes and is created using data from the underlying business object called Portfolio. Listing 2 shows these classes.

You’ll also notice that I’m using a class called QuoteFactory to obtain a Quote object using a stock symbol. These classes are part of the Neurotech Java Financial Library, a simple, open source API that can be used to retrieve stock quotes from the Web as well as other simple financial tasks.

Listing 3 shows the updated tradingapp-servlet.xml file and the portfolio.jsp file. If all goes well, when you deploy and reload the page you should see something very similar to Figure 3.

Figure 3. Improving the Portfolio: The portfolio view uses custom tags to display model data that is provided by the PortfolioController.

The cool thing is that the PortfolioController retrieves quotes from the Web using the Java Financial Library, so if you keep refreshing the page during trading hours, you’ll get updated quotes.

In summary, here is the flow to this page:

  1. The user goes to the portfolio.htm page.
  2. He is routed to the dispatcher Servlet (because all .htm pages are directed to the dispatcher Servlet).
  3. The DispatcherServlet loads the tradingapp-servlet.xml file and routes the user to the PortfolioController.
  4. The PortfolioController creates the model and view and passes control back to the DispatcherServlet.
  5. The DispatcherServlet makes the model data accessible via session or request parameters.
  6. The DispatcherServlet routes to the JSP pages.
  7. The JSP is rendered and the presentation is sent back to the user.

The Logon Page
Now you know how to create a page with dynamically updated content, but what good is a Web application that has no way to capture user input from an HTML form? We could implement the Controller interface in order to do form processing, but that would require us to do a lot of manual processing or request parameters and storing things on the session. Personally, I’ve hand coded more form-processing code in this fashion than I ever hope to again. Thus, out of sheer laziness, I will show you how Spring simplifies form handling via the SimpleFormController by building a logon page.

Listing 4 shows the logon JSP. The tag and the tag are in the spring.tld tag library descriptor that comes with Spring. Add this file to your WEB-INF directory and then add the following to your web.xml and include.jsp files.

/WEB-INF/web.xml               /spring          /WEB-INF/spring.tld     /WEB-INF/jsp/include.jsp

The bind tag tells Spring to bind the enclosed form element to the bean property specified by the path attribute. For example the username input parameter will be bound to the username field on a bean named “credentials.” The credentials bean is a special type of bean called a “command” or a “form-backing bean.” Spring uses command beans for data binding while processing forms. The name used to reference this bean and its class type is defined in the tradingapp-servlet.xml file in the logonForm bean (see Listing 5).

I’ve also added a new entry to the handler mapping to point to our logon form when the user navigates (or is routed) to the logon.htm URL. The logon form has several properties:

  • commandClass?the class of the object that will be used to represent the data in this form.
  • commandName?the name of the command object.
  • sessionForm?if set to false, Spring uses a new bean instance (i.e. command object) per request, otherwise it will use the same bean instance for the duration of the session.
  • validator?a class that implements Spring’s Validator interface, used to validate data that is passed in from the form.
  • formView?the JSP for the form, the user is sent here when the controller initially loads the form and when the form has been submitted with invalid data.
  • successView?the JSP that the user is routed to if the form submits with no validation errors.

Here is the code for the Controller:

/WEB-INF/src/com/devx/tradingapp/web/LogonFormController.javapackage com.devx.tradingapp.web;import javax.servlet.ServletException;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.mvc.SimpleFormController;import org.springframework.web.servlet.view.RedirectView;public class LogonFormController extends SimpleFormController {    public ModelAndView onSubmit(Object command) throws ServletException {        return new ModelAndView(new RedirectView(getSuccessView()));    }}

There’s really not much to it. All the FormController does is forward to the success view. The validator takes care of authenticating the user. If the user provides an invalid username or password, the validator will return the user to the form and display an error message. Listing 6 shows the code for the validator.

The validator has a supports method and a validate method. The supports method is called to see if the validator supports a given object type. We want our validator to be able to validate objects of the type Credentials, because that is the command object that we are using for this form.

The validate method does some checks and calls the rejectValue method on the Errors class if validation fails. This method takes four parameters: the name of the field that failed validation, the key value of the error message that exists in a resource file (I’ll explain in a second), a string array of values to substitute into the error message in the resource file, and the default error message that should be displayed if the resource file cannot be found. If any errors are found on the Errors object after validate is done running, Spring will forward control back to the original form JSP so that the errors can be displayed.

You may have noticed above that I also added a ResourceBundleMessageSource bean definition to the tradingapp-servlet.xml file. This is a reference to a properties file that contains application messages that can be defined and accessed throughout the application. These messages can be accessed in many ways, including being directly accessed from JSPs or, as we just saw, by the Errors object to provide error messages. This file must exist in the top level of your classpath, so I just put it in the WEB-INF/classes directory. I’ve jumped the gun and included all the error messages that our application will use in the file:

/WEB-INF/classes/messages.propertieserror.login.not-specified=User credentials not specified (try guest/guest).error.login.invalid-user=Username not valid, try 'guest'error.login.invalid-pass=Password not valid, try 'guest'error.trade.insufficient-funds=You do not have enough money to place this ordererror.trade.not-enough-shares=You do not have that many shareserror.trade.dont-own=You don't own this stockerror.trade.invalid-symbol=Invalid ticker symbol: {0}

Here is the code for the infamous Credentials class (the command/form-backing object):

WEB-INF/src/com/devx/tradingapp/business/Credentials.javapackage com.devx.tradingapp.business;public class Credentials {    private String username;    private String password;    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }}

Now you can change the index.jsp page in the root directory to point to logon.htm.

/index.jsp

Now if you load index.jsp, you will see the logon page, as shown in Figure 4.

Figure 4. Validating: When the logon page does not validate correctly, the user is returned to the form page where the validation errors are displayed.

In summary, here is the flow through this form:

  1. The user goes to the logon.htm page.
  2. He is routed to the dispatcher servlet (because all .htm pages are directed to the dispatcher Servlet).
  3. The DispatcherServlet loads the tradingapp-servlet.xml file and routes the user to the LogonFormController.
  4. The LogonFormController loads the command bean (form-backing object) and routes the user to the page defined in the formView (logon.jsp).
  5. The user fills out the form and submits it.
  6. The user is directed back to the controller and in turn the validator.
  7. If the validator fails, the user is sent back to the form view and error messages are displayed (back to logon.jsp and step 5).
  8. If the validator doesn’t fail, the controller’s onSubmit method is called and the user is forwarded to the successView JSP (portfolio.jsp).

The Trade Wizard
Often times we have more than one screen that a user interacts with in order to complete a given task. This sequence of screens is often called a “wizard.” The last MVC component I will introduce you to is the AbstractWizardFormController. This controller allows you to carry the same command object through an entire flow of Web pages, thus allowing you to break up the presentation into multiple stages that act on the same model.

For the example, I’ll create a wizard that allows a user to trade stock. This wizard will start with a page that takes the order and then goes to a confirmation page where the user will choose to either execute or cancel the order. If the order is cancelled, the user will be returned to the portfolio page, if the order is executed the user is sent to an acknowledgement page to tell them that their order was filled.

First I need a way to get to the trade page, so I’ll put a link to the trade page on the portfolio page.

/WEB-INF/jsp/portfolio.jsp
">Make a trade
">Log out

devx-admin

Share the Post: