Month: December 2018

Spring Boot – Deploy WAR file to External Tomcat

http://www.javaguides.net/2018/09/spring-boot-deploy-war-file-to-external-tomcat.html

In this article, we will discuss how to deploy a Spring Boot web application WAR file to the external Tomcat servlet container.

It’s very simple to configure and deploy the Spring web application war file to an external Tomcat servlet container.

Please follow below three simple steps to configure and deploy the Spring web application war file to the externalTomcat servlet container.

Three steps for Spring Boot WAR deployment

  1. Change the packaging type.
<packaging>war</packaging>
  1. Add spring-boot-starter-tomcat as the provided scope
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <scope>provided</scope>
  </dependency>
  1. Spring Boot Application or Main class extends SpringBootServletInitializer
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class Springboot2WebappJspApplication extends SpringBootServletInitializer{

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Springboot2WebappJspApplication.class);
    }
 
    public static void main(String[] args) {
        SpringApplication.run(Springboot2WebappJspApplication.class, args);
    }
}

Let’s develop complete step by step Spring Boot 2 Web application using JSP as View.

Table of Contents

  1. What we’ll build
  2. Tools and Technologies Used
  3. Creating and Importing a Project
  4. Packaging Structure
  5. The pom.xml File
  6. The Springboot2WebappJspApplication.java File
  7. Create a JPA Entity called User.java
  8. Create Spring Data JPA Repository – UserRepository.java
  9. Create Spring Controller – UserController.java
  10. Configuring MySQL Database and JSP View Resolver
  11. Insert SQL Script
  12. Create a JSP View – users.jsp
  13. Running the Application

1. What we’ll build

We are building a simple Spring MVC web application and JSP as a view and we will deploy this application in an external servlet container that is Tomcat.

2. Tools and Technologies Used

  • Spring Boot – 2.0.4.RELEASE
  • JDK – 1.8 or later
  • Spring Framework – 5.0.8 RELEASE
  • Hibernate – 5.2.17.Final
  • Maven – 3.2+
  • IDE – Eclipse or Spring Tool Suite (STS)
  • Tomcat – 8.5+
  • JSP
  • Bootstrap 3+

3. Creating and Importing a Project

There are many ways to create a Spring Boot application. The simplest way is to use Spring Initializr at http://start.spring.io/, which is an online Spring Boot application generator.

Look at the above diagram, we have specified following details:

  • Generate: Maven Project
  • Java Version: 1.8 (Default)
  • Spring Boot:2.0.4
  • Group: net.guides.springboot2
  • Artifact: springboot2webappjsp
  • Name: springboot2webappjsp
  • Package Name : net.guides.springboot2.springboot2webappjsp
  • Packaging: jar (This is the default value)
  • Dependencies: Web, JPA, MySQL, DevTools

Once, all the details are entered, click on Generate Project button will generate a spring boot project and downloads it. Next, Unzip the downloaded zip file and import it into your favorite IDE.

4. Packaging Structure

Once we will import generated spring boot project in IDE, we will see some auto-generated files.

  1. pom.xml
  2. resources
  3. Springboot2WebappJspApplication.java
  4. Springboot2WebappJspApplicationTests.java

5. The pom.xml File

<?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>

    <groupId>net.guides.springboot2</groupId>
    <artifactId>springboot2-webapp-jsp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>springboot2-webapp-jsp</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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

        <!-- Need this to compile JSP -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- Optional, test for static content, bootstrap CSS -->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>3.3.7</version>
        </dependency>
    </dependencies>

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


</project>

Note that is above pom.xml, we have packaging type as war and tomcat starter as provided scope.

6. The Springboot2WebappJspApplication.java File

This class provides an entry point with the public static void main(String[] args) method, which you can run to start the application.Note that SpringBootServletInitializer run a SpringApplication from a traditional WAR deployment

package net.guides.springboot2.springboot2webappjsp;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class Springboot2WebappJspApplication extends SpringBootServletInitializer{

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Springboot2WebappJspApplication.class);
    }
 
    public static void main(String[] args) {
        SpringApplication.run(Springboot2WebappJspApplication.class, args);
    }
}

7. Create a JPA Entity called User.java

package net.guides.springboot2.springboot2webappjsp.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "user")
public class User {
    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Integer id;
    private String name;
 
    public User()
    {
    }

    public User(Integer id, String name)
    {
        this.id = id;
        this.name = name;
    }

    public Integer getId()
    {
        return id;
    }

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

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }
}

8. Create Spring Data JPA Repository – UserRepository.java

package net.guides.springboot2.springboot2webappjsp.repositories;

import org.springframework.data.jpa.repository.JpaRepository;

import net.guides.springboot2.springboot2webappjsp.domain.User;

public interface UserRepository extends JpaRepository<User, Integer>
{

}

9. Create Spring Controller – UserController.java

package net.guides.springboot2.springboot2webappjsp.controllers;

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 net.guides.springboot2.springboot2webappjsp.repositories.UserRepository;

@Controller
public class UserController {
    @Autowired
    UserRepository userRepo;

    @RequestMapping("/users")
    public String home(Model model) {
        model.addAttribute("users", userRepo.findAll());
        return "index";
    }
}

10. Configuring MySQL Database and JSP View Resolver

Configure application.properties to connect to your MySQL database. Let’s open an application.properties file and add following database configuration to it.

spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp

logging.level.org.springframework=INFO

################### DataSource Configuration ##########################
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/users_database
spring.datasource.username=root
spring.datasource.password=root

################### Hibernate Configuration ##########################

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

11. Insert SQL Script

Once you will run this application will create users table in a database and use below insert SQL script to populate a few records in users table.

INSERT INTO `users_database`.`user` (`id`, `name`) VALUES ('1', 'Salman');
INSERT INTO `users_database`.`user` (`id`, `name`) VALUES ('2', 'SRK');
INSERT INTO `users_database`.`user` (`id`, `name`) VALUES ('3', 'AMIR');
INSERT INTO `users_database`.`user` (`id`, `name`) VALUES ('4', 'Tiger');
INSERT INTO `users_database`.`user` (`id`, `name`) VALUES ('5', 'Prabhas');

12. Create a JSP View – users.jsp

Let’s create a users.jsp view to show the list of users. Locate under webapp/WEB-INF/jsp folder.

<!DOCTYPE html>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html lang="en">
<head>

<link rel="stylesheet" type="text/css"
 href="webjars/bootstrap/3.3.7/css/bootstrap.min.css" />
<c:url value="/css/main.css" var="jstlCss" />
<link href="${jstlCss}" rel="stylesheet" />

</head>
<body>
    <div class="container">
        <header>
           <h1>Spring MVC + JSP + JPA + Spring Boot 2</h1>
        </header>
        <div class="starter-template">
           <h1>Users List</h1>
            <table class="table table-striped table-hover table-condensed table-bordered">
                <tr>
                   <th>Id</th>
                   <th>Name</th>
                </tr>
                <c:forEach var="user" items="${users}">
                   <tr>
                        <td>${user.id}</td>
                        <td>${user.name}</td>
                   </tr>
                 </c:forEach>
            </table>
        </div>

    </div>
 <script type="text/javascript"
  src="webjars/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>

13. Running the Application

  1. It is a maven project so create a war file using the following command:
mvn clean install or mvn clean package
  1. Once maven builds success then WAR file is generated under a target folder.

Just copy war file to external tomcat webapps folder and start the tomcat server.

  1. Hit this link to a browser – http://localhost:8080/springboot2-webapp-jsp/users

Note that you can change the context name from springboot2-webapp-jsp-0.0.1-SNAPSHOT to springboot2-webapp-jsp or as per your requirement.

GitHub Repository

The source code of this article available on my GitHub repository – https://github.com/RameshMF/spring-boot-tutorial/tree/master/springboot2-webapp-jsp-WAR

Spring Boot and WordPress CMS Integration

https://kamranzafar.org/2016/08/08/spring-boot-and-wordpress-integration/

 

There are a lot of excellent open source content management systems available today,  WordPress being one of them, which is widely used. WordPress is a PHP based CMS so not a lot of cohesion is available with other technologies like Java, and is simply ignored as a viable content management option just for being non-Java.

In this post I will demonstrate how WordPress can be integrated with Spring Boot applications, all made possible with WordPress REST plugin and a Spring client. Both of these are open source and available for free. Below is a simple design diagram that explains how this integration works. This post assumes that the reader has prior knowledge of WordPress and Spring Boot.


spring-wpapi-simple
First install and activate WP-API v2 plugin on the WordPress site. After activation, you could verify that the plugin is working by accessing http://yoursite/wp-json/wp/v2/posts, which should display all the posts in JSON format.In the spring boot application add the following dependency in order to include the Spring WP-API client.

Below is a sample configuration we need in the application.properties file, so that we can connect our Spring Boot application to our WordPress site.

The Spring WP-API client needs the RestTemplate so lets create a bean in our Application and autowire the Spring client. We also need to add component scan annotation so that Spring finds and autowires all the required dependencies.

Now our spring boot application is all setup to connect to out WordPress site in order to retrieve and create content. So lets try and lookup all the posts having the keyword “Spring”, below is how we can do this.

The complete test application is available with the Spring WP-API client on Github.

This is just a small example of how we can integrate Spring Boot and WordPress. We can take this further by properly integrating WordPress in the Spring web applications platform, e.g. by enabling Single Sign On using the CAS plugin.


spring-wpapi-cas
And we can evolve this design even further by having a second-level content storage, like a database or an in-memory caching solution etc. This storage can serve as a cache and can also be used for additional configuration, so that we display relevant content faster in our Spring applications.

spring-wpapi-cas-db
For more information please see the documentation of the WordPress REST plugin and Spring WP-API client.

How to Create Spring Boot Application Step by Step

http://www.adeveloperdiary.com/java/spring-boot/create-spring-boot-application-step-step/

 

How to Create Spring Boot Application Step by Step

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedInPrint this pageShare on TumblrShare on Reddit

Spring Boot had been built for Rapid Application Development. In this tutorial we will learn How to Create Spring Boot Application using some easy examples. We will also focus on How to deploy spring boot application in different application servers.

Here are the following topics that we will cover in this series:

  1. Create Spring Boot Application using
    • start.spring.io
    • Eclipse STS
    • IntelliJ IDEA STS
  2. Run Spring Boot Application using
    • Java CLI
    • Eclipse/IntelliJ IDEA
  3. Create a Basic Spring Boot application using REST
  4. How to use Spring Actuator
  5. Deploy Spring Boot application in
    • IBM Liberty Profile
    • IBM Application Server 8.5

If you need an introduction of Spring Boot please find my previous post below.

Create Spring Boot Application using start.spring.io

The best way of bootstrapping Spring Boot application is by using Spring Initializr. Let’s first start by opening http//start.spring.io.As you already know, you can use either Maven or Gradle to build, however we will use Maven in this tutorial. Click on Switch to the full Version and you will be able to see the below screen.

Software Needed

  • JDK 1.8 (You can use 1.7 or 1.6)
  • Maven 3.x

Steps :

  • Select Maven Project
  • If you want, change the Group/Package name. We will use com.adeveloperdiary
  • Change the Artifact to SpringBoot, Name will automatically change to the same
  • Leave the packaging to Jar, Java Version to 1.8 (Make sure you have JDK 1.8 in your local or use 1.7 )
  • Either type the Dependencies or select them below. We will add Web and Actuator here
  • Click on Generate Project button to download the zip file

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Now Extract the zip and you will have the following files.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Open Terminal and navigate to the above folder. Type mvn clean packageand press enter. The Build will start now.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Once the build has been completed, you will have the SpringBoot-0.0.1-SNAPSHOT.jar created inside the target folder.

The Size of the jar would be around 13MB since it will have the embedded Tomcat server in it.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Create Spring Boot Application using Eclipse

We will use STS Toolkit to bootstrap when using eclipse. I am using eclipse MARS .1 version. We will first install the STS (SpringSource Tools Suite). Open Eclipse Marketplace, Type STS in Find and install the STS.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Then open Spring perspective.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Create a New -> Spring Starter Project.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Enter the following details. Click Next.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Select Web and Actuator. Click on Next.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Click on Finish.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

This should create the Spring Boot Project in Eclipse.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Create Spring Boot Application using IntelliJ IDEA

We will now use IntelliJ IDEA to create our Spring Boot Application.I recommend to use the latest version of IntelliJ. Create a New Project. Select Spring Initializr. Click on Next.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Enter the following details. Click Next.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Select Web and Actuator. Click Next.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Enter the project Name and click Finish.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Your Spring Boot Project has been created now.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Run Spring Boot Application using CLI

We had created the jar file, now we will run it from Command Line by executing this line

You should be able to see Spring Boot in the Command Line.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

The server should have started and the default port number will also be displayed as below.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Run Spring Boot Application in Eclipse

Its much easier to run the Spring Boot app in eclipse. Select the project, Right Click and, move to Run As and click on Spring Boot App. Again, remember you need to select the project to get this option, not the pom file.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Here is the output.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Run Spring Boot Application in IntelliJ IDEA

Its probably most easy, click on the run icon.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

You should be able to see the logs that the application has started.

How to Create Spring Boot Application Step by Step adeveloperdiary.com

Conclusion

Hope this Step by Step approach will help you. Next we will learn how to create RESTServices and use Actuator in Spring Boot. Later we will also learn how to deploy Spring Boot Application in IBM Liberty Profile and IBM WAS 8.5 Server.

This is the 2nd part of Getting Started with Spring Boot Series. Find all the parts here.

  1. An Introduction to Spring Boot
  2. How to Create Spring Boot Application Step by Step
  3. How to create RESTFul Webservices using Spring Boot
  4. How to deploy Spring Boot application in IBM Liberty and WAS 8.5

Step-by-step Spring Boot RESTful web services example in Java using STS

