Spring Boot With Spring Data JPA
Check out this tutorial to get started with Spring Data JPA.
Join the DZone community and get the full member experience.
Join For FreeWelcome to the Spring Boot with Spring Data JPA tutorial! In this tutorial, we are going to see how Spring Data JPA provides complete abstraction over the DAO layer. We don’t need to write the implementation for the DAO layer anymore; Spring Data auto-generates the implementation DAO implementations.
We already had an introduction to Spring Boot, and for this tutorial, we will use Spring Boot along with Spring Data. You will also see how Spring Boot auto-configuration helps to get data source configurations done, hassle-free.
In our tutorial Spring Boot Rest Service, we created a DogService
, which included a simple CRUD service based on the Mock Data Provider. We will use the same DogService
and replace the Mock Data Provider with the actual MySQL database along with Spring Data and JPA.
Dependency Configuration
In this tutorial, I am using a MySQL database along with Spring Data. Here is the build.gradle file:
buildscript {
ext {
springBootVersion = '2.1.0.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.amitph.spring'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
implementation('org.springframework.boot:spring-boot-starter-web')
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile('mysql:mysql-connector-java:8.0.13')
testImplementation('org.springframework.boot:spring-boot-starter-test')
}
Learn more about JPA and Spring Data JPA here:
- Java Persistence API Guide
- Spring Data JPA – Query Methods
- Pagination and Sorting with Spring Data JPA
- Spring Data JPA Composite Key with @EmbeddedId
Datasource Configuration
We now have dependencies configured. It is not time to tell which data source to connect to. Here is my application.yml with Spring Boot data source entries.
spring:
datasource:
url: jdbc:mysql://localhost:33099/dogs
password: <ENTER _ PASSWORD _ HERE >
username: root
driver-class-name: "com.mysql.jdbc.Driver"
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
hibernate:
ddl-auto: update
Here, we have the specified JDBC URL, username, password, and driver class name (MySQL).
Apart from this, there are JPA specific configurations. First is the database-platform, which tells us the underlying Hibernate features to consider under the MySQL query dialect. This is so that all the database operations will be handled in MySQL specific syntax. The second JPA configuration is ddl-auto, which tells Hibernate to create the respective database and table structure, if not already present.
When this option is turned on, Hibernate will create the database structure based on the Entity Beans and the data source.
Entity Bean
The first code level thing we will do is write an Entity Bean. Here is what the Oracle Documentation says about Entity Beans.
Using JPA, you can designate any POJO class as a JPA entity – a Java object whose nontransient fields should be persisted to a relational database using the services of an entity manager obtained from a JPA persistence provider (either within a Java EE EJB container or outside of an EJB container in a Java SE application).
In simpler words, the JPA Entity is any Java POJO, which can represent the underlying table structure. As our service is based on theDog
table, we will create a Dog
Entity object.
package com.amitph.spring.dogs.repo;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Dog {
@Id
@GeneratedValue
private long id;
private String name;
private int age;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
The above POJO is annotated with @Entity
, which is to denote this is an entity object for the table name Dog.
Then, there are three fields that represent the datable table columns. Field id
is our Primary Key and, hence, marked as @Id
.
The field id
is also marked with @GeneratedValue
, which denotes that this is an Auto-Increment column and Hibernate will take care of putting in the next value. Hibernate will first query the underlying table to know the max value of the column and increment it with next insert. This also means that we don’t need to specify any value for the Id
column and can leave it blank.
Repository Interface
The Repository represents the DAO layer, which typically does all the database operations. Thanks to Spring Data, who provides the implementations for these methods. Let’s have a look at our DogsRepoisitory
, which extends the CrudRepository
:
package com.amitph.spring.dogs.repo;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface DogsRepository extends CrudRepository<Dog, Long> {}
There are no method declarations here in the DogsRepository
. That is because Spring Data’s CrudInterface
has already declared basic CRUD methods.
Here, we are done with the JPA and Spring data things — in other words, the DAO layer. Let’s now write a simple Service Layer and a Controller.
Controller and Service Layer
As we have our data access layer done, we will write our controller and service layer. Notice that the DogsRepository
is annotated with @Repository
, which also adds it to the Spring Context. We can now Autowire
the repository in Service
.
Dogs Service
This class has simple CRUD methods. It also converts the Entity bean to a DTO (data transfer object). DTO is also a simple Java POJO, which is used to transfer data between systems. Here, we are returning DTOs from our REST endpoints.
package com.amitph.spring.dogs.service;
import com.amitph.spring.dogs.model.DogDto;
import com.amitph.spring.dogs.repo.Dog;
import com.amitph.spring.dogs.repo.DogsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
@Component
public class DogsService {
@Autowired DogsRepository repository;
public void add(DogDto dto) {
repository.save(toEntity(dto));
}
public void delete(long id) {
repository.deleteById(id);
}
public List<Dog> getDogs() {
return (List<Dog>) repository.findAll();
}
public Dog getDogById(long id) {
Optional<Dog> optionalDog = repository.findById(id);
return optionalDog.orElseThrow(() -> new DogNotFoundException("Couldn't find a Dog with id: " + id));
}
private Dog toEntity(DogDto dto) {
Dog entity = new Dog();
entity.setName(dto.getName());
entity.setAge(dto.getAge());
return entity;
}
}
Dogs Controller
The Dogs Controller is a standard REST controller with simple CRUD endpoints. The job of the controller is to handle the HTTP requests and invoke the Service class methods.
package com.amitph.spring.dogs.web;
import com.amitph.spring.dogs.model.DogDto;
import com.amitph.spring.dogs.repo.Dog;
import com.amitph.spring.dogs.service.DogsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/dogs")
public class DogsController {
@Autowired DogsService service;
@GetMapping
public List<Dog> getDogs() {
return service.getDogs();
}
@PostMapping
public void postDogs(@RequestBody DogDto dto) {
service.add(dto);
}
@GetMapping("/{id}")
public Dog getById(@PathVariable(required = true) long id) {
return service.getDogById(id);
}
@DeleteMapping("/{id}")
public void delete(@PathVariable(required = true) long id) {
service.delete(id);
}
}
Now, the Dogs Service is ready to run. Start the application and execute the HTTP endpoints — that’s it.
Conclusion
This is the end of our Spring Boot with Spring data and JPA tutorial. We saw how to use Spring Data’s abstraction for the Data Access Layer. We saw how to represent a database table in the form of Entity Bean and how to Use Spring Data’s autogenerated repository implementations. Additionally, we also saw how to use Spring Boot to conduct automatic datasource configurations.
In the Spring Boot Rest Service post, we have already seen creating a RESTful web service with Spring Boot. In the current article, we did not care about Exception Handling. Visit Spring Rest Service Exception Handling to learn about handling exceptions. We also skipped the unit testing part here, which will be covered in upcoming articles.
For the full source code and examples used here, please visit https://github.com/amitrp/dog-service-jpa.
Published at DZone with permission of Amit Phaltankar. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments