CRUD Operations with Spring Boot
Java, Maven, Hibernate, JPA, Spring Data, Spring Boot
Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”. It is based on a model of
Convention over Configuration
and good intentions.
Introduction
This is the sixth part part of a series of posts focused on Hibernate
and JPA
. In my previous post we demonstrated how to write
CRUD functions using interfaces in Spring Data. In this post we will
look at reducing configuration with Spring Boot and writing less boilerplate code.
At the end of this post you will have familiarised yourself with Spring Boot
.
Prerequisites
Project Structure
Building up on previous posts, our folder structure will remain relatively the same:
.
|__src/
| |__main/
| | |__java/
| | | |__com/
| | | | |__tutorial/
| | | | | |__Application.java
| | | | | |__entity/
| | | | | | |__Person.java
| | | | | |__repository/
| | | | | | |__PersonRepository.java
| | |__resources/
| | | |__application.properties
| | | |__dbChangelog.xml
| | | |__log4j2.properties
|__pom.xml
Setting up Dependencies
To set up a Spring Boot
project we need the following dependencies
- spring-boot-starter
Modify the pom.xml
file by making the following changes:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath />
</parent>
<properties>
<hibernate.version>5.2.6.Final</hibernate.version><!-- Override version 5.0 used by Spring Boot -->
<java.version>1.8</java.version>
</properties>
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion><!-- Hibernate EntityManager was merged into Hibermate core in 5.2 -->
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat</groupId><!-- We will be using HikariCP pooling library -->
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Wow! That’s a lot of changes. But that will be all for our POM.xml
.
Naming Strategy
Hibernate 5 deprecated the legacy NamingStrategy
in favour of
ImplicitNamingStrategy
and PhysicalNamingStrategy
. With the release of Spring Boot 1.4, a new
SpringPhysicalNamingStrategy
is auto configured
to align with Hibernate 5.
Part of the mapping of an object model to the relational database is mapping names from the object model to the corresponding database names. The SpringPhysicalNamingStrategy
uses snake case for the database names. In this regard we will modify our
Liquibase Changelog
file.
file: src/main/resources/dbChangelog.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd">
<property name="autoIncrement" value="true" dbms="mysql,h2,postgresql,oracle,mssql"/>
<changeSet id="0" author="julius" dbms="h2,postgresql,oracle">
<createSequence sequenceName="hibernate_sequence" startValue="1" incrementBy="1"/>
</changeSet>
<changeSet id="1" author="julius">
<comment>Create Person table</comment>
<createTable tableName="person">
<column name="id" type="bigint" autoIncrement="${autoIncrement}">
<constraints primaryKey="true" nullable="false" />
</column>
<column name="first_name" type="varchar(255)"/>
<column name="last_name" type="varchar(255)"/>
<column name="date_of_birth" type="date"/>
<column name="created_date" type="timestamp"/>
<column name="modified_date" type="timestamp"/>
</createTable>
</changeSet>
</databaseChangeLog>
Plumbing
We now made a few minor changes to get Spring Boot up and running.
file: src/main/resources/application.properties
:
spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.javax.persistence.provider=org.hibernate.jpa.HibernatePersistenceProvider
spring.jpa.properties.hibernate.hikari.dataSourceClassName=org.h2.jdbcx.JdbcDataSource
spring.jpa.properties.hibernate.hikari.dataSource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MVCC=true
spring.jpa.properties.hibernate.hikari.dataSource.user=sa
spring.jpa.properties.hibernate.hikari.dataSource.password=
spring.jpa.properties.hibernate.hikari.minimumIdle=5
spring.jpa.properties.hibernate.hikari.maximumPoolSize=10
spring.jpa.properties.hibernate.hikari.idleTimeout=30000
spring.jpa.properties.hibernate.connection.handling_mode=delayed_acquisition_and_hold
spring.jpa.properties.hibernate.connection.provider_class=org.hibernate.hikaricp.internal.HikariCPConnectionProvider
liquibase.change-log=classpath:/dbChangelog.xml
liquibase.check-change-log-location=true
liquibase.contexts=test
liquibase.drop-first=true
liquibase.enabled=true
Spring Boot
Spring Boot is all about reducing the amount of boilerplate code you have to write.
Remove:
file: src/main/java/com/tutorial/Application.java
:
@Configuration
@EnableJpaRepositories
@EnableTransactionManagement
@PropertySource("classpath:application.properties")
replace with:
@SpringBootApplication
Next remove all beans from the Application
class and we end up with this:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
PersonRepository repository = ctx.getBean(PersonRepository.class);
Person person = new Person();
person.setFirstName("Julius");
person.setLastName("Krah");
person.setCreatedDate(LocalDateTime.now());
person.setDateOfBirth(LocalDate.of(1990, Month.APRIL, 4));
// Create person
repository.save(person);
// Hibernate generates id of 1
Optional<Person> p = repository.findOne(1L);
p.ifPresent(consumer -> {
consumer.setModifiedDate(LocalDateTime.now());
consumer.setFirstName("Abeiku");
});
// Update person record
repository.save(p.get());
p = Optional.empty();
// Read updated record
p = repository.findOne(1L);
p.ifPresent(consumer -> {
System.out.format("Person updated: %s", consumer);
});
// Delete person
repository.delete(p.get());
p = Optional.empty();
p = repository.findOne(1L);
}
}
That’s it.
Conclusion
In this post we did a rewrite of our previous articles in the series to use Spring Boot. We also saw how easy it is to configure a
Spring Boot project.
As usual you can find the full example to this guide in the github repository. Until the next post, keep doing cool things .