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