Wednesday, February 8, 2012

Spring 3.0 Restful Web Services


A simplified explanation of REST

Imagine you are surfing the net and come to a web page of a nice car (a resource). The page is identified by a URL and the content is a HTML document (a representation of the car). Inside the web page, it contains other resources (e.g. tyres), which are also identified by another set URLs. When you follow one of the links and traverse to another resource, you are transferring the state to the representation of another resource.

This sequence of operations is well captured by Roy’s explanation in his dissertation - "The name "Representational State Transfer" is intended to evoke an image of how a well-designed Web application behaves: a network of web pages (a virtual state-machine), where the user progresses through the application by selecting links (state transitions), resulting in the next page (representing the next state of the application) being transferred to the user and rendered for their use."

In REST, everything is identified by a URI, and the response is a representation of the resource. It can be a HTML document, an image, or an XML document. REST is just a style of how a state changes. It is not a standard.


RESTful Web Services

REST was initially described in the context of HTTP and HTML, but it is not limited to that protocol. It has been widely adopted in the web services interfaces to become RESTful Web Services.

RESTful Web Services API is built on top of the simple HTTP request and response protocol and use the REST style for the representation state transfer. It basically uses the following HTTP methods to mimic the CRUD operations, and the payload is usually in XML or JSON.

The Provider

Our application is a simple CRUD system for managing a list of persons. We'll start our project with the provider service which produces XML and JSON representations of our data.

1. Domain Layer

A Pojo, annotated with JAXB annotation, so that it can output in XML file. Besides, later we use this model to display in different views.

package com.saurabh.common.model;
 
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
 
@XmlRootElement(name = "fruit")
public class Fruit {
 
 String name;
 int quality;
 
 public String getName() {
  return name;
 }
 
 @XmlElement
 public void setName(String name) {
  this.name = name;
 }
 
 public int getQuality() {
  return quality;
 }
 
 @XmlElement
 public void setQuality(int quality) {
  this.quality = quality;
 }
 
 public Fruit(String name, int quality) {
  this.name = name;
  this.quality = quality;
 }
 
 public Fruit() {
 }
 
}
 

2. JSON and XML View

To output JSON and XML views, you don’t need to do any extra works, Spring MVC will handle the conversion automatically. 
 

3. RSS View

To output RSS View, you need to extend AbstractRssFeedView.

package com.saurabh.common.rss;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.view.feed.AbstractRssFeedView;
import com.mkyong.common.model.Fruit;
import com.sun.syndication.feed.rss.Channel;
import com.sun.syndication.feed.rss.Content;
import com.sun.syndication.feed.rss.Item;
 
public class RssFeedView extends AbstractRssFeedView {
 
 @Override
 protected void buildFeedMetadata(Map<String, Object> model, Channel feed,
  HttpServletRequest request) {
 
  feed.setTitle("Sample Title");
  feed.setDescription("Sample Description");
  feed.setLink("http://google.com");
 
  super.buildFeedMetadata(model, feed, request);
 }
 
 
 @Override
 protected List<Item> buildFeedItems(Map<String, Object> model,
   HttpServletRequest request, HttpServletResponse response)
   throws Exception {
 
  Fruit fruit = (Fruit) model.get("model");
  String msg = fruit.getName() + fruit.getQuality();
 
  List<Item> items = new ArrayList<Item>(1);
  Item item = new Item();
  item.setAuthor("saurabh");
  item.setLink("http://springfollowers.com");
 
  Content content = new Content();
  content.setValue(msg);
 
  item.setContent(content);
 
  items.add(item);
 
  return items;
 }
}

4. JSP View

A JSP page to display the model data.
File : list.jsp

<html>
<body>
 <h1>Spring @MVC ContentNegotiatingViewResolver</h1>
 
 Fruit Name : ${model.name} <br />
 Fruit Quality : ${model.quality}
 
</body>
</html>
 

5. Controller

Spring controller, to generate a “fruit” model and return it.

package com.saurabh.common.controller;
 
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.mkyong.common.model.Fruit;
 
@Controller
@RequestMapping("/fruit")
public class FruitController {
 
 @RequestMapping(value="{fruitName}", method = RequestMethod.GET)
 public String getFruit(@PathVariable String fruitName, ModelMap model) {
 
  Fruit fruit = new Fruit(fruitName, 1000);
  model.addAttribute("model", fruit);
 
  return "list";
 
 }
 
}

6. ContentNegotiatingViewResolver example

The code should be self-explanatory. However, you have to define the “order” property, where lower value get higher priority. In this case, when a URL is requested, Spring MVC will use “ContentNegotiatingViewResolver” (order=1) to return a suitable view (based on file extension declared in “mediaTypes” property), if not match, then use “InternalResourceViewResolver” (order=2) to return a default JSP page.

applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 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/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
 
 <context:component-scan base-package="com.mkyong.common.controller" />
 
 <mvc:annotation-driven />
 
 <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
   <property name="order" value="1" />
   <property name="mediaTypes">
  <map>
     <entry key="json" value="application/json" />
     <entry key="xml" value="application/xml" />
     <entry key="rss" value="application/rss+xml" />
  </map>
   </property>
 
   <property name="defaultViews">
  <list>
    <!-- JSON View -->
    <bean
   class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
    </bean>
 
    <!-- RSS View -->
    <bean class="com.mkyong.common.rss.RssFeedView" />
 
    <!-- JAXB XML View -->
    <bean class="org.springframework.web.servlet.view.xml.MarshallingView">
   <constructor-arg>
    <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
       <property name="classesToBeBound">
     <list>
        <value>com.mkyong.common.model.Fruit</value>
     </list>
       </property>
    </bean>
   </constructor-arg>
    </bean>
   </list>
   </property>
   <property name="ignoreAcceptHeader" value="true" />
 
 </bean>
 
 <!-- If no extension matched, use JSP view -->
 <bean
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="order" value="2" />
  <property name="prefix">
   <value>/WEB-INF/pages/</value>
  </property>
  <property name="suffix">
   <value>.jsp</value>
  </property>
 </bean>
 
</beans>
 
Together with the default HTML view resolver, as shown in the configuration above,
it can now accept requests, like /apple.html, /apple.xml,/apple.rss or /apple.json
and returns the appropriate format, such as HTML, XML,RSS or JSON respectively. 
 
 

7. Demo

Same model and display in different views, via ContentNegotiatingViewResolver.
http://localhost:8080/SpringMVC/fruit/banana.xml , display as XML file.
spring mvc and xml demo
http://localhost:8080/SpringMVC/fruit/banana.json , display as JSON file.
spring mvc and json demo
http://localhost:8080/SpringMVC/fruit/banana.rss , display as RSS file.
spring mvc and RSS demo
http://localhost:8080/SpringMVC/fruit/banana , display as JSP page.
spring mvc and JSP demo

 
 Thanks & Regards
Er. Saurabh Kumar

 



 

1 comment:

  1. Very helpful blog, Please continue with latest blogs.

    Thanks
    Manoj

    ReplyDelete