DEV Community

loizenai
loizenai

Posted on

Spring Boot One to One Mapping Example - Spring Crud Example using One to One Mapping

https://loizenai.com/spring-boot-one-to-one-mapping-example/

Tutorial: "Spring Boot One to One Mapping Example - Spring Crud Example using One to One Mapping"

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.

  • Technologies - Spring Boot One to One Mapping Example:
  • Java 8
  • Maven 3.5.4
  • SpringToolSuite version 3.9.4.RELEASE
  • SpringBoot 2.0.4.RELEASE

    Overview - Spring Boot One to One Mapping Example

    We have 2 models Student & Contact with one-to-one relationship:

[caption id="attachment_4771" align="alignnone" width="504"]Spring Boot One to One - Model Relationships - Spring Boot One to One Mapping Example Spring Boot One to One - Model Relationships[/caption]

We create a SpringBoot project as below:

[caption id="attachment_4772" align="alignnone" width="701"]Spring Boot Rest Apis Hibernate Spring JPA One To One Postgresql Architecture - Spring Boot One to One Mapping Example Spring Boot Rest Apis Hibernate Spring JPA One To One Postgresql Architecture[/caption]

[caption id="attachment_4773" align="alignnone" width="346"]SpringBoot Project Structure - Spring Boot One to One Mapping Example SpringBoot Project Structure[/caption]

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. Let's go!

Create SpringBoot project - Spring Boot One to One Mapping Example

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>

SpringBoot OneToOne Models - Spring Boot One to One Mapping Example

- Student model ->
code class="language-java">
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;
    }
}

SpringBoot JPA Repositories - Spring Boot One to One Mapping Example

- 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 SpringBoot Rest APIs - Spring Boot One to One Mapping Example

- 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 List getAllStudents() {
        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 List getAllContacts(){
        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 : [caption id="attachment_4774" align="alignnone" width="358"]Spring Boot Rest Apis Hibernate Spring Jpa One To One Postgresql Tables Created By JPA Spring Boot Rest Apis Hibernate Spring Jpa One To One Postgresql Tables Created By JPA[/caption] - Add Students : [caption id="attachment_4775" align="alignnone" width="572"]Spring Boot Rest Apis Hibernate Spring JPA One-to-one Postgresql Tables - post a student data Spring Boot Rest Apis Hibernate Spring JPA One-to-one Postgresql Tables - post a student data[/caption] - Add Contacts : [caption id="attachment_4776" align="alignnone" width="566"]Spring Boot Rest Apis Hibernate Spring Jpa One-to-one Postgresql Post a Contact Spring Boot Rest Apis Hibernate Spring Jpa One-to-one Postgresql Post a Contact[/caption] - Update Contact : [caption id="attachment_4777" align="alignnone" width="569"]Spring Boot Rest Apis Hibernate Spring JPA One-to-one Postgresql Put Contact Spring Boot Rest Apis Hibernate Spring JPA One-to-one Postgresql Put Contact[/caption] - Update Student : [caption id="attachment_4778" align="alignnone" width="588"]Spring Boot Rest Apis Hibernate Spring JPA One-to-one Postgresql Put a student Spring Boot Rest Apis Hibernate Spring JPA One-to-one Postgresql Put a student[/caption] - Get All Students : [caption id="attachment_4779" align="alignnone" width="332"]Spring Boot Rest Apis Hibernate Spring Jpa one-to-one Postgresql Get All Student Spring Boot Rest Apis Hibernate Spring Jpa one-to-one Postgresql Get All Student[/caption] - Get All Contacts : [caption id="attachment_4780" align="alignnone" width="330"]Spring Boot Rest Apis Hibernate Spring Jpa One To One Postgresql Get All Contacts Spring Boot Rest Apis Hibernate Spring Jpa One To One Postgresql Get All Contacts[/caption] - Delete a Student : [caption id="attachment_4781" align="alignnone" width="426"]Spring Boot Rest Apis Hibernate Spring JPA One-to-one Postgresql Tables Delete a Student Spring Boot Rest Apis Hibernate Spring JPA One-to-one Postgresql Tables Delete a Student[/caption] - Delete a Contact : [caption id="attachment_4782" align="alignnone" width="392"]Spring Boot Rest Apis Hibernate Spring JPA One-to-one Postgresql Tables Delete a Contact Spring Boot Rest Apis Hibernate Spring JPA One-to-one Postgresql Tables Delete a Contact[/caption] 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)

SourceCode

SpringBoot-RestAPIs-OneToOne

Top comments (0)