Friday, 3 March 2017

RESTFul API in Spring MVC : CRUD Operation

REST stands for Representational State Transfer. It’s an is an architectural style which can be used to design web services, that can be consumed from a variety of clients. The core idea is that, rather than using complex mechanisms such as CORBA, RPC or SOAP to connect between machines, simple HTTP is used to make calls among them.

In a REST webservices, resources are being manipulated using a common set of HTTP verbs.

GET : It is used when user sends a Read request
POST : It is used when user sends a Create request
PUT : It is used when user sends a Update request
DELETE : It is used when user sends a Delete request

So, in the example below we will use all the above HTTP verbs.

REST services are basically developed to send the JSON response, because it is very light weight and easy to parse for any third party application compared to XML. REST services are not only to send JSON response, it can send XML as well. It's totally depend on the requirement.

In this example, we are gonna to use java based configuration for Spring and Hibernate, instead of XML based configuration.

We will use Spring 4.2.5 for this example.

After this blog, you should have learned to:

1) How to develop REST websevices in Spring and Hibernate
2) How to use different HTTP verbs
3) How to send response in JSON

To compile this example, you should have the below:

1) Eclipse
2) JDK 1.6+
3) MySql 5
4) Tomcat 8+
5) Any REST API client to test, in this example we will use POSTMAN

In this example, we are gonna to create REST API for the employees manipulation:

1) Add Employee: http://localhost:8081/RestApi/employees/ 
2) Delete Employee: http://localhost:8081/RestApi/employees/{employeeId}
3) Update Employee: http://localhost:8081/RestApi/employees/{employeeId}
4) List Employee: http://localhost:8081/RestApi/employees/
5) Get Employee based on id: http://localhost:8081/RestApi/employees/{employeeId}

Download the project from here

So let's start the project:

Your project structure will look like:



1) Create a Maven project and keep the name RestService

Open pom.xml and copy the dependency:

<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>RestService</groupId>
  <artifactId>RestService</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <properties>
    <java-version>1.8</java-version>
    <org.springframework-version>4.2.5.RELEASE</org.springframework-version>
    <org.aspectj-version>1.6.10</org.aspectj-version>
    <org.slf4j-version>1.6.6</org.slf4j-version>
    <failOnMissingWebXml>false</failOnMissingWebXml>
  </properties>
  
  <dependencies>
    <!-- Spring -->
    <dependency>

      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${org.springframework-version}</version>
      <exclusions>
        <!-- Exclude Commons Logging in favor of SLF4j -->
        <exclusion>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
    <dependency>

      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>4.1.4.Final</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>4.1.0.Final</version>
    </dependency>
   
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${org.springframework-version}</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>${org.springframework-version}</version>
    </dependency> 

    <!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
      <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>   
    
    <!-- Logging -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>${org.slf4j-version}</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jcl-over-slf4j</artifactId>
      <version>${org.slf4j-version}</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>${org.slf4j-version}</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.15</version>
      <exclusions>
        <exclusion>
          <groupId>javax.mail</groupId>
          <artifactId>mail</artifactId>
        </exclusion>
        <exclusion>
          <groupId>javax.jms</groupId>
          <artifactId>jms</artifactId>
        </exclusion>
        <exclusion>
          <groupId>com.sun.jdmk</groupId>
          <artifactId>jmxtools</artifactId>
        </exclusion>
        <exclusion>
          <groupId>com.sun.jmx</groupId>
          <artifactId>jmxri</artifactId>
        </exclusion>
      </exclusions>
      <scope>runtime</scope>
    </dependency>

    <!-- @Inject -->
    <dependency>
      <groupId>javax.inject</groupId>
      <artifactId>javax.inject</artifactId>
      <version>1</version>
    </dependency>

    <!-- Servlet -->
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>2.2.2</version>
    </dependency>
    <!-- Servlet API, JSTL -->

    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
  
  <dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-core</artifactId>
   <version>2.6.5</version>
  </dependency>
  <dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.6.5</version>
  </dependency>
  
  <dependency>
   <groupId>org.codehaus.jackson</groupId>
   <artifactId>jackson-core-asl</artifactId>
   <version>1.9.13</version>
  </dependency>


    <dependency>
      <groupId>org.codehaus.jackson</groupId>
      <artifactId>jackson-mapper-asl</artifactId>
      <version>1.9.13</version>
    </dependency>
   

    
  

  </dependencies>
  <build>
    <finalName>RestApi</finalName>
  </build>
</project>       

Create an entity called Employee and paste the below code:

package com.test.domain;

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

@Entity
@Table(name="Employee")
public class Employee {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 @Column(name="id")
 private Integer id;
 
 @Column(name="firstName")
 private String firstName;
 
