Enterprise Java

Spring 3 RESTful Web Services

Spring 3 provides support for RESTful Web services. In this tutorial we will show you how to implement a RESTful Web service in Spring or, if you want, to expose an existing Spring service as a RESTful Web service. To make things more interesting we are going to continue from where we left of at our previous article about Spring GWT Hibernate JPA Infinispan HornetQ integration. We are going to use our GWTSpringInfinispanHornetQ project and expose our “employeeService” CRUD functionality as a RESTful Web service. Of course you can follow this article just to be informed on how to expose your Spring services as RESTful Web services.

The most popular approach for implementing RESTful Web services is Sun’s JAX-RS specification. There are several projects available that support JAX-RS such as CXF, Jersey, RESTEasy and Restlet. Most of them provide Spring support also. Spring does not directly support JAX-RS, instead RESTful functionality is added to feature Spring MVC itself. If you are not familiar with Spring MVC framework please consult the appropriate chapter of Spring documentation here. For the impatient a brief overview follows.

Spring MVC stands for Model View Controller. It helps in building flexible and loosely coupled web applications. The Model – View – Controller design pattern insures separation of concerns (business logic, presentation logic and navigation logic) in a multi-tier web application. “Controllers” are responsible for receiving the request from the user and calling the back – end services. Models are responsible for encapsulating the application data. Views render response back to the user with using the model object. In short :

When a request is sent to the Spring MVC Framework the following sequence of events happen.

  • The “DispatcherServlet” first receives the request
  • The “DispatcherServlet” consults the “HandlerMapping” and invokes the “Controller” associated with the request
  • The “Controller” process the request by calling the appropriate service methods and returns a “ModeAndView” object to the “DispatcherServlet”. The “ModeAndView” object contains the model data and the view name
  • The “DispatcherServlet” sends the view name to a “ViewResolver” to find the actual “View” to invoke
  • The “DispatcherServlet” passes the model object to the “View” to render the result
  • The “View” with the help of the model data renders the result and return it back to the user

Enough talk! Lets get our hands dirty!

We will need the “cglib” bytecode generation library and “asm” bytecode manipulation framework in order for Spring to properly apply AOP aspects to “Controller” objects. We will use “cglib” version 2.2 that you can download from here and “asm” binary distribution that you can download from here. Locate asm-all-3.3.jar under /lib/all folder of the “asm” binary distribution and place both asm-all-3.3.jar and cglib-2.2.jar under /war/WEB-INF/lib folder of your project.

Finally we will need Jackson JSON processor. We will use version 1.5.3 of the “core” and “mapper” distributions that you can download from here. Place both jackson-core-asl-1.5.3.jar
and jackson-mapper-asl-1.5.3.jar under /war/WEB-INF/lib folder of your project.

We have to take care of dependences for our Eclipse project. The following jars should be included in the Java build path of the project :

  • org.springframework.web-3.0.1.RELEASE-A.jar

As stated above the “DispatcherServlet” is a single servlet that manages the entire request – handling process. Like any other servlet it needs to be configured in the web deployment descriptor or our application. Locate the “web.xml” file under /war/WEB-INF folder and add the following :

