Building Spring MVC with Maven

This article assumes that your workspace is C:\www.

Generating archetype

C:\ Command Prompt
C:\www>mvn archetype:generate -Dfilter=maven-archetype-webapp
Choose archetype:
1: remote -> org.apache.maven.archetypes:maven-archetype-webapp 
(An archetype which contains a sample Maven Webapp project.)
Choose a number or apply filter 
(format: [groupId:]artifactId, case sensitive contains): : 1
1: 1.0-alpha-1
2: 1.0-alpha-2
3: 1.0-alpha-3
4: 1.0-alpha-4
5: 1.0
Choose a number: 5: ↵
Define value for property 'groupId': : net.java_school
Define value for property 'artifactId': : spring-bbs
Define value for property 'version':  1.0-SNAPSHOT: : ↵
Define value for property 'package':  net.java_school: : ↵
Confirm properties configuration:
groupId: net.java_school
artifactId: spring-bbs
version: 1.0-SNAPSHOT
package: net.java_school
 Y: : ↵

When the build is complete, the spring-bbs folder is created at C:\www.
C:\www\spring-bbs is the root directory of the Maven project.

Since src/main/webapp right above WEB-INF is the documentbase, create the Tomcat context file as below.

spring-bbs.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context
    docBase="C:/www/spring-bbs/src/main/webapp"
    reloadable="true">
</Context>

Copy the spring-bbs.xml file to the CATALINA_HOME/conf/Catalina/localhost folder.
After restart Tomcat, visit http://localhost:8080/spring-bbs to see the web application is working.

Spring MVC Test

Modify pom.xml as shown below.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
    http://maven.apache.org/maven-v4_0_0.xsd">
    
  <modelVersion>4.0.0</modelVersion>
  <groupId>net.java_school</groupId>
  <artifactId>spring-bbs</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>spring-bbs Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <properties>
    <spring.version>5.2.1.RELEASE</spring.version>
    <jdk.version>11</jdk.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${spring.version}</version>
    </dependency>    
    <!-- Oracle JDBC Driver -->
    <dependency>
      <groupId>com.oracle</groupId>
      <artifactId>ojdbc6</artifactId>
      <version>11.2.0.2.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
    <dependency>
      <groupId>commons-dbcp</groupId>
      <artifactId>commons-dbcp</artifactId>
      <version>1.4</version>
    </dependency>
    <!-- Logging -->
    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.12.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.12.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-jcl -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-jcl</artifactId>
        <version>2.12.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.4</version>
    </dependency>    
    <!-- Servlet JSP JSTL -->
    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.1</version>
      <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/jstl/jstl -->
    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
  </dependencies>
  <build>
    <finalName>spring-bbs</finalName>
    <pluginManagement>
      <plugins>
	      <plugin>
		      <artifactId>maven-compiler-plugin</artifactId>
		      <version>3.1</version>
		      <configuration>
			      <source>${jdk.version}</source>
			      <target>${jdk.version}</target>
			      <compilerArgument></compilerArgument>
			      <encoding>UTF-8</encoding>
		      </configuration>
	      </plugin>
	      <plugin>
		      <artifactId>maven-clean-plugin</artifactId>
		      <version>2.4.1</version>
		      <configuration>
			      <filesets>
				      <fileset>
					      <directory>src/main/webapp/WEB-INF/classes</directory>
				      </fileset>
				      <fileset>
					      <directory>src/main/webapp/WEB-INF/lib</directory>
				      </fileset>
			      </filesets>
		      </configuration>
	      </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

Oracle JDBC is not provided by the Maven repository.
Therefore, you have to save ojdbc6.jar to the local repository with the following command.

mvn install:install-file -Dfile=ojdbc6.jar -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.2.0 -Dpackaging=jar

You can download ojdbc6.jar from http://www.oracle.com/technetwork/apps-tech/jdbc-112010-090769.html.

Modify web.xml as shown below.

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<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"
  metadata-complete="true">
    
  <display-name>Spring BBS</display-name>
	
  <filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
      </init-param>
      <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
        
  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
    
  <servlet>
    <servlet-name>spring-bbs</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
    
  <servlet-mapping>
    <servlet-name>spring-bbs</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  
  <error-page>
    <error-code>404</error-code>
    <location>/WEB-INF/views/400.jsp</location>
  </error-page>

  <error-page>
    <error-code>500</error-code>
    <location>/WEB-INF/views/500.jsp</location>
  </error-page> 
 
