How to create a basic Spring MVC web

How to createa Spring MVC web application using maven. We will start from scratch creating the project with maven, then we will add some depencencies and create the java code. Finally we will build the .war file.

Project initial setup

First of all we are going to start creating the project with maven.

mvn archetype:generate -DgroupId=com.testspringmvc.app -DartifactId=TestSpringMVC -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

This creates a project called TestSprintMVC with the following file structure:

TestSpringMVC/
├── pom.xml
└── src
    └── main
        ├── resources
        └── webapp
            ├── index.jsp
            └── WEB-INF
                └── web.xml

5 directories, 3 files

Now we are going to convert it to an eclipse project. This step is not necessary if you are not going to use eclipse as IDE:

cd TestSpringMVC/
mvn eclipse:eclipse -Dwtpversion=2.0

With the parameter -Dwtpversion=2.0 we change the pom.xml to generate a .war instead a .jar file as output.

 

Library configuration

All the library configuration is done in the POM.xml file. We are going to add the following libraries:

groupId artifactId version scope
org.springframework spring-core 4.2.6.RELEASE
org.springframework spring-web 4.2.6.RELEASE
org.springframework spring-webmvc 4.2.6.RELEASE
org.springframework spring-context 4.2.6.RELEASE
org.slf4j slf4j-nop 1.7.21
jstl jstl 1.2
junit junit 4.12 test
org.springframework spring-test 4.2.6.RELEASE test
javax.servlet javax.servlet-api 3.1.0 test

You can download this pom.xml file fom: Download pom.xml

You can check the latest versions of this libraries in http://search.maven.org/

Coding with spring

We are going to create different packages and java classes. Inside src/main we are going to create the java folder. Then we are going to create two packages com.testspringmvc.app.data and com.testspringmvc.app.web.

TestSpringMVC/src/main/java/com/testspringmvc/app/
├── data
│   ├── ApplicationFactoryBean.java
│   └── BasicModelBean.java
└── web
    └── BaseController.java

Now in the com.testspringmvc.app.data package we are going to create our data model. It is a simple data model which only stores an integer value:

package com.testspringmvc.app.data;
public class BasicModelBean {
	int data;
	public void init() {
		data = 1;
	}
	public void destroy() {
		data = 0;
	}
	public void setData(int data) {
		this.data = data;
	}
	public int getData() {
		return data;
	}
}

We are going to register this class as a Bean in order to make it available in different parts of the application. We will do it with the help of the class ApplicationFactoryBean.

package com.testspringmvc.app.data;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ApplicationFactoryBean {
	@Bean(initMethod = "init", destroyMethod = "destroy")
	public BasicModelBean basicModelBean(){
		return new BasicModelBean();
	}
}

Then we need the controller, the class which will receive the http requests and will use the data model accordingly. This class will be in the com.testspringmvc.app.web package:

package com.testspringmvc.app.web;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.testspringmvc.app.data.BasicModelBean;

@Controller
public class BaseController {
	static Logger log = Logger.getLogger(BaseController.class);

	@Autowired
	BasicModelBean basicModel;

	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String indexPage(ModelMap model) {
		log.debug("Called indexPage");
		int v = basicModel.getData();
		model.addAttribute("data", ++v);
		basicModel.setData(v);
		return "index";
	}
}

What this controller does is to get the basicModel singlenton and increments in one the value of the data. Then it puts this new value in the web model attribute (ModelMap class) and save it in the singleton.
The return “index” of this method just tells the ViewResolver implementation which view return. In this case it will be the file index.jsp that we will create in the next section.

 

Spring MVC configuration

Now we have to update the file main/webapp/WEB-INF/web.xml:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
 <display-name>Test Spring MVC</display-name>
 
 <servlet>
  <servlet-name>webmvc-dispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>webmvc-dispatcher</servlet-name>
  <url-pattern>/</url-pattern>
 </servlet-mapping>
 
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/webmvc-dispatcher-servlet.xml</param-value>
 </context-param>
 
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
</web-app>

We have updated the servlet version to 3.1. What we say here to the servlet container is that we have a servlet called webmvc-dispatcher that will be called when we request a URL under /, which in effect means all the URLs. This servlet will be implemented by the spring class DispatcherServlet. And the configuration parameters for the DispatcherServlet class are found in the file: /WEB-INF/webmvc-dispatcher-servlet.xml.

