Chapter 22. mvc-no-boot (optional)

22.1. Introduction

In this lab you will implement basic Spring MVC Controllers to invoke application functionality and display results to the user. This lab assumes you are not using Spring Boot, for example because you are responsible for maintaining existing applications.

What you will learn:

  1. How to set up required Spring MVC infrastructure
  2. How to expose Controllers as endpoints mapped to web application URLs

Specific subjects you will gain experience with:

  1. DispatcherServlet
  2. @Controller
  3. InternalResourceViewResolver

Estimated time to complete: 30 minutes

22.2. Setting up a Tomcat Server

There should be a Servers folder in STS on the left hand side and it should be open. It should contain a Tomcat server ready to run.

If there is no such folder, or it is empty, you will need to setup a new server. For assistance see Appendix H, Using Web Tools Platform (WTP) for details.

22.3. Quick Instructions

Quick instructions for this exercise have been embedded within the lab materials in the form of TODO comments. To display them, open the Tasks view (Window >> Show View >> Tasks (not Task List)).

22.4. Detailed Instructions

The instructions for this lab are organized into two main sections. In the first section you will be briefed on the web application functionality you will implement in this lab, then you will review the pre-requisite infrastructure needed to develop with Spring MVC. In the remaining sections you will actually implement the required web application functionality.

22.4.1. Setting up the Spring MVC infrastructure

Spring MVC is a comprehensive web application development framework. Let’s see how we have used it to implement the current system.

22.4.1.1. The Requirement

The web application we are developing should allow users to see a list of all accounts in the system, then view details about a particular account. This desired functionality is shown below:

accountList

Figure 22.1. GET /accounts/accountList



You should see a listing of all accounts by name with links to view details. Once implemented, clicking on a link will take you to the account details page as shown below (however this is not yet implemented).

accountDetails

Figure 22.2. Show Details for Account '0'



22.4.1.2. Running the application

In this first step you will assess the initial state of the web application.

(TODO-01) Begin by deploying the web application this project as-is (see Appendix H, Using Web Tools Platform (WTP) for how to run).

Once deployed, navigate to the index page at http://localhost:8080/mvc. You should see the index page display. Now click the View Account List link. You should see a list of accounts display successfully. This 'accountList' functionality has been pre-implemented for you. We will review and change some of that in a moment, but it at least gets you started with the application.

[Note] Note

If your application deploys successfully there should be a lot of logging output in the console window and the images on the page should appear correctly. If you have problems, try the following before asking for help. Stop the server. Right-click on the server in the Servers panel and select Clean …​. Now right-click again on the server and select Clean Work Directory …​. Try running the server again.

Now try clicking on one of the account links. You will get a 404 indicating there is no handler for this request because the 'accountDetails' functionality has not yet been implemented.

22.4.1.3. Review the application configuration

Quickly assess the initial configuration of the "backend" of this web application. To do this, open WebInitializer in the config package. Notice that the root configuration has already been defined to bootstrap your application-layer from RootConfig class. Open this file to see the beans that make up this layer. You will see that it simply imports other configurations and establishes transaction management, all with just a few annotations.

The accountManager is the key service that can load accounts from the database for display. The web layer, which will be hosted by the Spring MVC DispatcherServlet, will call into this service to handle user requests for account information.

With an understanding of the application-layer configuration, move on to the next step to review the web-layer configuration.

22.4.1.4. Review the Spring MVC DispatcherServlet configuration

The central infrastructure element of Spring MVC is the DispatcherServlet. This servlet’s job is to dispatch HTTP requests made to the web application to handlers you define. As a convenience, this lab has already deployed a DispatcherServlet for you with a basic boilerplate configuration. In this step, you will review this configuration and see how the existing functionality of the web application is implemented.

