spring

Spring with Maven Tutorial

In this post, we feature a comprehensive Tutorial on Spring with Maven. Spring Framework is a Java application framework that provides many useful services for building applications. Apache Maven is a software project management and comprehension tool. In this article, I will demonstrate how to build a web application utilizing Spring MVC framework as a Maven project.

1. Introduction

Apache Maven is a software project management and comprehension tool. Maven can manage a project’s build, reporting and documentation from a central piece of information based on the concept of a project object model (POM). Spring is a Java application framework that provides many useful services for building applications. It contains many modules such as core, beans, context, expression language, AOP, JDBC, JMS, Web, etc.

In this example, I will build a web application as a Maven project to demonstrate these Spring modules:

2. Technologies Used

The example code in this article was built and run using:

  • Java 1.8.101 (1.8.x will do fine)
  • Maven 3.3.9 (3.3.x will do fine)
  • Spring boot 1.5.14 (Higher version will do fine)
  • Spring 4.x (Higher version will do fine)
  • Eclipse Oxygen (Any Java IDE would work)
  • H2 Database

3. Spring Boot Web Application

There are many ways to create a Spring boot web application. The easiest way for me is via the Spring starter tool with the steps below:

  1. Go to https://start.spring.io/.
  2. Select Maven Project with Java and Spring Boot version 1.5.14 and type in webJPA, and H2 in the “search for dependencies” bar.
  3. Enter the group name as jcg.zheng.demo and artifact as spring-boot-web-jsp-demo.
  4. Click the Generate Project button.

A maven project will be generated and downloaded to your workstation. Import it into your Eclipse workspace.

3.1 Web Application Overview

In this example, I will build a web application with these features:

  1. Valid account users can login to view their account’s reward point and the transaction history.
  2. Invalid account users will be rejected by the application.
  3. A URL to load account transaction history.

3.2 Dependency

Maven pom.xml manages the project libraries. Here is the generated pom.xml from step 3.

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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<artifactId>spring-boot-web-jsp-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<name>spring-boot-web-jsp-demo</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.14.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- JSTL -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
		</dependency>

		<!-- Need this to compile JSP for Embedded Tomcat -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>		
		</dependency>
	
		<!-- Spring MVC -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
		</dependency>

	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

4. Web Views

I found it’s useful to define the web views first when working on a web application. There are four views based on the requirements:

  • Home view – the web application’s landing page.
  • Valid user’s view – a valid user can view the account reward point and the transaction history.
  • Invalid user’s view – display an error message to an invalid user.
  • Error view – the exception handling view.

All of these views are placed at webapp/WEB-INF/jsp directory. We will configure them in the application.properties at step 5.1.

4.1 Home View

In this step, I will create a home.jsp page, which displays the server’s local time, the welcome message from the Spring managed property, and a login form.

home.jsp

<!DOCTYPE html>

<html lang="en">
<head>

</head>
<body>

	<h1>Spring Boot Web JSP Example</h1>
	<h2>Message From Property: ${message}</h2>
	<h3>The time on the server is ${serverTime}.</h3>

	<form action="user" method="post">
		<input type="text" name="userName"><br> <input
			type="submit" value="Login">
	</form>

</body>

</html>

4.2 User View

In this step, I will create a user.jsp page to display a valid user’s reward point and the transaction history.

user.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<spring:url value="/css/main.css" var="demoCSS" />

<link href="${demoCSS}" rel="stylesheet">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>User Home Page</title>
</head>
<body>
	<h3>Hi ${account.firstname} ${account.lastname}!</h3>

	<p>Account Id: ${account.id}     Reward Point:${account.rewardPoint}</p>

	<h3>Transaction Detail</h3>

	<table>
		<tr>
			<th>Date</th>
			<th>Payee</th>
			<th>Description</th>
			<th>Amount</th>
		</tr>
		<c:forEach var="listValue" items="${account.transactions}">
			<tr>
				<td>${listValue.createdDate}</td>
				<td>${listValue.payeeName}</td>
				<td>${listValue.description}</td>
				<td>${listValue.amount}</td>
			</tr>
		</c:forEach>
	</table>

</body>
</html>

4.3 Invalid User View

In this step, I will create an invalidUser.jsp page to display an invalid user message.

invalidUser.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ page session="false"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Error</title>
</head>
<body>
	<h2>Invalid User!</h2>
	<p>${userName} is not found in the system!</p>
</body>
</html>

4.4 Error View

In this step, I will create an error.jsp page to handle any unexpected exceptions.

error.jsp

<!DOCTYPE html>

<html lang="en">
<head>