</web-app>

A filter that calls setCharacterEncoding ("UTF-8") for every request is required for non-English language Web sites, and it must be declared before any other filters.

Spring MVC's DispatcherServlet servlet is declared and mapped.
Because the name of the DispatcherServlet is spring-bbs, the name of the Spring configuration file is determined by sprng-bbs-servlet.xml.
Create a spring-bbs-servlet.xml file in the WEB-INF folder as shown below.

spring-bbs-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:mvc="http://www.springframework.org/schema/mvc"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc.xsd">
	
</beans>

Create the following Java source for testing.

Player.java
package net.java_school.soccer;

public class Player {
	private String id;
	private String passwd;
	private String name;
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPasswd() {
		return passwd;
	}
	public void setPasswd(String passwd) {
		this.passwd = passwd;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
}
PlayerDao.java
package net.java_school.soccer;

public class PlayerDao {

	public Player selectOne(String id) {
		Player player = new Player();
		if (id != null && id.equals("1")) {
			player.setName("Lionel Messi");
		} else if (id != null && id.equals("2")) {
			player.setName("Cristiano Ronaldo");
		} else {
			player.setName("Neymar");
		}
		return player;
	}

}
PlayerService.java
package net.java_school.soccer;

public class PlayerService {
	private PlayerDao dao;
	
	public void setDao(PlayerDao dao) {
		this.dao = dao;
	}

	public Player getPlayer(String id) {
		return dao.selectOne(id);
	}
	
}
PlayerController.java
package net.java_school.soccer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

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 PlayerController implements Controller {
	
	private PlayerService service;
	
	public void setService(PlayerService service) {
		this.service = service;
	}
	
	public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse res) throws Exception {
		String id = req.getParameter("id");
		Player player = service.getPlayer(id);
		
		Map<String, Object> model = new HashMap<String, Object>();
		model.put("player", player);
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("/WEB-INF/views/player/test.jsp");
		modelAndView.addAllObjects(model);
		
		return modelAndView;
	}
	
}

Create test.jsp as shown below.

/src/main/webapp/WEB-INF/views/player/test.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>TEST</title>
</head>
<body>
${player.name }
</body>
</html>
C:\ Command Prompt
C:\www\sprng-bbs>mvn clean compile war:inplace

Restart Tomcat and visit http://localhost:8080/spring-bbs/player/test?id=1.

SimpleUrlHandlerMapping

Change the handler mapping to use SimpleUrlHandlerMapping.
Open the spring-bbs-servlet.xml file and modify it as shown below.

spring-bbs-servlet.xml
<!-- omit -->

<!-- HandlerMapping -->
<bean id="handlerMapping" 
  class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	
  <property name="mappings">
    <value>
	/player/test=playerController
    </value>
  </property>
	
</bean>

<bean id="playerController" 
  class="net.java_school.soccer.PlayerController"
  p:service-ref="playerService" />
	
<!-- omit -->

The name attribute of the playerController element must be removed.

<bean id="playerController" name="/player/test"

Restart Tomcat and visit http://localhost:8080/spring-bbs/player/test?id=1.

InternalResourceViewResolver

InternalResourceViewResolver is an intuitive and easy to understand view resolver.
Open the spring-bbs-servlet.xml file and add the following to the <!-- ViewResolver --> section.

spring-bbs-servlet.xml
<!-- ViewResolver -->
<bean id="internalResourceViewResolver" 
	class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="viewClass">
		<value>org.springframework.web.servlet.view.JstlView</value>
	</property>
	<property name="prefix">
		<value>/WEB-INF/views/</value>
	</property>
	<property name="suffix">
		<value>.jsp</value>
	</property>
</bean>

Modify PlayerController.java as shown below.

PlayerController.java
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("player/test");
modelAndView.addAllObjects(model);

return modelAndView;

With the InternalResourceViewResolver setting, player/test will be interpreted as /WEB-INF/views/player/test.jsp.
Since the Java source has changed, rebuild it.
Restart Tomcat and visit http://localhost:8080/spring-bbs/player/test?id=1.

