Spring REST CRUD Example with JPA Configuration

Learn to create REST APIs for crud operations using Spring REST and JPA configuration (H2 database as backend) without Spring boot auto configuration feature.

1. Maven dependencies

In this example, we are using following modules and their dependencies.

  • spring-webmvc – for request handling
  • spring-data-jpa – provides interfaces with methods supporting reading, updating, deleting, and creating records against a back end data store.
  • persistence-api – JPA specification
  • javax.persistence – JPA implementation
  • hibernate-entitymanager – as entity maneger provider
  • Jackson – for JSON support
  • H2 – as database
<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>

	<groupId>com.howtodoinjava.rest</groupId>
	<artifactId>SpringRestExample</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<name>SpringRestExample</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<spring.version>5.1.6.RELEASE</spring.version>
		<maven.compiler.source>1.8</maven.compiler.source>
    	<maven.compiler.target>1.8</maven.compiler.target>
	</properties>

	<dependencies>
		<!-- spring webmvc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		
		<!-- spring data jpa -->
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-jpa</artifactId>
			<version>2.1.6.RELEASE</version>
		</dependency>
		
		<!-- persistence api -->
		<dependency>
			<groupId>javax.persistence</groupId>
			<artifactId>persistence-api</artifactId>
			<version>1.0.2</version>
		</dependency>
		
		<!-- persistence implementation -->
		<dependency>
			<groupId>org.eclipse.persistence</groupId>
			<artifactId>javax.persistence</artifactId>
			<version>2.1.0</version>
		</dependency>
		
		<!-- entity manager provider -->
		<dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.4.2.Final</version>
        </dependency>
        
        <!-- H2 database -->
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<version>1.4.199</version> 
		</dependency>
		
		<!-- JSON support -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.9.8</version>
		</dependency>
	</dependencies>
</project>

2. DispatcherServlet declaration