Return to WebInitializer and notice MvcConfig is listed as the servlet config class. Also notice that a /accounts/* path is mapped to it.

Now open the MvcConfig configuration class and review it. First, notice how component scanning is used to detect all controllers within a specific package. This keeps us from having to define individual bean declarations for each controller, which can be great when we have dozens or hundreds of controllers. Other than this, the configuration is largely empty.

Next, review the Java implementation of the AccountController to see how it works. Notice how the @RequestMapping annotation ties the /accountList URL to the accountList() method and how this method delegates to the AccountManager to load a list of Accounts. This list is added to the model for display to the user. Finally it requests the accountList.jsp view to render the list by returning its location as a String telling the DispatcherServlet to use this view to render the model.

[Note] Note

Notice that the view name is specified as the full path relative to the Servlet’s context root. The default ViewResolver simply forwards to the resource at that location. We fix that next.

22.4.1.5. Reviewing the whole system

Lets quickly summarize the big picture. Return to your web browser, and click on the "View Account List" link again. You should see the account list display again successfully. Clicking on that link issued a GET request to http://localhost:8080/mvc/accounts/accountList which set the following steps in motion:

  1. The request was first received by the Servlet Engine, which routed it to the DispatcherServlet.
  2. The DispatcherServlet then invoked the accountList() method on the AccountController based on the @RequestMapping annotation.
  3. Next, the AccountController loaded the account list and selected the "accountList.jsp" view.
  4. Finally, the accountList.jsp rendered the response which you see before you.

At this point you should have a good feel for how everything works so far. You should also have an idea of how to add the remaining "accountDetails" functionality to this application. You simply need to define a new method encapsulating this functionality, test it, and map it to the appropriate URL. You’ll do that soon.

But first let’s get rid of those absolute paths to views.

22.4.2. Add a View Resolver

The view name in our handler method uses an absolute path. this means the method is aware of the specific type of view that will be rendered (JSPs in this case). Spring recommends decoupling request handling from response rendering details. In this step, you will add a ViewResolver to provide a level of indirection.

(TODO-02) Navigate to the MvcConfig class and add a bean definition of type InternalResourceViewResolver. This will override the default ViewResolver and enable the use of logical view names within the Controller code. You should now specify two properties on the view resolver bean definition: prefix and suffix. Review the current view names to determine these values.

[Tip] Tip

The DispatcherServlet automatically recognizes any bean definitions of type ViewResolver. Therefore, you can use any method name for your @Bean method (recall that the method name defines the bean name).

Now refactor the existing controller (TODO-03) and test (TODO-04) so that only a simple view name such as accountList is used. The AccountControllerTests should now pass.

Now (TODO-05) restart the web application. If you are still able to view the list of accounts, your changes are correct.

22.4.3. Implementing another Spring MVC handler method

Now you will implement the handler method that supports the functionality for the missing account details page. Once you have completed this section, you will no longer get a 404 when you click on an account link from the account list view. Instead, you will see the details of that account.

22.4.3.1. Implement the account details request handler

(TODO-06) In the AccountController, add a method to handle requests for account details. The method should use the account identifier passed with the HTTP request to load the account, add it to the model, and then select a view. What name (key) will you use for the account attribute when you add it to the model?

[Tip] Tip

In your web browser, try clicking on an account and look at the URL to see which parameter name is used to pass in the account identifier. Ignore the 404 error.

The JSP has already been implemented for you. Review it in the WEB-INF/views directory to see what attribute name it is expecting.

22.4.3.2. Testing the controller

We’re almost done! There are two things we still have to do. First of all, we have to test the controller.

(TODO-07) Open AccountControllerTests and review how the accountList() method has been tested. As you can see, it just calls the handler method (without having to worry about doing any web setup) and inspects if the model has been correctly filled. In this step, we will do the same for the accountDetails() method.

Implement a method called testHandleDetailsRequest() to test the controller - in a similar way to testHandleListRequest(). There should be one attribute in the model. What is its name? What type is it? Get the attribute and confirm it contains the right data. Don’t forget to annotate the new method with @Test.

[Note] Note

The ability to test Spring MVC Controllers out-of-the-container is a useful feature. Strive to create a test for each controller in your application. You’ll find it proves more productive to test your controller logic using automated unit tests, than to rely solely on manual testing within your web browser.

When all tests pass, carry on.

22.4.4. Running the application

Finally (TODO-08) try to run the web application again and make sure the functionality you implemented works. If it doesn’t, try to find where you might have gone wrong and possibly talk to your instructor.

22.4.5. EXTRA CREDIT: Mock MVC Testing

If there is time left, you can try this optional section.

Spring’s Mock MVC testing framework allows a JUnit test to drive Spring MVC as if it was running in a container - enabling more powerful testing that the simple AccountControllerTests you have been using.

Open the class MockMvcTests and follow the TODO steps. Most of the code has been written for you. The important part is to see if you understand how the tests work - we did not cover Mock MVC testing in the course notes.

For more information, refer to the Online Documentation