Creating Your First Spring Web MVC Application

In this article, based on chapter 3 of Spring in Practice, Willie Wheeler, John Wheeler and Joshua White show you how to build a simple Spring Java application to manage a roster.  You will write some Spring Web MVC code with a goal to get an intuitive feel for how things work in Spring Web MVC.

This article is based on Spring in Practice, to be published in April 2012. It is being reproduced here by permission from Manning Publications. Manning early access books and ebooks are sold exclusively through Manning. Visit the book’s page for more information.

In this article, we’ll build a simple application (in the broadest sense of the term) to manage a roster of some sort. We’re going to do this without tons of detailed explanation; our goal is just to get an intuition for how things work in Spring Web MVC rather than exhaustively cover all the bases. We’ll begin with our app configuration.

 

Configuring the application

Listing 1 shows a bare-bones web.xml configuration, but it will work just fine for us.

Listing 1 A simple DispatcherServlet configuration in web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>main</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet          #1
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>main</servlet-name>
<url-pattern>/main/*</url-pattern>                             #2
</servlet-mapping>
</web-app>

#1 Declares DispatcherServlet
#2 Maps requests to it

We’ve defined a minimal DispatcherServlet (#1), which is Spring Web MVC’s front controller, and we’ve indicated that we want to send /main/* requests to it (#2). We’re not tied to that particular mapping; that’s just what we have chosen.

Now, let’s see our application context. We didn’t define a ContextLoaderListener in web.xml above, so you might be wondering where the app context comes from. The answer is that each DispatcherServlet instance creates its own local app context using an XML configuration we provide, so here’s that configuration in listing 2.

Listing 2 /WEB-INF/main-servlet.xml, the DispatcherServlet’s local app context
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<bean name=”/roster/*”
/>            #1

<bean
p:prefix=”/WEB-INF/jsp/”
p:suffix=”.jsp”/>                                              #2
</beans>
#1 Our controller bean
#2 Maps view names to views

DispatcherServlet knows where to find this file by using a convention you can probably guess. We can configure the location, but we won’t worry about that right now.

First, we define our controller, which we’re calling RosterController (#1). The controller’s name specifies the requests that the RosterController services.

We’re also defining a ViewResolver (#2), which allows us to convert logical view names to views. For now, it’s enough to know that a logical view name such as foo will be converted to /WEB-INF/jsp/foo.jsp given the definition above. When dealing with JSP views in particular, it’s a good practice to place them somewhere inside the WEB-INF folder (WEB-INF/jsp is the official recommendation) so that clients can’t access them directly. That’s what we’re doing here.

We’re going to create a controller shortly, but, in preparation for that, let’s create a domain object to represent a member of our roster.

A simple domain object

Listing 3 shows Member.java, a simple domain object we’ll use in our controller.

Listing 3 Member.java
package springinpractice.ch3.model;

public class Member {
private String firstName;
private String lastName;

public Member() { }

public Member(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

public String getFirstName() { return firstName; }

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() { return lastName; }

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String toString() {
return firstName + ” ” + lastName;
}
}

There isn’t anything too special here. We’ve included two constructors because we’ll eventually need both of them.

Now let’s get to the controller, which is a little more interesting.

Writing a basic controller

In listing 4 we have our RosterController. For our purposes, it’s fine to simply hardcode some fake roster data, so that’s what we’ll do.

Listing 4 RosterController.java, our simple controller
package springinpractice.ch3.web;

import java.util.*;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import springinpractice.ch3.model.Member;

@Controller #1
public final class RosterController { #2
private List members = new ArrayList();

public RosterController() {
members.add(new Member(“John”, “Lennon”));
members.add(new Member(“Paul”, “McCartney”));
members.add(new Member(“George”, “Harrison”));
members.add(new Member(“Ringo”, “Starr”));
}

@RequestMapping #3
public void list(Model model) { #4
model.addAttribute(members); #5
}

@RequestMapping
public void member(@RequestParam(“id”) Integer id, Model model) { #6
model.addAttribute(members.get(id));
}
}
#1 @Controller for controllers
#2 Just a POJO
#3 Maps requests to method
#4 Model provided
#5 Passes data to view
#6 Accepts request param

There’s a lot packed into this small controller class, and we’re relying heavily on conventions. So don’t feel bad if you’re not seeing the details on how everything is wired up; we’ll have plenty of time to get to that in the pages ahead.

Because our controller is a POJO, it is useful for certain purposes (for example, for request mapping purposes) to have alternative way to flag it as a controller. That’s what the @Controller annotation is doing (#1). We’re not extending any other classes or implementing any interfaces (#2); we’re effectively defining our own contract for this controller.

WARNING: FAKE, HARDCODED DATA!

It should be obvious that we’ve just hardcoded the member list into the controller. In a real application you’d likely grab that from a service bean. But we’re just trying to see how the MVC part works so we’re just faking the member list.

We’ve attached a @RequestMapping attribute to the list() and member() methods (#3). This identifies the methods as request-servicing methods. The actual paths involved are specified by conventions; here the paths are /roster/list[.*] and /roster/member[.*] respectively, where * is any extension. For example, /roster/list, /roster/list.do, and /roster/list.html all map to the list() method.

The signature of the list() method is largely up to us. We declare whatever we’d like to have, within certain bounds, of course. (This is the part I really like about Spring Web MVC.) We’ve declared a Model parameter (#4), which means that Spring will automatically pass us a Model object (essentially it functions as a Map, even though doesn’t actually implement that interface). Anything we put on the Model will be available to the JSP as a JSP EL variable. Here, we’ve placed the list of members on the Model (#5). When we place objects on the model, they are stored as name/value pairs. Here, we haven’t explicitly assigned a name to the attribute, so Spring will automatically generate the name by convention. Since the type is List, the generated name is memberList. We’ll be able to access it from our JSP using ${memberList}.

At #6, we can see another example of the flexible method signatures in action. This time, we’ve declared that we want to accept an HTTP parameter called id, and we want it to be automatically parsed into an Integer. That’s exactly what happens here. (I told you it was cool.) And again, with the model we haven’t provided an explicit attribute name, so the name will be autogenerated based on the attribute type. Here, the name will be member, and it will be available to the JSP using ${member}.

You may have noticed that we haven’t explicitly specified any view names here. You might be wondering how DispatcherServlet knows which view gets the request after a given handler method is done with it. The answer is that we’re using a convention that automatically translates the request URL to a logical view name. Since the request URL for the list() method is /roster/list[.*], the view name according to the convention will be list. Similarly, since the request URL for the member() method is /roster/member[.*], the view name will be member.

Another thing to note is that we’ve defined a couple of different actions. We can define as many as we like, but for now we’re keeping it simple. Normally you would keep closely related functionality together in a single controller like we’re doing here.

Now let’s peek at our master and details JSPs.

Implementing our master and details views

First, listing 5 shows list.jsp, which displays the whole roster.

Listing 5 /WEB-INF/jsp/roster/list.jsp, a roster master page

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
<head>
<title>Roster</title>
</head>
<body>
<h1>Roster</h1>
<ul>
<c:forEach var=”member” items=”${memberList}”>              #1
<li>
<a href=”member.do?id=${status.index}”>           #2
<c:out value=”${member}”></c:out>
</a>
</li>
</c:forEach>
</ul>
</body>
</html>

#1 Member list exposed as ${memberList}
#2 Passing id param

In this listing, you can see that we’re able to reference the memberList attribute we set in the controller through a JSP EL variable (#1). We just list the members, with their names being links to details pages. You can also see that we’re passing an id parameter along, which the member() method expects, as we saw in listing 4.

The details page, member.jsp, appears in listing 6 below.

Listing 6 /WEB-INF/jsp/roster/member.jsp, a member details page

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Member: ${member}</title>
</head>
<body>
<h1>Member: ${member}</h1>                                     #1
<p><a href="list.do">Back</a></p>
</body>
</html>

#1 Member exposed as ${member}

Nothing too great happening here—we just have another example of grabbing data from the Model and displaying it in the JSP (#1).

Let’s stop at this point to admire the beauty of our work. Point your browser at http://localhost:8080/sip/main/roster/list.do. It won’t win any design awards, but it works.

Summary

We tried our hand at writing some Spring Web MVC code with a goal to get an intuitive feel for how things work in Spring Web MVC.

Related Posts:

One thought on “Creating Your First Spring Web MVC Application

Comments are closed.