We have configured the DispatcherServlet in web.xml file which will route the incoming requests to appropriate controller methods.

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
	<display-name>Employee Management REST APIs</display-name>

	<servlet>
		<servlet-name>rest</servlet-name> 
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>rest</servlet-name>
		<url-pattern>/api/rest/*</url-pattern>
	</servlet-mapping>

</web-app>

3. Spring and JPA configuration

In rest-servlet.xml file we have configured the component scanning and annotation based config support. Along with it, we have configured the entity manager and datasource configuration.

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context/
	http://www.springframework.org/schema/context/spring-context.xsd
	http://www.springframework.org/schema/data/jpa/ 
    http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd
    http://www.springframework.org/schema/tx/ 
    http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
	http://www.springframework.org/schema/mvc/
	http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<context:component-scan base-package="com.howtodoinjava.demo" />
	<mvc:annotation-driven />
	<jpa:repositories base-package="com.howtodoinjava.demo.repository" entity-manager-factory-ref="emf"/>
	
	<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
	    <property name="packagesToScan" value="com.howtodoinjava.demo.model" />
	    <property name="dataSource" ref="dataSource" />
	
	    <property name="jpaProperties">
	        <props>
	            <prop key="hibernate.show_sql">true</prop>
	            <prop key="hibernate.format_sql">true</prop>
	            <prop key="hibernate.hbm2ddl.auto">create</prop>
	            <prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
	        </props>
	    </property>
	
	    <property name="persistenceProvider">
	        <bean class="org.hibernate.jpa.HibernatePersistenceProvider"></bean>
	    </property>
	
	</bean>
	
	<bean class="org.springframework.jdbc.datasource.SimpleDriverDataSource" id="dataSource">
        <property name="driverClass" value="org.h2.Driver" />
        <property name="url" value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;TRACE_LEVEL_SYSTEM_OUT=2" />
    </bean>
	
	<tx:annotation-driven transaction-manager="transactionManager" />
	
	<bean class="org.springframework.orm.jpa.JpaTransactionManager"  id="transactionManager">
	    <property name="dataSource" ref="dataSource" />
	</bean>
</beans>

4. Entity class

We have only one entity class which will be persisted in DB and will be returned as response from REST APIs.

  • @Entity – JPA annotation to make the object ready for storage in a JPA-based data store.
  • @Table – Name of the table in data storage where this entity will be stored.

Read More : JPA 2 Persistence Annotations

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "tbl_employee")
public class Employee implements Serializable {
	private static final long serialVersionUID = 1L;

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

	private String firstName;

	private String lastName;

	private String email;

	public Employee() {
	}

	//Getters and setters

	@Override
	public String toString() {
		return "EmployeeVO [id=" + id + ", firstName=" + firstName + ", 
				lastName=" + lastName + ", email=" + email	+ "]";
	}
}

5. Repository

We have created JpaRepository implementation as EmployeeRepository which provides all defaults operations for performing search, get, update and delete operations on employee entities.

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.howtodoinjava.demo.model.Employee;

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {

}

6. REST Controller

The REST controller defines all CRUD methods which can be invoked to perform operations on employee resource.

In given controller, @RestController annotation indicates that the data returned by the methods will be written straight into the response body instead of rendering a template. Other annotations (@GetMapping, @PostMapping, @PutMapping and @DeleteMapping) map the HTTP requests to corresponding methods.

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
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.howtodoinjava.demo.model.Employee;
import com.howtodoinjava.demo.repository.EmployeeRepository;

@RestController
@RequestMapping(value = "/employee-management", produces = { MediaType.APPLICATION_JSON_VALUE })
public class EmployeeRESTController 
{
	@Autowired
	private EmployeeRepository repository;

	public EmployeeRepository getRepository() {
		return repository;
	}

	public void setRepository(EmployeeRepository repository) {
		this.repository = repository;
	}

	@GetMapping(value = "/employees")
	public List<Employee> getAllEmployees() {
		return repository.findAll();
	}

	@PostMapping("/employees")
	Employee createOrSaveEmployee(@RequestBody Employee newEmployee) {
		return repository.save(newEmployee);
	}

	@GetMapping("/employees/{id}")
	Employee getEmployeeById(@PathVariable Long id) {
		return repository.findById(id).get();
	}

	@PutMapping("/employees/{id}")
	Employee updateEmployee(@RequestBody Employee newEmployee, @PathVariable Long id) {

		return repository.findById(id).map(employee -> {
			employee.setFirstName(newEmployee.getFirstName());
			employee.setLastName(newEmployee.getLastName());
			employee.setEmail(newEmployee.getEmail());
			return repository.save(employee);
		}).orElseGet(() -> {
			newEmployee.setId(id);
			return repository.save(newEmployee);
		});
	}

	@DeleteMapping("/employees/{id}")
	void deleteEmployee(@PathVariable Long id) {
		repository.deleteById(id);
	}
}

7. Spring REST CRUD Operations Demo

Let’s test the API operations to validate they work.

7.1. Create employee

HTTP POST : http://localhost:8080/SpringRestExample/api/rest/employee-management/employees

{
    "firstName": "lokesh",
    "lastName": "gupta",
    "email": "abc@gmail.com"
}
HTTP Response code : 200

{
	"id": 1,
	"firstName": "lokesh",
	"lastName": "gupta",
	"email": "abc@gmail.com"
}

Create few more employees for testing.

7.2. Get employees collection

HTTP GET : http://localhost:8080/SpringRestExample/api/rest/employee-management/employees
HTTP Response code : 200

[
	{
		"id": 1,
		"firstName": "lokesh",
		"lastName": "gupta",
		"email": "abc@gmail.com"
	},
	{
		"id": 2,
		"firstName": "Amit",
		"lastName": "Sharma",
		"email": "xyz@gmail.com"
	}
]

7.3. Get employee by id

HTTP GET : http://localhost:8080/SpringRestExample/api/rest/employee-management/employees/1
HTTP Response code : 200

{
	"id": 1,
	"firstName": "lokesh",
	"lastName": "gupta",
	"email": "abc@gmail.com"
}

7.4. Update employee

HTTP PUT : http://localhost:8080/SpringRestExample/api/rest/employee-management/employees/1

{
    "firstName": "Lucky",
    "lastName": "Gupta",
    "email": "abc@gmail.com"
}
HTTP Response code : 200

{
	"id": 1,
	"firstName": "Lucky",
	"lastName": "Gupta",
	"email": "abc@gmail.com"
}

7.5. Delete employee

HTTP DELETE : http://localhost:8080/SpringRestExample/api/rest/employee-management/employees/1
HTTP Response code : 200

Happy Learning !!

Comments

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode