Many To One(Uni-directional) Relational Mapping with Spring Boot + Spring Data JPA + H2 Database

In this tutorial , we will see Many To One mapping of two entities using Spring Boot and Spring Data JPA using H2 database.

GitHub Link 

Tools:

  • Spring Boot
  • Spring Data JPA
  • H2 Database
  • IntelliJ IDEA
  • Maven

We have two entities Student and Department. Many students are part of one Department (Many To One).

This is called Many To One mapping between two entities. For each of this entity, table will be created in database. So there will be two tables created in database.

create table address (id bigint generated by default as identity, name varchar(255), primary key (id));
create table student (id bigint generated by default as identity, mobile integer, name varchar(255), address_id bigint, primary key (id));
alter table student add constraint FKcaf6ht0hfw93lwc13ny0sdmvo foreign key (address_id) references address(id);

Each table has primary key as ID . Two tables has Many To One relationship between them as each department has many students in them.

STUDENT table has foreign key as DEPT_ID in it. So STUDENT is a child table and DEPARTMENT table is parent table in this relationship. FOREIGN KEY constraint adds below restrictions –

  1. We can’t add records in child table if there is no entry in parent table. Ex. You can’t add department ID reference in STUDENT table if department ID is not present in DEPARTMENT table.
  2. You can’t delete the records from parent table unless corresponding references are deleted from child table . Ex. You can’t delete the entry
    DEPARTMENT table unless corresponding students from STUDENT table are deleted . You can apply ON_DELETE_CASCADE with foreign key constraint if you want to delete students from STUDENT table automatically when department is deleted.
  3. If you want to insert a student into STUDENT table then corresponding department should already be present in DEPARTMENT table.
  4. When any department is updated in DEPARTMENT table then child table will also see the updated reference from parent table

Now we will see how can we form this relationship using Spring data JPA entities.

Step 1: Define all the dependencies required for this project

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.myjavablog</groupId>
<artifactId>springboot-jpa-one-to-many-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-jpa-one-to-many-demo</name>
<description>Demo project for Spring Boot</description>
<pre><code><properties>
    <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-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-jdbc</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <!--<scope>runtime</scope>-->
    </dependency>

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

    <!-- https://mvnrepository.com/artifact/colt/colt -->
    <dependency>
        <groupId>colt</groupId>
        <artifactId>colt</artifactId>
        <version>1.2.0</version>
    </dependency>

</dependencies>

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

spring-boot-starter-data-jpa – This jar is used to connect to database .It also has a support to provide different JPA implementations to interact with the database like Hibernate, JPA Repository, CRUD Repository etc.

h2 – Its used to create H2 database when the spring boot application boots up. Spring boot will read the database configuration from application.properties file and creates a DataSource out of it.

Step 2: Define the Model/Entity classes

Student.java

package com.myjavablog.model;

import org.springframework.stereotype.Repository;

import javax.annotation.Generated;
import javax.persistence.*;
import java.util.Optional;

@Entity
@Table(name = "STUDENT")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String name;

    @Column
    private int mobile;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "DEPT_ID")
    private Department department;

    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 getMobile() {

        return mobile;
    }

    public void setMobile(int mobile) {

        this.mobile = mobile;
    }

    public Department getDepartment() {

        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }
}

Department.java

package com.myjavablog.model;

import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = "DEPARTMENT")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column
private String name;

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;
}
}

Below are the Annotations used while creating the entity classes –

Spring Data JPA Annotations –

  • @Entity – This annotation marks the class annotations.
  • @Table – This annotation creates table in database.
  • @Id – It creates primary key in table.
  • @GeneratedValue – It defines primary key generation strategy like AUTO,IDENTITY,SEQUENCE etc.
  • @Column It defines column property for table.
  • @ManyToOne – This annotation creates Many to One relationship between Student and Department entities. The cascade property (CascadeType.ALL) defines what should happen with child table records when something happens with parent table records. On DELETE, UPDATE , INSERT operations in parent table child table should also be affected. Only @ManyToOne annotation is enough to form one-to-many relationaship. This annotation is generally used in child entity to form Unidirectional relational mapping.
  • @JoinColumn – You can define column which creates foreign key in a table. In our example, DEPT_ID is a foreign key in STUDENT table which references to ID in DEPARTMENT table.

Step 3: Create the JPA repositories to query STUDENT and DEPARTMENT tables

StudentRepository and AddressRepository implemets JpaRepository which has methods to perform all CRUD operations. It has methods like save(), find(), delete(),exists(),count() to perform database operations.

package com.myjavablog.dao;

import com.myjavablog.model.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
public Student findByName(String name);
}

package com.myjavablog.dao;

import com.myjavablog.model.Address;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AddressRepository extends JpaRepository<Address, Long>{
}

Step 4: Create the class BeanConfig to configure the bean for H2 database

This class creates a bean ServletRegistrationBean and autowires it to spring container. This bean actually required to access H2 database from console through browser.

package com.myjavablog;

import org.h2.server.web.WebServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfig {
@Bean
ServletRegistrationBean h2servletRegistration() {
    ServletRegistrationBean registrationBean = new ServletRegistrationBean(new WebServlet());
    registrationBean.addUrlMappings("/console/*");
    return registrationBean;
}
}

Step 5: Last but not the least, You need to define application properties.

#DATASOURCE (DataSourceAutoConfiguration & #DataSourceProperties)
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=
#Hibernate
#The SQL dialect makes Hibernate generate better SQL for the chosen #database
spring.jpa.properties.hibernate.dialect =org.hibernate.dialect.H2Dialect
spring.datasource.driverClassName=org.h2.Driver
#Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
server.port=8082
server.error.whitelabel.enabled=false

Step 6: Create the spring boot main file

package com.myjavablog;