https://www.theserverside.com/video/Step-by-step-Spring-Boot-RESTful-web-services-example-in-Java

In a previous article about important RESTful principles and how to create a beautiful RESTful API, I used the example of a web service that kept track of an ongoing, global score for an online rock-paper-scissors application. In this step-by-step Spring Boot RESTful web services example, we’ll implement that scenario using the Spring Web APIs and the Eclipse based SpringSource Tool Suite (STS) as the IDE.

Review of the RESTful API

The RESTful score service will provide the following functions:

RESTful clients can find out the current number of wins, losses and ties through a GET request to the following URL:

www.mcnz.com/rps/score | GET

This invocation will return a JSON string in the following format:

{ "wins":"5", "losses":"3", "ties": "0"}

RESTful clients can update the score by invocating the same URL through a PUT invocation while also passing query parameters. Again, the program will return a JSON-based representation of the score after the update. A better design would be to use JSON as the payload, but query parameters are used here for the sake of simplicity.

www.mcnz.com/rps/score?wins=1&losses=2&ties=3 | PUT

With the RESTful API, the user cannot directly set the number of wins, losses or ties. The client can only use a POST invocation to increment values one at a time. This is not an idempotent function, so it is handled through a POST. In this case, a simple number is returned to the program as opposed to a JSON string.

You can use a simple GET invocation on the appropriate resource locator to obtain the number of wins, losses or ties:

www.mcnz.com/rps/score/wins | GET

www.mcnz.com/rps/score/ties | GET

www.mcnz.com/rps/score/losses | GET

This step-by-step Spring Boot RESTful web services example in Java has very few prerequisites, but it does assume that you have the SpringSource Tool Suite (STS) installed. If that’s the case, you are ready to jump on the fast track to developing RESTful web services with Spring.

Step 1. Create the RESTful Spring Boot project

The first step in this exercise is to create a new Spring Boot project named restful-spring-example that uses both the Web and DevTools features. This is accomplished by kicking off the Spring Starter Project wizard in Eclipse. Select the Spring Web and DevTools options and click Finish on the Spring Boot project wizard.

Spring Boot project wizard
How to start a Spring Boot RESTful web services project

Step 2: Create the Java classes

The next step is to open the restful-spring-example project and create two classes: Score.java and ScoreService.java.

Right click on the com.mcnz.restful.spring.boot package and choose to create a new class named Score. The Score class is used to keep track of the global number of wins, losses and ties that occur in the online rock-paper-scissors game. The Score class will maintain the number of wins, losses and ties as static variables of type int. State should never be held within a RESTful web service, so this class represents the externalization of state.

package com.mcnz.restful.spring.boot;

public class Score {
  public static int WINS, LOSSES, TIES;
}

After you code the Score class, create a second Java component named ScoreService. We’ll use the ScoreService class to provide access to — and the ability to manipulate — the Score. The first iteration of the class used in this Spring Boot web service example will have getter methods that return the number of wins, losses and ties, along with update methods that can increment the number of wins, losses and ties by one.

Create the RESTful Spring Boot ScoreService class
How to create the ScoreService class for the step-by-step RESTful web services example

Here is the first iteration of the ScoreService class before we decorate it with RESTful annotations and subsequently configure it as a Spring Boot web service.

package com.mcnz.restful.spring.boot;
/* Spring Boot web service example class */
public class ScoreService {
   
   public String updateScore(int wins, int losses, int  ties) {
      Score.WINS = wins;
      Score.TIES = ties;
      Score.LOSSES = losses;
      /* to be updated to return JSON */
      return this.toString();
   }

   public int increaseWins()   { return ++Score.WINS;   }
   public int increaseTies()   { return ++Score.TIES;   }
   public int increaseLosses() { return ++Score.LOSSES; }

   public int getWins()   { return Score.WINS;   }
   public int getTies()   { return Score.TIES;   }
   public int getLosses() { return Score.LOSSES; }
}

/* End of Spring Boot web service example class. */

Step 3: Annotate the Spring Boot example class

With the first iteration of the ScoreService component coded, the next step is to transform it into a Spring Boot RESTful web service by decorating the class declaration with the @RestController annotation. The @RestController annotation informs the Spring Boot framework that the class contains methods that will be invoked through a web-based resource URL.

@RestController
public class ScoreService { … }

Step 4: Annotate RESTful Spring methods

Step four is to add @RequestMapping annotations to methods. These annotations define the HTTP method used along with the structure of the resource URLs that will be used to invoke them. In the previous tutorial about how to create beautiful RESTful APIs, we established that we would invoke the update methods through a POST, and all getter methods sensibly through a GET invocation. The URLs are all resource based, so use of the URL path is /score/wins to get information about the number of wins and the path /score/ties to increase the number of ties.

Fully decorated with Spring Boot RESTful web service annotations, the next iteration of the ScoreService class looks as follows:

/* Spring Boot web service example class */
@RestController
public class ScoreService {

  @RequestMapping(value="/score", method=RequestMethod.PUT, )
  public String updateScore(int wins, int losses, int ties) {
     Score.WINS = wins;
     Score.TIES = ties;
     Score.LOSSES = losses;
     return this.toString(); /* to be updated to return JSON */
   }
   @RequestMapping(value="/score/wins", method=RequestMethod.POST)
   public int increaseWins()   { return ++Score.WINS;   }
  
   @RequestMapping(value="/score/ties", method=RequestMethod.POST)
   public int increaseTies()   { return ++Score.TIES;   }

   @RequestMapping(value="/score/losses", method=RequestMethod.POST)
   public int increaseLosses() { return ++Score.LOSSES; }

   @RequestMapping(value="/score/wins", method=RequestMethod.GET)
   public int getWins()   { return Score.WINS;   }

   @RequestMapping(value="/score/ties", method=RequestMethod.GET)
   public int getTies()   { return Score.TIES;   }

   @RequestMapping(value="/score/losses", method=RequestMethod.GET)
   public int getLosses() { return Score.LOSSES; }
}
/* End of Spring Boot web service example class */

Step 5: Generate RESTful JSON responses

This step-by-step Spring Boot RESTful web services example needs to generate a JSON-based response for the client. There are excellent frameworks like Jackson and GSON, which you should use in larger projects, but for this simple RESTful web services example, we will simply employ some Java String manipulation to generate the JSON.

The getScore() method needs to return a JSON string formatted in the following manner:

{ "wins":"5", "losses":"3", "ties": "0"}

Here is how the un-annotated getScore() method looks when coded to return a JSON string:

public String getScore() {
  String pattern = 
     "{ \"wins\":\"%s\", \"losses\":\"%s\", \"ties\": \"%s\"}";
  return String.format(pattern,Score.WINS, Score.LOSSES, Score.TIES);
}

Note that you’ll use this same pattern match and String format approach again to return a JSON-based representation of the score in the updateScore method.

Since the getScore() method now returns JSON, you need to add a new produces attribute to the @RequestMapping annotation. The fully annotated getScore() method that indicates that JSON will be returned to the calling program looks as follows:

@RequestMapping(value="/score", 
            method=RequestMethod.GET, 
                  produces=MediaType.APPLICATION_JSON_VALUE)
public String getScore() {
  String pattern = 
       "{ \"wins\":\"%s\", \"losses\":\"%s\", \"ties\": \"%s\"}";
  return String.format(pattern,  Score.WINS, Score.LOSSES, Score.TIES);
}

In order to generate JSON, the updateScore method follows a similar pattern of updated annotations and String manipulation within the code:

@RequestMapping(value="/score", 
    method=RequestMethod.PUT, 
       produces=MediaType.APPLICATION_JSON_VALUE)

public String updateScore(int wins, int losses, int ties) {
  Score.WINS = wins;
  Score.TIES = ties;
  Score.LOSSES = losses;
 String pattern = 
     "{ \"wins\":\"%s\", \"losses\":\"%s\", \"ties\": \"%s\"}";
  return String.format(pattern,Score.WINS, Score.LOSSES, Score.TIES);     
}

QueryParam to method signature mapping

To update the ScoreService, the client will use the /score path while it passes query parameters to represent the number of wins, losses and ties. For example, a request to update the number of wins to 99, ties to 88 and losses to 7 would look like this:

http://www.mcnz.com/score?wins=99&ties=88&losses=7

As long as the updateScore method has method parameters that match the names of the query parameters, the Spring Boot web services framework will assign the queryParam values to the correspondingly named method signature parameter.

http://www.mcnz.com/score?wins=99&ties=88&losses=7

public String updateScore(int wins, int losses, int ties) { … }

The updateScore method will take the values passed into the method and assign them to the corresponding properties of the ScoreService class. An updated JSON string will be sent to the client indicating the new, updated value of the score. You’ll use the same process used to generate JSON in the getScore()method here. The full method implementation is as follows:

@RequestMapping(value="/score", 
     method=RequestMethod.PUT, 
        produces=MediaType.APPLICATION_JSON_VALUE)

public String updateScore(int wins, int losses, int ties) {
  Score.WINS = wins;
  Score.TIES = ties;
  Score.LOSSES = losses;
  String pattern = 
     "{ \"wins\":\"%s\", \"losses\":\"%s\", \"ties\": \"%s\"}";
  return String.format(pattern, Score.WINS, Score.LOSSES, Score.TIES);
}

With the updateScore method coded, the step-by-step Spring Boot RESTful web services example is code complete, and the only steps left are to test and deploy.

Step 6:  Run the Spring Boot RESTful web service

To run the application, simply right click on the restful-spring-example project and choose Run As → Spring Boot App and Maven will package the application and deploy it to the STS server. When the console window indicates the Tomcat-based server has finished starting, open a browser window and go to localhost:8080/score/wins. A value of zero will appear.

Step 7: Test the RESTful Spring Boot service

To test the increaseWins method, run the following two CURL command in a Bash shell:

$ curl -X POST "http://localhost:8080/score/wins"
$ curl -X GET "http://localhost:8080/score/"

The output of the second command is:

{ "wins":"1", "losses":"0", "ties": "0"}

Now trigger a PUT invocation, with query parameters being used to carry the payload:

$ curl -X PUT "http://localhost:8080/score?wins=31&losses=11&ties=22"

This results in an output of:

{ "wins":"31", "losses":"11", "ties": "22"}

And that’s it, a complete, step-by-step Spring Boot RESTful web services example that creates a fully functional Spring Boot application.

How to improve the RESTful Spring example

Now there is plenty of room for improvement and expansion when it comes to this step-by-step Spring Boot RESTful web services example.

Obviously, using the static variables in the Score class is a poor way to manage state, so at the very least we should offload the job of state management to a JavaBean with an ObjectOutputStream. And neither a JavaBeans or RESTful web service should be responsible for data persistence, so there will be opportunities to integrate Hibernate, JPA and Spring Boot web services. We could also invoke the Spring Boot RESTful web service example through a Spring MVC app or a Spring RestTemplate instead of CURL, and of course, it would be nice to package this app in an executable JAR file with an embedded Tomcat or embedded WebSphere Liberty server and deploy it as a microservice. But all of those things would complicate the example and distract from the core purpose, which is to demonstrate just how easy it is to develop a RESTful Spring web service using the Spring Boot framework.

These aforementioned issues will be addressed in subsequent tutorials. The source code for this step-by-step Spring Boot RESTful web services example can be found on GitHub.

Spring Boot and Embedded Servers – Tomcat, Jetty and Undertow

http://www.springboottutorial.com/spring-boot-with-embedded-servers-tomcat-jetty

 


This guide will help you understand why embedded servers are gaining popularity. We will discuss the different options that Spring Boot supports – Tomcat, Jetty and Undertow.

You will learn

  • What is an embedded server?
  • Why are embedded servers getting popular?
  • What are the different embedded servers that Spring Boot supports?
  • How do you switch from one embedded server to another?

What is an Embedded Server?

Think about what you would need to be able to deploy your application (typically) on a virtual machine.

  • Step 1 : Install Java
  • Step 2 : Install the Web/Application Server (Tomcat/Websphere/Weblogic etc)
  • Step 3 : Deploy the application war

What if we want to simplify this?

How about making the server a part of the application?

You would just need a virtual machine with Java installed and you would be able to directly deploy the application on the virtual machine. Isn’t it cool?

This idea is the genesis for Embedded Servers.

When we create an application deployable, we would embed the server (for example, tomcat) inside the deployable.

For example, for a Spring Boot Application, you can generate an application jar which contains Embedded Tomcat. You can run a web application as a normal Java application!

Embedded server implies that our deployable unit contains the binaries for the server (example, tomcat.jar).

Creating an Embedded Server Project with Spring Initializr

Spring Initializr http://start.spring.io/ is great tool to bootstrap your Spring Boot projects.

Image

As shown in the image above, following steps have to be done

  • Launch Spring Initializr and choose the following
    • Choose com.in28minutes.springboot.tutorial.basics.example as Group
    • Choose spring-boot-tutorial-basics as Artifact
    • Choose following dependencies
      • Web
      • DevTools
  • Click Generate Project.
  • Import the project into Eclipse. File -> Import -> Existing Maven Project.

Default Embedded Server with Spring Boot – Tomcat

We have included Spring Boot Starter Web in our dependencies when creating the spring boot project.

Let’s take a quick look at the dependencies for spring-boot-starter-web

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-tomcat</artifactId>
  <version>2.0.0.RELEASE</version>
  <scope>compile</scope>
</dependency>

You can see that by default Starter Web includes a dependency on starter tomcat.

Starter Tomcat has the following dependencies.

<dependency>
  <groupId>org.apache.tomcat.embed</groupId>
  <artifactId>tomcat-embed-core</artifactId>
  <version>8.5.23</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.apache.tomcat.embed</groupId>
  <artifactId>tomcat-embed-el</artifactId>
  <version>8.5.23</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.apache.tomcat.embed</groupId>
  <artifactId>tomcat-embed-websocket</artifactId>
  <version>8.5.23</version>
  <scope>compile</scope>