<servlet>
 <servlet-name>dispatcher</servlet-name>
 <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class>
 <load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
 <servlet-name>dispatcher</servlet-name>
 <url-pattern>/restServices/*</url-pattern>
</servlet-mapping>

By default the “DispatcherServlet” will look for a file named as “{servlet-name}–servlet.xml” to load the Spring MVC configuration. In our case “dispatcher-servlet.xml”. Here we use the url – pattern as “/restServices/*” in order for the “DispatcherServlet” to handle all incoming requests under the designated pattern only. Create a “dispatcher–servlet.xml” file and place it under /war/WEB-INF folder as shown below :

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

<context:component-scan base-package="com.javacodegeeks.gwtspring.server.endpoints" />

<tx:annotation-driven />

<mvc:annotation-driven />

</beans>

Things to notice here :

  • We set the base-package attribute of the “context:component-scan” configuration element to where our Spring MVC annotated classes will reside
  • We use the “tx:annotation-driven” configuration element in order to be able to inject transactional behavior to our MVC classes
  • The “mvc:annotation-driven” is a Spring 3 configuration element that greatly simplifies Spring MVC setup. This tag registers the “HandlerMapping” and “HandlerAdapter” required to dispatch requests to your @Controller annotated classes. In addition, it applies sensible defaults based on what is present in your classpath. Such defaults include (among others) :
    • Support for formatting Number fields with @NumberFormat annotation
    • Support for formatting Date, Calendar, and Joda Time fields with @DateTimeFormat annotation, if Joda Time is on the classpath
    • Support for validating @Controller annotated class inputs with @Valid annotation, if a JSR-303 Provider is on the classpath
    • Support for reading and writing XML, if JAXB is on the classpath
    • Support for reading and writing JSON, if Jackson is on the classpath

Create an “endpoints” subpackage under the “server” package of your project. As far as GWT is concerned service endpoints are server side components so all classes must be placed under the “server” package. Under “endpoints” subpackage place the “EmployeeServiceController” class as shown below :

package com.javacodegeeks.gwtspring.server.endpoints;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.javacodegeeks.gwtspring.shared.dto.EmployeeDTO;
import com.javacodegeeks.gwtspring.shared.services.EmployeeService;

@Controller
@RequestMapping("/employeeService")
public class EmployeeServiceController {

 @Autowired
 EmployeeService employeeService;

 @RequestMapping(value = "/{id}", method = RequestMethod.GET)
 @ResponseBody
 public EmployeeDTO findEmployee(@PathVariable("id") long employeeId) {
  return employeeService.findEmployee(employeeId);
 }

 @RequestMapping(value = "/{id}/{name}/{surname}/{job}", method = RequestMethod.POST)
 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 public String saveEmployee(@PathVariable("id") long employeeId, @PathVariable String name, @PathVariable String surname, @PathVariable("job") String jobDescription) throws Exception {
  employeeService.saveEmployee(employeeId, name, surname, jobDescription);
  return "redirect:/restServices/employeeService/" + employeeId;
 }

 @RequestMapping(value = "/{id}/{name}/{surname}/{job}", method = RequestMethod.PUT)
 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 public String updateEmployee(@PathVariable("id") long employeeId, @PathVariable String name, @PathVariable String surname,  @PathVariable("job") String jobDescription) throws Exception {
  employeeService.updateEmployee(employeeId, name, surname, jobDescription);
  return "redirect:/restServices/employeeService/" + employeeId;
 }

 @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 @ResponseBody
 public String deleteEmployee(@PathVariable("id") long employeeId) throws Exception {
  employeeService.deleteEmployee(employeeId);
  return "OK";
 }

}

We provide as reference the “EmployeeService” and “EmployeeDTO” implementations :

package com.javacodegeeks.gwtspring.server.services;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.javacodegeeks.gwtspring.server.dao.EmployeeDAO;
import com.javacodegeeks.gwtspring.server.utils.NotificationsProducer;
import com.javacodegeeks.gwtspring.shared.dto.EmployeeDTO;
import com.javacodegeeks.gwtspring.shared.services.EmployeeService;

@Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService {

 @Autowired
 private EmployeeDAO employeeDAO;

 @Autowired
 NotificationsProducer notificationsProducer;

 @PostConstruct
 public void init() throws Exception {
 }

 @PreDestroy
 public void destroy() {
 }

 public EmployeeDTO findEmployee(long employeeId) {
  return employeeDAO.findById(employeeId);
 }

 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 public void saveEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception {

  EmployeeDTO employeeDTO = employeeDAO.findById(employeeId);

  if(employeeDTO == null) {
   employeeDTO = new EmployeeDTO(employeeId, name,surname, jobDescription);
   employeeDAO.persist(employeeDTO);
  }

 }

 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 public void updateEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception {

  EmployeeDTO employeeDTO = employeeDAO.findById(employeeId);

  if(employeeDTO != null) {
   employeeDTO.setEmployeeName(name);
   employeeDTO.setEmployeeSurname(surname);
   employeeDTO.setJob(jobDescription);
  }

}

 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 public void deleteEmployee(long employeeId) throws Exception {

  EmployeeDTO employeeDTO = employeeDAO.findById(employeeId);

  if(employeeDTO != null)
   employeeDAO.remove(employeeDTO);

 }

 @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
 public void saveOrUpdateEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception {

  EmployeeDTO employeeDTO = new EmployeeDTO(employeeId, name,surname, jobDescription);

  employeeDAO.merge(employeeDTO);

  notificationsProducer.sendNotification("Save Or Update Employee with values : \nID : " + employeeId + "\nName : " + name + "\nSurname : " + surname + "\nJob description : " + jobDescription);

 }

}

As you can see the “EmployeeServiceController” acts as a wrapper class for the “employeeService” class. We take a reference of the actual service and implement methods that invoke directly the service functionality. To inject “EmployeeServiceController” class with “Controller” functionality we just have to annotate it as such. The @Controller annotation designates that the annotated class is a “Controller” class available for the “DispatcherServlet” to delegate requests to it.

At the beginning of this tutorial we spoke of how the “DispatcherServlet” uses “HandlerMappings” to select the appropriate “Controllers” so as to delegate user requests. The @RequestMapping annotation is used for mapping Web requests onto specific handler classes and/or handler methods. So by using the @RequestMapping(“/employeeService”) annotation at type level we instruct “DispatcherServlet” to delegate all Web requests under the “/employeeService” resource URI to the “EmployeeServiceController” instance. Furthermore we use the @RequestMapping annotation at method level to narrow “DispatcherServlet” delegation to specific operations based on the requested resource URI. You should have noticed the use of the @PathVariable annotation. In Spring 3 the use of URI templates through the @PathVariable annotation is introduced. A URI template is a URI – like string, containing one or more variable names. When these variables are substituted for values, the template becomes a URI. Thus a client HTTP GET request for the “/employeeService/1” resource URI will be delegated to “findEmployee” operation of our “EmployeeServiceController” instance and the value of “employeeId” parameter will be set to 1.

NOTE: @RequestMapping will only be processed if a corresponding “HandlerMapping” (for type level annotations) and/or “HandlerAdapter” (for method level annotations) is present in the dispatcher. Thanks to Spring 3 MVC simplifications, the use of “mvc:annotation-driven” configuration element in “dispatcher-servlet.xml” handles all of our configuration needs.

At the beginning of this tutorial we spoke of how the “Controller” processes each request by calling the appropriate service methods and returns a “ModeAndView” object to the “DispatcherServlet”. The “ModeAndView” object contains the model data and the view name in order to be properly rendered back to the client. This behavior is not always desirable. In our example for instance we want to serialize service responses right to the HTTP response body. The @ResponseBody annotation can be put on a method and indicates that the return type should be written straight to the HTTP response body (and not placed in a Model, or interpreted as a view name). According to client accepted content type(s) (information derived from the “Accept” HTTP Header field of client request) we will return XML or JSON representations of service replies. For that we use the JAXB marshaller and unmarshaller through Spring OXM module and the Jackson JSON processor.

Lastly, you should notice the “saveEmployee” and “updateEmployee” operations. These two are not @ResponseBody annotated, and return the “redirect:/restServices/employeeService/ + employeeId” String. A “Controller” method can return a “special” String value that issues commands to the “DispatcherServlet”. With the aforementioned redirect command the “DispatcherServlet” will redirect the call to the “Controller” method associated with the specified URI resource (in our case the “findEmployee” operation). Thus when a client issues a “saveEmployee” or “updateEmployee” command will receive as a reply the XML or JSON representation of the “employeeDTO” object just inserted or updated.

Below we present the DTO class.

package com.javacodegeeks.gwtspring.shared.dto;

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

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Cache (usage=CacheConcurrencyStrategy.TRANSACTIONAL)
@Entity
@XmlRootElement
@Table(name = "EMPLOYEE")
public class EmployeeDTO implements java.io.Serializable {

 private static final long serialVersionUID = 7440297955003302414L;

 @Id
 @Column(name="employee_id")
 private long employeeId;

 @Column(name="employee_name", nullable = false, length=30)
 private String employeeName;

 @Column(name="employee_surname", nullable = false, length=30)
 private String employeeSurname;

 @Column(name="job", length=50)
 private String job;

 public EmployeeDTO() {
 }

 public EmployeeDTO(int employeeId) {
  this.employeeId = employeeId;        
 }

 public EmployeeDTO(long employeeId, String employeeName, String employeeSurname,
 String job) {
  this.employeeId = employeeId;
  this.employeeName = employeeName;
  this.employeeSurname = employeeSurname;
  this.job = job;
 }

 public long getEmployeeId() {
  return employeeId;
 }

 public void setEmployeeId(long employeeId) {
  this.employeeId = employeeId;
 }

 public String getEmployeeName() {
  return employeeName;
 }

 public void setEmployeeName(String employeeName) {
  this.employeeName = employeeName;
 }

 public String getEmployeeSurname() {
  return employeeSurname;
 }

 public void setEmployeeSurname(String employeeSurname) {
  this.employeeSurname = employeeSurname;
 }

 public String getJob() {
  return job;
 }

 public void setJob(String job) {
  this.job = job;
 }
}

The only thing to notice here is that we have annotated the DTO class with @XmlRootElement annotation in order to be properly marshaled by JAXB marshaller.

Thats it! To deploy the web application just copy the /war folder in Apache – Tomcat “webapps” folder. You can change the name of the war folder to whatever you like, preferably rename it after the project name e.g. GWTSpringInfinispanHornetQRemoting

Prior lunching the application do not forget to create the database schema, here “javacodegeeks”.

For this example we have used Apache Derby Database version 10.6.1.0. You can download the binary distribution here. Locate derby.jar under /lib directory of the distribution and place it under /war/WEB-INF/lib directory of your project. To configure the embedded database with Spring, add the following configuration code to your applicationContext.xml under /war/WEB-INF directory :

<bean id="dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
 <property name="uniqueResourceName" value="javacodegeeks" />
 <property name="xaDataSourceClassName" value="org.apache.derby.jdbc.EmbeddedXADataSource" />
 <property name="xaProperties">
  <props>
   <prop key="databaseName">javacodegeeks</prop>
   <prop key="createDatabase">create</prop>
  </props>
 </property>
 <property name="maxPoolSize" value="50" />
 <property name="minPoolSize" value="20" />
</bean> 

You can download RESTClient and test the REST interface of your “employeeService” as dictated below :

  • Issue a POST request for “http://localhost:8080/GWTSpringInfinispanHornetQRemoting/restServices/employeeService/1/myName/mySurname/myJob” and you should retrieve an XML representation of the newly created “employeeDTO” as shown below :
<?xml version="1.0" encoding="UTF-8" standalone="yes">
<employeeDTO>
 <employeeId>1</employeeId>
 <employeeName>myName</employeeName>
 <employeeSurname>mySurname</employeeSurname>
 <job>myJob</job>
</employeeDTO>
  • Issue a GET request for http://localhost:8080/GWTSpringInfinispanHornetQRemoting/restServices/employeeService/1 and you will receive the same result with the POST operation
  • Issue a PUT request and update any field you like from the “employeeDTO” object. The service will reply with the updated “employeeDTO” XML representation
  • Issue a DELETE request for http://localhost:8080/GWTSpringInfinispanHornetQRemoting/restServices/employeeService/1 and you should receive the “OK” reply!
  • Issue the above commands after adding a HTTP header directive to define the accepted content type to “application/json”. The returned “employeeDTO” representation should be as shown below :
{"employeeId":1,"employeeName":"myName","employeeSurname":"mySurname","job":"myJob"}

You can download the project from here (required 3rd party libraries as described at the beginning and previous articles are not included)

Have fun!

Justin

Related Articles :

Byron Kiourtzoglou

Byron is a master software engineer working in the IT and Telecom domains. He is an applications developer in a wide variety of applications/services. He is currently acting as the team leader and technical architect for a proprietary service creation and integration platform for both the IT and Telecom industries in addition to a in-house big data real-time analytics solution. He is always fascinated by SOA, middleware services and mobile development. Byron is co-founder and Executive Editor at Java Code Geeks.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

7 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
khalid moin
khalid moin
12 years ago

awesome…. very descriptive… 

devendra katiyar
devendra katiyar
12 years ago

I also build the same application when trying to run http://localhost:8080/springrestws/restServices/employeeService/1
getting the below error .
WARNING: No mapping found for HTTP request with URI [/springrestws/restServices/employeeService/1] in DispatcherServlet with name ‘dispatcher’

Bala
Bala
11 years ago

This is simply superb article. This was very helpful for me.
Thanks a lot.

Sudha
Sudha
11 years ago

This was very helpful to me.
Thank You so much.

Sanjukta Parida
Sanjukta Parida
10 years ago

I want to know the REST URL for delete operation

Ankit Patel
Ankit Patel
9 years ago

Thanks for your post.

I am clear with all these thing, but what if i want to create a wrapper api to access this web service. can it be possible?

Please reply me as soon as possible.

Shweta
Shweta
9 years ago

where are the EmployeeService interface here?

Back to top button