import com.myjavablog.dao.DepartmentRepository;
import com.myjavablog.dao.StudentRepository;
import com.myjavablog.model.Department;
import com.myjavablog.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

import java.util.Arrays;

@SpringBootApplication
public class SpringbootJpaOneToManyDemoApplication implements CommandLineRunner {
@Autowired
private DepartmentRepository departmentRepository;

@Autowired
private StudentRepository studentRepository;

public static void main(String[] args) {

    SpringApplication.run(SpringbootJpaOneToManyDemoApplication.class, args);
}

@Override
public void run(String... args) throws Exception {
//Unidirectional Mapping
	Department department = new Department();
	department.setName("COMPUTER");
        departmentRepository.save(department);

	Student student = new Student();
		student.setDepartment(departmentRepository.findDepartmentByName("COMPUTER"));
		student.setName("Anup");
		student.setMobile(989911);
		Student student1 = new Student();
		student1.setDepartment(departmentRepository.findDepartmentByName("IT"));
		student1.setName("John");
		student1.setMobile(89774);
		studentRepository.saveAll(Arrays.asList(student,student1));
}
}

Step 7: Now run the application

Run the application as a java application or as spring boot application spring-boot:run

Once you run the application records will be inserted to tables as below –

Step 8: This application also has REST endpoints to expose the services as below –

Save department –

Add students under created department –

We can check database entries to cross verify –

One To Many (Bi-directional) Relational Mapping with Spring Boot + Spring Data JPA + H2 Database

In this tutorial , we will see One To Many mapping of two entities using Spring Boot and Spring Data JPA using H2 database.

GitHub Link 

Tools:

  • Spring Boot
  • Spring Data JPA
  • H2 Database
  • IntelliJ IDEA
  • Maven

We have two entities Student and Department. Many students are part of one Department (Many To One). And vice a versa i.e. each
Department has many students in it (One To Many) .

This is called One To Many and Many To One mapping between two entities. For each of this entity, table will be created in database. So there will be two tables created in database.

create table address (id bigint generated by default as identity, name varchar(255), primary key (id));
create table student (id bigint generated by default as identity, mobile integer, name varchar(255), address_id bigint, primary key (id));
alter table student add constraint FKcaf6ht0hfw93lwc13ny0sdmvo foreign key (address_id) references address(id);

Each table has primary key as ID . Two tables has One To Many relationship between them. All student has department associated with them and each
department has many students in them.

STUDENT  table has foreign key as DEPT_ID in it. So STUDENT is a child table and DEPARTMENT table is parent table in this relationship. FOREIGN KEY constraint adds below restrictions –

  1. We can’t add records in child table if there is no entry in parent table. Ex. You can’t add department ID reference in STUDENT table if department ID is not present in DEPARTMENT table.
  2. You can’t delete the records from parent table unless corresponding references are deleted from child table . Ex. You can’t delete the entry
    DEPARTMENT table unless corresponding students from STUDENT table are deleted . You can apply ON_DELETE_CASCADE with foreign key constraint if you want to delete students from STUDENT table automatically when department is deleted.
  3. If you want to insert a student into STUDENT table then corresponding department should already be present in DEPARTMENT table.
  4. When any department is updated in DEPARTMENT table then child table will also see the updated reference from parent table

Now we will see how can we form this relationship using Spring data JPA entities.

Step 1: Define all the dependencies required for this project

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.myjavablog</groupId>
<artifactId>springboot-jpa-one-to-many-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-jpa-one-to-many-demo</name>
<description>Demo project for Spring Boot</description>
<pre><code><properties>
    <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-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-jdbc</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <!--<scope>runtime</scope>-->
    </dependency>

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

    <!-- https://mvnrepository.com/artifact/colt/colt -->
    <dependency>
        <groupId>colt</groupId>
        <artifactId>colt</artifactId>
        <version>1.2.0</version>
    </dependency>

</dependencies>

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

spring-boot-starter-data-jpa – This jar is used to connect to database .It also has a support to provide different JPA implementations to interact with the database like Hibernate, JPA Repository, CRUD Repository etc.

h2 – Its used to create H2 database when the spring boot application boots up. Spring boot will read the database configuration from application.properties file and creates a DataSource out of it.

Step 2: Define the Model/Entity classes

Student.java

package com.myjavablog.model;

import org.springframework.stereotype.Repository;

import javax.annotation.Generated;
import javax.persistence.*;
import java.util.Optional;

@Entity
@Table(name = "STUDENT")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String name;

    @Column
    private int mobile;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "DEPT_ID")
    private Department department;

    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 getMobile() {

        return mobile;
    }

    public void setMobile(int mobile) {

        this.mobile = mobile;
    }

    public Department getDepartment() {

        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }
}

Department.java

package com.myjavablog.model;

import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = "DEPARTMENT")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column
private String name;

@OneToMany(mappedBy = "department")
private List<Student> studentList;

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 List<Student> getStudentList() {
return studentList;
}
public void setStudentList(List<Student> studentList) {
this.studentList = studentList;
}
}

Below are the Annotations used while creating the entity classes –

Spring Data JPA Annotations –

  • @Entity – This annotation marks the class annotations.
  • @Table – This annotation creates table in database.
  • @Id – It creates primary key in table.
  • @GeneratedValue – It defines primary key generation strategy like AUTO,IDENTITY,SEQUENCE etc.
  • @Column It defines column property for table.
  • @OneToMany – This annotation is used in the owning entity/Parent entity. This annotation is required in only if you want Bi-directional relational mapping.
  • @ManyToOne – This annotation creates Many to one relationship between Student and Department entities. The cascade property (CascadeType.ALL) defines what should happen with child table records when something happens with parent table records. On DELETE, UPDATE , INSERT operations in parent table child table should also be affected. Both @OneToMany and @ManyToOne annotations are required to form Bi-directional relational mapping.
  • @JoinColumn – You can define column which creates foreign key in a table. In our example, DEPT_ID is a foreign key in STUDENT table which references to ID in DEPARTMENT table.

Step 3: Create the JPA repositories to query STUDENT and DEPARTMENT tables

StudentRepository and AddressRepository implemets JpaRepository which has methods to perform all CRUD operations. It has methods like save(), find(), delete(),exists(),count() to perform database operations.

package com.myjavablog.dao;

import com.myjavablog.model.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
public Student findByName(String name);
}

package com.myjavablog.dao;

import com.myjavablog.model.Address;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AddressRepository extends JpaRepository<Address, Long>{
}

Step 4: Create the class BeanConfig to configure the bean for H2 database

This class creates a bean ServletRegistrationBean and autowires it to spring container. This bean actually required to access H2 database from console through browser.

package com.myjavablog;

import org.h2.server.web.WebServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfig {
@Bean
ServletRegistrationBean h2servletRegistration() {
    ServletRegistrationBean registrationBean = new ServletRegistrationBean(new WebServlet());
    registrationBean.addUrlMappings("/console/*");
    return registrationBean;
}
}

Step 5: Last but not the least, You need to define application properties.

#DATASOURCE (DataSourceAutoConfiguration & #DataSourceProperties)
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=
#Hibernate
#The SQL dialect makes Hibernate generate better SQL for the chosen #database
spring.jpa.properties.hibernate.dialect =org.hibernate.dialect.H2Dialect
spring.datasource.driverClassName=org.h2.Driver
#Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
server.port=8082
server.error.whitelabel.enabled=false

Step 6: Create the spring boot main file

package com.myjavablog;

import com.myjavablog.dao.DepartmentRepository;
import com.myjavablog.dao.StudentRepository;
import com.myjavablog.model.Department;
import com.myjavablog.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

import java.util.Arrays;

@SpringBootApplication
public class SpringbootJpaOneToManyDemoApplication implements CommandLineRunner {
@Autowired
private DepartmentRepository departmentRepository;

@Autowired
private StudentRepository studentRepository;

public static void main(String[] args) {

    SpringApplication.run(SpringbootJpaOneToManyDemoApplication.class, args);
}

@Override
public void run(String... args) throws Exception {
    //Bi-directional mapping
		Department department1 = new Department();
		department1.setName("IT");

		//Students list
		Student student = new Student();
		student.setName("Danny");
		student.setMobile(33333);
		student.setDepartment(department1);
		Student student1 = new Student();
		student1.setName("Mark");
		student1.setMobile(11111);
		student1.setDepartment(department1);

		//department1.setStudentList(Arrays.asList(student,student1));
		department1.getStudentList().add(student);
		department1.getStudentList().add(student1);

		departmentRepository.save(department1);

		//Get the list of students from department
		Department department = departmentRepository.findDepartmentById(1l);

		for(Student s : department.getStudentList())
			System.out.println(s);
}
}

Step 7: Now run the application

Run the application as a java application or as spring boot application spring-boot:run

Once you run the application records will be inserted to tables as below –

Step 8: This application also has REST endpoints to expose the services as below –

Save department –

Add students under created department –

We can check database entries to cross verify –

Bi-directional Relational Mapping –

To create the bi-directional mapping between entities, we need to below changes in entities –

The idea with bidirectional one-to-many association is to allow you to keep a collection of child entities in the parent and enable you to persist and retrieve the child entities via the parent entity.

In our example, Department entity has list of students in it. So we can access all students from particular department.

//Bi-directional mapping
		Department department = new Department();
		department.setName("IT");

		//Students list
		Student student = new Student();
		student.setName("Danny");
		student.setMobile(33333);
		Student student1 = new Student();
		student1.setName("Mark");
		student1.setMobile(11111);

		department.setStudentList(Arrays.asList(student,student1));

		departmentRepository.save(department);

Hibernate automatically issues insert statements and saves the Students added to the Department.

Similarly, you could fetch Students via the Department entity like so –

    //Retrieve department
    Department department1 = departmentRepository.findDepartmentById(1l);

   // Retrieve students from Department
    System.out.println(department1.getStudentList());

When you write department1.getStudentList(), hibernate loads all the comments from the database if they are not already loaded.

Problems with bidirectional one-to-many mapping

  • A bidirectional mapping tightly couples the many-side of the relationship to the one-side.
  • In our example, If you load students via the Department entity, you won’t be able to limit the number of students loaded. That essentially means that you won’t be able to paginate.
  • If you load students via the Department  entity, you won’t be able to sort them based on different properties. You can define a default sorting order using @OrderColumn annotation but that will have performance implications.
  • You’ll have to face multiple times LazyInitializationException.

When can you use a bidirectional one-to-many mapping

A bidirectional one-to-many mapping might be a good idea if the number of child entities is limited.

Moreover, A bidirectional mapping tightly couples the many-side of the relationship to the one-side. Many times, this tight coupling is desired.

Example:

When you have to design an application for multiple choices questions then you should have two entities like Question and Choice. When you fetch the Question then Choices will also be fetched with that question. So Question and Choice has tight coupling between them.

So to decide between bidirectional and unidirectional mappings, you should think whether the entities have a tight coupling or not

One To One Relationship with Spring Boot + Spring Data JPA + H2 Database

In this tutorial , we will see One To One mapping of two entities using Spring Boot and Spring Data JPA using H2 database.

GitHub Link 

Tools:

  • Spring Boot
  • Spring Data JPA
  • H2 Database
  • IntelliJ IDEA
  • Maven
  • Lombok

We have two entities Student and Address. Each student has single address attached to him. And vice a versa i.e. each address is attached to student .