</head>
<body>

	<h1>Caught Unexpected Exception</h1>

	<h2>from: ${content}.</h2>
	<p>due to: ${error}.</p>

</body>

</html>

5. Spring MVC Framework

5.1 Configuration

Spring MVC framework configures the views based on the naming convention.

application.properties

# Spring MVC view prefix.
spring.mvc.view.prefix: /WEB-INF/jsp/

# Spring MVC view suffix.
spring.mvc.view.suffix: .jsp

# Locations of static resources.
spring.resources.staticLocations:/resources/static/

#disable the white label when using an embedded servlet container.
server.error.whitelabel.enabled = false

spring.mvc.throw-exception-if-no-handler-found=true

welcome.message: Hello from Spring boot Web JSP Demo!

5.2 Controller

@Controller is a stereotype annotation. It is a specialization of the @Component class and allows implementation classes to be auto-detected. It is a part of the Spring MVC framework and typically used on request handling methods along with a @RequestMapping annotation. It returns a ModelAndView object.

In this step, I will create a WelcomeController class which provides four methods:

  • welcome – maps to the web application root context ("/") and returns the home view.
  • user – maps to the web application user context ("/user") and returns the user view for a valid user andinvalidUser view for an invalid user.
  • setup – maps to the web application context ("/loadTestData").
  • exceptionHandler – annotates with @ExceptionHandler for any unexpected exceptions.

WelcomeController.java

package jcg.zheng.demo.spring;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import jcg.zheng.demo.spring.entity.Account;
import jcg.zheng.demo.spring.model.User;
import jcg.zheng.demo.spring.repository.AccountRepository;
import jcg.zheng.demo.spring.service.AccountService;
import jcg.zheng.demo.spring.util.TestData;

@Controller
public class WelcomeController {
	@Autowired
	private AccountService accountService;

	@Autowired
	private AccountRepository acctRep;

	// inject via application.properties
	@Value("${welcome.message:test}")
	private String message = "Hello World";

	@RequestMapping("/")
	public String welcome(Locale locale, Map model) {
		model.put("message", this.message);
		System.out.println("Home Page Requested, locale = " + locale);
		Date date = new Date();
		DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

		String formattedDate = dateFormat.format(date);

		model.put("serverTime", formattedDate);
		return "home";
	}

	@RequestMapping("/loadTestData")
	public String setup() {
		Account maryZheng = TestData.createDummy("maryZheng", "Mary", "Zheng");
		maryZheng.addTransactions(TestData.createTransaction("KOHL", "Birthday gifts", new BigDecimal(300)));
		maryZheng.addTransactions(TestData.createTransaction("Macy", "Allen clothes", new BigDecimal(100)));
		maryZheng.addTransactions(TestData.createTransaction("Home Depot", "house items", new BigDecimal(1000)));
		maryZheng.addTransactions(TestData.createTransaction("Wal-mart", "small items", new BigDecimal(60)));
		acctRep.save(maryZheng);

		Account demo = TestData.createDummy("demo", "Demo", "JCG");
		demo.addTransactions(TestData.createTransaction("Shop&Save", "food items", new BigDecimal(60)));
		demo.addTransactions(TestData.createTransaction("Webster", "school supplies", new BigDecimal(260)));
		acctRep.save(demo);

		return "home";
	}

	@RequestMapping(value = "/user", method = RequestMethod.POST)
	public String user(@Validated User user, Model model) {
		System.out.println("User Page Requested");
		model.addAttribute("userName", user.getUserName());

		Account foundUser = accountService.findByUsername(user.getUserName());
		if (foundUser != null) {
			model.addAttribute("account", foundUser);
			return "user";
		} else {
			return "invalidUser";
		}
	}

	@ExceptionHandler(Exception.class)
	public String exceptionHandler(HttpServletRequest request, Exception ex, Model model) {
		model.addAttribute("content", request.getRequestURL());
		model.addAttribute("error", ex.getMessage());
		return "error";
	}

}

Note: All methods return String instead of ModelAndView for easier test. Spring will wrap it as a ModelAndView object with the matching view name.

5.3 Model

Spring MVC framework provides the Model object to allow the controller class and UI view to pass the data between them. In this example, the User class contains the Account object which includes a list of RewardTransaction objects.

5.3.1 User

User class contains a user name and an account object.

User.java

package jcg.zheng.demo.spring.model;

import jcg.zheng.demo.spring.entity.Account;

public class User {

	private String userName;

	private Account account;

	public Account getAccount() {
		return account;
	}

	public void setAccount(Account account) {
		this.account = account;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

}

5.3.2 Account

Account class includes the first name, last name, and list of RewardTransaction.

Account.java

package jcg.zheng.demo.spring.entity;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "ACCOUNT")
public class Account {

	@Id
	@GeneratedValue
	@Column(name = "ID")
	private Integer id;
	
	@Column(name = "First_Name")
	private String firstname;
	
	@Column(name = "Last_Name")
	private String lastname;
	
	private String username;

	@OneToMany(mappedBy="account", cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = RewardTransaction.class)
	private List transactions = new ArrayList();

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	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 BigDecimal getRewardPoint() {
		return transactions.stream().map(RewardTransaction::getAmount)
        .reduce(BigDecimal.ZERO, BigDecimal::add);  
		 
	}

	public List getTransactions() {
		return transactions;
	}

	public void addTransactions(RewardTransaction transaction) {
		transaction.setAccount(this);
		this.transactions.add(transaction);
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

}

5.3.3 RewardTransaction

RewardTransaction includes the transaction date, amount, description, and payee name.

RewardTransaction.java

package jcg.zheng.demo.spring.entity;

import java.math.BigDecimal;
import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Entity
public class RewardTransaction {

	@Id
	@GeneratedValue
	private Long id;
	private Date createdDate;
	private BigDecimal amount;
	private String description;
	private String payeeName;

	@ManyToOne
	@JoinColumn(name = "ACCOUNT_ID")
	private Account account;

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getPayeeName() {
		return payeeName;
	}

	public void setPayeeName(String payeeName) {
		this.payeeName = payeeName;
	}

	public Date getCreatedDate() {
		return createdDate;
	}

	public void setCreatedDate(Date createdDate) {
		this.createdDate = createdDate;
	}

	public BigDecimal getAmount() {
		return amount;
	}

	public void setAmount(BigDecimal amount) {
		this.amount = amount;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public Account getAccount() {
		return account;
	}

	public void setAccount(Account account) {
		this.account = account;
	}

}

6. Spring Beans

In this step, I will create several Spring beans to manage the user’s reward account.

6.1 AccountRepository

In this step, I will create an AccountRepository interface with the findByUserName method and annotate it with Spring @Repository stereotype annotation.

AccountRepository.java

package jcg.zheng.demo.spring.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import jcg.zheng.demo.spring.entity.Account;

@Repository
public interface AccountRepository extends JpaRepository<Account, Integer> {
	@Query("SELECT acct from Account acct WHERE acct.username = :username")
	Account findByUserName(@Param("username") String userName);
}

6.2 AccountService

AccountService interface defines the findByUserName method.

AccountService.java

package jcg.zheng.demo.spring.service;

import jcg.zheng.demo.spring.entity.Account;

public interface AccountService {
	Account findByUsername(String username);

}

6.3 AccountServiceImpl

AccountServiceImpl implements AccountService interface and annotates it with @Service annotation. It depends the Spring AccountRepository bean and invokes its findByUserNamemethod.

AccountServiceImpl.java

package jcg.zheng.demo.spring.service.impl;

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

import jcg.zheng.demo.spring.entity.Account;
import jcg.zheng.demo.spring.repository.AccountRepository;
import jcg.zheng.demo.spring.service.AccountService;

@Service
public class AccountServiceImpl implements AccountService {

	@Autowired
	private AccountRepository acctDao;

	@Override
	public Account findByUsername(String username) {
		return acctDao.findByUserName(username);
	}
}

6.4 Java Configuration

The generated SpringBootWebApplication  is annotated with @SpringBootApplication. It is equivalent to use  @Configuration@EnableAutoConfiguration, and @ComponentScan with their default attributes.

We will annotate it with @EnableJpaRepositories. It enables Spring to scan the base package and all its sub-packages for any interfaces extending Repository or one of its sub-interfaces. For each interface found, Spring creates the appropriate bean to handle invocation of the query methods.

SpringBootWebApplication.java

package jcg.zheng.demo.spring;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaRepositories(basePackages = "jcg.zheng.demo.spring")
public class SpringBootWebApplication extends SpringBootServletInitializer {

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(SpringBootWebApplication.class);
	}

	public static void main(String[] args) throws Exception {
		SpringApplication.run(SpringBootWebApplication.class, args);
	}

}

7. Junit Tests

7.1 AccountTest

we will test the Account class’ getRewardPoint method which is used in the user view.

AccountTest.java

package jcg.zheng.demo.spring.entity;

import static org.junit.Assert.assertEquals;

import java.math.BigDecimal;

import org.junit.Test;

import jcg.zheng.demo.spring.util.TestData;

public class AccountTest {

	@Test
	public void test_Account_getRewardPoint() {
		Account acct = TestData.createDummy("test", "firstNm", "lastNm");
		acct.addTransactions(TestData.createTransaction("payee", "desp", new BigDecimal(10)));
		acct.addTransactions(TestData.createTransaction("payee2", "desp2", new BigDecimal(15)));
		
		assertEquals(25, acct.getRewardPoint().intValue());
	}

}

7.2 AccountServiceImplTest

We will test AccountServiceImp to make sure findByUserName works as expected.

AccountServiceImplTest.java

package jcg.zheng.demo.spring.service.impl;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

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 jcg.zheng.demo.spring.TestConfig;
import jcg.zheng.demo.spring.entity.Account;
import jcg.zheng.demo.spring.repository.AccountRepository;
import jcg.zheng.demo.spring.service.AccountService;
import jcg.zheng.demo.spring.util.TestData;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestConfig.class })
public class AccountServiceImplTest {

	@Autowired
	private AccountService classToTest;
	
	@Autowired
	private AccountRepository acctRepo;

	@Test
	public void findByUsername_not_found() {
		Account foundAcct = classToTest.findByUsername("testUser");
		assertNull(foundAcct);
	}

	@Test
	public void findByUsername_found() {
		
		acctRepo.save(TestData.createDummy("MaryZheng", "Mary", "Zheng"));
		Account foundAcct = classToTest.findByUsername("MaryZheng");
		assertNotNull(foundAcct);
		assertEquals(1, foundAcct.getId().intValue());
	}
}

7.3 WelcomeControllerTest

We will test the WelcomeController.

WelcomeControllerTest.java

package jcg.zheng.demo.spring;

import static org.junit.Assert.assertEquals;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

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.ui.Model;
import org.springframework.validation.support.BindingAwareModelMap;

import jcg.zheng.demo.spring.model.User;
import jcg.zheng.demo.spring.service.AccountService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestConfig.class })
public class WelcomeControllerTest {
	
	@Autowired
	private WelcomeController welController;
	
	@Autowired
	private AccountService accountService;

	@Test
	public void welcome_view() {		
		Map model= new HashMap();
		Locale locale = new Locale.Builder().setLanguage("en").setRegion("MO").build();
		String viewName = welController.welcome(locale, model);
		assertEquals("home", viewName);
	}
	
	@Test
	public void invalidUser_view() {				
		
		User user = new User();
		user.setUserName("not exist");
		Model model = new BindingAwareModelMap();
		String viewName = welController.user(user , model );
		assertEquals("invalidUser", viewName);
	}
	
}

8. Demo

Now, we completed the web application. Here is the project structure.

Spring with Maven - Project Structure
Figure 0 Project Structure

We will demonstrate the web application to show it meets the business requirements.

8.1 Start the Web Application

First, start the web application with command java -jar target\spring-boot-web-jsp-demo-0.0.1-SNAPSHOT.jar.

Confirmed the web application is up and running by viewing the server output.

Server output

C:\gitworkspace\spring-boot-web-jsp-demo>java -jar target\spring-boot-web-jsp-demo-0.0.1-SNAPSHOT.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v1.5.14.RELEASE)

2018-06-29 15:22:43.448  INFO 19076 --- [           main] j.z.d.spring.SpringBootWebApplication    : Starting SpringBootWebApplication v0.0.1-SNAPSHOT on SL2LS431841 with PID 19076 (C:\gitworkspace\spring-boot-web-jsp-demo\target\spring-boot-web-jsp-demo-0.0.1-SNAPSHOT.jar started by shu.shan in C:\gitworkspace\spring-boot-web-jsp-demo)
2018-06-29 15:22:43.448  INFO 19076 --- [           main] j.z.d.spring.SpringBootWebApplication    : No active profile set, falling back to default profiles: default
2018-06-29 15:22:43.698  INFO 19076 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1698c449: startup date [Fri Jun 29 15:22:43 CDT 2018]; root of context hierarchy
2018-06-29 15:22:46.142  INFO 19076 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$EnhancerBySpringCGLIB$5edb6f43] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-06-29 15:22:47.282  INFO 19076 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2018-06-29 15:22:47.345  INFO 19076 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2018-06-29 15:22:47.345  INFO 19076 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.31
2018-06-29 15:22:48.585  INFO 19076 --- [ost-startStop-1] org.apache.jasper.servlet.TldScanner     : At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
2018-06-29 15:22:48.960  INFO 19076 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-06-29 15:22:48.960  INFO 19076 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 5262 ms
2018-06-29 15:22:49.256  INFO 19076 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2018-06-29 15:22:49.272  INFO 19076 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-06-29 15:22:49.272  INFO 19076 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-06-29 15:22:49.272  INFO 19076 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-06-29 15:22:49.272  INFO 19076 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2018-06-29 15:22:49.397  INFO 19076 --- [           main] o.s.j.d.e.EmbeddedDatabaseFactory        : Starting embedded database: url='jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'
2018-06-29 15:22:50.054  INFO 19076 --- [           main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2018-06-29 15:22:50.085  INFO 19076 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [        name: default        ...]
2018-06-29 15:22:50.319  INFO 19076 --- [           main] org.hibernate.Version                   : HHH000412: Hibernate Core {5.0.12.Final}
2018-06-29 15:22:50.319  INFO 19076 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2018-06-29 15:22:50.335  INFO 19076 --- [           main] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist
2018-06-29 15:22:50.475  INFO 19076 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2018-06-29 15:22:51.159  INFO 19076 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2018-06-29 15:22:52.874  INFO 19076 --- [           main] org.hibernate.tool.hbm2ddl.SchemaUpdate  : HHH000228: Running hbm2ddl schema update
2018-06-29 15:22:52.921  INFO 19076 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: ACCOUNT
2018-06-29 15:22:52.937  INFO 19076 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: ACCOUNT
2018-06-29 15:22:52.952  INFO 19076 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: RewardTransaction
2018-06-29 15:22:52.952  INFO 19076 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: RewardTransaction
2018-06-29 15:22:53.140  INFO 19076 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2018-06-29 15:22:53.693  INFO 19076 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
2018-06-29 15:22:54.609  INFO 19076 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1698c449: startup date [Fri Jun 29 15:22:43 CDT 2018]; root of context hierarchy
2018-06-29 15:22:54.875  INFO 19076 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/loadTestData]}" onto public java.lang.String jcg.zheng.demo.spring.WelcomeController.setup()
2018-06-29 15:22:54.875  INFO 19076 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/user],methods=[POST]}" onto public java.lang.String jcg.zheng.demo.spring.WelcomeController.user(jcg.zheng.demo.spring.model.User,org.springframework.ui.Model)
2018-06-29 15:22:54.875  INFO 19076 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String jcg.zheng.demo.spring.WelcomeController.welcome(java.util.Locale,java.util.Map)
2018-06-29 15:22:54.875  INFO 19076 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-06-29 15:22:54.875  INFO 19076 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-06-29 15:22:55.015  INFO 19076 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-06-29 15:22:55.389  INFO 19076 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-06-29 15:22:55.514  INFO 19076 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2018-06-29 15:22:55.514  INFO 19076 --- [           main] j.z.d.spring.SpringBootWebApplication    : Started SpringBootWebApplication in 12.926 seconds (JVM running for 13.906)

8.2 Home View

Go to http://localhost:8080/, which displays the landing page.

Spring with Maven - Welcome Page
Figure 1 Welcome Page

8.3 Invalid User View

Enter maryZheng and click the login button.

It displays the invalid user page.

Spring with Maven - Invalid User
Figure 2 Invalid User

8.4 User View

Go to http://localhost:8080/loadTestData.

Go to http://localhost:8080/ and enter maryZheng and click the login button.

It displays the Mary Zheng’s account.

Spring with Maven - User Page
Figure 3 User Page

8.5 Error View

Go to http://localhost:8080/loadTestData, it will load the same data again.

Go to http://localhost:8080/ and enter maryZheng and click the login button.

It displays the exception page.

Spring with Maven - Error Page
Figure 4 Error Page

9. Summary

In this example, we created a Spring MVC web application utilizing the Spring boot, Spring JPA, and Spring MVC framework in a few short steps.

  1. Generate the Spring boot MVC project via the starter tool
  2. Add Account and User model classes
  3. Add the JSP view pages
  4. Create a Controller for the views
  5. Create Spring AccountService and AccountRepository beans to manage the account

10. References

11. Download the Source Code

This example consists of a Spring MVC Web application as a Maven project.

Download
You can download the full source code of the Spring with Maven Tutorial: Spring with Maven Tutorial

Mary Zheng

Mary has graduated from Mechanical Engineering department at ShangHai JiaoTong University. She also holds a Master degree in Computer Science from Webster University. During her studies she has been involved with a large number of projects ranging from programming and software engineering. She works as a senior Software Engineer in the telecommunications sector where she acts as a leader and works with others to design, implement, and monitor the software solution.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button