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

Was this post helpful?

Join 7000+ Awesome Developers

Get the latest updates from industry, awesome resources, blog updates and much more.

* We do not spam !!

3 thoughts on “Spring REST CRUD Example with JPA Configuration”

  1. Can we add multiple AUTH_API_KEY for different users? Or alternatively authorize users using credentials from database?

    Reply

Leave a Comment

HowToDoInJava

A blog about Java and related technologies, the best practices, algorithms, and interview questions.