This is called One To One mapping between two entities. For each of this entity, table will be created in database. So there will be two tables created in database.

create table address (id bigint generated by default as identity, name varchar(255), primary key (id));
create table student (id bigint generated by default as identity, mobile integer, name varchar(255), address_id bigint, primary key (id));
alter table student add constraint FKcaf6ht0hfw93lwc13ny0sdmvo foreign key (address_id) references address(id);

Each table has primary key as ID . Two tables has One To One relationship between them. Each student has address associated with him and each address has one student.

STUDENT table has foreign key as ADDRESS_ID in it. So STUDENT is a child table and ADDRESS table is parent table in this relationship.

Now we will see how can we form this relationship using Spring data JPA entities.

Step 1: Define all the dependencies required for this project

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.myjavablog</groupId>
<artifactId>spring-boot-data-jpa-one-to-one</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-data-jpa-one-to-one</name>
<description>Demo project for Spring Boot</description>
<pre><code><properties>
    <java.version>1.8</java.version>
</properties>

<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>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <!--<scope>runtime</scope>-->
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!-- For JSP compilation -->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>

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

  • Lombok – We will be using lombok third party library to reduce boilerplate code for model/data objects, e.g., it can generate getters and setters for those object automatically by using Lombok annotations. The easiest way is to use the @Data annotation.
  • spring-boot-starter-data-jpa – This jar is used to connect to database .It also has a support to provide different JPA implementations to interact with the database like Hibernate, JPA Repository, CRUD Repository etc.
  • h2 – Its used to create H2 database when the spring boot application boots up. Spring boot will read the database configuration from application.properties file and creates a DataSource out of it.

Step 2: Define the Model/Entity

Student.java

package com.myjavablog.model;

import org.springframework.stereotype.Repository;

import javax.annotation.Generated;
import javax.persistence.*;
import java.util.Optional;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "STUDENT")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column
private String name;

@Column
private int mobile;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "ADDRESS_ID")
private Address address;


public Student(String name, int mobile, Address address) {
    this.name=name;
    this.mobile=mobile;
    this.address=address;
}

@Override
public String toString() {
    return "Student{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", mobile=" + mobile +                
            '}';
}
}

Address.java

package com.myjavablog.model;

import javax.persistence.*;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "ADDRESS")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column
private String name;

@OneToOne(mappedBy = "address")
private Student student;

public Address(String name) {
    this.name =name;
}

@Override
public String toString() {
    return "Address{" +
            "id=" + id +
            ", name='" + name + '\'' +
            '}';
}
}

Below are the Annotations used while creating the entity classes –

Lombok annotations –

  • @Data – Define this class as Model class
  • @Builder – To build the model object at runtime ex. Create mock object for unit testing
  • @AllArgsConstructor – Create constructor with all arguments
  • @NoArgsConstructor – Default constructor

Spring Data JPA Annotations –

  • @Entity – This annotation marks the class annotations.
  • @Table – This annotation creates table in database.
  • @Id – It creates primary key in table.
  • @GeneratedValue – It defines primary key generation strategy like AUTO,IDENTITY,SEQUENCE etc.
  • @Column It defines column property for table.
  • @OneToOne – This annotation creates one to one relationship between Student and Address entities. The cascade property (CascadeType.ALL) defines what should happen with child table records when something happens with parent table records. On DELETE, UPDATE , INSERT operations in parent table child table should also be affected.
  • @JoinColumn – You can define column which creates foreign key in a table. In our example, ADDRESS_ID is a foreign key in STUDENT table which references to ID in ADDRESS table.

Step 3: Create the JPA repositories to query STUDENT and ADDRESS tables

StudentRepository and AddressRepository implemets JpaRepository which has methods to perform all CRUD operations. It has methods like save(), find(), delete(),exists(),count() to perform database operations.

package com.myjavablog.dao;

import com.myjavablog.model.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
public Student findByName(String name);
}

package com.myjavablog.dao;

import com.myjavablog.model.Address;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AddressRepository extends JpaRepository<Address, Long>{
}

Step 4: Create the class BeanConfig to configure the bean for H2 database

This class creates a bean ServletRegistrationBean and autowires it to spring container. This bean actually required to access H2 database from console through browser.

package com.myjavablog;

import org.h2.server.web.WebServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfig {
@Bean
ServletRegistrationBean h2servletRegistration() {
    ServletRegistrationBean registrationBean = new ServletRegistrationBean(new WebServlet());
    registrationBean.addUrlMappings("/console/*");
    return registrationBean;
}
}

Step 5: Lat but not the least, You need to define application properties.

<h1>DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)</h1>
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=
<h1>Hibernate</h1>
<h1>The SQL dialect makes Hibernate generate better SQL for the chosen database</h1>
spring.jpa.properties.hibernate.dialect =org.hibernate.dialect.H2Dialect
spring.datasource.driverClassName=org.h2.Driver
<h1>Hibernate ddl auto (create, create-drop, validate, update)</h1>
spring.jpa.hibernate.ddl-auto = update

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
server.port=8082
server.error.whitelabel.enabled=false

Step 6: Now run the application

Once you run the application records will be inserted to tables as below –

Spring Boot + Spring Data JPA + H2 Database

In this example , we will create a simple Spring boot application which will interact with the H2 database using Spring JPA library.

H2 database is an in memory database .For this tutorial , we will use H2 database for this demo so that we don’t need to perform heavy installation for other database like Oracle,MySQL.

GitHub Link

Tools –

  • Spring Boot
  • Spring JPA
  • H2 Database
  • IntelliJ IDEA editor
  • Maven
  • Lombok

Step 1: Create the simple spring boot web application in IntelliJ IDEA editor

Our final Project structure will look like below–

