SpringBoot + Hibernate Spring JPA One-to-One Association + PostgreSQL | CRUD RestAPIs Post/Get/Put/Delete
In the tutorial, we show how to expose Crud RestAPIs Post/Get/Put/Delete
to interact with Hibernate Spring JPA One-to-One relationship models using SpringBoot and PostgreSQL database.
Related posts:
– How to use Spring JPA with PostgreSQL | Spring Boot
– React Redux + Spring Boot + PostgreSQL CRUD example
– How to query alter domain models by Spring JPA Projection
– How to configure Spring JPA One to One Relationship – SpringBoot
– Spring JPA Hibernate One to Many Relationship – SpringBoot + MySQL
– Spring JPA Hibernate Many to Many – SpringBoot + PostgreSQL
Related page:
Technologies
- Java 8
- Maven 3.5.4
- SpringToolSuite version 3.9.4.RELEASE
- SpringBoot 2.0.4.RELEASE
Demo
Overview
We have 2 models Student
& Contact
with one-to-one
relationship:
We create a SpringBoot project as below:
Hibernate JPA configuration for 2 models Student
& Contact
:
– Student
model ->
@Entity @Table(name = "students") @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) public class Student implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "name") private String name; @Column(name = "age") private int age; @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "student") private Contact contact; public Student() {} public Student(String name, int age) { this.name = name; this.age = age; } // Getters & Setters methods // ...
– Contact
model ->
@Entity @Table(name = "contacts") @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) public class Contact implements Serializable{ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "city") private String city; @Column(name = "phone") private String phone; @OneToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "student_id", nullable = false) private Student student; public Contact() { } public Contact(String city, String phone) { this.city = city; this.phone = phone; } // Getters & Setters methods // ...
We exposes RestAPIs for Post/Get/Put/Delete
Students & Contacts:
– Students ->
@GetMapping("/api/students")
: get all Students@GetMapping("/api/students/{id}")
: get a Student by ID@PostMapping("/api/students")
: post a Student@PutMapping("/api/students/{id}")
: update a Student@DeleteMapping("/api/students/{id}")
: delete a Student
– Contacts ->
@GetMapping("/contacts")
: get all Contacts@GetMapping("/students/{studentId}/contacts")
: get a Contact by Student’s ID@PostMapping("/students/{studentId}/contacts")
: add a Contact@PutMapping("/contacts/{contactId}")
: update a Contact@DeleteMapping("/contacts/{contactId}")
: delete a Contact by ID
Now we’ll create a project from scratch ->
Practice
Create SpringBoot project
We use SpringToolSuite to create a Java 8
SpringBoot project with below 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.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency>
OneToOne Models
– Student
model ->
package com.ozenero.springrestapi.onetoone.model; import java.io.Serializable; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.Table; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @Entity @Table(name = "students") @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) public class Student implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "name") private String name; @Column(name = "age") private int age; @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "student") private Contact contact; public Student() {} public Student(String name, int age) { this.name = name; this.age = age; } public void setId(Long id) { this.id = id; } public Long getId() { return this.id; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } public void setAge(int age) { this.age =age; } public int getAge() { return this.age; } }
– Contact
model ->
package com.ozenero.springrestapi.onetoone.model; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.Table; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @Entity @Table(name = "contacts") @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) public class Contact implements Serializable{ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "city") private String city; @Column(name = "phone") private String phone; @OneToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "student_id", nullable = false) private Student student; public Contact() { } public Contact(String city, String phone) { this.city = city; this.phone = phone; } public void setId(Long id) { this.id = id; } public Long getId() { return this.id; } public void setCity(String city) { this.city = city; } public String getCity() { return this.city; } public void setPhone(String phone) { this.phone = phone; } public String getPhone() { return this.phone; } public void setStudent(Student student) { this.student = student; } public Student getStudent() { return this.student; } }
JPA Repositories
– StudentRepository
->
package com.ozenero.springrestapi.onetoone.jpa; import org.springframework.data.jpa.repository.JpaRepository; import com.ozenero.springrestapi.onetoone.model.Student; public interface StudentRepository extends JpaRepository{ }
– ContactRepository
model ->
package com.ozenero.springrestapi.onetoone.jpa; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import com.ozenero.springrestapi.onetoone.model.Contact; public interface ContactRepository extends JpaRepository{ List findByStudentId(Long studentId); }
Add datasource configurations in application.properties
file ->
spring.datasource.url=jdbc:postgresql://localhost/testdb spring.datasource.username=postgres spring.datasource.password=123 spring.jpa.generate-ddl=true #spring.jackson.serialization.fail-on-empty-beans=false
Expose Rest APIs
– StudentController
->
package com.ozenero.springrestapi.onetoone.rest; import java.util.List; import java.util.Optional; import javax.validation.Valid; 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.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ozenero.springrestapi.onetoone.exception.NotFoundException; import com.ozenero.springrestapi.onetoone.jpa.StudentRepository; import com.ozenero.springrestapi.onetoone.model.Student; @RestController @RequestMapping("/api") public class StudentController { @Autowired private StudentRepository studentRepository; @GetMapping("/students") public ListgetAllStudents() { return studentRepository.findAll(); } @GetMapping("/students/{id}") public Student getStudentByID(@PathVariable Long id) { Optional optStudent = studentRepository.findById(id); if(optStudent.isPresent()) { return optStudent.get(); }else { throw new NotFoundException("Student not found with id " + id); } } @PostMapping("/students") public Student createStudent(@Valid @RequestBody Student student) { return studentRepository.save(student); } @PutMapping("/students/{id}") public Student updateStudent(@PathVariable Long id, @Valid @RequestBody Student studentUpdated) { return studentRepository.findById(id) .map(student -> { student.setName(studentUpdated.getName()); student.setAge(studentUpdated.getAge()); return studentRepository.save(student); }).orElseThrow(() -> new NotFoundException("Student not found with id " + id)); } @DeleteMapping("/students/{id}") public String deleteStudent(@PathVariable Long id) { return studentRepository.findById(id) .map(student -> { studentRepository.delete(student); return "Delete Successfully!"; }).orElseThrow(() -> new NotFoundException("Student not found with id " + id)); } }
– ContactController
->
package com.ozenero.springrestapi.onetoone.rest; import java.util.List; import javax.validation.Valid; 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.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.ozenero.springrestapi.onetoone.exception.NotFoundException; import com.ozenero.springrestapi.onetoone.jpa.ContactRepository; import com.ozenero.springrestapi.onetoone.jpa.StudentRepository; import com.ozenero.springrestapi.onetoone.model.Contact; @RestController @RequestMapping("/api") public class ContactController { @Autowired private ContactRepository contactRepository; @Autowired private StudentRepository studentRepository; @GetMapping("/contacts") public ListgetAllContacts(){ return contactRepository.findAll(); } @GetMapping("/students/{studentId}/contacts") public Contact getContactByStudentId(@PathVariable Long studentId) { if(!studentRepository.existsById(studentId)) { throw new NotFoundException("Student not found!"); } List contacts = contactRepository.findByStudentId(studentId); if(contacts.size() > 0) { return contacts.get(0); }else { throw new NotFoundException("Contact not found!"); } } @PostMapping("/students/{studentId}/contacts") public Contact addContact(@PathVariable Long studentId, @Valid @RequestBody Contact contact) { return studentRepository.findById(studentId) .map(student -> { contact.setStudent(student); return contactRepository.save(contact); }).orElseThrow(() -> new NotFoundException("Student not found!")); } @PutMapping("/contacts/{contactId}") public Contact updateContact(@PathVariable Long contactId, @Valid @RequestBody Contact contactUpdated) { return contactRepository.findById(contactId) .map(contact -> { contact.setCity(contactUpdated.getCity()); contact.setPhone(contactUpdated.getPhone()); return contactRepository.save(contact); }).orElseThrow(() -> new NotFoundException("Contact not found!")); } @DeleteMapping("/contacts/{contactId}") public String deleteContact(@PathVariable Long contactId) { return contactRepository.findById(contactId) .map(contact -> { contactRepository.delete(contact); return "Deleted Successfully!"; }).orElseThrow(() -> new NotFoundException("Contact not found!")); } }
Run & Check Results
– Run the SpringBoot project with commandline mvn spring-boot:run
.
2 tables is created in PostgreSQL ->
– Add Students ->
– Add Contacts ->
– Update Contact ->
– Update Student ->
– Get All Students ->
– Get All Contacts ->
– Delete a Student ->
– Delete a Contact ->
Note: PostgreSQL commandline ->
PostgreSQL\9.6\bin>psql.exe --username="postgres" -W
: connect to PostgreSQL ->
C:\Program Files\PostgreSQL\9.6\bin>psql.exe --username="postgres" -W Password for user postgres: psql (9.6.9) WARNING: Console code page (437) differs from Windows code page (1252) 8-bit characters might not work correctly. See psql reference page "Notes for Windows users" for details. Type "help" for help.
– \l
: List of databases
– \c testdb
: connect to “testdb”
– \d
: List of relations ->
testdb=# \d List of relations Schema | Name | Type | Owner --------+-----------------+----------+---------- public | contacts | table | postgres public | contacts_id_seq | sequence | postgres public | students | table | postgres public | students_id_seq | sequence | postgres (4 rows)
– testdb=# \q
: Exit