 @Column(name="lastName")
 private String lastName;
 public Integer getId() {
  return id;
 }
 public String getFirstName() {
  return firstName;
 }
 public String getLastName() {
  return lastName;
 }
 public void setId(Integer id) {
  this.id = id;
 }
 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }
 public void setLastName(String lastName) {
  this.lastName = lastName;
 }
 
 
}     

Create a controller with name EmployeeController and paste the below code:

package com.test.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.test.model.EmployeeModel;
import com.test.service.EmployeeService;


@RestController
public class EmployeeController {
 
 @Autowired
 EmployeeService employeeService;

 /**
  * This method is used to list employees.
  * @return List of employees
  */
 @RequestMapping(value = "/employees", method = RequestMethod.GET)
 public ResponseEntity<List<EmployeeModel>> listEmployees(){
  List<EmployeeModel> employeeModel =  employeeService.listEmployees();
  if(employeeModel!=null){
   return new ResponseEntity<List<EmployeeModel>>(employeeModel,HttpStatus.OK); 
  }
  return new ResponseEntity<List<EmployeeModel>>(HttpStatus.NOT_FOUND);
  
 }
 
 /**
  * This method is used to get the employees based on the employee id
  * @param empId
  * @return Employee details
  */
 @RequestMapping(value = "/employees/{empId}", method = RequestMethod.GET)
 public ResponseEntity<EmployeeModel> getEmployee(@PathVariable("empId")Integer empId){
  EmployeeModel employeeModel =  employeeService.getEmployee(empId);
  if(employeeModel!=null){
   return new ResponseEntity<EmployeeModel>(employeeModel,HttpStatus.OK);
  }
  return new ResponseEntity<EmployeeModel>(HttpStatus.NOT_FOUND);
 }
 
 /**
  * This method is used to add an employee.
  * @param employee object
  * @return employee
  */
 @RequestMapping(value = "/employees", method = RequestMethod.POST)
 public ResponseEntity<EmployeeModel> addEmployee(@RequestBody EmployeeModel employeeModel){
  employeeModel =  employeeService.addEmployee(employeeModel);
  return new ResponseEntity<EmployeeModel>(employeeModel,HttpStatus.CREATED);
 }
 
 /**
  * This method is used to update employee
  * @param employee id 
  * @param employee object
  * @return employee
  */
 @RequestMapping(value = "/employees/{empId}", method = RequestMethod.PUT)
 public ResponseEntity<EmployeeModel> updateEmployee(@PathVariable("empId")Integer empId,@RequestBody EmployeeModel employeeModel){
  employeeModel.setId(empId);
  EmployeeModel updatedEmployeeModel =  employeeService.updateEmployee(employeeModel);
  return new ResponseEntity<EmployeeModel>(updatedEmployeeModel,HttpStatus.OK);
 }
 
 /**
  * This method is used to delete employee
  * @param emloyee id
  * @return
  */
 @RequestMapping(value = "/employees/{empId}", method = RequestMethod.DELETE)
 public ResponseEntity<Void> deleteEmployees(@PathVariable("empId")Integer empId){
  EmployeeModel employeeModel = employeeService.getEmployee(empId);
  if(employeeModel!=null){
   employeeService.deleteEmployee(employeeModel);
   return new ResponseEntity<Void>(HttpStatus.OK);
  }
  return new ResponseEntity<Void>(HttpStatus.NOT_FOUND);  
  
 }
}

Create a interface EmployeeService.java and add the below code.

package com.test.service;

import java.util.List;

import com.test.model.EmployeeModel;

public interface EmployeeService {

 public EmployeeModel getEmployee(Integer empId);
 public List<EmployeeModel> listEmployees();
 public EmployeeModel addEmployee(EmployeeModel employeeModel);
 public void deleteEmployee(EmployeeModel employeeModel);
 public EmployeeModel updateEmployee(EmployeeModel employeeModel);
}       

Create a class EmployeeServiceImpl.java and add the below code. This will implement the EmployeeService class.

package com.test.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.test.converter.EmployeeConverter;
import com.test.domain.Employee;
import com.test.model.EmployeeModel;
import com.test.repository.EmployeeRepository;

@Service
public class EmployeeServiceImpl implements EmployeeService {

 @Autowired
 private EmployeeRepository empRepository;
 
 
 @Override
 public EmployeeModel getEmployee(Integer empId) {
  return EmployeeConverter.convertToModel(empRepository.getEmployee(empId));
 }

 @Override
 public List<EmployeeModel> listEmployees() {
  List<Employee> listEmployee = empRepository.listEmployees();
  List<EmployeeModel> employeeModel = new ArrayList<EmployeeModel>();
  for(Employee employee : listEmployee){
   employeeModel.add(EmployeeConverter.convertToModel(employee));
   
  }
  return employeeModel;
 }