Step 2: Now define all maven dependencies required in this project

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.myjavablog</groupId>
<artifactId>springhibernatewithh2database</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springhibernatewithh2database</name>
<description>Demo project for Spring Boot</description>
<pre><code><properties>
    <java.version>1.8</java.version>
</properties>

<dependencies>

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

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

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-jdbc</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <!--<scope>runtime</scope>-->
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

</dependencies>

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

  • Lombok – We will be using lombok third party library to reduce boilerplate code for model/data objects, e.g., it can generate getters and setters for those object automatically by using Lombok annotations. The easiest way is to use the @Data annotation.
  • spring-boot-starter-data-jpa – This jar is used to connect to database .It also has a support to provide different JPA implementations to interact with the database like Hibernate, JPA Repository, CRUD Repository etc.
  • h2 – Its used to create H2 database when the spring boot application boots up. Spring boot will read the database configuration from application.properties file and creates a DataSource out of it.

Step 2: Create the Model class

package com.myjavablog.pojo;

import javax.persistence.*;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table
public class UserDetails {
<pre><code>@Id
@Column
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column
private String firstName;
@Column
private String lastName;
@Column
private String email;
@Column
private String password;</code></pre>
}

We have used Lombok library in Model class . You can see below annotation which are coming from Lambok jar –

  • @Data – Define this class as Model class
  • @Builder – To build the model object at runtime ex. Create mock object for unit testing
  • @AllArgsConstructor – Create constructor with all arguments
  • @NoArgsConstructor – Default constructor

So Lombok takes care of everything for you right from creating setters/ getters, Constructor , Build runtime objects and avoids boilerplate code .

Step 3: Configuration for the H2 database bean

package com.myjavablog.config;

import org.h2.server.web.WebServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfig {
<pre><code>@Bean
ServletRegistrationBean h2servletRegistration() {
    ServletRegistrationBean registrationBean = new ServletRegistrationBean(new WebServlet());
    registrationBean.addUrlMappings("/console/*");
    return registrationBean;
}</code></pre>
}

We can also configure the security for the application.

package com.myjavablog.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
<pre><code>@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity.csrf().disable().authorizeRequests().antMatchers("/").permitAll().and().authorizeRequests()
            .antMatchers("/console/**").permitAll()
            .antMatchers("/list/**").permitAll();
    httpSecurity.headers().frameOptions().disable();
}</code></pre>
}

Step 4: Service layer

package com.myjavablog.service;

import com.myjavablog.pojo.UserDetails;

import java.util.List;

public interface UserService {
public List getUserDetails();
}

package com.myjavablog.service;

import com.myjavablog.dao.UserDao;
import com.myjavablog.pojo.UserDetails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements UserService {
<pre><code>@Autowired
UserDao userDao;

@Override
public List getUserDetails() {

    return userDao.getUserDetails();
}
}

Step 5: DAO layer

package com.myjavablog.dao;

import com.myjavablog.pojo.UserDetails;

import java.util.List;

public interface UserDao {
<pre><code>public List getUserDetails();
}

package com.myjavablog.dao;

import com.myjavablog.pojo.UserDetails;

import javax.persistence.*;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository
public class UserDaoImpl implements UserDao {
@PersistenceContext
private EntityManager entityManager ;

@Override
public List getUserDetails() {
    Criteria criteria;
    criteria = entityManager.unwrap(Session.class).createCriteria(UserDetails.class);
    return criteria.list();
}
}

Step 7: Create Controller class

package com.myjavablog.controller;

import com.myjavablog.pojo.UserDetails;
import com.myjavablog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.List;

@Controller
public class UserController {
@Autowired
private UserService userService;

@RequestMapping(value = "/list", method = RequestMethod.GET)
public ResponseEntity userDetails() {

    List userDetails = userService.getUserDetails();
    return new ResponseEntity(userDetails, HttpStatus.OK);
}
}

Step 8 : Create a properties file to configure Spring boot application and database

spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
server.port=8081
server.error.whitelabel.enabled=false

Step 9: Now application is ready . Run the application and Java application and access URL http://localhost:8081/console to access H2 database.

Once you connect to it you can insert records to table.

Now you can access the application to get the list of users.

Spring boot Data JPA+ Angular JS + MySQL Database CRUD

Github Link: 

We are using  Spring boot version 2.0.0.RELEASE . We will be creating simple TodoManager application using which we can manage our daily todo tasks. We will be using angular for front end. It will provide user interface from which you can add, update or delete tasks in todo list.We will use controller, JpaRepository classes to achieve these functionalities.We will connect to MySQL database using SessionFactory class of hibernate.

Tools used for below project –

  1. Spring Boot 2.0.0.RELEASE
  2. Spring 5.0.4.RELEASE
  3. Tomcat Embed 8
  4. Maven 3.3
  5. Java 8
  6. Spring Tool Suite IDE (STS)
  7. Spring Data JPA 2.0.5.RELEASE
  8. MySql 5.1.21

Step 1: Project Structure

Step 2: Create a project named TodoListManagerJPA in STS (Refer Create new project in STS)

Step 3: Change pom.xml as below –

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.anup.springboot</groupId>
<artifactId>TodoListManagerJPA</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>Springboot JPA Maven Webapp</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath />
</parent>

<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>

<!-- JSTL for JSP -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>

<!-- For JSP compilation -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>

<!-- mySQL DB -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.21</version>
</dependency>

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

</dependencies>

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

<!-- <plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin> -->
</plugins>

<finalName>TodoListManagerJPA</finalName>
</build>
</project>

The spring-boot-starter-parent provides you all maven defaults required for any spring project. Since we are developing a web application, we also need to add spring-boot-starter-web dependency. Additionally we need to include spring-boot-starter-data-jpa to run this application with MySQL database.You need to also put mysql-connector-java for MySql JDBC driver.If you are using any other database, you need to use different database connector.
Let’s do hibernate configuration first.

