In this chapter, we will cover:
Setting up a Spring RESTful Web-Service, using RESTful features in Spring MVC
Using the RESTClient
tool to access a Spring RESTful Web-Service
Setting up a Spring RESTful Web-Service using HTTP message conversion
Creating a WS client for the Spring RESTful Web-Service using Spring template classes
Simple Object Access Protocol (SOAP) allows applications to communicate with one another using XML as the communication format (SOAP is well understood), but because it is XML-based, it tends to be verbose, even for very simple Web-Service scenarios.
Representational State Transfer (REST), published as a doctoral dissertation by Roy Fielding in 2000, aimed at simplifying the usage of Web-Service.
While SOAP uses a lot of XML (that looks very complex) to communicate, REST uses very lightweight and human-readable data (for example, the request URI http://localhost:8080/LiveRestaurant/customerAccount/234 returns 123-3456
. Compare this simple request and response with SOAP request/response envelop, already presented in the earlier chapters of this book. Since REST Web-Service implementation is very flexible and could be very easy, it requires no toolkit. However, SOAP-based Web-Services need tools for simplification (for example, to call a SOAP Web-Service, you would use tools to generate client-side proxy classes for a contract-last Web-Service class, or use tools to generate domain classes from a schema in a contract-first Web-Service). In the earlier chapters, you will have realized how strict a contract-first Web-Service is with the request/response
format (it must match the contract). The REST Web-Service request/response
format is all up to developers, and could be designed as easily as possible. While using SOAP Web-Services, using JavaScript is not easy (it needs a lot of code). REST usage is simplified using AJAX technologies and the JSON format.
Here are some of REST's demerits: REST only works over HTTP;calling a RESTful Web-Service is limited by HTTP verbs: GET, POST, PUT, and DELETE.
RESTful was built on the principles of REST, in which HTTP's methods are used based on their concepts. For example, HTTP's GET, POST, PUT
, and DELETE
are all used in a RESTful architecture that match their meaning in the same fashion as with HTTP.
RESTful Web-Services expose the state of its resources. In this chapter, for example, a RESTful service is exposed to get the list of available order items and the order object, when an order is placed in an online restaurant. To get a list of the available order items, the GET
method is used, and for placing an order, the POST
method is used. The method PUT
could be used to add/update an entry, and DELETE
could be used to delete an entry.
Here is the sample URL to make a RESTful Web-Service call and to get the list of available order items:
http://localhost:8080/LiveRestaurant/orderItems.
The following is the return response (response format is not necessarily in XML format; it could be in JSON, plain-text, or any format):
<list>
<orderItem>
<name>Burger</name>
<id>0</id>
</orderItem>
<orderItem>
<name>Pizza</name>
<id>1</id>
</orderItem>
<orderItem>
<name>Sushi</name><id>2</id>
</orderItem>
<orderItem>
<name>Salad</name>
<id>3</id>
</orderItem>
</list>
There are several implementations of the RESTful Web-Service such as Restlet, RestEasy
, and Jersey. Jersey
, the most significant one in this group, is the implementation of JAX-RS (JSR 311).
Spring, being a widely-used framework of Java EE, introduced support for RESTful Web-Services in release 3. RESTful has been integrated into Spring's MVC layer that allows applications to build on Spring using RESTful features. The most significant of these features includes:
Annotations, such as @RequestMapping
and @PathVariable
, used for URI mappings and passing parameters.
ContentNegotiatingViewResolver
, which allows the usage of different MIME types (such as text/xml, text/json
, and text/plain)
HttpMessageConverter
, which allows the production of multiple representations, based on the client requests (such as ATOM, XML, and JSON).
Spring 3.0 supports RESTful Web-Services based on Spring MVC. Spring uses annotations to set up a RESTful Web-Service and needs to be configured (within the Spring application context file) to scan for annotation. A spring MVC controller is required to set up a RESTful Web-Service. The @Controller
annotation tags a class as the MVC controller (http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html). The @RequestMapping
annotation maps incoming requests to an appropriate Java method in the controller class. Using this annotation, you can define the URI and the HTTP method that is mapped to a Java class method. For example, in the following example, the method loadOrderItems
will be called if the request URI is followed by /orderItems
, and @PathVariable
is for injecting the value of the request parameters ({cayegoryId}
) variable into a method parameter (String cayegoryId):
@RequestMapping( value="/orderItem/{cayegoryId}", method=RequestMethod.GET ) public ModelAndView loadOrderItems(@PathVariable String cayegoryId) {...}
In this recipe, implementing a RESTful Web-Service using Spring 3 MVC is presented. The client project of this Web-Service is implemented here, but it will be detailed in the last recipe of this chapter: Creating a WS client for Spring RESTful Web-Service using Spring template classes.
In this recipe, the project's name is LiveRestaurant_R-9.1
(the LiveRestaurant_R-9.1-Client
project is included in the code for testing purposes) with the following Maven dependencies:
com.springsource.javax.servlet-2.5.0.jar
spring-oxm-3.0.5.RELEASE.jar
spring-web-3.0.5.RELEASE.jar
spring-webmvc-3.0.5.RELEASE.jar
xstream-1.3.1.jar
commons-logging-1.1.1.jar
spring-oxm
is the Spring support for Object/XML mapping, spring-web
and spring-webmvc
are the support for Seb and MVC support, and xstream
is for the Object/XML mapping framework.
Configure MessageDispatcherServlet
inside the web.xml
file (URL:http://<host>:<port>/<appcontext>
/* is to be forwarded to this servlet).
Define the controller file (OrderController.java
).
Define the domain POJOs (Order.java,OrderItem.java
) and services (OrderService, OrderServiceImpl)
.
Configure the server-side application context-file (order-servlet.xml
).
Run the following command on Liverestaurant_R-9.1:
mvn clean package tomcat:run
Run the following command on Liverestaurant_R-9.1-Client:
mvn clean package
Here is client-side output:
.... Created POST request for "http://localhost:8080/LiveRestaurant/order/1"
.....Setting request Accept header to [application/xml, text/xml, application/*+xml]
.... POST request for "http://localhost:8080/LiveRestaurant/order/1" resulted in 200 (OK)
.....Reading [com.packtpub.liverestaurant.domain.Order] as "application/xml;charset=ISO-8859-1"
.....
.....Created GET request for "http://localhost:8080/LiveRestaurant/orderItems"
.....Setting request Accept header to [application/xml, text/xml, application/*+xml]
.....GET request for "http://localhost:8080/LiveRestaurant/orderItems" resulted in 200 (OK)
Browse to this link: http://localhost:8080/LiveRestaurant/orderItems, and you will be provided with the following response:
<list>
<orderItem>
<name>Burger</name>
<id>0</id>
</orderItem>
<orderItem>
<name>Pizza</name>
<id>1</id>
</orderItem>
<orderItem>
<name>Sushi</name><id>2</id>
</orderItem>
<orderItem>
<name>Salad</name>
<id>3</id>
</orderItem>
</list>
The application is an MVC web project, in which a controller returns Spring's Model
and View
objects. Spring's MarshallingView
marshalls the model object into XML, using a marshaller
(XStreamMarshaller
), and the XML will be sent back to the client.
All requests will come to DispatcherServlet
, which will be forwarded to the controller - OrderController
, and based on the request URI, an appropriate method will be called that will return a response back to the caller. The following configuration in web.xml
forwards all the requests to the DispatcherServlet:
<servlet> <servlet-name>order</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>order</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
The following setting in order-context.xml
causes Spring to detect all annotations in the package (this includes OrderService
and OrderController)
. The BeanNameViewResolver
is for mapping a name (orderXmlView
in OrderController)
to a view (the bean orderXmlView)
, which is an instance of org.springframework.web.servlet.view.xml.MarshallingView:
<context:component-scan base-package= "com.packtpub.liverestaurant.orderservice" /> <bean class= "org.springframework.web.servlet.view.BeanNameViewResolver" /> <bean id="orderXmlView" class= "org.springframework.web.servlet.view.xml.MarshallingView"> ... </bean>
@Controller
tags the class OrderController
as the controller in an MVC pattern. All caller requests will be forwarded to this class, and based on the request URI, an appropriate method will be called. For example, the method placeOrder
will be called if any URI similar to http://<host>:<port>/<appcontext>/order/1
with an HTTP POST
method comes from a caller request.
@RequestMapping(value = "/order/{orderId}", method = RequestMethod.POST) public ModelAndView placeOrder(@PathVariable String orderId) {..}
@PathVariable
causes the orderId
parameter from the URI to be injected and passed to the placeOrder
method.
The body of the method, placeOrder
, calls a method from the OrderService
interface and returns the Order
object:
Order order = orderService.placeOrder(orderId); ModelAndView mav = new ModelAndView("orderXmlView", BindingResult.MODEL_KEY_PREFIX + "order", order); return mav;
Then, it builds a view based on marshalling the Order
object into the XML format, using the Marshallingview
bean (MarshallingView, which is the view in MVC, uses XStreamMarshaller
to marshall the model object into XML format), and returns it to the caller of the service.
<bean id="orderXmlView" 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>
The loadOrderItems
method works in the same way, except that the URI should be similar to the following pattern: http://<host>:<port>/<appcontext>/orderItems
, with an HTTP GET:
@RequestMapping(value = "/orderItems", method = RequestMethod.GET) public ModelAndView loadOrderItems() { List<OrderItem> orderItems = orderService.listOrderItems(); ModelAndView modelAndView = new ModelAndView("orderXmlView", BindingResult.MODEL_KEY_PREFIX + "orderItem", orderItems); return modelAndView; }
In this recipe, the database activities are not implemented. However, in a real application, the HTTP method DELETE
could be used to delete an entity (for example, orderItem)
from the database, and the PUT
method could be used to update a record (for example, order)
.
REST Client is an application to call and test RESTful Web-Services. REST Client is provided as a Firefox/Flock add-on. The Firefox REST Client supports all HTTP methods, RFC2616 (HTTP/1.1), and RFC2518 (WebDAV). Using this add-on, you can build your own customized URI, add a header, send it to RESTful Web-Services, and get the response back.
In this recipe, we will learn how to use Firefox REST Client to test how a RESTful Web-Service is presented. This recipe uses the first recipe of this chapter, Setting up a Spring RESTful Web-Service using RESTful features in Spring MVC, as RESTful Web-Services.
Run LiveRestaurant_R-9.1
from this chapter.
Open the Firefox browser and go to Tools | Rest Client.
Change the Method to GET and enter the URL: http://localhost:8080/LiveRestaurant/orderItems, and click on Send:
Here is the result:
Change Method to POST, enter the URL: http://localhost:8080/LiveRestaurant/order/1, and click on Send:
The client and server on the HTTP protocol exchange data using text format. Eventually, there are requirements to accept different request formats and covert the text format into a meaningful format, such as an Object or the JSON format. Spring provides features to provide multiple requests/presentations to/from the same text format.
Spring 3 introduced ContentNegotiatingViewResolver
, which can select various views from the same URI and can provide multiple presentations.
The alternate way of doing the same task is using the HttpMessageConverter
interface and the @ResponseBody
annotation. Implementation of the HttpMessageConverter
interface from Spring converts HTTP messages into several formats. Its widely used implementations include:
StringHttpMessageConverter
implementation reads/writes text from the HTTP request/response. This is the default converter.
MarshallingHttpMessageConverter
implementation marshalls/unmarshalls objects from the text HTTP request/response. It gets a constructor argument to specify the type of Marshaller (such as Jaxb, XStream
, and so on).
MappingJacksonHttpMessageConverter
implementation converts text into the JSON data format or vice-versa.
In this recipe, message conversion using MarshallingHttpMessageConverter, MappingJacksonHttpMessageConverter
, and AtomFeedHttpMessageConverter
is presented. Since this project is similar to the first recipe of this chapter, Setting up a Spring RESTful Web-Service using RESTful features in Spring MVC, it is reused as a template for the project. The difference in this recipe is in the controller implementation and the application context configuration.
The client project of this Web-Service is implemented here, but it will be detailed in the last recipe of this chapter, Creating a WS client for Spring RESTful Web-Service using Spring template classes.
In this recipe, the project's name is LiveRestaurant_R-9.2 (LiveRestaurant_R-9.2-Client
is included in the code for testing purposes in this recipe. However, it will be explained in the last recipe), and it has the following Maven dependencies:
com.springsource.javax.servlet-2.5.0.jar
spring-oxm-3.0.5.RELEASE.jar
spring-web-3.0.5.RELEASE.jar
spring-webmvc-3.0.5.RELEASE.jar
xstream-1.3.1.jar
commons-logging-1.1.1.jar
jackson-core-asl-1.7.5.jar
jackson-mapper-asl-1.7.5.jar
rome-1.0.jar
jackson-core
and jackson-mapper
support the JSON format and the others support the ATOM format.
Configure the DispatcherServlet
inside the web.xml
file (URL:http://<host>:<port>/<appcontext>
/* is to be forwarded to this servlet).
Define domain POJOs (Order.java,OrderItem.java
) and services (OrderService, OrderServiceImpl)
Configure the server-side application context-file (order-servlet.xml
) and register the converters.
Change the Method to POST and add a Request Header: Name - accept
, Value - application/json
. Enter the URL http://localhost:8080/LiveRestaurant/orderJson/1 and click on Send:
Change the Method to GET, and add Request Header: Name - accept
, Value - application/atom+xml
. Enter the URL http://localhost:8080/LiveRestaurant/orderItemsFeed and click on Send:
This recipe is almost the same as the first recipe of this chapter, except that it uses the message converter and @ResponseBody
to provide multiple presentations.
In the first recipe, MarshallingView
was responsible for converting the response to the selected XML type of the view (using XstreamMarshaller)
. However, here, the message converters are responsible for rendering data models into a selected format, MarshallingHttpMessageConverter
is responsible for converting the List<OrderItem>
to the application/xml
format (using XstreamMarshaller)
, and MappingJacksonHttpMessageConverter
is used to convert an order into the application/json
format. AtomFeedHttpMessageConverter
is used to convert Feed
(that wraps XML content generated from List<OrderItem>
using XStreamMarshaller
into the application/atom+xml
format:
<context:component-scan base-package= "com.packtpub.liverestaurant.orderservice" /> <bean id="xStreamMarshaller" class= "org.springframework.oxm.xstream.XStreamMarshaller"/> <bean class="org.springframework. web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" /> <bean class="org.springframework. web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> <property name="messageConverters"> <list> <ref bean="marshallingConverter" /> <ref bean="jsonConverter" /> <ref bean="atomConverter" /> </list> </property> </bean> <bean id="marshallingConverter" class="org.springframework. http.converter.xml.MarshallingHttpMessageConverter"> <constructor-arg> <bean class="org.springframework.oxm.xstream.XStreamMarshaller"> <property name="autodetectAnnotations" value="true"/> </bean> </constructor-arg> <property name="supportedMediaTypes" value="application/xml"/> </bean> <bean id="jsonConverter" class="org.springframework. http.converter.json.MappingJacksonHttpMessageConverter"> <property name="supportedMediaTypes" value="application/json" /> </bean> <bean id="atomConverter"class="org.springframework. http.converter.feed.AtomFeedHttpMessageConverter"> <property name="supportedMediaTypes" value="application/atom+xml" /> </bean>
In the controller, the following code causes the controller's method to accept the request URI method's POST
format — json:
@RequestMapping(method=RequestMethod.POST, value="/orderJson/{orderId}", headers="Accept=application/json") public @ResponseBody Order placeOrderJson(@PathVariable String orderId) { Order order=orderService.placeOrder(orderId); return order; }
And it returns the Order
object in JSON format (using @ResponseBody
and MappingJacksonHttpMessageConverter
, configured in order-context.xml):
{"message":"Order Pizza has been placed","ref":"Ref:1","orderItemId":"1"}
The following code causes the controller's method to accept the request URI method's GET
format — atom:
@RequestMapping(method=RequestMethod.GET, value="/orderItemsFeed", headers="Accept=application/atom+xml") public @ResponseBody Feed loadOrderItemsAtom() { Feed feed = null; try { feed= getOrderItemsFeed(orderService.listOrderItems()); } catch (Exception e) { throw new RuntimeException(e); } return feed; }
It also returns the List<OrderItem>
object in Atom
format (using @ResponseBody
and AtomFeedHttpMessageConverter
, configured in order-context.xml):
<?xml version="1.0" encoding="UTF-8"?> <feed xmlns="http://www.w3.org/2005/Atom"> <title>OrderItems Atom Feed</title> <entry> <title>Burger</title> <id>0</id> <content type="xml"> <com.packtpub.liverestaurant.domain.OrderItem><name> Burger</name><id>0</id></com.packtpub. liverestaurant.domain.OrderItem> </content> </entry> <entry> <title>Pizza</title> <id>1</id> <content type="xml"><com.packtpub.liverestaurant.domain. OrderItem><name>Pizza</name><id>1< /id></com.packtpub.liverestaurant.domain.OrderItem> </content> </entry> ...
Spring provides varieties of template classes that simplify many complexities using different technologies. For example, WebServiceTemplate
is for calling a SOAP-based Web-Service, and JmsTemplate
is for sending/receiving JMS messages. Spring also has the RestTemplate
to simplify the interaction with RESTful Web-Services.
Create an instance of RestTemplate
(can be done using the @Autowired
feature)
Configure one-to-many message converters (as described in the previous recipe)
Call methods of RestTemplate
to call a RESTful Web-Service and get a response back
In this recipe, we will learn to consume a RESTful Web-Service using the RestTemplate
. This recipe uses the third recipe of this chapter, Setting up a Spring RESTful Web-Service using HTTP Message Conversion, as the RESTful Web-Service.
In this recipe, the project's name is LiveRestaurant_R-9.2-Client
(LiveRestaurant_R-9.2
is included in this recipe to set up a RESTful server, as explained earlier in the recipe Setting up a Spring RESTful Web-Service using HTTP Message Conversion) with the following Maven dependencies:
spring-oxm-3.0.5.RELEASE.jar
spring-web-3.0.5.RELEASE.jar
xstream-1.3.1.jar
commons-logging-1.1.1.jar
jackson-core-asl-1.7.5.jar
jackson-mapper-asl-1.7.5.jar
rome-1.0.jar
junit-4.6.jar
spring-test-3.0.5.RELEASE.jar
Define domain POJOs (Order.java, OrderItem.java)
and services (OrderService, OrderServiceImpl)
.
Configure the client-side application context-file (order-servlet.xml
) and register the converters.
Create a helper class (OrderClient
) that wraps calling the RESTful Web-Service using the RestTemplate
.
Run the following command on Liverestaurant_R-9.2:
mvn clean package tomcat:run
Run the following command on Liverestaurant_R-9.2-Client:
mvn clean package
Here is the client-side output:
....
.. Created GET request for "http://localhost:8080/LiveRestaurant/orderItems"
.. Setting request Accept header to [application/xml, text/xml, application/*+xml, application/json]
.. GET request for "http://localhost:8080/LiveRestaurant/orderItems" resulted in 200 (OK)
.. Reading [java.util.List] as "application/xml" using ....
.. Created POST request for "http://localhost:8080/LiveRestaurant/orderJson/1"
.. Setting request Accept header to [application/xml, text/xml, application/*+xml, application/json]
.. POST request for "http://localhost:8080/LiveRestaurant/orderJson/1" resulted in 200 (OK)
.. Reading [com.packtpub.liverestaurant.domain.Order] as "application/xml" using ...
...Created GET request for "http://localhost:8080/LiveRestaurant/orderItemsFeed"
.. Setting request Accept header to [application/xml, text/xml, application/*+xml, application/json, application/atom+xml]
.. GET request for "http://localhost:8080/LiveRestaurant/orderItemsFeed" resulted in 200 (OK)
.. Reading [com.sun.syndication.feed.atom.Feed] as "application/xml" using ...
Application context loaded by OrderServiceClientTest
, loads, instantiates, and injects RestTemplate
into OrderClient
. This class calls the controller's method using RestTemplate
and returns a value back to the test suite class (OrderServiceClientTest
).
In the suite class test methods, the response will be compared with the desired values.
The applicationContext.xml
defines the restTemplate
bean and sets a list of message converters:
...... <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"> <property name="messageConverters"> <list> <ref bean="xmlMarshallingHttpMessageConverter" /> <ref bean="jsonConverter" /> <ref bean="atomConverter" /> </list> </property> </bean> <bean id="xmlMarshallingHttpMessageConverter" class="org.springframework. http.converter.xml.MarshallingHttpMessageConverter"> <constructor-arg> <ref bean="xStreamMarshaller" /> </constructor-arg> </bean> <bean id="xStreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"> <property name="annotatedClasses"> <list> <value>com.packtpub.liverestaurant.domain.Order</value> <value>com.packtpub.liverestaurant.domain.OrderItem</value> </list> </property> </bean> <bean id="atomConverter" class="org.springframework. http.converter.feed.AtomFeedHttpMessageConverter"> <property name="supportedMediaTypes" value="application/atom+xml" /> </bean> <bean id="jsonConverter" class="org.springframework. http.converter.json.MappingJacksonHttpMessageConverter"> <property name="supportedMediaTypes" value="application/json" /> </bean>
Converters set inside the messageConverters
are responsible for converting requests/responses in different formats (XML, JSON, ATOM) back to object
type. XstreamMarshaller
gets the list of recognized POJOs (Order, OrderItem)
, using the annotation tags in those classes.
OrderClient.java
is a helper class that wraps calling RESTful Web-Services, using RestTemplate:
protected RestTemplate restTemplate; private final static String serviceUrl = "http://localhost:8080/LiveRestaurant/"; @SuppressWarnings("unchecked") public List<OrderItem> loadOrderItemsXML() { HttpEntity<String> entity = getHttpEntity(MediaType.APPLICATION_XML); ResponseEntity<List> response = restTemplate.exchange(serviceUrl + "orderItems", HttpMethod.GET, entity, List.class); return response.getBody(); } ..... ... public String loadOrderItemsAtom() { HttpEntity<String> httpEntity = getHttpEntity(MediaType.APPLICATION_ATOM_XML); String outputStr = null; ResponseEntity<Feed> responseEntity = restTemplate.exchange(serviceUrl + "orderItemsFeed", HttpMethod.GET, httpEntity, Feed.class); WireFeed wireFeed = responseEntity.getBody(); WireFeedOutput wireFeedOutput = new WireFeedOutput(); try { outputStr = wireFeedOutput.outputString(wireFeed); } catch (Exception e) { throw new RuntimeException(e); } return outputStr; } private HttpEntity<String> getHttpEntity(MediaType mediaType) { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(mediaType); HttpEntity<String> httpEntity = new HttpEntity<String>(httpHeaders); return httpEntity; }
This recipe uses only two methods of the RestTemplate
(exchange and postForEntity)
. However, RestTemplate
supports several caller methods:
In this chapter:
Setting up a Spring RESTful Web-Service using RESTful features in Spring MVC
Setting up a Spring RESTful Web-Service using HTTP message conversion
The book, RESTful Java Web Services, at http://www.packtpub.com/restful-java-web-services/book.