Spring Boot – Http GET with JPA and H2 Database

Welcome to this little tutorial about Spring Boot and it´s usage of JPA with the In Memory Database H2.

If you already have worked with an In Memory Database in your Java code you may have seen what a mess of work it is. You have to configure, implement and check a lot.
After you have done this (or before) you have to add the JPA implementation and their ressource to your project. Furthermore you must configure JPA and (in the worst case) you´ll be stopped by some annoying errors and exceptions.

Let´s get that done more simple and effective.

Project Setup

After you have created a Maven project please add the following dependencies and the spring boot maven plugin to your pom.

<parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.0.2.RELEASE</version>
</parent> 
   
   <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</groupId>
           <artifactId>spring-web</artifactId>
       </dependency>

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

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

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

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


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

 

Great, now let´s move on with the implementation of our Entity

Book Entity

Let´s say we want to implement a little book store. Nothing special. Our first Use Case is to retrieve every book that is stored in the In Memory Database

package com.javadevcorner.bookStore.entity;

import javax.persistence.Entity;
import javax.persistence.Id;

/**
 *
 * @author javadevcorner.com
 */
@Entity
public class Book {
    
    @Id
    private long id; 
    private String name; 

    public Book() {
    }
    
    public Book(long id, String name) {
        this.id = id;
        this.name = name;
    }
    
   //getter, setter and the stuff you want to have

}

Until now, everything we have done is just basic. You may know this already. That´s fine and good. Now we will take a look to Spring Boot.

Persistence Logic

Now create a package that is called repository. Use this package to create an Interface in it, which is implemented as follows:

package com.javadevcorner.bookStore.repository;

import com.javadevcorner.bookStore.entity.Book;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

/**
 *
 * @author javadevcorner.com
 */
@Repository
public interface BookRepository extends CrudRepository<Book, Long> {
    
}

Our Interface BookRepository is extending the Spring Boot CrudRepository in the parameterized way, we need it for our book. Be aware, that the first parameter is the Object (our Entity) which we want to be handled by the repository and the second parameter is the datatype of the entity id.
Furthermore our Interface is annotated with @Repository, which marks the interface as an Repository for the Spring Boot Framework.
(You could also use @Component if you want to. It´s the “super type”)

Business Logic

Now, after we have finished with our persistence layer, we start implementing our business logic. Please create a package called control (or business) and implement the following Interface

package com.javadevcorner.bookStore.control;

import com.javadevcorner.bookStore.entity.Book;
import java.util.List;

/**
 *
 * @author javadevcorner.com
 */
public interface BookService {
    
    public List<Book> getAllBooks();
}

This interface will be used as “the contract”. It will provide the methods to all other components.

To work with this interface, we implement it in a new component called BookServiceImpl. In this implementation we will use our BookRepository to get all of our data.

package com.javadevcorner.bookStore.control;

import com.javadevcorner.bookStore.entity.Book;
import com.javadevcorner.bookStore.repository.BookRepository;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 *
 * @author javadevcorner.com
 */
@Service
public class BookServiceImpl implements BookService{

    @Autowired
    private BookRepository bookRepository;
    
    
    public List<Book> getAllBooks() {
        
        List<Book> allBooks = new ArrayList<>();
        bookRepository.findAll().forEach(allBooks::add);
        
        return allBooks;
    }
}

The @Autowired annotation is injecting our repository to this component / service.

In line 24, we´re using our BookRepository. The findAll() method of our repository is returning an interator which we transform to a book and add this to a list. If you are not familiar with Java 8, the code in line 24 is equivalent to:

for(Book book : bookRepository.findAll()) {
            allBooks.add(book);
}

Boundary

Till now we have implemented our repository, business logic and the entity. Now we implement the GET-Method. To achieve this, we create a @RestController in the new package boundary. 

package com.javadevcorner.bookStore.boundary;

import com.javadevcorner.bookStore.control.BookService;
import com.javadevcorner.bookStore.entity.Book;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/**
 *
 * @author javadevcorner.com
 */
@RestController
public class BookResource {

    @Autowired
    private BookService bookService;

    @RequestMapping("/")
    @ResponseBody
    public List<Book> allBooks() {
        return bookService.getAllBooks();
    }

}

After we have annotated our Resource with @RestController it is known by Spring Boot as a Rest Resource. For now we only need to have one method which returns all of our books. To get all of this we inject the BookService in our RestController and use it´s method getAllBooks() to return all of our books.

Please pay attention to @RequestMapping(“/”). It is used to control which URL you have to navigate to, to call your Rest Resource.

Data Preperation

If you´d now start the application, you wouldn´t see anything. Of course, we haven´t present data yet. Let´s get it done now.

package com.javadevcorner.bookStore.appStarter;

import com.javadevcorner.bookStore.entity.Book;
import com.javadevcorner.bookStore.repository.BookRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 *
 * @author javadevcorner.com
 */
@Component
public class BookMockDataCreator {
    
    
    @Autowired
    private BookRepository bookRepository;
    
    public void setup() {
        bookRepository.save(new Book(1, "Lord of the Rings 1"));
        bookRepository.save(new Book(2, "Lord of the Rings 2"));
        bookRepository.save(new Book(3, "Lord of the Rings 3"));
    }
    
}

Please implement the following class in your appStarter package. As you can see, we use our BookRepository again. Now we use it´s save method to store some new Books.

After we have implemented a behaviour to store some new books we need to call this implementation on our Application Startup. For this, we modify the StartUp Class that contains the main method

package com.javadevcorner.bookStore.appStarter;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

/** 
 * 
 * @author javadevcorner.com 
 */

@SpringBootApplication
@ComponentScan("com.javadevcorner.bookStore")
@EntityScan("com.javadevcorner.bookStore")
@EnableJpaRepositories("com.javadevcorner.bookStore")
public class BookApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext ctx 
         = SpringApplication.run(BookApplication.class, args);
        ctx.getBean(BookMockDataCreator.class).setup();
    }
}

We use our ApplicationContext to get a specific bean (or component) and execute a specific method of this bean.

Please make be sure as well, that you have annotated the BookApplication correctly.

Start the Application

After you have implemented all these things, take a moment, be happy, open the Command Line Interface of your choice, move to your project (level of your pom.xml) and type:

mvn spring-boot:run

After you press enter, a lot of Output will be presented and Spring Boot will launch a Tomcat Server to Port 8080 (may you have to change this Port, if already used).

Navigate to your http://localhost:8080 (our any other port you have specified) and watch our output:

 

Thanks for reading and have fun using Spring Boot with JPA and the H2 In Memory Database

Feel free to share

Leave a Reply

Your email address will not be published. Required fields are marked *

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