Step 4: Create a  “application.properties”  file in package /src/main/resources

spring.mvc.view.prefix: /WEB-INF/views/
spring.mvc.view.suffix: .jsp
server.port=8081

## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/test?useSSL=false
spring.datasource.username = root
spring.datasource.password = root

## Hibernate Properties

# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update

In the above properties file, the last two properties are for hibernate. Spring Boot uses Hibernate as the default JPA implementation.

The property spring.jpa.hibernate.ddl-auto is used for database initialization. I’ve used the value “update”for this property.

It does two things –

  • When you define a domain model, a table will automatically be created in the database and the fields of the domain model will be mapped to the corresponding columns in the table.
  • Any change to the domain model will also trigger an update to the table. For example, If you change the name or type of a field, or add another field to the model, then all these changes will be reflected in the mapped table as well.

Using update for spring.jpa.hibernate.ddl-auto property is fine for development. But, For production, You should keep the value of this property to “validate”, and use a database migration tool like Flyway for managing changes in the database schema.

Step 5: Create a “Task.java” model class in com.myjavablog.springboot.pojo package

package com.myjavablog.springboot.pojo;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

/**
* @author anup
*
*/

@Entity
@Table(name="TASKS")
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = {"createdAt", "updatedAt"},
allowGetters = true)
public class Task implements Serializable {

/**
*
*/
private static final long serialVersionUID = 1L;

@Id
@Column(name="ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name="TASK_NAME")
private String taskName;

@Column(name="TASK_DESC")
private String taskDesc;

@Column(name="STATUS")
private String status;

@Column(nullable = false, updatable = false , name= "CREATED_AT")
@Temporal(TemporalType.TIMESTAMP)
@CreatedDate
private Date createdAt;

@Column(nullable = false, name= "UPDATED_AT")
@Temporal(TemporalType.TIMESTAMP)
@LastModifiedDate
private Date updatedAt;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getTaskName() {
return taskName;
}

public void setTaskName(String taskName) {
this.taskName = taskName;
}

public String getTaskDesc() {
return taskDesc;
}

public void setTaskDesc(String taskDesc) {
this.taskDesc = taskDesc;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public Date getCreatedAt() {
return createdAt;
}

public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}

public Date getUpdatedAt() {
return updatedAt;
}

public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
}

@Entity – This marks class as Entity

@Table – This maps class to database table

@Id – Marks the class variable as primary key column in table

@Column – Marks it as a column in table , we can also configure name attribute defining its name in database table

@Temporal – annotation is used with java.util.Dateand java.util.Calendar classes. It converts the date and time values from Java Object to compatible database type and vice versa.

@JsonIgnoreProperties – annotation is a Jackson annotation. Spring Boot uses Jackson for Serializing and Deserializing Java objects to and from JSON.This annotation is used because we don’t want the clients of the rest api to supply the createdAt and updatedAt values. If they supply these values then we’ll simply ignore them. However, we’ll include these values in the JSON response.

@EntityListeners(AuditingEntityListener.class)

In our Task model we have annotated createdAt and updatedAt fields with @CreatedDate and @LastModifiedDate annotations respectively.

Now, what we want is that these fields should automatically get populated whenever we create or update an entity.

To achieve this, we need to do two things –

  1. Add Spring Data JPA’s AuditingEntityListener to the domain model. We have already done this in our Task model with the annotation @EntityListeners(AuditingEntityListener.class).
  2. Enable JPA Auditing in the main application. Open TodoManagerApplication.java and add @EnableJpaAuditing annotation.

@GeneratedValue – Marking a field with the @GeneratedValue annotation specifies that a value will be automatically generated for that field. This is primarily intended for primary key fields .There are below types of strategies –

GenerationType.AUTO It is the default generation type and lets the persistence provider choose the generation strategy.

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

GenerationType.IDENTITY – The GenerationType.IDENTITY is the easiest to use but not the best one from a performance point of view. It relies on an auto-incremented database column and lets the database generate a new value with each insert operation. From a database point of view, this is very efficient because the auto-increment columns are highly optimized, and it doesn’t require any additional statements.

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

GenerationType.SEQUENCE – The GenerationType.SEQUENCE is my preferred way to generate primary key values and uses a database sequence to generate unique values.

If you don’t provide sequence name hibernate will provide its default sequence

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

You can change that by referencing the name of a @SequenceGenerator in the generator attribute of the @GeneratedValue annotation. The @SequenceGenerator annotation lets you define the name of the generator, the name, and schema of the database sequence and the allocation size of the sequence.

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_generator")
@SequenceGenerator(name="book_generator", sequenceName = "book_seq", allocationSize=50)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

GenerationType.TABLE – The GenerationType.TABLE gets only rarely used nowadays. It simulates a sequence by storing and updating its current value in a database table which requires the use of pessimistic locks which put all transactions into a sequential order. This slows down your application, and you should, therefore, prefer the GenerationType.SEQUENCE, if your database supports sequences, which most popular databases do

If you don’t provide sequence name hibernate will provide its default sequence

@Id
@GeneratedValue(strategy = GenerationType.TABLE)
@Column(name = "id", updatable = false, nullable = false)
private Long id;

Summary:

