Simple REST Web Service – Spring

The Service :
Create a project with Maven for Eclipse Dynamic Web Project from here.

Here I have used Spring Annotation up to my knowledge. I believe there are more things which can be annotated.

The Deployment Descriptor (web.xml) is the simplest

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5" id="WebApp_1291891438549">

  	<display-name>Spring REST Example1</display-name>
  	<servlet>
		<servlet-name>person</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>person</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
	
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

So we must have the person-servlet.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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:oxm="http://www.springframework.org/schema/oxm"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">

	<context:component-scan base-package="com.dyuti.spring.rest" />

	<!-- Format Output -->
	<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
	<bean id="personXmlView"
		class="org.springframework.web.servlet.view.xml.MarshallingView">
		<constructor-arg>
			<bean class="org.springframework.oxm.xstream.XStreamMarshaller">
				<property name="autodetectAnnotations" value="true" />
			</bean>
		</constructor-arg>
	</bean>
	<!--          -->

	<!-- Convert Input -->
	<bean
		class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
	<bean
		class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
		<property name="messageConverters">
			<list>
				<ref bean="marshallingHttpMessageConverter" />
			</list>
		</property>
	</bean>

	<bean id="marshallingHttpMessageConverter"
		class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
		<property name="marshaller" ref="jaxb2Marshaller" />
		<property name="unmarshaller" ref="jaxb2Marshaller" />
	</bean>

	<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
		<property name="classesToBeBound">
			<list>
				<value>com.dyuti.spring.rest.domain.Person</value>
			</list>
		</property>
	</bean>
	<!--          -->

	<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost/person" />
		<property name="username" value="root" />
		<property name="password" value="*****" />
	</bean>

	<bean id="mySessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="dataSource" ref="myDataSource" />
		<property name="annotatedClasses">
			<list>
				<value>com.dyuti.spring.rest.domain.Person</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<value>hibernate.dialect=org.hibernate.dialect.MySQLDialect</value>
		</property>
	</bean>

	<bean id="personDao" class="com.dyuti.spring.rest.dao.PersonDaoHibImpl">
		<property name="sessionFactory" ref="mySessionFactory" />
	</bean>
</beans>

We use org.springframework.oxm.xstream.XStreamMarshaller for converting Java Object to XML for sending through HTTP, and also converting HTTP XML data to corresponding Java Object.

The simple Person objec

package com.dyuti.spring.rest.domain;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;

import com.thoughtworks.xstream.annotations.XStreamAlias;

@XmlRootElement
@XStreamAlias("person")
@Entity
@Table(name = "person")
public class Person implements Serializable {

	private static final long serialVersionUID = 2675617253130859687L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int id;
	@Column
	private String name;
	@Column
	private int age;

	// Generate getter & setter here
}

Now the DAO and the Hibernate Implementation

package com.dyuti.spring.rest.dao;

import com.dyuti.spring.rest.domain.Person;

public interface PersonDao {
	
	public boolean save(Person person);
	
	public Person get(int id);
}
package com.dyuti.spring.rest.dao;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import com.dyuti.spring.rest.domain.Person;

@Repository("personDao")
public class PersonDaoHibImpl extends HibernateDaoSupport implements PersonDao {

	@Override
	public boolean save(Person person) {
		int id = (Integer) getHibernateTemplate().save(person);
		return id > 0 ? true : false;
	}

	@Override
	public Person get(int id) {
		return (Person) getHibernateTemplate().get(Person.class, id);
	}
}

And the service and its implementation

package com.dyuti.spring.rest.service;

import com.dyuti.spring.rest.domain.Person;

public interface PersonService {

	public boolean savePerson(Person p);
	
	public Person getPerson(int id);
}
package com.dyuti.spring.rest.service;

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

import com.dyuti.spring.rest.dao.PersonDao;
import com.dyuti.spring.rest.domain.Person;

@Service("personService")
public class PersonServiceImpl implements PersonService {

	@Autowired
	private PersonDao personDao;

	@Override
	public boolean savePerson(Person person) {
		return personDao.save(person);
	}

	@Override
	public Person getPerson(int id) {
		return personDao.get(id);
	}
}

The controller is the entry point and also the provider of the web service.

package com.dyuti.spring.rest.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
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.servlet.ModelAndView;

import com.dyuti.spring.rest.domain.Person;
import com.dyuti.spring.rest.service.PersonService;

@Controller
public class PersonController {

	@Autowired
	private PersonService personService;

	@RequestMapping(value = "/{id}", method = RequestMethod.GET)
	public ModelAndView getPerson(@PathVariable int id) {
		Person person = personService.getPerson(id);
		return new ModelAndView("personXmlView", BindingResult.MODEL_KEY_PREFIX
				+ "person", person);
	}