 @Override
 public EmployeeModel addEmployee(EmployeeModel employeeModel) {
  return EmployeeConverter.convertToModel(empRepository.addEmployee(EmployeeConverter.convertToDomain(employeeModel)));
 }

 @Override
 public void deleteEmployee(EmployeeModel employeeModel) {
  empRepository.deleteEmployee(EmployeeConverter.convertToDomain(employeeModel));
  
 }

 @Override
 public EmployeeModel updateEmployee(EmployeeModel employeeModel) {
  return EmployeeConverter.convertToModel(empRepository.updateEmployee(EmployeeConverter.convertToDomain(employeeModel)));
 }

 

}



Create a interface EmployeeRepository.java and add the below code:

package com.test.repository;

import java.util.List;

import com.test.domain.Employee;


public interface EmployeeRepository  {
 public Employee getEmployee(Integer empId);
 public List<Employee> listEmployees();
 public Employee addEmployee(Employee employeeDomain);
 public void deleteEmployee(Employee employeeDomain);
 public Employee updateEmployee(Employee employeeDomain);

}


Create a class EmployeeRepositoryImpl.java and add the below code. This class will implement the EmployeeRepository.java interface.

package com.test.repository;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.test.domain.Employee;

@Repository
@Transactional
public class EmployeeRepositoryImpl implements EmployeeRepository {

 @Autowired
 private SessionFactory sessionFactory;

 public void setSessionFactory(SessionFactory sf) {
  this.sessionFactory = sf;
 }
 
 

 @Override
 public Employee getEmployee(Integer empId) {
  Session session = this.sessionFactory.getCurrentSession(); 
  Employee employee = (Employee) session.get(Employee.class, empId);
  return employee;
 }

 @SuppressWarnings("unchecked")
 @Override
 public List<Employee> listEmployees() {
  Session session = this.sessionFactory.getCurrentSession();   
  List<Employee> employeeList =  session.createQuery("from Employee").list();
  return employeeList;
 }

 @Override
 public Employee addEmployee(Employee employeeDomain) {
  Session session = this.sessionFactory.getCurrentSession();
  session.save(employeeDomain);
  return employeeDomain;
 }

 @Override
 public void deleteEmployee(Employee employeeDomain) {
  Session session = this.sessionFactory.getCurrentSession(); 
  session.delete(employeeDomain);
  
 }

 @Override
 public Employee updateEmployee(Employee employeeDomain) {
  Session session = this.sessionFactory.getCurrentSession();
  Employee employee =  (Employee) session.merge(employeeDomain);
  return employee;
 }

}


In this use case, we have used java based configuration for hibernate ad spring. Create a HibernateConfiguration.java and paste the below code:

package com.test.configuration;

import java.beans.PropertyVetoException;
import java.util.Properties;

import javax.sql.DataSource;

import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;


@Configuration
@EnableTransactionManagement
@ComponentScan({ "com.test.configuration" })
@PropertySource(value = { "classpath:application.properties" })
public class HibernateConfiguration {
 @Autowired
    private Environment environment;
 
 private static final Logger logger = LoggerFactory.getLogger(HibernateConfiguration.class);
    @Bean
    public LocalSessionFactoryBean sessionFactory() throws PropertyVetoException {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan(new String[] { "com.test.domain" });
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
     }
     
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
        dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
        dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
        dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
  
        return dataSource;
    }
    
    
    private Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
        properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
        properties.put("connection.autoReconnect",  environment.getRequiredProperty("connection.autoReconnect"));
        properties.put("connection.autoReconnectForPools", environment.getRequiredProperty("connection.autoReconnectForPools"));
        properties.put("connection.is-connection-validation-required", environment.getRequiredProperty("connection.is-connection-validation-required")); 
        return properties;        
    }
    
    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory s) {
       HibernateTransactionManager txManager = new HibernateTransactionManager();
       txManager.setSessionFactory(s);
       return txManager;
    }
}  

We are not gonna to paste all these classes here as rest of the classes are in the project. So download the project and import the same on eclipse.

Create a war and deploy the same on the tomcat server.

Let's test the APIs

1) Add an Employee: POST verb is used to add an employee.
URL: http://localhost:8081/RestApi/employees




2) Update an Employee: PUT verb is used to update an employee.
URL: http://localhost:8081/RestApi/employees/{employeeId}


3) Get an Employee: GET verb is used to get an employee.
URL: http://localhost:8081/RestApi/employees/{employeeId}



4)  List Employees: GET verb is used to list employees.
URL: http://localhost:8081/RestApi/employees



5)  Delete an Employees: DELETE verb is used to delete an employee.
URL: http://localhost:8081/RestApi/employees{employeeId}




In the next blog, you will see the how to implement OAuth2 for the REST APIs.

No comments:

Post a Comment