  1. AUTO: Hibernate selects the generation strategy based on the used dialect,
  2. IDENTITY: Hibernate relies on an auto-incremented database column to generate the primary key,
  3. SEQUENCE: Hibernate requests the primary key value from a database sequence,
  4. TABLE: Hibernate uses a database table to simulate a sequence.

Step 6: Create database tables

create schema test;

create table TASKS (id bigint NOT NULL AUTO_INCREMENT, TASK_NAME varchar(255), TASK_DESC varchar(255), STATUS varchar(255) , CREATED_AT timestamp, UPDATED_AT timestamp, primary key (id));

INSERT INTO TASKS VALUES(1, 'Bath', 'Have a bath' , 'PENDING', SYSDATE, SYSDATE);

INSERT INTO TASKS VALUES(2, 'Snacks', 'Have snacks' , 'PENDING' , CURTIME() , CURTIME());

INSERT INTO TASKS VALUES(3, 'Office', 'Office' , 'PENDING' , CURTIME() , CURTIME());

INSERT INTO TASKS VALUES(4, 'Lunch', 'Lunch' , 'PENDING' , CURTIME() , CURTIME());

Controller class

Step 7: Create class “TodoController.java” in package com.myjavablog.springboot.controller

/**
*
*/
package com.myjavablog.springboot.controller;

import java.util.List;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
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.RestController;

import com.myjavablog.springboot.exception.ResourceNotFoundException;
import com.myjavablog.springboot.pojo.Task;
import com.myjavablog.springboot.repository.TodoRepository;

/**
* @author anup
*
*/

@RestController
public class TodoController {

@Autowired
TodoRepository todoRepository;

@PostMapping(value = "/todos/addTodo")
public Task addTodo(@Valid @RequestBody Task task) {
return todoRepository.save(task);
}

@PutMapping(value = "/todos/updateTodo")
public Task updateTodo(@Valid @RequestBody Task task) {

Task todo = todoRepository.findById(task.getId())
.orElseThrow(() -> new ResourceNotFoundException("Todo", "id", task.getId()));

todo.setStatus(task.getStatus());
todo.setTaskDesc(task.getTaskDesc());
todo.setTaskName(task.getTaskName());

Task updatedTask = todoRepository.save(todo);
return updatedTask;
}
@GetMapping(value = "/todos/getAllTodos")
public List<Task> getAllTodos() {
return todoRepository.findAll();
}

@DeleteMapping(value="/todos/deleteTodo/{id}")
public ResponseEntity<?> deleteCust(@PathVariable Long id) {
todoRepository.deleteById(id);

return ResponseEntity.ok().build();
}

}

@RestController annotation is a combination of Spring’s @Controller and @ResponseBody annotations.

Repository 

Step 8: Create interface “TodoRepository.java” in package “com.myjavablog.springboot.repository” and extend it from JpaRepository.

We have to create a repository to access Tasks from the database.

Well, Spring Data JPA comes to rescue us here. It comes with a JpaRepository interface which defines methods for all the CRUD operations on the entity, and a default implementation of JpaRepository called SimpleJpaRepository. JPA has eliminated lot of boilerplate code which we need to write for CRUD operations otherwise.

package com.myjavablog.springboot.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.myjavablog.springboot.pojo.Task;

/**
* @author anupb
*
*/
@Repository
public interface TodoRepository extends JpaRepository<Task, Long>{

}

we have annotated the interface with @Repository annotation. This tells Spring to bootstrap the repository during component scan.

Cool! That is all you have to do in the repository layer. You will now be able to use JpaRepository’s methods like save()findOne()findAll()count()delete() etc.

Custom Exception

Step 9: Create “ResourceNotFoundException.java” in “com.myjavablog.springboot.exception” package –

We have defined the Rest APIs for creating, retrieving, updating, and deleting a Task .

The APIs will throw a ResourceNotFoundException whenever a Task with a given id is not found in the database.

package com.myjavablog.springboot.exception;

import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.http.HttpStatus;
/**
* @author anupb
*
*/
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
private String resourceName;
private String fieldName;
private Object fieldValue;

public ResourceNotFoundException(String resourceName, String fieldName, Object fieldValue) {
super(String.format("%s not found with %s : '%s'", resourceName, fieldName, fieldValue));
this.resourceName = resourceName;
this.fieldName = fieldName;
this.fieldValue = fieldValue;
}

public String getResourceName() {
return resourceName;
}

public String getFieldName() {
return fieldName;
}

public Object getFieldValue() {
return fieldValue;
}
}

AngularJS UI Layer

Step 10: Create “index.jsp” under \src\main\webapp\WEB-INF\views\

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>

<html>
<head>
<link href="/css/app.css" rel="stylesheet"/>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"></script>
<script type="text/javascript" src="/js/app.js"></script>

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Todo Manager</title>
</head>
<body ng-app="todoManager" ng-controller="todoController">
</br>
<h4 class="todo">Todo Manager</h4>

<form ng-submit="submitTodo()">
<table>

<tr>
<th colspan="2">Add/Edit todo</th>
</tr>
<tr>
<td>Task Name</td>
<td><input type="text" ng-model="todoForm.taskName" /></td>
</tr>
<tr>
<td>Task Desc</td>
<td><input type="text" ng-model="todoForm.taskDesc" /></td>
</tr>
<tr>
<td>Status</td>
<td><select id="status" ng-model="todoForm.status" ng-options="x for x in status" /></select></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Submit"
class="blue-button" /></td>
</tr>
</table>
</form>

<table>
<tr>

<th width="120">Task Name</th>
<th width="120">Task Desc</th>
<th width="60">Status</th>
<th width="60">Operations</th>

</tr>

<tr ng-repeat="todo in todos" ng-init="statusCls=getClass(todo)">

<td>{{ todo.taskName }}</td>
<td>{{ todo.taskDesc }}</td>
<td class="statusCls"> {{ todo.status }} </td>

<td><a ng-click="editTodo(todo)" class="blue-button">Edit</a>
| <a ng-click="deleteTodo(todo)" class="red-button">Delete</a></td>
</tr>

</table>

</body>
</html>

Step 11: Create javascript file “app.js” under \src\main\resources\static\js\

var app = angular.module("todoManager" , []);