	@RequestMapping(value = "/add", method = RequestMethod.POST)
	public ModelAndView addPerson(@RequestBody Person person) {
		boolean result = personService.savePerson(person);
		return new ModelAndView("personXmlView", BindingResult.MODEL_KEY_PREFIX
				+ "person", result);
	}
}

Finally the 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>com.dyuti.spring.rest</groupId>
	<artifactId>SpringREST</artifactId>
	<packaging>war</packaging>
	<version>1.0-SNAPSHOT</version>
	<name>SpringREST</name>
	<url>http://maven.apache.org</url>

	<build>
		<finalName>SpringREST</finalName>
		<sourceDirectory>${basedir}/src/main/java</sourceDirectory>

		<resources>
			<resource>
				<directory>${basedir}/src/main/resources</directory>
			</resource>
		</resources>

		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.0.2</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-dependency-plugin</artifactId>
				<executions>
					<execution>
						<id>copy-dependencies</id>
						<phase>package</phase>
						<goals>
							<goal>copy-dependencies</goal>
						</goals>
						<configuration>
							<!-- configure the plugin here -->
						</configuration>
					</execution>
				</executions>
			</plugin>

			<plugin>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.0</version>
				<configuration>
					<webResources>
						<resource>
							<directory>${basedir}/src/main/webapp</directory>
							<filtering>false</filtering>
							<excludes>
								<exclude>WEB-INF/lib/*</exclude>
							</excludes>
						</resource>
					</webResources>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<dependencies>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.4</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>${commons.beanutils.version}</version>
		</dependency>
		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
			<version>${commons.collections.version}</version>
		</dependency>
		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>${commons.lang.version}</version>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>${commons.io.version}</version>
		</dependency>
		<dependency>
			<groupId>commons-digester</groupId>
			<artifactId>commons-digester</artifactId>
			<version>1.6</version>
			<exclusions>
				<exclusion>
					<groupId>xml-apis</groupId>
					<artifactId>xml-apis</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.1</version>
		</dependency>
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.2.1</version>
			<exclusions>
				<exclusion>
					<groupId>xml-apis</groupId>
					<artifactId>xml-apis</artifactId>
				</exclusion>
				<exclusion>
					<groupId>xerces</groupId>
					<artifactId>xerces</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>commons-pool</groupId>
			<artifactId>commons-pool</artifactId>
			<version>1.2</version>
			<exclusions>
				<exclusion>
					<groupId>xml-apis</groupId>
					<artifactId>xml-apis</artifactId>
				</exclusion>
				<exclusion>
					<groupId>xerces</groupId>
					<artifactId>xerces</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate</artifactId>
			<version>${hibernate.version}</version>
			<exclusions>
				<exclusion>
					<artifactId>ehcache</artifactId>
					<groupId>net.sf.ehcache</groupId>
				</exclusion>
				<exclusion>
					<artifactId>commons-collections</artifactId>
					<groupId>commons-collections</groupId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-annotations</artifactId>
			<version>${hibernate.annotations.version}</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-commons-annotations</artifactId>
			<version>${hibernate.annotations.version}</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.8</version>
		</dependency>

		<dependency>
			<groupId>org.apache.openejb</groupId>
			<artifactId>commons-dbcp-all</artifactId>
			<version>1.3</version>
		</dependency>

		<dependency>
			<groupId>javax.persistence</groupId>
			<artifactId>persistence-api</artifactId>
			<version>${jpa.version}</version>
		</dependency>

		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.0.0.GA</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-oxm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		

		<dependency>
			<groupId>com.thoughtworks.xstream</groupId>
			<artifactId>xstream</artifactId>
			<version>1.3.1</version>
		</dependency>

		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<properties>
		<spring.version>3.0.0.RELEASE</spring.version>
		<java.version>1.6</java.version>
		<servlet-api.version>2.5.0</servlet-api.version>
		<hibernate.annotations.version>3.3.0.ga</hibernate.annotations.version>
		<hibernate.version>3.2.6.ga</hibernate.version>
		<jpa.version>1.0</jpa.version>
		<commons.beanutils.version>1.7.0</commons.beanutils.version>
		<commons.collections.version>3.2</commons.collections.version>
		<commons.io.version>1.3.2</commons.io.version>
		<commons.lang.version>2.3</commons.lang.version>
	</properties>
</project>

So, the project is set up and deploy it on Tomcat.

The client :
The RestClient provided by Spring makes life very simple creating REST consumer.
Create another project (not necessary a web project, client can be anything, even if Ajax).

Create the same Person object from above.
Lets create the Spring context file, resides in the same package of the loader class under resource folder.

<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:oxm="http://www.springframework.org/schema/oxm"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
				http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
				http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">

	<context:component-scan base-package="com.dyuti.spring.rest" />

	<bean id="personSave" class="com.dyuti.spring.rest.controller.SavePerson">
		<property name="restTemplate">
			<ref bean="restTemplate" />
		</property>
	</bean>
	<bean id="restTemplate" class="org.springframework.web.client.RestTemplate"></bean>
</beans>

And the client class

package com.dyuti.spring.rest.controller;

import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.dyuti.spring.rest.domain.Person;

@Component
public class SavePerson {

	private RestTemplate restTemplate;

	private String restURL = "http://localhost:8080/SpringREST/";

	public void sendPerson() {
		Person person = new Person();
		person.setName("client");
		person.setAge(12);
		person.setId(3);

		Person p = restTemplate.getForObject(restURL + "2", Person.class);
		System.out.println(p.getName());

		String result = restTemplate.postForObject(restURL + "add", person,
				String.class);
		System.out.println(result);
	}

	public void setRestTemplate(RestTemplate restTemplate) {
		this.restTemplate = restTemplate;
	}
}

Run the client

package com.dyuti.spring.rest.controller;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class RunRest {

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
				"applicationContext.xml", RunRest.class);
		SavePerson savePerson = applicationContext.getBean("personSave",
				SavePerson.class);
		savePerson.sendPerson();
	}
}

I have used the same pom.xml for this project, which may require less packages.

Advertisements

14 Responses to Simple REST Web Service – Spring

  1. Ronak says:

    I have implemented the same way similar example, in which i am passing value List instead of Person in POST, but i am getting error like >> resulted in 415 (Unsupported Media Type); invoking error handler

    can you please helpout or point me to right direction like how can i pass List from client side and same I want to receive on WS server side.

    Thanks for your help in advance !!!

    • dyutiman says:

      I think what you can do is wrap the list in a object and then pass it. So the list will be a property of an object.
      try it and let me know if it works.

  2. Sanjay says:

    How can I configure the RESTful with 3 containers in one war to receive totally different url or context names like when consuming the web services.
    For example I have 3 containers which server totally business domain like CustomerService, Reservations etc. I want to have http://localhost:8080/customerservice and another http://localhost:8080/reservationservice.

    Any help is greatly appreciated.

  3. Deepak Kotla says:

    Hi..this article is best starting point to implement restful webservices using springframework.. I have implement one similar to this but not able to do the logging from the client. I want to log request xml sent to server and response xml received from server … If you can suggest the configuration it will be great helpful and by the way I am using org.apache.log4j.Logger for logging in the application and set the following properties in log4j.properties log4j.logger.httpclient.wire=DEBUG and log4j.logger.org.springframework.http=DEBUG but not seeing any thing in the logs…. Thanks in Advance.

    • dyutiman says:

      Hi Deepak,
      sorry for late reply, but to solve ur issue… i think u can try to configure a filter before the request comes to spring dispatcher servlet. in the filter i think u will get the raw data transferred via http.

      Other way is to listen to the http port and log everything which passes thru it, but then it will be outside ur app.

  4. Also, you might want to revise your POM to set the Spring Namespaces to 3.0 and update the Spring Version to 3.0.5.

    Regards,
    Gordon Dickens
    Twitter: http://twitter.com/gdickens
    Blog: http://technophile.gordondickens.com

  5. By using the url path “add” is not very RESTful. You are providing the server with a verb. The verbs are the ones provided by HTTP: GET, POST, PUT & DELETE.

    By using POST, you are, by common REST thinking, instructing the server to add the resource.

    Also, your URL should direct the server to a noun (in this example “person”.

    Your URLs should be:
    Retrieve a person: GET http://localhost:8080/SpringREST/person/{id}
    Save a new person: POST http://localhost:8080/SpringREST/person
    Update an existing person: PUT http://localhost:8080/SpringREST/person/{id}
    Delete a person: DELETE http://localhost:8080/SpringREST/person/{id}

    On the note of Web Browsers, they do not support PUT or DELETE so in Spring 3. You need to configure in HiddenHttpMethodFilter and on the pages your form with POST but you will pass in the form a hidden field with the value of PUT or DELETE.

    • Oops, forgot to include he hidden field

      <input type=”hidden” name=”_method” value=”PUT”/>

      If you are using Spring tag <form:form> the hidden field will be added for you automatically.

      • dyutiman says:

        Hi Gordon,
        very useful help. thanks for that. and what u mentioned makes perfect sense.
        This is the very first time I did something on Spring about WS. ‘ll keep ur suggestion in mind from next time.

        thanks and hope u ‘ll keep putting ur expert comments…

  6. swarne says:

    please explain a little bit more in steps and how to run and see an output etc..

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: