Spring Data Rest Example
In the previous few examples we demonstrated how the different spring data modules are configured and their support for the NoSql
databases. In this example, I will demonstrate how we can expose our CRUD Repository
as a REST Web-Service over the HTTP.
We will be using MySQL as the database for this project . However, the application which we shall build here will be largely independent of the underlying Database technology used. This is because of the abstraction layer added by the Spring Data Module.
So let’s get started with the project setup:
We will create a new Maven project with archetype as maven-archetype-webapp
. Update the pom.xml
with the below file :
pom.xml
<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>SpringDataRestExample1</groupId> <artifactId>SpringDataRestExample1</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>SpringDataRestExample</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>1.9.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-rest-webmvc</artifactId> <version>2.3.2.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.36</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>4.3.6.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.3.6.Final</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-eclipse-plugin</artifactId> <version>3.3</version> <configuration> <downloadSources>true</downloadSources> <downloadJavadocs>true</downloadJavadocs> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> <finalName>SpringDataRestExample</finalName> </build> </project>
This will add the required dependencies for the archives we will need for setting up this project. Let’s start with the implementation now.
We start by creating the entities that will be persisted to the MySql
server.
Person.java
package com.jcg.examples.entity; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity(name="person") public class Person implements Serializable { private static final long serialVersionUID = -5378396373373165919L; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long pId; @Column private String personName; @Column private double personAge; public Long getpId() { return pId; } public void setpId(Long pId) { this.pId = pId; } public String getPersonName() { return personName; } public void setPersonName(String personName) { this.personName = personName; } public double getPersonAge() { return personAge; } public void setPersonAge(double personAge) { this.personAge = personAge; } @Override public String toString() { return "Person [pId=" + pId + ", personName=" + personName + ", personAge=" + personAge + "]"; } }
We are using annotations to map the entity properties to the database table columns. Here is a brief description of the annotations we have used for mapping:
@Id
is used to mark the primary key of the entity. @Column
is used to map the properties of the entity to those of the table columns. In case, the name of the column happens to be different from the name of the property we can use the name
attribute of the @Column
annotation and pass the name of the table column.
Next we create a repository to persist the entity defined above to the database.
PersonRepo.java
package com.jcg.examples.repo; import java.util.List; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import org.springframework.data.rest.core.annotation.RepositoryRestResource; import org.springframework.data.rest.core.annotation.RestResource; import com.jcg.examples.entity.Person; @RepositoryRestResource public interface PersonRepo extends CrudRepository<Person, Long> { @RestResource(path="byName") public List findByPersonName(@Param("name") String personName); }
Spring Data Module provides us with a number of inbuilt method for manipulating the Data. We need not write the queries for basic data manipulation and reading. It is achieved by extending the CrudRepository
interface and declaring the proper Generics as per the Entity, which in our case is the <Person, Long>.
Also, we have a created a custom a method that searches based on the name
property of the Person
.
Now, we have annotated the repository with the @RepositoryRestResource
annotation. This marks the resource to be exported as a REST
resource which is available over the HTTP
. We may also choose to hide some methods by adding the annotation : @RestResource(exported = false)
. The same annotation can be used to annotate an entity property so that it is not transmitted over the network.
Now we create the spring-config.xml
and place it in the WEB-INF
folder. This file contains the configuration of the database and other required beans. Line 13 causes the spring container to scan the repo package for the classes annotated with the @RepositoryRestResource
to be exported.We can also use the path attribute of the @RestResource
to modify the path of the method.
spring-config.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="com.jcg.examples.repo" /> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost/test"/> <property name="username" value="root"/> <property name="password" value="toor"/> </bean> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="true"/> <property name="generateDdl" value="true"/> <property name="database" value="MYSQL"/> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/> <property name="packagesToScan" value="com.jcg.examples.entity"/> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"/> <jpa:repositories base-package="com.jcg.examples.repo" /> </beans>
Next is the most important web.xml
. We configure the ContextLoaderListener
to load the spring-config.xml
file and bind the Applicationcontext
lifecycle to that of the ServletContext
.This initializes the beans we have defined in the xml
The RepositoryRestDispatcherServlet
is used to expose the REST Resources over the network. The non-zero value of load-on-startup
marks the servlet to be eagerly loaded during the web-container initialization.
web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>Archetype Created Web Application</display-name> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring-config.xml</param-value> </context-param> <servlet> <servlet-name>rest</servlet-name> <servlet-class>org.springframework.data.rest.webmvc.RepositoryRestDispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>rest</servlet-name> <url-pattern>/api/*</url-pattern> </servlet-mapping> </web-app>
Deploy the above application to the Web-Server/Application Server you have configured and the REST service is ready to be consumed.
Here is the sample output when different HTTP methods are used. For the sake of this project I have used curl
, a command line tool, to test our REST Web-Service.
Command executed for GET
:
curl http://localhost:8080/SpringDataRestExample/api/persons
Command executed for POST
:
curl -i -X POST -H "Content-Type:application/json" -d "{ \"personName\" : \"Krishna\" , \"personAge\" : \"120\" }" http://localhost:8080/SpringDataRestExample/api/persons
In the windows console, single quote is not recognized as such we are forced to use the double quotes and escape sequence for passing the values.
Command executed for Search
:
curl http://localhost:8080/SpringDataRestExample/api/persons/search/byName?name=Krishna
We search using the query method findByPersonName
we wrote in PersonRepo
class. Had we not changed the path
of the method, it would be accessed using the actual method name.
Command executed for Delete
:
curl -X DELETE http://localhost:8080/SpringDataRestExample/api/persons/3
As you can see, this command deletes an entity with the id = 3.
Download the Source Code
Thus we demonstrated how the Spring Data REST repository is configured and we can use it for CRUD operation. However, the reader should note that this style of architecture is more suited for smaller to medium scale applications. In large scale applications omitting the service layer, altogether, may not be advisable.
You can download the source code of this example here: SpringDataRestExample.zip
I want to return pId also with personAge and personName in same object, But not like http://localhost:8080/SpringDataRestExample/api/persons/3. How to do that