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.
Table of Contents
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:
- Spring stereotype annotations
- Spring Model-View-Controller (MVC) framework
- Spring Data JPA
- Spring boot
- Spring property sources
- Spring test
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:
- Go to
https://start.spring.io/. - Select
Maven ProjectwithJavaand Spring Boot version 1.5.14 and type inweb,JPA, andH2in the “search for dependencies” bar. - Enter the group name as
jcg.zheng.demoand artifact asspring-boot-web-jsp-demo. - Click the
Generate Projectbutton.
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:
- Valid account users can login to view their account’s reward point and the transaction history.
- Invalid account users will be rejected by the application.
- 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 thehomeview.user– maps to the web application user context ("/user") and returns theuserview for a valid user andinvalidUserview for an invalid user.setup– maps to the web application context ("/loadTestData").exceptionHandler– annotates with@ExceptionHandlerfor 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.
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.
8.3 Invalid User View
Enter maryZheng and click the login button.
It displays the invalid user page.
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.
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.
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.
- Generate the Spring boot MVC project via the starter tool
- Add
AccountandUsermodel classes - Add the JSP view pages
- Create a
Controllerfor the views - Create Spring
AccountServiceandAccountRepositorybeans to manage the account
10. References
- https://stackoverflow.com/questions/7175509/which-is-better-return-modelandview-or-string-on-spring3-controller
- http://www.mkyong.com/spring-boot/spring-boot-hello-world-example-jsp/
- https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
- https://www.logicbig.com/tutorials/spring-framework/spring-boot/boot-serve-static.html
- http://www.springboottutorial.com/spring-boot-and-h2-in-memory-database
- https://www.journaldev.com/14476/spring-mvc-example
11. Download the Source Code
This example consists of a Spring MVC Web application as a Maven project.
You can download the full source code of the Spring with Maven Tutorial: Spring with Maven Tutorial







