How can I create a simple web application using Spring MVC?

Filed under: J2EE, Java, Maven, — Tags: MVC, Spring, TDD, jsp, xml — Thomas Sundberg — 2009-04-06

I want to to create a very simple web application using Spring. I want to create it using Maven as build tool.

Start with the usual Maven directory setup:

example
|-- pom.xml
`-- src
    |-- main
    |   |-- java
    |   |   `-- se
    |   |       `-- somath
    |   |           `-- experimental
    |   |               `-- controller
    |   |                   `-- SimpleFormController.java
    |   `-- webapp
    |       |-- index.html
    |       `-- WEB-INF
    |           |-- jsp
    |           |   `-- landingPage.jsp
    |           |-- SimpleSample-servlet.xml
    |           `-- web.xml
    `-- test
        `-- java
            `-- se
                `-- somath
                    `-- experimental
                        `-- controller
                            `-- SimpleFormControllerTest.java

Let's start with the content of the Maven pom:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.somath.experimental</groupId>
    <version>1.0-SNAPSHOT</version>
    <artifactId>MavenSpringWeb</artifactId>
    <name>Maven Spring Web</name>
    <packaging>war</packaging>
    <description>Demonstration on how to build a simple web app using Maven and Spring</description>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>2.5.6</version>
        </dependency>
    </dependencies>
</project>

This is a fairly standard pom. The dependency list isn't anything exotic. We want JUnit, we always do. And we need spring-webmvc since this is the framework we want to use.

The next step is to develop a simple controller, connect it and create a form to call it from and a landing page to display the result.

Let's start with a test for the controller:

src/test/java/se/somath/experimental/controller/SimpleFormControllerTest.java

package se.somath.experimental.controller;

import org.junit.Test;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

public class SimpleFormControllerTest {

    @Test
    public void AsserProperLandingPage() {
        SimpleFormController simpleFormController = new SimpleFormController();
        Model model = new ExtendedModelMap();

        String expectedLandingPageName = "landingPage";
        String expectedName = "My Name";
        String expectedHiddenParameter = "My Hidden Attribute";

        String actualLandingPageName = simpleFormController.mirrorGet(expectedName, expectedHiddenParameter, model);
        String actualName = (String) model.asMap().get("name");
        String actualHiddenParameter = (String) model.asMap().get("hiddenParameter");

        assertThat(actualLandingPageName, is(expectedLandingPageName));
        assertThat(actualName, is(expectedName));
        assertThat(actualHiddenParameter, is(expectedHiddenParameter));
    }
}

This is a simple JUnit test. The only exotic here might be the annotation @Test that is used to indicate that this is a JUnit test that should be verified every time we build the project with Maven. We verify that a model contains some expected values and that the return value from the controller is the name of a landing page. In this case it will be a jsp.

The next step would be to compile the project with

mvn install

This will of course fail, we haven't implemented the controller. Let's do that in:

src/main/java/se/somath/experimental/controller/SimpleFormController.java

package se.somath.experimental.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/form")
public class SimpleFormController {

    @RequestMapping(method = RequestMethod.GET)
    public String mirrorGet(String name, String hiddenParameter, Model model) {
        model.addAttribute("name", name);
        model.addAttribute("hiddenParameter", hiddenParameter);

        return "landingPage";
    }

    @RequestMapping(method = RequestMethod.POST)
    public String mirrorPost(String name, String hiddenParameter, Model model) {
        return mirrorGet(name, hiddenParameter, model);
    }
}

The things to notice here are the annotations

The @Controller annotation will indicate to Spring that this is a controller, the C in a Model View Controller, MVC, framework.

The @RequestMapping("/form") indicates that this controller should be called when somebody sends a request to web application with the name indicated in the pom earlier, MavenSpringWeb-1.0-SNAPSHOT/aServletName/form. AservletName isn't defined yet, it will be defined soon in web.xml.

The @RequestMapping(method = RequestMethod.GET) and @RequestMapping(method = RequestMethod.POST) indicates which method that should be called when a get or a post is received. To keep things simple, I just forward all calls to post to get and forget about them.

The get method doesn't really do anything interesting. This is where you probably would place a call to your model, perform some computing and then return the control to the method and view some kind of answer to the user. All I do is mirror two parameters and instruct that the view to show the user should be something called 'landingPage'.

Ok, we have a test and we have some production code. Now we want to make sure that this can be used as a part of a web application. Lets start with defining a web.xml so we get a servlet that will help us to forward any calls to our controller. Let's define it in

src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
        "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>Simple Sample</display-name>
    <servlet>
        <servlet-name>SimpleSample</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>SimpleSample</servlet-name>
        <url-pattern>/SimpleSample/*</url-pattern>
    </servlet-mapping>
</web-app>

All we do here is stating that we want a servlet bundled with Spring to be used as a dispatcher, org.springframework.web.servlet.DispatcherServlet.

Then we map this servlet so it catches any call to /SimpleSample with the row:

<url-pattern>/SimpleSample/*</url-pattern>

Spring requires that we define a file called ServletName-servlet.xml which will be SimpleSample-servlet.xml in our case. Define it in

src/main/webapp/WEB-INF/SimpleSample-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-2.5.xsd"
       default-autowire="byName">
    <context:component-scan base-package="com.agical.experimental"/>
    <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

The things to note here are:

We will use jsp as view technology. This could be a number of other technologies, but jsp will be good enough in this case.

The prefix defines a location where we should locate our jsp pages and the suffix indicates that they will be called .jsp.

So now we have a test, a controller, we define a servlet that will dispatch calls to the controller and we have defined a way to display the result. Let's create a jsp page that will be used to view the result. Create it in:

src/main/webapp/WEB-INF/jsp/landingPage.jsp

<%--@elvariable id="name" type="String"--%>
<%--@elvariable id="hiddenParameter" type="String"--%>
<%@ page contentType="text/html;charset=ISO-8859-1" language="java" %>

Name: ${name}
<br>
HiddenParameter: ${hiddenParameter}

The two first rows will define variables for Intellij Idea, it is only there as a convenience for Idea users. The two rows that may be a bit interesting are:

Name: ${name}

HiddenParameter: ${hiddenParameter}

But the only thing we do here is to expand two variables so we can see the values we sent to the controller.

Finally we want to call the web application. This could be done from a browser. But it will be a bit easier if we define a web page with a form. This could be the subject for some automated testing using a tool like Selenium, but that is a bit out of scope today. Let's create a simple form in:

src/main/webapp/index.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
<html>
<body>

<form action="./SimpleSample/form" method="GET">
    Name: <input type="text" name="name"/>
    <br>
    <input type="hidden" name="hiddenParameter" value="My hidden value"/>
    <input type="submit" value="Submit"/>
</form>

</body>
</html>

If we build and deploy the web application, we should be able to see that what ever name we entered in the form will show up on the landing page.

Build the project with Maven:

mvn clean install

Deploy the result

targetMavenSpringWeb-1.0-SNAPSHOT.war

on a servlet container and try to access is with a url similar to http://localhost:8080/MavenSpringWeb-1.0-SNAPSHOT/

And the result should look something like this:

Resources



(less...)

Pages

About
Events
Why

Categories

Agile
Automation
BDD
Clean code
Continuous delivery
Continuous deployment
Continuous integration
Cucumber
Culture
Design
DevOps
Executable specification
Git
Gradle
Guice
J2EE
JUnit
Java
Javascript
Kubernetes
Linux
Load testing
Maven
Mockito
New developers
Pair programming
PicoContainer
Presentation
Programming
Public speaking
Quality
React
Recruiting
Requirements
Scala
Selenium
Software craftsmanship
Software development
Spring
TDD
Teaching
Technical debt
Test automation
Tools
Web
Windows
eXtreme Programming

Authors

Thomas Sundberg
Adrian Bolboaca

Archives

Meta

rss RSS