</dependency>

Starter Tomcat brings in all the dependencies need to run Tomcat as an embedded server.

Run the web application using an Embedded Server

When you run SpringBootTutorialBasicsApplication.java as a Java Application, you would see that the server would start up and start serving requests.

An extract from the log

o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)

You can see that tomcat has started by default on port 8080.

You can customize the port in application.properties

server.port=9080

When you do a ‘mvn clean install’ on the project, a jar artifact named spring-boot-tutorial-basics-0.0.1-SNAPSHOT.jar is generated.

This jar can be used to run the application on any machine where Java 8 is installed.

The tomcat embedded server is also packaged inside this jar

Using Jetty as Embedded Server with Spring Boot

Remove the existing dependency on spring-boot-starter-web and add these in.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

Using Undertow as Embedded Server with Spring Boot

Remove the existing dependency on spring-boot-starter-web and add these in.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

Embedded Server Spring Boot Configuration

Spring Boot provides a number of options to configure the embedded server through application.properties

# EMBEDDED SERVER CONFIGURATION (ServerProperties)
server.compression.enabled=false # If response compression is enabled.
server.context-path= # Context path of the application.
server.display-name=application # Display name of the application.
server.error.include-stacktrace=never # When to include a "stacktrace" attribute.
server.error.path=/error # Path of the error controller.
server.error.whitelabel.enabled=true # Enable the default error page displayed in browsers in case of a server error.
server.port=8080 # Server HTTP port.
server.server-header= # Value to use for the Server response header (no header is sent if empty)
server.servlet-path=/ # Path of the main dispatcher servlet.

Here are a few Jetty specific options

server.jetty.acceptors= # Number of acceptor threads to use.
server.jetty.max-http-post-size=0 # Maximum size in bytes of the HTTP post or put content.
server.jetty.selectors= # Number of selector threads to use.

You can also configure ssl on the embedded server

server.ssl.ciphers= # Supported SSL ciphers.
server.ssl.client-auth= # Whether client authentication is wanted ("want") or needed ("need"). Requires a trust store.
server.ssl.enabled= # Enable SSL support.
server.ssl.enabled-protocols= # Enabled SSL protocols.
server.ssl.key-alias= # Alias that identifies the key in the key store.
server.ssl.key-password= # Password used to access the key in the key store.
server.ssl.key-store= # Path to the key store that holds the SSL certificate (typically a jks file).
server.ssl.key-store-password= # Password used to access the key store.
server.ssl.key-store-provider= # Provider for the key store.
server.ssl.key-store-type= # Type of the key store.
server.ssl.protocol=TLS # SSL protocol to use.
server.ssl.trust-store= # Trust store that holds SSL certificates.
server.ssl.trust-store-password= # Password used to access the trust store.
server.ssl.trust-store-provider= # Provider for the trust store.
server.ssl.trust-store-type= # Type of the trust store.

A few tomcat specific properties are listed below

server.tomcat.accept-count= # Maximum queue length for incoming connection requests when all possible request processing threads are in use.
server.tomcat.accesslog.directory=logs # Directory in which log files are created. Can be relative to the tomcat base dir or absolute.
server.tomcat.accesslog.enabled=false # Enable access log.
server.tomcat.basedir= # Tomcat base directory. If not specified a temporary directory will be used.
server.tomcat.max-connections= # Maximum number of connections that the server will accept and process at any given time.
server.tomcat.max-threads=0 # Maximum amount of worker threads.
server.tomcat.uri-encoding=UTF-8 # Character encoding to use to decode the URI.

For complete list options refer spring documentation – https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

Tutorial: Use Spring Boot to Build and Deploy WAR Files

https://stormpath.com/blog/tutorial-spring-boot-war-files

Spring Boot makes it easy to create stand-alone Java web applications. However in production environments, a web container often already exists. How do we deploy our apps in these situations and have them run side-by-side with other servlets? In this tutorial, we’ll walk through how to use WAR files to do just that.

Getting Started with With Spring Boot, Tomcat, and WAR Files

In a previous tutorial, we built a simple RESTful web app using Spring Boot. I’m going to use this as a base and show how to deploy it into a container. You can grab the code for this tutorial on GitHub.

To ensure an existing Spring Boot app is container-ready one needs do three things
– Renaming the embedded Tomcat libraries
– Repackage the output file as a WAR
– Wire the application up as a servlet

Tomcat Libraries

Building a Spring Boot application produces a runnable jar file by default. If your app includes server functionality, then Tomcat will be bundled with it. We need to ensure the Tomcat libraries don’t clash with an existing container (since the container will include the same libraries).

When we do a clean clone of our repo (grab the code on GitHub if you haven’t yet) and do an mvn clean package we end up with a target directory containing our runnable jar.

This jar contains Tomcat libraries. To confirm this, we can rename it to .zip and look at the lib directory.
LIB Tomcat

You’ll see various .jar files starting with tomcat-. Some of these will clash with a running instance of Tomcat. We need to tell Spring Boot to move them.

To WAR! AKA: Build Your WAR Files

First, we must tell Spring Boot we want a WAR file as output. This is as easy as adding one line to our pom.xml.

Now when we build the package with

we will see a .war file inside our target directory:
WAR file in target directory