app.controller("todoController" , function($scope, $http){

$scope.todos = [];
$scope.status = ["PENDING", "COMPLETED"];
$scope.todoForm = {
id : -1,
taskName : "",
taskDesc : ""
};

$scope.getClass = function(todo){

if(todo.status == 'PENDING')
return 'red';
else if(todo.status == 'COMPLETED'){
return 'green';
}
}

_refreshTodoData();

function _refreshTodoData(){

$http({
method : 'GET',
url : 'http://localhost:8082/todos/getAllTodos'
}).then(function successCallback(response) {
$scope.todos = response.data;

//alert($scope.todos);
}, function errorCallback(response) {
console.log(response.statusText);
});
}

$scope.submitTodo = function() {

var method = "";
var url = "";
if ($scope.todoForm.id == -1) {
//Id is absent in form data, it is create new todo operation
method = "POST";
url = '/todos/addTodo';
} else {
//Id is present in form data, it is edit todo operation
method = "PUT";
url = '/todos/updateTodo';
}

$http({
method : method,
url : url,
data : angular.toJson($scope.todoForm),
headers : {
'Content-Type' : 'application/json'
}
}).then( _success, _error );
};

$scope.deleteTodo = function(todo) {
$http({
method : 'DELETE',
url : '/todos/deleteTodo/' + todo.id
}).then(_success, _error);
};

$scope.editTodo = function(todo) {

$scope.todoForm.taskName = todo.taskName;
$scope.todoForm.taskDesc = todo.taskDesc;
$scope.todoForm.status = todo.status;
$scope.todoForm.id = todo.id;
};

function _success(response) {
//alert("success");
_refreshTodoData();
_clearFormData();
}

function _error(response) {
//alert("error");
console.log(response.statusText);
}

//Clear the form
function _clearFormData() {
$scope.todoForm.id = -1;
$scope.todoForm.taskName = "";
$scope.todoForm.taskDesc = "";
$scope.todoForm.status = "";

};
});

Step 12: Create CSS file “app.css” under \src\main\resources\static\css\ for adding style

.blue-button {
background: #25A6E1;
filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#25A6E1',
endColorstr='#188BC0', GradientType=0);
padding: 3px 5px;
color: #fff;
font-family: 'Helvetica Neue', sans-serif;
font-size: 12px;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 4px;
border: 1px solid #1A87B9;
cursor: pointer;
}

.red-button {
background: #CD5C5C;
padding: 3px 5px;
color: #fff;
font-family: 'Helvetica Neue', sans-serif;
font-size: 12px;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 4px;
border: 1px solid #CD5C5C;
cursor: pointer;
}

table {
font-family: "Helvetica Neue", Helvetica, sans-serif;
width: 50%;
}

caption {
text-align: left;
color: silver;
font-weight: bold;
text-transform: uppercase;
padding: 5px;
}

th {
background: SteelBlue;
color: white;
}

tbody tr:nth-child(even) {
background: WhiteSmoke;
}

tbody tr td:nth-child(2) {
text-align: center;
}

tbody tr td:nth-child(3), tbody tr td:nth-child(4) {
text-align: center;
font-family: monospace;
}

tfoot {
background: SeaGreen;
color: white;
text-align: right;
}

tfoot tr th:last-child {
font-family: monospace;
}

td, th {
border: 1px solid gray;
width: 25%;
text-align: left;
padding: 5px 10px;
}

#status{
width: 53%;
padding: 1px 0;
}

.todo {
font-size: 24px;
color: #CD5C5C;
text-transform: uppercase;
font-family: arial;
width: 50%;
background: #ccc;
text-align: center;
border-radius: 4px;
margin: 2% 0%;
padding: 3px 0;
box-shadow: 0px 1px 7px 1px grey;
}

.pending{
color: red;
}

.completed{
color: green;
}

  • $http – It’s used to make AJAX calls to server in order to submitTodo(), deleteTodo() , editTodo() task.
  • When you click on submit button on form, it actually calls POST or PUT depending on operation. If you click on edit and submit data then it will be PUT operation as it will update existing resource. If you directly submit data, then it will be POST operation to create new resource.
  • Every time you submit data, it calls _refreshTodoData() to refresh Todo table below.
  • When you call $http, you need to pass method type and URL, it will call it according, You can either put absolute URL or relative URL with respect to context root of web application.

Spring boot main file

Step 13: Create “TodoManagerApplication.java” a main spring file under com.anup.springboot

package com.myjavablog.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaAuditing
@EnableJpaRepositories(basePackages="com.myjavablog.springboot.repository")
public class TodoManagerApplication {

public static void main(String[] args) {
SpringApplication.run(TodoManagerApplication.class, args);
}
}

This is the mail file which bootstraps spring application.

We have just added @SpringBootApplication and it does all the work.
Let’s understand more about this annotation.
@SpringBootApplication is an annotation that adds all of the following:

@Configuration – It makes the class as a source of bean definitions for the application context.
@EnableAutoConfiguration – It enables Spring boot to add beans presents in classpath setting and various property setting.
Normally you would add @EnableWebMvc for a Spring MVC application, but Spring Boot adds it automatically when it sees spring-webmvc on the classpath.
This flags the application as a web application and activates key behaviors such as setting up a DispatcherServlet.
@ComponentScan – It tells Spring to look for other components, configurations, and services in the default package, allowing it to find the controllers.
If specific packages are not defined, scanning will occur from the package of the class that declares this annotation.

Run the application

Step 14: Right Click on Project -> Debug As -> Maven Build

Step 15: Provide goals as below – 

mvn clean install spring-boot:run (Cmd prompt)

Or

Step 16: Now once the application is up and running, you can access it from below link –

Adding new task –

Editing the task –

Deleting the task –

Now we will try to update Task which is not present in database. It should throw a custom exception and we will get response as shown below –

Bitnami