RequestMappingHandlerMapping

SimpleUrlHandlerMapping requires one controller per request.
With RequestMappingHandlerMapping, you can place a controller by use case.
RequestMappingHandlerMapping uses annotations and auto-scans for handler mappings.
Open the spring-bbs-servlet.xml file and remove the <! - HandlerMapping - >.
Modify spring-bbs-servlet.xml as shown below.

spring-bbs-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"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:p="http://www.springframework.org/schema/p"
	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
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc.xsd">
	
	<mvc:annotation-driven />
		
	<context:component-scan
		base-package="net.java_school.soccer" />
	
	<!-- ViewResolver -->
	<bean id="internalResourceViewResolver" 
		    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass">
			<value>org.springframework.web.servlet.view.JstlView</value>
		</property>
		<property name="prefix">
			<value>/WEB-INF/views/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>
	
	<bean id="playerService" class="net.java_school.soccer.PlayerService">
		<property name="dao" ref="playerDao" />
	</bean>
	
	<bean id="playerDao" class="net.java_school.soccer.PlayerDao" />
	
</beans>

<context:component-scan base-package="net.java_school.soccer" /> allows Spring to automatically find and register the annotated component.
(the component means Dao, Service, Controller)
With this setting, you can omit specific handler mapping settings from the Spring configuration file.
<mvc: annotation-driven /> makes all the annotation-based features available.
<context:component-scan /> does not work without <mvc:annotation-driven / >.
You need to annotate the controller to find the controller.
Modify the PlayerController.java file as follows:

PlayerController.java
package net.java_school.soccer;

import org.springframework.beans.factory.annotation.Autowired;
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("/player")
public class PlayerController {
	
	@Autowired
	private PlayerService service;
	
	@RequestMapping(value="/test", method={RequestMethod.GET, RequestMethod.POST})
	public String pickPlayer(String id, Model model) {
		Player player = service.getPlayer(id);
		model.addAttribute("player", player);
		return "player/test";
	}
}

After Bulid, restart Tomcat and visit http://localhost:8080/spring-bbs/player/test?id=1.

Annotations in PlayerController.java
@Controller in the class declaration indicates that the class is a controller component.
@RequestMapping("/player") in the class declaration indicates that the controller is responsible for all requests involving "/player".
@RequestMapping(value="/test",method={RequestMethod.GET,RequestMethod.POST}) in the method declaration indicates that the method is called in the "/player/test" request of GET or POST method.
@Autowired in the variable declaration causes the dependent object to be injected without a setter.
Even if the accessor of the variable is private, it is injected.

Component scan is running.
So if you apply annotations to services and Dao, you can omit these settings in spring-bbs-servlet.xml.

PlayerDao.java
package net.java_school.soccer;

import org.springframework.stereotype.Repository;

@Repository
public class PlayerDao {

	public Player selectOne(String id) {
		Player player = new Player();
		if (id != null && id.equals("1")) {
			player.setName("Lionel Messi");
		} else if (id != null && id.equals("2")) {
			player.setName("Cristiano Ronaldo");
		} else {
			player.setName("Neymar");
		}
		return player;
	}

}
PlayerService.java
package net.java_school.soccer;

import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;

@Service
public class PlayerService {
	@Autowired
	private PlayerDao dao;
	
	public Player getPlayer(String id) {
		return dao.selectOne(id);
	}
	
}

The Spring configuration file is simplified as follows:

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

	<mvc:annotation-driven />
		
	<context:component-scan
		base-package="net.java_school.soccer" />
		
	<!-- ViewResolver -->
	<bean id="internalResourceViewResolver" 
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass">
			<value>org.springframework.web.servlet.view.JstlView</value>
		</property>
		<property name="prefix">
			<value>/WEB-INF/views/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>
	
</beans>

Set up the project in eclipse

Start Eclipse and select your workspace as C:\www.
In the Project Explorer view, use the right mouse button to display the context menu.
Import the spring-bbs project into Eclipse.
Context menu Import
Maven Project Import
If the pom.xml file changes, you need to synchronize pom.xml with Eclipse.
eclipse and pom.xml synchronized

References