As before we can rename the file to .zip to see what’s inside. Everything is basically the same, just slightly re-ordered. Now lib is inside of WEB-INF anddemo` (where our project code sits) is in WEB-INF/classes.
Web INF Files

Renaming Tomcat

Next, we tell Spring Boot to move our Tomcat libraries out of this folder. In our previous pom.xml we included three dependencies for our project – one for REST, one for data access, and another for the database.

Now we append the Spring Boot Tomcat Starter to this (which links to the Tomcat libraries you need when embedding) and set the scope of the dependency to provided.

This will still include the .jar files as before but will put them in a new folder called lib-provided.

We can see this if we follow the same procedure as before. Once we mvn clean package and rename our .war to .zip we’ll see inside WEB-INF the new folder has appeared. Inside are all the embedded Tomcat libraries (and you’ll see they are no longer in lib).
Embedded Tomcat Libraries

Now our application will happily reside in a servlet container without clashing with its libraries.

Setting Up a Servlet

The only other thing we need to do is wire our application up to start as a servlet. And to do this we need to modify our application definition.

In the REST app mentioned our Application.java used the SpringBootApplication annotation on the main class and defined a main method.

To set the app up as a servlet we extend the main class with SpringBootServletInitializer and override the configure method using SpringApplicationBuilder.

And that’s it! This application will now happily run inside a Tomcat container!

Installing Tomcat

Deploying WAR files to Tomcat is as easy as copying the file to Tomcat’s webapps directory. But first, you need to install Tomcat. On Ubuntu, you can use apt-get.

This will install and start the server automatically on port 8080.

On Windows it’s just as easy – download and extract the binary distribution .zip file and run startup.bat in the bin directory. This will open up a console window showing the output of Catalina.
Tomcat Console

In both cases, you can check to see if everything is running by browsing to localhost:8080. You should see the Tomcat default homepage.
Tomcat

(Who knew Tomcat was so easy to use?!)

Copy the WAR File

The last step is copying the WAR to webapps. Here the name is important – whatever filename we choose will be used to map HTTP requests to our application. (All done automatically! I think this is amazing.) In an attempt to be more URL-friendly, I’m going to use demo.war.

On Ubuntu, this can be done with:

In Windows, use Explorer for the copy and then wait for the console window to show deployment messages.
WAR Deployment Message

And that’s it! Just by copying one file across our app is automatically booted and running side-by-side with the default Tomcat servlet.

Test Your WAR File Deployment

As before we test this by making calls using curl. Normally we called get on localhost but now our application is mapped to /demo/.

This shows you available URLs. To see what people objects are available you can use:

Or, create new ones with:

Note: In my testing I found the deploy on Windows to be somewhat brittle. Sometimes I needed to close and rerun startup.bat.

Run as a Standalone Application

One last thing – because our Tomcat libraries are still there (just moved) we are able to run this application on it’s own. So mvn spring-boot:run still works !

DEPLOY A SPRING BOOT APP ON YOUR OWN SERVER…

https://www.theguild.nl/deploy-a-spring-boot-app-on-your-own-server-in-less-than-15-minutes/

 

Hosted PaaS (Platform As A Service) offerings like Heroku and OpenShift are great but not always suitable or even possible to use. If you need or want full control over your data and servers, or you just want to host your latest side project but don’t want Heroku dyno sleeping you might just want to self host.

Traditionally self-hosting was painful and cumbersome but today there are plenty options to self-host your apps that are nearly as painless as a hosted PaaS solution. In this tutorial I will show you how to deploy an app on Dokku:

Dokku is an extensible, open source Platform as a Service that runs on a single server of your choice.

Dokku provides an environment very similar to Heroku technically, allowing Dokku to take advantage of Heroku buildpacks to deploy your apps. Dokku uses these buildpacks to automatically build Docker containers that can run your apps and services. Refer to the Dokku documentation for more information on Dokku.

For this tutorial we’ll be using this Spring Boot example app I’ve set up. It’s a very basic app with a single HTTP endpoint that serves up a semi-random quote retrieved from a Postgres database. It’s a completely vanilla Spring Boot app, except for a single file to instruct Dokku how to start the app but more on that later. Let’s get started!

1. GET A (VIRTUAL) SERVER

Get a server with root access. Dokku requires at least 1GB of RAM and officially only supports Ubuntu 14.04 x64.

For convenience you’ll want to assign a DNS hostname (dokku.example.org) to your servers IP and preferably even assign a wildcard record so you can deploy apps on <app name>.dokku.example.org.

2. INSTALL DOKKU

SSH into your server and execute the following command to kick off the Dokku installation. Run this either as root or make sure your user account has sudo permissions.

1
wget -qO- https://raw.githubusercontent.com/dokku/dokku/v0.4.14/bootstrap.sh | bash

Sit back, get some coffee, this will take a couple of minutes. When the command completes open your browser and navigate to the ip address or hostname assigned to your server to complete the Dokku setup.

Dokku setup

Provide your SSH public key here so you’ll be able to push your app to Dokku later via Git. Enable use virtualhost naming for apps and enter the hostname you assigned to your server in step 1.

That’s it, you now have a fully functional Dokku instance up and running! Let’s see what it takes to actually deploy an app.

3. PREPARE YOUR APP FOR DEPLOYMENT ON DOKKU

We’re about ready to deploy our first app. In general if you want to deploy an app on Dokku you don’t need to make a lot of modifications to your app. Especially if your app adheres to the Twelve Factor guidelines you should be fine. Most importantly your app should allow configuration via environment variables or command line parameters.

Fortunately Spring Boot embraces the Twelve Factor guidelines. Spring Boot supports configuration via environment variables out of the box and it’s trivial to implement your own.

Looking at the example app I prepared there are two important things to notice:

1. I’ve created two property aliases to allow configuration via $PORT and $DATABASE_URL. This is not strictly necessary but I prefer the more generic environment variables over the Spring specific ones.

1
2
3
// application.properties
spring.datasource.url=${database.url:jdbc:postgresql://localhost:5432/dokku-demo}
server.port=${port:8080}

2. I’ve added a Procfile to instruct Dokku how to start our app. Dokku will read this file during deployment and use the web process to boot our app. You can read more about Procfiles here.

1
2
# Procfile
web: env DATABASE_URL=$JDBC_DATABASE_URL target/dokku-boot-demo-0.0.1-SNAPSHOT.jar

During deployment Dokku invokes mvn install on our app so it will build a jar. Here we instruct Dokku that to launch our app it needs to execute the jar. We set the $DATABASE_URL to $JDBC_DATABASE_URLwhich is an environment variable provided by the Java buildpack that formats the database connection string for JDBC compatibility.

4. DEPLOY YOUR APP

Alright so now our app is Dokku compatible. Before we can push our app to Dokku we need to configure our application in Dokku. For simplicity enter the following dokku commands in an SSH session on your server. Later you can setup the Dokku CLI client to run these commands directly from your local machine.

First we’ll create our app in Dokku:

1
$ dokku apps:create my-app

Next we’ll install the Dokku Postgres plugin:

1
$ dokku plugin:install https://github.com/dokku/dokku-postgres.git postgres

This will pull in a Postgres Docker image so give it some time to complete.

Next create a Postgres instance for our app:

1
$ dokku postgres:create my-app-postgres

Link it to our app:

1
$ dokku postgres:link my-app-postgres my-app

That’s all the configuration we need, let’s actually deploy our app now!

First clone the example app to your local machine:

1
2
$ git clone https://github.com/kabisa/dokku-boot-demo.git
$ cd dokku-boot-demo

Dokku uses a Git push to deploy model, meaning that you push your app sources into Dokku using Git. To deploy you simply add a git remote to your repository pointing to Dokku and git push every time you want to deploy your latest changes.

Execute the following command in your shell. Replace dokku.example.org with your actual Dokku hostname.

1
$ git remote add dokku dokku@dokku.example.org:my-app

And finally push our app to Dokku:

1
$ git push dokku master

Dokku will now detect our app is a Java app, build a Docker image suitable to run Java apps, compile the app and run it.

You should see similar output as below:

Dokku deploy gif

Open your browser at http://my-app.dokku.example.org/ and see a nice random quote!

CLOSING THOUGHTS

Dokku takes a bit of one time setup but once you have your Dokku instance ready, deploying new applications will be a breeze. Do note that Dokku was designed for simple single server setups. If you need fancy stuff like clustering, access control etc you might want to look at one of the more comprehensive projects in this space like FlynnDeis or Cloud Foundry.

Even though Dokku is quite simple, we’ve only scratched the surface of what it can do. You now have a fully functional Dokku instance so go ahead and explore the Dokku docs to see what more is possible!

If there’s no suitable Heroku buildpack for your app you can always deploy a raw Docker container using Dokku by simply including a Dockerfile in the root of your project.

If you’re planning to deploy a more complex Spring Boot app to Dokku you might want to look into Spring Cloud Connectors. Spring Cloud Connectors can automatically detect that you’re running in a cloud platform, and configure your HTTP port and database automatically for you. Spring Cloud Connectors officially don’t support Dokku, but the Heroku support works just fine with Dokku.

Also be sure to check out the plugins that Dokku offers to make use of databases, message brokers etc. There’s even a Dokku Let’s Encrypt plugin for dead easy Let’s Encrypt SSL certificates.

Happy deploying!

Me 2016 square

PASCAL WIDDERSHOVEN

Full Stack Developer • Github: pascalw • Twitter: @_pascalw

Deploying Spring Boot Applications

One of the many questions I get around this concerns deployment strategies for Boot applications. Spring Boot builds on top of Spring and serves wherever Spring can serve. It enjoys Spring’s portability. Spring Boot lets the developer focus on the application’s development first, and removes the need to be overly concerned with every other aspect of its lifecycle, including deployment and management.

It aims to be production ready, out of the box. As part of this, Spring Boot does a few things differently, by default, that may be at first alien to some. In this post, I hope to briefly cover some of the common strategies for deploying a Spring Boot applications. I’ll ever so briefly introduce it, and some sample code, before we dive deeper. Feel free to skip this section and start at the Embedded Web Server Deployment section.

Getting Started with Spring Boot

If you haven’t used Spring Boot yet, do! There are many ways to get started, including the Spring Initializr at start.spring.io webservice and – if you’re using Spring Tool Suite – there’s a more familiar, integrated wizard that ultimately invokes that same webservice. I usually start by checking the Actuator, and Web checkboxes, then choosing to generate a Maven Project. This will give you two starter classes, Application.java, and ApplicationTests.java, as well as a ready-to-use Maven pom.xml file.

Here is the unzipped starter project:

  pwd
/Users/jlong/Downloads/starter
  starter  tree
.
├── pom.xml
└── src
    ├── main
       └── java
           └── demo
               └── Application.java
    └── test
        └── java
            └── demo
                └── ApplicationTests.java

7 directories, 3 files
  starter  

The Maven build depends on Spring Boot started dependencies. These dependencies are opinionated. They bring in known, ready-to-use stacks aligned with the the task before you, not the technology stacks you might use: put another way, if you want to build a web application, then simple depend on the Spring Boot starter web dependency, like this:

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

The Maven build inherits information about which dependency versions to use from its parent pom, also provided by Spring Boot. You don’t need to worry about lining up common Spring project versions and third party dependencies.

The generated Java classes are boilerplate (this is why they’re generated!). You won’t often change the classes themselves, though you can. By the end of this blog you’ll have a common recipe for deploying Spring Boot applications. This is (hopefully!) the only boilerplate you’ll encounter in Spring Boot. Here is the Application.java class that Spring Boot provides:

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

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

For the purpose of demonstration during post, we’ll add in a RESTful Spring MVC controller. Here’s the revised Application.java code page complete with a Spring MVC REST controller that responds with “Hello, World” when a request to /hello/World is made:

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

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

@RestController
class GreetingController {
    
    @RequestMapping("/hello/{name}")
    String hello(@PathVariable String name) {
        return "Hello, " + name + "!";
    }
}

Embedded Web Server Deployment

Out of the box, Spring Boot uses a public static void main entry-point that launches an embedded web server for you.

If you use the Maven build (mvn clean install) provided by the Spring Boot Initialzr, you’ll get a fat jar. This jar is handy because it includes all the other dependencies and things like your web server inside the archive. You can give anybody this one .jar and they can run your entire Spring application with no fuss: no build tool required, no setup, no web server configuration, etc: just java -jar ...your.jar.

Tomcat

When you run your application, Spring Boot will detect that you have a Spring MVC controller and start up an embedded Apache Tomcat 7 instance, by default. You should be able to test the REST endpoint by opening up your browser and hitting http://localhost:8080/hello/World.

There are lots of configuration options for the embedded Tomcat. You can enable HTTPS (SSL/TLS termination) for your webservice fairly easily by providing an EmbeddedServletContainerCustomizer, as I do in this example. The module described there is a turnkey web application that can run on HTTPS, requires only a SSL/TLS certificate, and embeds its own webserver. Running that particular application is dead simple: java -Dspring.profiles.active=production -Dkeystore.file=file:///$PWD/src/main/resources/keystore.p12 -jar target/oauth-1.0.0.BUILD-SNAPSHOT.jar.

This EmbeddedServletContainerCustomizer configuration SPI lets you tap most of the power of explicit XML configuration for a standalone Apache Tomcat instance. Smaller things, like which port the server runs on, can be configured by specifying properties either through the command line (as --D-style arguments) or through a loaded property file (Spring Boot will automatically consult any properties in a file named application.properties on the CLASSPATH, for example). Thus, to change the port on which Tomcat listens, you might specify --Dserver.port=8081, to have it listen on port 8081. If you specify server.port=0, it’ll automatically find an unused port to listen on, instead.

By default, Spring Boot uses Tomcat 7. If you want to use Tomcat 8, just say so! You need only override the Maven build’s tomcat.version property and this will trigger the resolution of later builds of Apache Tomcat.

<properties>
  <tomcat.version>8.0.3</tomcat.version>
</properties>

Jetty

Of course, some of you may want to use the Jetty embedded servlet container. Jetty’s a fine choice, as well. You can simply exclude the Spring Boot starter Tomcat module and then import the Spring Boot Starter Jetty module. Spring Boot will automatically delegate to that, instead. Here’s the revised dependencies section of our Maven build:

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
		</dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
		</dependency>
	</dependencies>

If you want to switch to Jetty 9, that’s easy as well. Ensure you have the following propertiesin your Maven build.

<properties>
    <java.version>1.7</java.version>
    <jetty.version>9.1.0.v20131115</jetty.version>
    <servlet-api.version>3.1.0</servlet-api.version>
</properties>

What about the Java EE Application Server?

But, I imagine you wondering, “how do I deploy it to an existing Tomcat installation, or to the classic Java EE application servers (some of which cost a lot of money!) like WebSphere, WebLogic, or JBoss?” Easy! It’s still just Spring, after all, so very little else is required. You’ll need to make three intuitive changes: move from a jar build to a war build in Maven: comment out the declaration of the spring-boot-maven-plugin plugin in your pom.xml file, then change the Maven packaging type to war. Finally, add a web entry point into your application. Spring configures almost everything for you using Servlet 3 Java configuration. You just need to give it the opportunity. Modify your Application entry-point class thusly:

package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(applicationClass, args);
    }

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

    private static Class<Application> applicationClass = Application.class;
}


@RestController
class GreetingController {

    @RequestMapping("/hello/{name}")
    String hello(@PathVariable String name) {
        return "Hello, " + name + "!";
    }
} 

This new base class – SpringBootServletInitializer – taps into a Servlet 3 style Java configuration API which lets you describe in code what you could only describe in web.xmlbefore. Such configuration classes are discovered and invoked at application startup. This gives Spring Boot a chance to tell the web server about the application, including the reqired Servlets, Filters and Listeners typically required for the various Spring projects.

This new class can now be used to run the application using embeddedd Jetty or Tomcat, internally, and it can be deployed to any Servlet 3 container. You may experience issues if you have classes that conflict with those that ship as parter of a larger application server. In this case, use your build tool’s facilities for excluding or making optional the relevant APIs. Here are the changes to the Maven build that I had to make to get the starter Spring Boot REST service up and running on JBoss WildFly (the AS formerly known as JBoss AS):

<?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>

	<groupId>org.demo</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>

    <packaging>war</packaging>
	<description>Demo project</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.0.0.BUILD-SNAPSHOT</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
		</dependency>
	</dependencies>

	<properties>
        <start-class>demo.Application</start-class>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.7</java.version>
	</properties>
	<repositories>
		<repository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>http://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</repository>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>http://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>
	<pluginRepositories>
		<pluginRepository>
			<id>spring-snapshots</id>
			<name>Spring Snapshots</name>
			<url>http://repo.spring.io/snapshot</url>
			<snapshots>
				<enabled>true</enabled>
			</snapshots>
		</pluginRepository>
		<pluginRepository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>http://repo.spring.io/milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</pluginRepository>
	</pluginRepositories>
</project>

I was then able to re-run the build and cp the built .war to the $WILDFLY_HOME/standalone/deployments directory.

Start the application server if it’s not already running, and you should then be able to bring the application up at http://localhost:8080/$YOURAPP/hello/World. Again, I’ve substituted $YOURAPP for the name of your application, as built.

To the Cloud!

No story about deployments would be complete without touching on the fastest growing deployment target today: the cloud! Of course, when we talk about cloud it helps to be specific: if you’re talking about deploying to an Amazon Web Services or a Google Compute Engine, directly, then it’s business as usual, just as though you were running the application on a Linux box on your own datacenter. Because, basically, that’s what you’re doing.

PaaS Deployment on Cloud Foundry and Heroku

If you’re trying to deploy the application to a Platform-as-a-service, Spring’s vaunted portability buys you a lot of options here. Deployment to Heroku, especially with the fat-jar approach, is the status quo for Heroku since that platform as a service expects you to bring-your-own-container, anyway! Simply put the java -jar incantation in your Procfile and you’re off to the races.

With Cloud Foundry you can deploy the application either standalone or as a .war-style web application. Once you’ve built your application (using, for example, mvn clean install) and installed the cf command line tool, simply answer the cf push command’s prompts as I have below:

  cf push --path target/demo-0.0.1-SNAPSHOT.jar

Name> $YOURAPP

Instances> 1

1: 128M
2: 256M
3: 512M
4: 1G
Memory Limit> 256M

Creating $YOURAPP... OK

1: $YOURAPP
2: none
Subdomain> $YOURAPP

1: cfapps.io
2: none
Domain> cfapps.io

Creating route $YOURAPP.cfapps.io... OK
Binding $YOURAPP.cfapps.io to $YOURAPP... OK

Create services for application?> n

Bind other services to application?> n

Save configuration?> y

Saving to manifest.yml... OK
Uploading $YOURAPP... OK
Preparing to start $YOURAPP... OK
-----> Downloaded app package (8.7M)
-----> Java Buildpack source: system
-----> Downloading Open JDK 1.7.0_51 from http://d2vm4m9hl67ira.cloudfront.net/openjdk/lucid/x86_64/openjdk-1.7.0_51.tar.gz (1.4s)
       Expanding Open JDK to .java-buildpack/open_jdk (1.3s)
-----> Downloading Spring Auto Reconfiguration 0.8.7 from http://d2vm4m9hl67ira.cloudfront.net/auto-reconfiguration/auto-reconfiguration-0.8.7.jar (0.0s)
-----> Uploading droplet (43M)
Checking status of app '$YOURAPP'...
  0 of 1 instances running (1 starting)
  0 of 1 instances running (1 starting)
  1 of 1 instances running (1 running)
Push successful! App '$YOURAPP' available at http://$YOURAPP.cfapps.io

The application shoud be up and running, and accessible from http://$YOURAPP.cfapps.io/hello/Cloud%20Foundry where, again, I’ve used $YOURAPP as a placeholder for the name of your application.

Conclusion

Not bad for one little Application class and a few tweaks to a build-file!

Spring Boot aims to be production ready, by default. This means that it ships with useful defaults out of the box that may be overriden, if necessary. By default, Spring Boot provides an embedded Apache Tomcat build. By default, Spring Boot configures everything for you in a way that’s most natural from development to production in today’s platforms, as well as in the leading platforms-as-a-service.

Spring Boot provides plenty of opportunities to override the configuration, including configurable properties and customization callbacks.

Looking forward, I can already see another few posts continuing this discussion into things like management of Spring Boot applications via monitoring and management tools (JMX and JConsole, New Relic, etc.) as well as security concerns. Spring Boot, happily, provides answers for all of these concerns, and more.

Your Next Steps with Boot

The Spring Boot documentation is coming together rapidly as it moves to 1.0, and in the meantime there are many great resources to continue exploring. Check out one of my favorite grab bag pages for tips ’n tricks, the How To document and don’t forget to check out the Spring IO guides, most of which build on Spring Boot!

I’d love to carry this discussion forward online. I want to know what other questions you want answered in your investigation of Spring Boot, so don’t be shy. I’ll be doing a virtual JUG on Spring Boot on April 9th, 2014, live! The event is worldwide and interactive, so please bring your questions, comments and feedback.

 

<!–  https://spring.io/blog/2014/03/07/deploying-spring-boot-applications  –>

Create a REST API with Spring Boot

Why Spring Boot?

Spring Boot is a framework that bootstraps a Java web application without the XML configuration headaches that come with a typical Spring application.   The framework adopts an opinionated approach to configuration by making decisions based on the use cases that fit the majority of modern web apps.  In other words, it follows the philosophy of convention over configuration.

With Spring Boot, we can create an application that bundles all dependencies and it’s servlet container so it doesn’t even require a traditional WAR deployment.    We’ll have a fat executable JAR that can be run as a standard Linux service.

SeatingNow

Let’s imagine we’re developing a restaurant reservation application called SeatingNow to compete with OpenTable.   Users can create an account, search for restaurants, book a reservation, and receive notifications via SMS or e-mail.

The application consists of the following microservices:

  • Account
  • Search
  • Restaurant
  • Reservation
  • Search
  • Messaging

Each of these microservices has a REST API and its own MySQL database.  The services will be accessed by desktop and mobile users via an API gateway.

In this article, we’ll focus on building the API for the Restaurant microservice.

REST Endpoints

Our application will expose the following endpoints:

  • GET /v1/reservations - Retrieves all reservations
  • GET /v1/reservations/{id} -Retrieves a specific reservation based on ID
  • POST /v1/reservations - Creates a new reservation
  • PUT /v1/reservations/{id} - Updates an existing reservation
  • DELETE /v1/reservations/{id} - Removes a specific reservation based on ID

Technology Stack

We’ll be using the following technologies for the application:

  • Spring Tool Suite (STS) 3.83
  • Spring Boot 1.5.1
  • Spring Data JPA 1.11
  • Spring MVC 4.3.6
  • MySQL 5.7
  • Maven 3.3.9

Getting Started

There are a few different ways that we can begin development:

We’ll use the Spring Tool Suite for this project.  STS is based on Eclipse and customized for developing Spring applications.  It comes with built-in Tomcat server, validation of config files among other handy features that makes life easier.

Installing Spring Tool Suite

Spring Tool Suite comes packaged as a zip file and does not use an install wizard or store anything in the Windows registry.   So we can just unzip the file and put it anywhere.

On first launch, it will ask us where we want our workspace to live.   This is the directory that holds all of our projects and settings.

Creating the Project

Let’s launch Spring Tool Suite and select File->New -> Spring Starter project

We can configure it as a Maven project and enter the Group, Artifact, and Package as below.  Click Next.

The next screen will ask to select our dependencies.  These selections will get populated into Maven’s pom.xml file.

For our project, we want the following dependencies:

  • Core -> Dev Tools
    • This dependency makes development easier for us by adding some neat features like automatic Tomcat restarts after each file change.  Not required but useful to have.
  • SQL -> JPA, MySQL
    • These dependencies will allow our app to communicate with a MySQL/MariaDB database.   JPA is the Java Persistence framework and will do the heavy lifting on the querying side so we don’t have to write boilerplate SQL statements for routine operations.
  • Web -> Web
    • This dependency allows us to create a REST API based on Spring MVC

 

Click Finish to create the project.

Maven pom.xml

Our project has now been created so let’s look at the Maven configuration file.  Double-click on the file in Package Explorer and go to the tab named “pom.xml” in the main window pane.

 

Parent project

We’ve got a parent project named spring-boot-start-parent

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.5.1.RELEASE</version>
</parent>

This configuration block declares that our project is a child of the parent project and thus inherits a host of default Maven configurations.

Dependencies

Now let’s check out the dependencies section:

<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>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
  </dependency>
  
  <dependency> 
    <groupId>mysql</groupId> 
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope> 
  </dependency> 
  
  <dependency> 
    <groupId>org.springframework.boot</groupId>     
    <artifactId>spring-boot-starter-test</artifactId> 
    <scope>test</scope> 
  </dependency>
</dependencies>

These artifacts (and their own dependencies) have all been downloaded automatically by Maven and the JARs can be viewed by expanding the Maven dependencies under Package Explorer:

Build

In order to make our final JAR executable, we’ll need to add an element named executable into this section:

<build>
  <plugins>
    <plugin>
	  <groupId>org.springframework.boot</groupId>
	  <artifactId>spring-boot-maven-plugin</artifactId>
	  <configuration>
	    <executable>true</executable>
      </configuration>
    </plugin>
  </plugins>
</build>

Application Class

The Application class containing the main method is created for us automatically by the Project wizard.

package com.codebyamir.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ReservationApp {

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

}

Notice that the class is annotated with @SpringBootApplication.  This annotation is shorthand for three annotations:  @Configuration, @EnableAutoConfiguration and @ComponentScan.

What does this do for us?

  • @Configuration tags the class as a source of bean definitions for the application context.
  • @EnableAutoConfiguration tells Spring Boot to start adding beans based on class path settings, other beans, and various property settings.
  • @ComponentScan tells Spring to look for other components, configurations, and services in the the com.codebyamir.springboot package.

Notice that there was no XML configuration required.

Our main method delegates to Spring Boot’s SpringApplication class by calling run.  SpringApplication will bootstrap our application, starting Spring which will in turn start the embedded Tomcat server.

We need to pass SeatingNow.class as an argument so SpringApplication knows the primary component.

The static run method performs a number of important setup tasks:

  • Sets the default configuration
  • Starts Spring application context
  • Performs classpath scan
  • Starts Tomcat server

If we run the project as a Java application (Right click project -> Run As -> Java Application), we see a bunch of output in the console with some fancy ASCII art:

 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.5.1.RELEASE)
2017-03-11 08:29:25.096  INFO 5484 --- [           main] com.codebyamir.springboot.SeatingNow   : Starting ReservationApp on SURFACEBOOK with PID 5484 (C:\Users\amirb\Documents\workspace-sts-3.8.3.RELEASE\seatingnow-api\target\classes started by amirb in C:\Users\amirb\Documents\workspace-sts-3.8.3.RELEASE\seatingnow-api)
2017-03-11 08:29:25.100  INFO 5484 --- [           main] com.codebyamir.springboot.SeatingNow   : No active profile set, falling back to default profiles: default
2017-03-11 08:29:25.188  INFO 5484 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5427c60c: startup date [Tue Feb 21 22:29:25 EST 2017]; root of context hierarchy
2017-03-11 08:29:26.478  INFO 5484 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration' of type [class org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2017-03-11 08:29:26.562  INFO 5484 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'validator' of type [class org.springframework.validation.beanvalidation.LocalValidatorFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2017-03-11 08:29:26.958  INFO 5484 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-03-11 08:29:26.978  INFO 5484 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2017-03-11 08:29:26.980  INFO 5484 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.11
2017-03-11 08:29:27.152  INFO 5484 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2017-03-11 08:29:27.153  INFO 5484 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1969 ms
2017-03-11 08:29:27.381  INFO 5484 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2017-03-11 08:29:27.386  INFO 5484 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-03-11 08:29:27.387  INFO 5484 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-03-11 08:29:27.387  INFO 5484 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-03-11 08:29:27.387  INFO 5484 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2017-03-11 08:29:27.845  INFO 5484 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5427c60c: startup date [Tue Feb 21 22:29:25 EST 2017]; root of context hierarchy
2017-03-11 08:29:27.950  INFO 5484 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.map<java.lang.string, java.lang.object="">> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-03-11 08:29:27.951  INFO 5484 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-03-11 08:29:27.982  INFO 5484 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-03-11 08:29:27.982  INFO 5484 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-03-11 08:29:28.067  INFO 5484 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-03-11 08:29:28.215  INFO 5484 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2017-03-11 08:29:28.275  INFO 5484 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-03-11 08:29:28.280  INFO 5484 --- [           main] com.codebyamir.springboot.ReservationApp   : Started ReservationApp in 3.576 seconds (JVM running for 3.95)</java.util.map<java.lang.string,>

We’ve started Tomcat server on localhost with its default port 8080.   Let’s check it out in our browser:

We get an error page from the Tomcat server.

What’s happening here?  There is no mapping for “/” so it tries to go to “/error” but there’s no mapping for that either so it returns a 404.

This is normal so no worries.  The server is running, but we haven’t defined any API endpoints yet.

Set server.error.whitelabel.enabled=false in application.properties to switch the whitelabel error page off and restore the default error page from Tomcat.

Populate the Database

One of the tenets of microservice architecture is one database per service.  So let’s create and initialize the database with some sample data:

CREATE DATABASE seatingnow_reservation;

USE seatingnow_reservation;

CREATE TABLE reservation (
`id` int(1) NOT NULL AUTO_INCREMENT,
`user_id` int(1) NOT NULL,
`party_size` tinyint(1) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`restaurant_id` int(1) NOT NULL, 
PRIMARY KEY (`id`)
) ENGINE=InnoDB CHARSET=utf8mb4;

INSERT INTO reservation VALUES 
(NULL,100,2,NOW(),800), 
(NULL,101,3,NOW() + INTERVAL 1 DAY,800), 
(NULL,102,5,NOW() + INTERVAL 2 DAY,800)

Here we are creating 3 reservations that correspond to users 100, 101, and 102.

  • Amir (user_id=100) has a reservation for 2 at restaurant XYZ (restaurant_id=800) on 3-11-2017 at 6pm
  • Beth (user_id=101) has a reservation for 3 at restaurant XYZ (restaurant_id=800) on 3-12-2017 at 6pm
  • Joe (user_id=102) has a reservation for 5 at restaurant XYZ (restaurant_id=800) on 3-13-2017 at 6pm

The columns user_id and restaurant_id would typically be foreign key references to other table columns named user.id and restaurant.id but we are simplifying things here a bit.

Entity Class

In order to model a reservation, we need to create a class called Reservation which is annotated with @Entity marking it as a JPA entity.

We’ll store the reservation id, name of the person who made the reservation, the reservation date/time, and the size of the party.

Since our class name is in title case (Reservation) and our table name is in lower case (reservation), we’ll need to let Spring know about this by using @Table(name=”reservation”) before our class declaration.

We tell Spring the private key of our table by using the @Id annotation.   The @Columnannotations are for other columns we want to use.   If any of the database column names differ from our instance variables, then we must explicitly specify the database column name as part of the annotation – @Column(name=”user_id”) 

light_bulb (2).png

Avoid camelcase column names in your database because Hibernate converts these into snake case. 

package com.codebyamir.springboot.reservation;

import java.time.LocalDateTime;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

// Model class 

@Entity
@Table(name="reservation")
public class Reservation {
	
	@Id
	private Long id;
	
	@Column
	private LocalDateTime dt;

	
	@Column(name="user_id")
	private Long userId;
	
	@Column(name="restaurant_id")
	private Long restaurantId;
	
	public Long getRestaurantId() {
		return restaurantId;
	}

	public void setRestaurantId(Long restaurantId) {
		this.restaurantId = restaurantId;
	}

	// Hibernate will convert camel case column names to snake case!!!
	// Don't use camelcase columns in DB
	@Column(name="party_size")
	private int partySize;
	
	
	
	public Reservation() {}
	
	public Reservation(Long id,  Long userId, int partySize) {
		this.id = id;
	
		this.userId = userId;
		this.partySize = partySize;
	}
		
	public Long getId() {
		return id;
	}

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

	public LocalDateTime getDt() {
		return dt;
	}

	public void setDt(LocalDateTime dt) {
		this.dt = dt;
	}

	public Long getUserId() {
		return userId;
	}

	public void setUserId(Long userId) {
		this.userId = userId;
	}

	public int getPartySize() {
		return partySize;
	}

	public void setPartySize(int partySize) {
		this.partySize = partySize;
	}

}

Repository Interface

In a typical Java application, we would expect to write a class that implements ReservationRepository.  But since we’re using Spring Data JPA, we don’t have to worry about that.   JPA will create an implementation on the fly during run-time.

All we have to do is extend the CrudRepository interface like below:

package com.codebyamir.springboot.reservation;

import org.springframework.data.repository.CrudRepository;

public interface ReservationRepository extends CrudRepository<Reservation,String> {

}

We specify the generic parameters for the entity and ID that we are working with (Reservation and String).   We will inherit several methods for saving, deleting, and finding Reservation entities.

We may also define our own methods here if we wish like findByDate() and findByLastName().   For this example, we do not need to define any additional methods.

Service Class

We now create our service class named ReservationService and annotate it with @Service.

Service classes contain the business logic and call methods in the repository layer.

package com.codebyamir.springboot.reservation;

import java.util.ArrayList;
import java.util.List;

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

@Service	
public class ReservationService {

	@Autowired
	private ReservationRepository reservationRepository;
	
	// Retrieve all rows from table and populate list with objects
	public List getAllReservations() {
		
		List reservations = new ArrayList<>();
		reservationRepository.findAll().forEach(reservations::add);
		
		return reservations;
	}
	
	// Retrieves one row from table based on given id
	public Reservation getReservation(Long id) {
		return reservationRepository.findOne(id);
	
	}
	
	// Inserts row into table 
	public void addReservation(Reservation reservation) {
		reservationRepository.save(reservation);
	}
	
	// Updates row in table
	public void updateReservation(Long id, Reservation reservation) {
		reservationRepository.save(reservation);
	}
	
	// Removes row from table
	public void deleteReservation(Long id) {
		reservationRepository.delete(id);
	}
}

Controller Class

In order to handle HTTP requests, we must add a controller.   This will be a Java class named ReservationController with a @RestController annotation applied to it.

Inside this class, we define methods that handle the actions for each URI by using the @RequestMapping annotation.   The controller class creates an instance of class ReservationService to perform its work thanks to the @Autowired annotation.

package com.codebyamir.springboot.reservation;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/v1")
public class ReservationController {
	
	@Autowired
	private ReservationService reservationService;
	
	// ------------ Retrieve all reservations ------------
	@RequestMapping(value = "/reservations", method = RequestMethod.GET)
	public List getAllReservations() {
		
		return reservationService.getAllReservations();
		
	}
	
	// ------------ Retrieve a reservation ------------
	@RequestMapping(value = "/reservations/{id}", method = RequestMethod.GET)
	public Reservation getReservation(@PathVariable String id) {
		return reservationService.getReservation(id);
	}
	
	// ------------ Create a reservation ------------
	@RequestMapping(value = "/reservations", method = RequestMethod.POST)
	public void addReservation(@RequestBody Reservation reservation) {
		reservationService.addReservation(reservation);
		
	}
	
	// ------------ Update a reservation ------------
	@RequestMapping(value = "/reservations/{id}", method = RequestMethod.PUT)
	public void updateReservation(@RequestBody Reservation reservation,@PathVariable String id) {
		reservationService.updateReservation(id, reservation);
	}
	
	// ------------ Delete a reservation ------------
	@RequestMapping(value = "/reservations/{id}", method = RequestMethod.DELETE)
	public void deleteReservation(@PathVariable String id) {
		reservationService.deleteReservation(id);
	}
}

JPA Converter Class

JPA does not know how to serialize LocalDateTime objects which poses a problem for us since our entity class has one.   The solution to this problem is to create a helper class that instructs JPA on conversion:

package com.codebyamir.springboot.reservation;

import java.sql.Timestamp;
import java.time.LocalDateTime;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter(autoApply = true)
public class LocalDateTimeAttributeConverter implements AttributeConverter {
	
    @Override
    public Timestamp convertToDatabaseColumn(LocalDateTime locDateTime) {
    	return (locDateTime == null ? null : Timestamp.valueOf(locDateTime));
    }

    @Override
    public LocalDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
    	return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime());
    }
}

Configuration with application.properties

In this project, we will use an application.properties file in /src/main/resources.   Spring Boot reads this file on startup to determine how to connect to our database.

server.address=127.0.0.1
spring.datasource.url=jdbc:mysql://localhost:3306/seatingnow?autoReconnect=true&useSSL=false
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

We could have also used O/S environment variables or an external application.properties file to specify these values.   All the configuration options can be found here.

Start the Application

Let’s restart the application and see how it looks.   The console output will tell us if there are any issues connecting to the database.

Our output below looks normal so let’s move forward and test our API.

09:39:45.496 [main] DEBUG org.springframework.boot.devtools.settings.DevToolsSettings - Included patterns for restart : []
09:39:45.500 [main] DEBUG org.springframework.boot.devtools.settings.DevToolsSettings - Excluded patterns for restart : [/spring-boot-starter/target/classes/, /spring-boot-autoconfigure/target/classes/, /spring-boot-starter-[\w-]+/, /spring-boot/target/classes/, /spring-boot-actuator/target/classes/, /spring-boot-devtools/target/classes/]
09:39:45.500 [main] DEBUG org.springframework.boot.devtools.restart.ChangeableUrls - Matching URLs for reloading : [file:/C:/Users/amirb/Documents/workspace-sts-3.8.3.RELEASE/course-api/target/classes/]

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

2017-03-11 09:39:45.936  INFO 24732 --- [  restartedMain] c.codebyamir.springboot.ReservationApp   : Starting ReservationApp on SURFACEBOOK with PID 24732 (C:\Users\amirb\Documents\workspace-sts-3.8.3.RELEASE\course-api\target\classes started by amirb in C:\Users\amirb\Documents\workspace-sts-3.8.3.RELEASE\course-api)
2017-03-11 09:39:45.937  INFO 24732 --- [  restartedMain] c.codebyamir.springboot.ReservationApp   : No active profile set, falling back to default profiles: default
2017-03-11 09:39:46.013  INFO 24732 --- [  restartedMain] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5c6c80b1: startup date [Sat Mar 11 09:39:46 EST 2017]; root of context hierarchy
2017-03-11 09:39:48.173  INFO 24732 --- [  restartedMain] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration' of type [class org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2017-03-11 09:39:48.261  INFO 24732 --- [  restartedMain] trationDelegate$BeanPostProcessorChecker : Bean 'validator' of type [class org.springframework.validation.beanvalidation.LocalValidatorFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2017-03-11 09:39:48.342  INFO 24732 --- [  restartedMain] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [class org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$EnhancerBySpringCGLIB$925fe313] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2017-03-11 09:39:49.127  INFO 24732 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-03-11 09:39:49.147  INFO 24732 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service Tomcat
2017-03-11 09:39:49.149  INFO 24732 --- [  restartedMain] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.11
2017-03-11 09:39:49.290  INFO 24732 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2017-03-11 09:39:49.291  INFO 24732 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3283 ms
2017-03-11 09:39:49.470  INFO 24732 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2017-03-11 09:39:49.475  INFO 24732 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-03-11 09:39:49.475  INFO 24732 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-03-11 09:39:49.475  INFO 24732 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-03-11 09:39:49.475  INFO 24732 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2017-03-11 09:39:50.223  INFO 24732 --- [  restartedMain] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2017-03-11 09:39:50.242  INFO 24732 --- [  restartedMain] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
	name: default
	...]
2017-03-11 09:39:50.337  INFO 24732 --- [  restartedMain] org.hibernate.Version                    : HHH000412: Hibernate Core {5.0.11.Final}
2017-03-11 09:39:50.339  INFO 24732 --- [  restartedMain] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2017-03-11 09:39:50.341  INFO 24732 --- [  restartedMain] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist
2017-03-11 09:39:50.395  INFO 24732 --- [  restartedMain] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2017-03-11 09:39:50.536  INFO 24732 --- [  restartedMain] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
2017-03-11 09:39:51.442  INFO 24732 --- [  restartedMain] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2017-03-11 09:39:52.580  INFO 24732 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5c6c80b1: startup date [Sat Mar 11 09:39:46 EST 2017]; root of context hierarchy
2017-03-11 09:39:52.794  INFO 24732 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/v1/reservations/{id}],methods=[GET]}" onto public com.codebyamir.springboot.reservation.Reservation com.codebyamir.springboot.reservation.ReservationController.getReservation(java.lang.Long)
2017-03-11 09:39:52.795  INFO 24732 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/v1/reservations],methods=[POST]}" onto public void com.codebyamir.springboot.reservation.ReservationController.addReservation(com.codebyamir.springboot.reservation.Reservation)
2017-03-11 09:39:52.796  INFO 24732 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/v1/reservations/{id}],methods=[DELETE]}" onto public void com.codebyamir.springboot.reservation.ReservationController.deleteReservation(java.lang.Long)
2017-03-11 09:39:52.796  INFO 24732 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/v1/reservations/{id}],methods=[PUT]}" onto public void com.codebyamir.springboot.reservation.ReservationController.updateReservation(com.codebyamir.springboot.reservation.Reservation,java.lang.Long)
2017-03-11 09:39:52.797  INFO 24732 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/v1/reservations],methods=[GET]}" onto public java.util.List com.codebyamir.springboot.reservation.ReservationController.getAllReservations()
2017-03-11 09:39:52.802  INFO 24732 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-03-11 09:39:52.802  INFO 24732 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-03-11 09:39:52.852  INFO 24732 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-03-11 09:39:52.853  INFO 24732 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-03-11 09:39:52.946  INFO 24732 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-03-11 09:39:53.447  INFO 24732 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2017-03-11 09:39:53.547  INFO 24732 --- [  restartedMain] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2017-03-11 09:39:53.704  INFO 24732 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-03-11 09:39:53.726  INFO 24732 --- [  restartedMain] c.codebyamir.springboot.ReservationApp   : Started ReservationApp in 8.205 seconds (JVM running for 8.823)

Test the API

We have a few options for testing the API.  Some popular utilities are curl (command-line) and Postman (GUI).  We can also use the browser for any GET requests.

Retrieve all reservations [GET /v1/reservations]

curl -X GET -H "Content-Type: application/json" http://localhost:8080/v1/reservations

[
  {
    "id": 1,
    "dt": {
      "dayOfMonth": 12,
      "dayOfWeek": "SUNDAY",
      "dayOfYear": 71,
      "month": "MARCH",
      "monthValue": 3,
      "year": 2017,
      "hour": 21,
      "minute": 1,
      "nano": 0,
      "second": 11,
      "chronology": {
        "id": "ISO",
        "calendarType": "iso8601"
      }
    },
    "userId": 100,
    "restaurantId": 800,
    "partySize": 2
  },
  {
    "id": 2,
    "dt": {
      "dayOfMonth": 13,
      "dayOfWeek": "MONDAY",
      "dayOfYear": 72,
      "month": "MARCH",
      "monthValue": 3,
      "year": 2017,
      "hour": 21,
      "minute": 1,
      "nano": 0,
      "second": 11,
      "chronology": {
        "id": "ISO",
        "calendarType": "iso8601"
      }
    },
    "userId": 101,
    "restaurantId": 800,
    "partySize": 3
  },
  {
    "id": 3,
    "dt": {
      "dayOfMonth": 14,
      "dayOfWeek": "TUESDAY",
      "dayOfYear": 73,
      "month": "MARCH",
      "monthValue": 3,
      "year": 2017,
      "hour": 21,
      "minute": 1,
      "nano": 0,
      "second": 11,
      "chronology": {
        "id": "ISO",
        "calendarType": "iso8601"
      }
    },
    "userId": 102,
    "restaurantId": 800,
    "partySize": 5
  }
]

 

Delete a reservation [DELETE /v1/reservations/2]

curl -X DELETE -H "Content-Type: application/json" -H "Cache-Control: no-cache""http://localhost:8080/v1/reservations/2"

 

Run the Executable JAR as a Linux Service

The executable jar is named reservation-microservice-0.0.1-SNAPSHOT.jar.

We can run it as a Linux System V init service like so:

# ln -s /home/ec2-user/reservation-microservice-0.0.1-SNAPSHOT.jar /etc/init.d/springApp
# /etc/init.d/springApp
Usage: /etc/init.d/springApp {start|stop|force-stop|restart|force-reload|status|run}

The script supports the standard service startstoprestart and status commands.

  • Writes a PID file in /var/run/springApp/springApp.pid
  • Writes console logs to /var/log/springApp.log
<!–  https://www.codebyamir.com/blog/create-rest-api-with-spring-boot –>

Spring Data JPA Repository Example

Home » Enterprise Java » spring » Data » Spring Data JPARepository Example

About Mary Zheng

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.
 

Spring Data JPARepository Example

 

1. Introduction

Spring Data is a part of Spring Framework. It simplifies the data access process for both relational and non-relational databases. Java Persistence API (JPA) is Java’s standard API specification for object-relational mappingSpring Data JPA is a part of Spring Data and it supports Hibernate 5, OpenJPA 2.4, and EclipseLink 2.6.1.

Spring Data repository significantly reduces the amount of boilerplate code required to implement data access layers for various persistence stores. Spring Data JpaRepository interface extends CrudRepository and provides finder methods out of the box.

In this example, I will demonstrate how to use Spring Data JpaRepository to create, update, delete, and search contact data in a relational database.

Want to master Spring Data ?

 

Subscribe to our newsletter and download the Spring Data Ultimate Guide right now!

In order to help you master Spring Data, we have compiled a kick-ass guide with all the major features and use cases! Besides studying them online you may download the eBook in PDF format!


 

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)
  • Eclipse Mars (Any Java IDE would work)
  • Spring data 1.5.10.RELEASE
  • Hibernate 5.0.12.Final
  • H2 1.4.196

3. Spring Boot JPA Project

Spring Boot Starters provides more than 30 starters to ease the dependency management for your project. The easiest way to generate a Spring Boot JPA with Hibernate project is via 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.10 and Add both JPA and H2 in the “search for dependencies”
  3. Enter the group name as jcg.zheng.demo and artifact as jpademo
  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 POM

The generated pom.xml includes H2 and spring-boot-starter-data-jpa, which uses Hibernate as the implementation of JPA.

pom.xml

01<?xml version="1.0" encoding="UTF-8"?>
04    <modelVersion>4.0.0</modelVersion>
05 
06    <groupId>jcg.zheng.demo</groupId>
07    <artifactId>spring-jparepository-demo</artifactId>
08    <version>0.0.1-SNAPSHOT</version>
09    <packaging>jar</packaging>
10 
11    <name>spring-jparepository-demo</name>
12    <description>Demo Spring Data JPA Application</description>
13 
14    <parent>
15        <groupId>org.springframework.boot</groupId>
16        <artifactId>spring-boot-starter-parent</artifactId>
17        <version>1.5.10.RELEASE</version>
18        <relativePath />
19    </parent>
20 
21    <properties>
22        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
24        <java.version>1.8</java.version>   
25    </properties>
26 
27    <dependencies>       
28 
29        <dependency>
30            <groupId>org.springframework.boot</groupId>
31            <artifactId>spring-boot-starter-data-jpa</artifactId>
32        </dependency>
33 
34        <dependency>
35            <groupId>com.h2database</groupId>
36            <artifactId>h2</artifactId>
37            <scope>runtime</scope>
38        </dependency>
39 
40        <dependency>
41            <groupId>org.springframework.boot</groupId>
42            <artifactId>spring-boot-starter-test</artifactId>
43            <scope>test</scope>
44        </dependency>
45    </dependencies>
46 
47 
48    <build>
49        <plugins>
50            <plugin>
51                <groupId>org.springframework.boot</groupId>
52                <artifactId>spring-boot-maven-plugin</artifactId>
53            </plugin>
54        </plugins>
55    </build>
56</project>

3.2 JPA Demo Application

The generated JpaDemoApplication.java 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.

We will configure several Spring Beans to manage transactions in the H2 datasource.

JpaDemoApplication.java

01package jcg.zheng.demo.jpademo;
02 
03import javax.persistence.EntityManagerFactory;
04import javax.sql.DataSource;
05 
06import org.springframework.boot.SpringApplication;
07import org.springframework.boot.autoconfigure.SpringBootApplication;
08import org.springframework.context.annotation.Bean;
09import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
10import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
11import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
12import org.springframework.orm.jpa.JpaTransactionManager;
13import org.springframework.orm.jpa.JpaVendorAdapter;
14import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
15import org.springframework.orm.jpa.vendor.Database;
16import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
17 
18@SpringBootApplication
19@EnableJpaRepositories(basePackages = "jcg.zheng.demo.jpademo")
20public class JpaDemoApplication {
21 
22    public static void main(String[] args) {
23        SpringApplication.run(JpaDemoApplication.class, args);
24    }
25 
26    @Bean
27    public DataSource dataSource() {
28        return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
29    }
30 
31    @Bean
32    public JpaVendorAdapter jpaVendorAdapter() {
33        HibernateJpaVendorAdapter bean = new HibernateJpaVendorAdapter();
34        bean.setDatabase(Database.H2);
35        bean.setGenerateDdl(true);
36        bean.setShowSql(true);
37        return bean;
38    }
39 
40    @Bean
41    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
42            JpaVendorAdapter jpaVendorAdapter) {
43        LocalContainerEntityManagerFactoryBean bean = new LocalContainerEntityManagerFactoryBean();
44        bean.setDataSource(dataSource);
45        bean.setJpaVendorAdapter(jpaVendorAdapter);
46        bean.setPackagesToScan("jcg.zheng.demo.jpademo");
47        return bean;
48    }
49 
50    @Bean
51    public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
52        return new JpaTransactionManager(emf);
53    }
54}

Note: Configure four Spring Beans – dataSource, jpaVendorAdapter, entityManagerFactory, transactionManager to manage the transactions.

4. Domains

In this step, we will create two domains – Contact and ContactNote. Use the JPA annotations to map them to two tables in a database. These two tables have a one-to-many relationship.

4.1 Contact

The Contact entity class is mapped to CONTACT table in the database. All the fields are mapped to columns with the @Column annotation.

Contact.java

001package jcg.zheng.demo.jpademo.entity;
002 
003import java.util.ArrayList;
004import java.util.List;
005 
006import javax.persistence.CascadeType;
007import javax.persistence.Column;
008import javax.persistence.Entity;
009import javax.persistence.EnumType;
010import javax.persistence.Enumerated;
011import javax.persistence.FetchType;
012import javax.persistence.GeneratedValue;
013import javax.persistence.Id;
014import javax.persistence.OneToMany;
015import javax.persistence.Table;
016 
017import jcg.zheng.demo.jpademo.type.PhoneType;
018 
019@Entity
020@Table(name = "CONTACT")
021public class Contact {
022 
023    @Id
024    @GeneratedValue
025    @Column(name = "ID")
026    private Long id;
027 
028    @Column(name = "First_Name")
029    private String firstName;
030 
031    @Column(name = "Last_Name")
032    private String lastName;
033 
034    @Column(name = "Email")
035    private String email;
036 
037    @Column(name = "Phone_Number")
038    private String phoneNumber;
039 
040    @Column(name = "Phone_Type")
041    @Enumerated(EnumType.STRING)
042    private PhoneType phoneType;
043 
044    @OneToMany(mappedBy="contact", cascade = CascadeType.ALL, fetch = FetchType.EAGER, targetEntity = Contact_Note.class)
045    private List notes;
046 
047    public Contact() {
048    }
049 
050    public Contact(String firstName, String lastName, String email, PhoneType phoneType, String phone) {
051 
052        this.firstName = firstName;
053        this.lastName = lastName;
054        this.email = email;
055        this.phoneType = phoneType;
056        this.phoneNumber = phone;
057    }
058 
059    public Long getId() {
060        return id;
061    }
062 
063    public String getFirstName() {
064        return firstName;
065    }
066 
067    public void setFirstName(String firstName) {
068        this.firstName = firstName;
069    }
070 
071    public String getLastName() {
072        return lastName;
073    }
074 
075    public void setLastName(String lastName) {
076        this.lastName = lastName;
077    }
078 
079    public String getEmail() {
080        return email;
081    }
082 
083    public void setEmail(String email) {
084        this.email = email;
085    }
086 
087    public void setId(Long id) {
088        this.id = id;
089    }
090 
091    public String getPhoneNumber() {
092        return phoneNumber;
093    }
094 
095    public void setPhoneNumber(String phoneNumber) {
096        this.phoneNumber = phoneNumber;
097    }
098 
099    public PhoneType getPhoneType() {
100        return phoneType;
101    }
102 
103    public void setPhoneType(PhoneType phoneType) {
104        this.phoneType = phoneType;
105    }
106 
107    public List getNotes() {
108        if (this.notes == null) {
109            this.notes = new ArrayList<>();
110        }
111        return this.notes;
112    }
113     
114    public void addNote(Contact_Note note){
115        getNotes().add(note);
116        note.setContact(this);
117    }
118 
119    public void setNotes(List addresses) {
120        this.notes = addresses;
121    }
122 
123}

4.2 Contact Note

The Contact_Note entity class is mapped to Contact_Note table in the database. Each contact can have many contact notes.

Contact_Note.java

01package jcg.zheng.demo.jpademo.entity;
02 
03import javax.persistence.Entity;
04import javax.persistence.GeneratedValue;
05import javax.persistence.Id;
06import javax.persistence.JoinColumn;
07import javax.persistence.ManyToOne;
08 
09@Entity
10public class Contact_Note {
11 
12    @Id
13    @GeneratedValue
14    private Long id;
15 
16    private String message;
17 
18    @ManyToOne
19    @JoinColumn(name = "CONTACT_ID")
20    private Contact contact;
21 
22    public Contact_Note() {
23        super();
24    }
25 
26    public Long getId() {
27        return id;
28    }
29 
30    public void setId(Long id) {
31        this.id = id;
32    }
33 
34    public Contact getContact() {
35        return contact;
36    }
37 
38    public void setContact(Contact contact) {
39        this.contact = contact;
40    }
41 
42    public String getMessage() {
43        return message;
44    }
45 
46    public void setMessage(String message) {
47        this.message = message;
48    }
49 
50}

4.3 Phone Type

Phone type is defined as an enum and is mapped to the Phone_type column in the CONTACT table.

PhoneType.java

1package jcg.zheng.demo.jpademo.type;
2 
3public enum PhoneType {
4    OFFICE, HOME, MOBILE, OTHER;
5}

5. ContactRepository

The repository interface must extend Repository and be typed to the domain class and an ID type. In this step, we will annotate ContactRepository with @Repository and extend it from JpaRepository along with the Contact domain and its ID type. It serves two purposes:

  1. By extending JpaRepository we get a bunch of generic CRUD methods to create, update, delete, and find contacts.
  2. It allows Spring to scan the classpath for this interface and create a Spring bean for it.

ContactRepository.java

01package jcg.zheng.demo.jpademo.repository;
02 
03import java.util.List;
04 
05import org.springframework.data.jpa.repository.JpaRepository;
06import org.springframework.data.jpa.repository.Query;
07import org.springframework.data.repository.query.Param;
08import org.springframework.stereotype.Repository;
09import org.springframework.transaction.annotation.Transactional;
10 
11import jcg.zheng.demo.jpademo.entity.Contact;
12import jcg.zheng.demo.jpademo.type.PhoneType;
13 
14@Repository
15@Transactional
16public interface ContactRepository extends JpaRepository<Contact, Long> {
17 
18    @Query("SELECT con FROM Contact con  WHERE con.phoneType=(:pType) AND con.lastName= (:lName)")
19    List findByLastNameAndPhoneType(@Param("pType") PhoneType pType, @Param("lName") String lName);
20 
21}

We will create ContactRepositoryTest which utilizes SpringRunner and @DataJpaTest to demonstrate that ContactRepository can create, update, delete, and find contacts with just a few lines of code.

ContactRepositoryTest.java

001package jcg.zheng.demo.jpademo.repository;
002 
003import static org.junit.Assert.assertEquals;
004import static org.junit.Assert.assertNull;
005 
006import java.util.List;
007 
008import org.junit.Test;
009import org.junit.runner.RunWith;
010import org.springframework.beans.factory.annotation.Autowired;
011import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
012import org.springframework.test.context.junit4.SpringRunner;
013 
014import jcg.zheng.demo.jpademo.entity.Contact;
015import jcg.zheng.demo.jpademo.entity.Contact_Note;
016import jcg.zheng.demo.jpademo.type.PhoneType;
017 
018@RunWith(SpringRunner.class)
019@DataJpaTest
020public class ContactRepositoryTest {
021 
022    @Autowired
023    private ContactRepository contactRepo;
024 
025    @Test
026    public void it_can_find_the_contact_after_save_it() {
027        Contact contact = new Contact("Mary", "Zheng", "test@test.com", PhoneType.HOME, "6365272943");
028        Contact_Note note = new Contact_Note();
029        note.setMessage("She is a java geek");
030        contact.addNote(note); 
031         
032        contactRepo.save(contact);
033         
034        List contacts = contactRepo.findAll();
035         
036        assertEquals(1, contacts.size());
037        assertEquals("Mary", contacts.get(0).getFirstName());
038        assertEquals("Zheng", contacts.get(0).getLastName());
039        assertEquals("test@test.com", contacts.get(0).getEmail());
040        assertEquals(PhoneType.HOME, contacts.get(0).getPhoneType());
041        assertEquals("6365272943", contacts.get(0).getPhoneNumber());
042        assertEquals(1, contacts.get(0).getNotes().size());
043        assertEquals("She is a java geek", contacts.get(0).getNotes().get(0).getMessage());
044    }
045 
046    @Test
047    public void it_can_delete_the_contact_after_save_it() {
048        Contact contact = new Contact("Mary", "Zheng", "test@test.com", PhoneType.HOME, "6365272943");
049        Contact_Note note = new Contact_Note();
050        note.setMessage("She is a java geek");
051        contact.addNote(note);
052         
053        contactRepo.save(contact);
054         
055        List foundContacts = contactRepo.findAll();
056 
057        contactRepo.delete(foundContacts.get(0));
058         
059        List contacts = contactRepo.findAll();
060        assertEquals(0, contacts.size());
061 
062    }
063     
064    @Test
065    public void it_can_update_the_contact_after_save_it() {
066        Contact contact = new Contact("Mary", "Zheng", "test@test.com", PhoneType.HOME, "6365272943");  
067         
068        contactRepo.save(contact);     
069      
070        contact.setEmail("mary.zheng@test.com");
071        contactRepo.save(contact);
072         
073        List contacts = contactRepo.findAll();
074        assertEquals(1, contacts.size());
075        assertEquals("mary.zheng@test.com", contacts.get(0).getEmail());
076    }
077 
078 
079    @Test
080    public void it_can_find_contacts_by_name_and_type() {
081 
082        contactRepo.save(new Contact("Mary", "Zheng", "mary.zheng@jcg.org", PhoneType.HOME, "6368168164"));
083        contactRepo.save(new Contact("Tom", "Smith", "tom.smith@jcg.org", PhoneType.MOBILE, "(636) 527-2943"));
084        contactRepo.save(new Contact("John", "Joe", "john.joe@jcg.org", PhoneType.OFFICE, "(314) 527 2943"));
085        contactRepo.save(new Contact("Cindy", "Chang", "cindy.change@jcg.org", PhoneType.OTHER, "404-789-1456"));
086 
087        List contactsWithZheng = contactRepo.findByLastNameAndPhoneType(PhoneType.HOME, "Zheng");
088         
089        assertEquals(1, contactsWithZheng.size());
090        Contact foundContact = contactsWithZheng.get(0);
091        assertEquals("Mary", foundContact.getFirstName());
092        assertEquals("Zheng", foundContact.getLastName());
093        assertEquals("mary.zheng@jcg.org", foundContact.getEmail());
094        assertEquals(PhoneType.HOME, foundContact.getPhoneType());
095        assertEquals("6368168164", foundContact.getPhoneNumber());
096        assertEquals(0, foundContact.getNotes().size());       
097    }
098     
099    @Test
100    public void it_return_null_when_not_found(){
101        Contact found = contactRepo.findOne(2L);
102        assertNull(found);
103    }
104 
105}

6. Demo Time

Execute the Junit tests to confirm that the ContactRepository is working as expected.

6.1 Save

it_can_find_the_contact_after_save_it output

012018-03-08 19:21:55.074  INFO 5024 --- [           main] j.z.d.j.r.ContactRepositoryTest          : Starting ContactRepositoryTest on SL2LS431841 with PID 5024 (started by Shu.Shan in C:\MZheng_Java_workspace\Java Code Geek Examples\spring-jparepository-demo)
022018-03-08 19:21:55.076  INFO 5024 --- [           main] j.z.d.j.r.ContactRepositoryTest          : No active profile set, falling back to default profiles: default
032018-03-08 19:21:55.104  INFO 5024 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7671cb68: startup date [Thu Mar 08 19:21:55 CST 2018]; root of context hierarchy
042018-03-08 19:21:55.544  INFO 5024 --- [           main] beddedDataSourceBeanFactoryPostProcessor : Replacing 'dataSource' DataSource bean with embedded version
052018-03-08 19:21:55.545  INFO 5024 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'dataSource' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=jpaDemoApplication; factoryMethodName=dataSource; initMethodName=null; destroyMethodName=(inferred); defined in jcg.zheng.demo.jpademo.JpaDemoApplication] with [Root bean: class [org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration$EmbeddedDataSourceFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]
062018-03-08 19:21:56.184  INFO 5024 --- [           main] o.s.j.d.e.EmbeddedDatabaseFactory        : Starting embedded database: url='jdbc:h2:mem:b7b1d620-048e-4b5e-9675-3c3fd4742c3e;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'
072018-03-08 19:21:56.703  INFO 5024 --- [           main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
082018-03-08 19:21:56.724  INFO 5024 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
09    name: default
10    ...]
112018-03-08 19:21:56.894  INFO 5024 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.0.12.Final}
122018-03-08 19:21:56.898  INFO 5024 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
132018-03-08 19:21:56.900  INFO 5024 --- [           main] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist
142018-03-08 19:21:56.985  INFO 5024 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
152018-03-08 19:21:57.211  INFO 5024 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
162018-03-08 19:21:57.988  INFO 5024 --- [           main] org.hibernate.tool.hbm2ddl.SchemaUpdate  : HHH000228: Running hbm2ddl schema update
172018-03-08 19:21:58.029  INFO 5024 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: CONTACT
182018-03-08 19:21:58.030  INFO 5024 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: CONTACT
192018-03-08 19:21:58.038  INFO 5024 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: Contact_Note
202018-03-08 19:21:58.040  INFO 5024 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: Contact_Note
212018-03-08 19:21:58.121  INFO 5024 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
222018-03-08 19:21:58.503  INFO 5024 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
232018-03-08 19:21:58.975  INFO 5024 --- [           main] j.z.d.j.r.ContactRepositoryTest          : Started ContactRepositoryTest in 4.345 seconds (JVM running for 5.428)
242018-03-08 19:21:59.035  INFO 5024 --- [           main] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context [DefaultTestContext@2ea6137 testClass = ContactRepositoryTest, testInstance = jcg.zheng.demo.jpademo.repository.ContactRepositoryTest@400cff1a, testMethod = it_can_find_the_contact_after_save_it@ContactRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@41ee392b testClass = ContactRepositoryTest, locations = '{}', classes = '{class jcg.zheng.demo.jpademo.JpaDemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@1e67a849 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1f554b06, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@131276c2, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4d95d2a2, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@d7556ade, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@528931cf], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@65b97f47]; rollback [true]
25Hibernate: call next value for hibernate_sequence
26Hibernate: call next value for hibernate_sequence
27Hibernate: insert into CONTACT (Email, First_Name, Last_Name, Phone_Number, Phone_Type, ID) values (?, ?, ?, ?, ?, ?)
28Hibernate: insert into Contact_Note (CONTACT_ID, message, id) values (?, ?, ?)
29Hibernate: select contact0_.ID as ID1_0_, contact0_.Email as Email2_0_, contact0_.First_Name as First_Na3_0_, contact0_.Last_Name as Last_Nam4_0_, contact0_.Phone_Number as Phone_Nu5_0_, contact0_.Phone_Type as Phone_Ty6_0_ from CONTACT contact0_
302018-03-08 19:21:59.317  INFO 5024 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test context [DefaultTestContext@2ea6137 testClass = ContactRepositoryTest, testInstance = jcg.zheng.demo.jpademo.repository.ContactRepositoryTest@400cff1a, testMethod = it_can_find_the_contact_after_save_it@ContactRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@41ee392b testClass = ContactRepositoryTest, locations = '{}', classes = '{class jcg.zheng.demo.jpademo.JpaDemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@1e67a849 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1f554b06, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@131276c2, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4d95d2a2, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@d7556ade, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@528931cf], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]].
312018-03-08 19:21:59.329  INFO 5024 --- [       Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@7671cb68: startup date [Thu Mar 08 19:21:55 CST 2018]; root of context hierarchy
322018-03-08 19:21:59.337  INFO 5024 --- [       Thread-2] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
  • Line 28-29: two Insert statements

6.2 Update

it_can_update_the_contact_after_save_it output

012018-03-08 19:24:43.821  INFO 18416 --- [           main] j.z.d.j.r.ContactRepositoryTest          : Starting ContactRepositoryTest on SL2LS431841 with PID 18416 (started by Shu.Shan in C:\MZheng_Java_workspace\Java Code Geek Examples\spring-jparepository-demo)
022018-03-08 19:24:43.822  INFO 18416 --- [           main] j.z.d.j.r.ContactRepositoryTest          : No active profile set, falling back to default profiles: default
032018-03-08 19:24:43.846  INFO 18416 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7671cb68: startup date [Thu Mar 08 19:24:43 CST 2018]; root of context hierarchy
042018-03-08 19:24:44.327  INFO 18416 --- [           main] beddedDataSourceBeanFactoryPostProcessor : Replacing 'dataSource' DataSource bean with embedded version
052018-03-08 19:24:44.328  INFO 18416 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'dataSource' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=jpaDemoApplication; factoryMethodName=dataSource; initMethodName=null; destroyMethodName=(inferred); defined in jcg.zheng.demo.jpademo.JpaDemoApplication] with [Root bean: class [org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration$EmbeddedDataSourceFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]
062018-03-08 19:24:44.992  INFO 18416 --- [           main] o.s.j.d.e.EmbeddedDatabaseFactory        : Starting embedded database: url='jdbc:h2:mem:be0f302a-c332-4e7a-9d25-83126b6dcb66;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'
072018-03-08 19:24:45.520  INFO 18416 --- [           main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
082018-03-08 19:24:45.544  INFO 18416 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
09    name: default
10    ...]
112018-03-08 19:24:45.698  INFO 18416 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.0.12.Final}
122018-03-08 19:24:45.703  INFO 18416 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
132018-03-08 19:24:45.705  INFO 18416 --- [           main] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist
142018-03-08 19:24:45.811  INFO 18416 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
152018-03-08 19:24:46.051  INFO 18416 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
162018-03-08 19:24:46.834  INFO 18416 --- [           main] org.hibernate.tool.hbm2ddl.SchemaUpdate  : HHH000228: Running hbm2ddl schema update
172018-03-08 19:24:46.868  INFO 18416 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: CONTACT
182018-03-08 19:24:46.869  INFO 18416 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: CONTACT
192018-03-08 19:24:46.878  INFO 18416 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: Contact_Note
202018-03-08 19:24:46.879  INFO 18416 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: Contact_Note
212018-03-08 19:24:46.966  INFO 18416 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
222018-03-08 19:24:47.286  INFO 18416 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
232018-03-08 19:24:47.689  INFO 18416 --- [           main] j.z.d.j.r.ContactRepositoryTest          : Started ContactRepositoryTest in 4.281 seconds (JVM running for 5.307)
242018-03-08 19:24:47.754  INFO 18416 --- [           main] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context [DefaultTestContext@2ea6137 testClass = ContactRepositoryTest, testInstance = jcg.zheng.demo.jpademo.repository.ContactRepositoryTest@400cff1a, testMethod = it_can_update_the_contact_after_save_it@ContactRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@41ee392b testClass = ContactRepositoryTest, locations = '{}', classes = '{class jcg.zheng.demo.jpademo.JpaDemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@1e67a849 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1f554b06, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@131276c2, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4d95d2a2, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@d7556ade, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@528931cf], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@3c5dbdf8]; rollback [true]
25Hibernate: call next value for hibernate_sequence
26Hibernate: insert into CONTACT (Email, First_Name, Last_Name, Phone_Number, Phone_Type, ID) values (?, ?, ?, ?, ?, ?)
27Hibernate: update CONTACT set Email=?, First_Name=?, Last_Name=?, Phone_Number=?, Phone_Type=? where ID=?
28Hibernate: select contact0_.ID as ID1_0_, contact0_.Email as Email2_0_, contact0_.First_Name as First_Na3_0_, contact0_.Last_Name as Last_Nam4_0_, contact0_.Phone_Number as Phone_Nu5_0_, contact0_.Phone_Type as Phone_Ty6_0_ from CONTACT contact0_
292018-03-08 19:24:47.910  INFO 18416 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test context [DefaultTestContext@2ea6137 testClass = ContactRepositoryTest, testInstance = jcg.zheng.demo.jpademo.repository.ContactRepositoryTest@400cff1a, testMethod = it_can_update_the_contact_after_save_it@ContactRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@41ee392b testClass = ContactRepositoryTest, locations = '{}', classes = '{class jcg.zheng.demo.jpademo.JpaDemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@1e67a849 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1f554b06, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@131276c2, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4d95d2a2, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@d7556ade, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@528931cf], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]].
302018-03-08 19:24:47.913  INFO 18416 --- [       Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@7671cb68: startup date [Thu Mar 08 19:24:43 CST 2018]; root of context hierarchy
312018-03-08 19:24:47.916  INFO 18416 --- [       Thread-2] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
  • Line 27: Update statement

6.3 Delete

it_can_delete_the_contact_after_save_it output

012018-03-08 19:25:54.514  INFO 13708 --- [           main] j.z.d.j.r.ContactRepositoryTest          : Started ContactRepositoryTest in 4.379 seconds (JVM running for 5.38)
022018-03-08 19:25:54.573  INFO 13708 --- [           main] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context [DefaultTestContext@2ea6137 testClass = ContactRepositoryTest, testInstance = jcg.zheng.demo.jpademo.repository.ContactRepositoryTest@400cff1a, testMethod = it_can_delete_the_contact_after_save_it@ContactRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@41ee392b testClass = ContactRepositoryTest, locations = '{}', classes = '{class jcg.zheng.demo.jpademo.JpaDemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@1e67a849 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1f554b06, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@131276c2, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4d95d2a2, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@d7556ade, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@528931cf], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@3c5dbdf8]; rollback [true]
03Hibernate: call next value for hibernate_sequence
04Hibernate: call next value for hibernate_sequence
05Hibernate: insert into CONTACT (Email, First_Name, Last_Name, Phone_Number, Phone_Type, ID) values (?, ?, ?, ?, ?, ?)
06Hibernate: insert into Contact_Note (CONTACT_ID, message, id) values (?, ?, ?)
07Hibernate: select contact0_.ID as ID1_0_, contact0_.Email as Email2_0_, contact0_.First_Name as First_Na3_0_, contact0_.Last_Name as Last_Nam4_0_, contact0_.Phone_Number as Phone_Nu5_0_, contact0_.Phone_Type as Phone_Ty6_0_ from CONTACT contact0_
08Hibernate: delete from Contact_Note where id=?
09Hibernate: delete from CONTACT where ID=?
10Hibernate: select contact0_.ID as ID1_0_, contact0_.Email as Email2_0_, contact0_.First_Name as First_Na3_0_, contact0_.Last_Name as Last_Nam4_0_, contact0_.Phone_Number as Phone_Nu5_0_, contact0_.Phone_Type as Phone_Ty6_0_ from CONTACT contact0_
112018-03-08 19:25:54.778  INFO 13708 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test context [DefaultTestContext@2ea6137 testClass = ContactRepositoryTest, testInstance = jcg.zheng.demo.jpademo.repository.ContactRepositoryTest@400cff1a, testMethod = it_can_delete_the_contact_after_save_it@ContactRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@41ee392b testClass = ContactRepositoryTest, locations = '{}', classes = '{class jcg.zheng.demo.jpademo.JpaDemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@1e67a849 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1f554b06, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@131276c2, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4d95d2a2, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@d7556ade, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@528931cf], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]].
122018-03-08 19:25:54.783  INFO 13708 --- [       Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@7671cb68: startup date [Thu Mar 08 19:25:50 CST 2018]; root of context hierarchy
132018-03-08 19:25:54.785  INFO 13708 --- [       Thread-2] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
  • Line 8-9: two Delete statements

6.4 Find

it_can_find_contacts_by_name_and_type output

012018-03-08 19:26:42.878  INFO 13712 --- [           main] j.z.d.j.r.ContactRepositoryTest          : Started ContactRepositoryTest in 4.246 seconds (JVM running for 5.266)
022018-03-08 19:26:42.949  INFO 13712 --- [           main] o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context [DefaultTestContext@2ea6137 testClass = ContactRepositoryTest, testInstance = jcg.zheng.demo.jpademo.repository.ContactRepositoryTest@400cff1a, testMethod = it_can_find_contacts_by_name_and_type@ContactRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@41ee392b testClass = ContactRepositoryTest, locations = '{}', classes = '{class jcg.zheng.demo.jpademo.JpaDemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@1e67a849 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1f554b06, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@131276c2, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4d95d2a2, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@d7556ade, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@528931cf], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@3c5dbdf8]; rollback [true]
03Hibernate: call next value for hibernate_sequence
04Hibernate: call next value for hibernate_sequence
05Hibernate: call next value for hibernate_sequence
06Hibernate: call next value for hibernate_sequence
07Hibernate: insert into CONTACT (Email, First_Name, Last_Name, Phone_Number, Phone_Type, ID) values (?, ?, ?, ?, ?, ?)
08Hibernate: insert into CONTACT (Email, First_Name, Last_Name, Phone_Number, Phone_Type, ID) values (?, ?, ?, ?, ?, ?)
09Hibernate: insert into CONTACT (Email, First_Name, Last_Name, Phone_Number, Phone_Type, ID) values (?, ?, ?, ?, ?, ?)
10Hibernate: insert into CONTACT (Email, First_Name, Last_Name, Phone_Number, Phone_Type, ID) values (?, ?, ?, ?, ?, ?)
11Hibernate: select contact0_.ID as ID1_0_, contact0_.Email as Email2_0_, contact0_.First_Name as First_Na3_0_, contact0_.Last_Name as Last_Nam4_0_, contact0_.Phone_Number as Phone_Nu5_0_, contact0_.Phone_Type as Phone_Ty6_0_ from CONTACT contact0_ where contact0_.Phone_Type=? and contact0_.Last_Name=?
122018-03-08 19:26:43.098  INFO 13712 --- [           main] o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test context [DefaultTestContext@2ea6137 testClass = ContactRepositoryTest, testInstance = jcg.zheng.demo.jpademo.repository.ContactRepositoryTest@400cff1a, testMethod = it_can_find_contacts_by_name_and_type@ContactRepositoryTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@41ee392b testClass = ContactRepositoryTest, locations = '{}', classes = '{class jcg.zheng.demo.jpademo.JpaDemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@1e67a849 key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration, org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManagerAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1f554b06, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@131276c2, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@4d95d2a2, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@d7556ade, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@528931cf], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]]].
132018-03-08 19:26:43.103  INFO 13712 --- [       Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@7671cb68: startup date [Thu Mar 08 19:26:39 CST 2018]; root of context hierarchy
142018-03-08 19:26:43.105  INFO 13712 --- [       Thread-2] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
  • Line 11: Select statements

7. Summary

In this example, we built a Spring Boot project to demonstrate how easy it is to configure and use Spring data JpaRepository to manage the data in the database.

Spring Data JPA provides an abstraction to the persistence layer and has a common API. All you have to do is to implement a Repository interface, declare the repository methods and annotate the methods with @Query that should be executed.

However, There are some pitfalls when using JPA. Please check here for detail.

8. Download the Source Code

This example consists of a Spring Boot JPA project.

Download
You can download the full source code of this example here: Spring Data JpaRepository Example

 

 

Show Buttons
Hide Buttons