Now the content of the file /WEB-INF/webmvc-dispatcher-servlet.xml:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.testspringmvc.app" />

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/views/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>

</beans>

This file contains all the Spring required configuration. The context:component-scan tag is used for Spring to find all the Spring relevant annotation like @Controller, @Bean,…

The tag bean creates one bean based on the class InternalResourceViewResolver. This is the class incharged of providing the view redering. It will search for this pages with extension .jsp in the directory /WEB-INF/views/.

Now we need to create a file called index.jsp in the directory /WEB-INF/views/. This is because our BaseController.java will always return “index”.

The file index.jsp will be something like this:

<html>
<body>
<h2>Hello World!</h2>
<h2>Data : ${data}</h2>
</body>
</html>

The value ${data} is the one that we defined in BaseController.indexPage(ModelMap) with the line:

model.addAttribute(&amp;amp;amp;amp;quot;data&amp;amp;amp;amp;quot;, ++v);

We can remove the original file src/main/webapp/index.jsp, we do not need it.

Testing

It is recommended to create unitary tests for all the classes we create. Here we are going to write some simple tests just to show how should be implemented.
All the tests will be under the folder src/test/java. There we will have two packages and two classes to test our implementation. The test directory tree will be something like this:

TestSpringMVC/src/test/
└── java
    └── com
        └── testspringmvc
            └── app
                ├── data
                │   └── BasicModelBeanTest.java
                └── web
                    └── BaseControllerTest.java

First we are going to write the class BasicModelBeanTest:

package com.testspringmvc.app.data;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;

import com.testspringmvc.app.data.BasicModelBean;
import com.testspringmvc.app.data.ApplicationFactoryBean;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationFactoryBean.class, loader = AnnotationConfigContextLoader.class)
public class BasicModelBeanTest {
	@Autowired
	BasicModelBean basicModel;
	@Test
	public void testSetDataValue() {
		Assert.assertEquals(basicModel.getData(), 1);
		basicModel.setData(2);
		Assert.assertEquals(basicModel.getData(), 2);
	}
}

In this simple class we load the BasicModelBean class and check that the initial value of getData is 1 and that we can change that value. It is a simple test.

Now we want to test the controller and see if the view returned is correct. To do that we will implement the class BaseControllerTest.

package com.testspringmvc.app.web;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration // This provides a mock ServletContext
@ContextConfiguration({ "file:src/main/webapp/WEB-INF/webmvc-dispatcher-servlet.xml" })
public class BaseControllerTest {

	private MockMvc mockMvc;
	@Autowired
	private WebApplicationContext context;

	@Before
	public void init() throws NoSuchFieldException {
		this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
	}

	@Test
	public void get_correct_data() throws Exception {
		mockMvc.perform(MockMvcRequestBuilders.get("/")).andExpect(status().isOk())
				.andExpect(view().name("index"))
				.andExpect(model().attribute("data", 2));

		mockMvc.perform(MockMvcRequestBuilders.get("/")).andExpect(status().isOk())
				.andExpect(model().attribute("data", 3));
	}
}

In BaseControllerTest we mock http calls and see how the class BaseController responds.

Se puede probar los tests en linea de comandos ejecutando:

TestSpringMVC$ mvn test

Logging

In the class BaseController we added some basic logging using log4j, here we are going to configure in the files called log4j.properties. We are going to create two, one for testing and the other for a real installation.

The one for testing will go in src/test/resources/log4j.properties:

log4j.rootLogger=DEBUG, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %-5p %c{1}:%L - %m%n

The one deployed will go in src/main/resources/log4j.properties:

log4j.rootLogger=INFO, file
log4j.appender.file.layout.ConversionPattern=%d %-5p %c{1}:%L - %m%n
log4j.appender.file.File=${catalina.base}/logs/testspringmvc.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.MaxBackupIndex=1
log4j.appender.file.MaxFileSize=100KB
log4j.appender.file=org.apache.log4j.RollingFileAppender

Compiling and publishing

To compile you only need to execute:

mvn package

This will generate the file target/TestSpringMVC.war which can be deployed in a servlet container.

References:
More about Spring MVC: Tutorialspoint
More about Sprint MVC testing: MVC unit test

Source Codehttps://github.com/calabozo/TestSpringMVC

 

1 thought on “How to create a basic Spring MVC web

  1. Pingback: JGiven with Spring | Small tips that I don't want to forget

Leave a comment