|
|
|
|
@ -38,368 +38,6 @@
@@ -38,368 +38,6 @@
|
|
|
|
|
configuration</link> to understand the general programming model.</para> |
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
<section id="rest-creating-services"> |
|
|
|
|
<title>Creating RESTful services</title> |
|
|
|
|
|
|
|
|
|
<para>Spring's annotation-based MVC framework serves as the basis for |
|
|
|
|
creating RESTful Web Services. As such, you configure your servlet |
|
|
|
|
container as you would for a Spring MVC application using Spring's <link |
|
|
|
|
linkend="mvc-servlet">DispatcherServlet</link>.</para> |
|
|
|
|
|
|
|
|
|
<section id="rest-uritemplate"> |
|
|
|
|
<title>URI Templates</title> |
|
|
|
|
|
|
|
|
|
<para>RESTful services use URIs to name resources. To facilitate |
|
|
|
|
accessing the information contained in a URI, its structure follows |
|
|
|
|
conventions so that it can easily be described in a parameterized form. |
|
|
|
|
The <ulink url="http://bitworking.org/projects/URI-Templates/">proposed |
|
|
|
|
RFC</ulink> for URI Templates defines how an URI is parameterized. For |
|
|
|
|
example, the URI Template</para> |
|
|
|
|
|
|
|
|
|
<programlisting>http://www.example.com/users/{userid}</programlisting> |
|
|
|
|
|
|
|
|
|
<para>contains the variable 'userid'. If we assign the variable the |
|
|
|
|
value "fred", then 'expanding' the URI Template gives.</para> |
|
|
|
|
|
|
|
|
|
<programlisting>http://www.example.com/users/fred</programlisting> |
|
|
|
|
|
|
|
|
|
<para>When processing a request the URI can be compared to an expected |
|
|
|
|
URI Template in order to extract a collection of variables.</para> |
|
|
|
|
|
|
|
|
|
<para>Spring uses the <classname>@RequestMapping</classname> method |
|
|
|
|
annotation to define the URI Template for the request. The |
|
|
|
|
<classname>@PathVariable</classname> annotation is used to extract the |
|
|
|
|
value of the template variables and assign their value to a method |
|
|
|
|
variable. A Spring controller method to process above example is shown |
|
|
|
|
below;</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="java">@RequestMapping(value="/users/{userId}", method=RequestMethod.GET) |
|
|
|
|
public String getUser(@PathVariable String userId) { |
|
|
|
|
// implementation omitted... |
|
|
|
|
}</programlisting> |
|
|
|
|
|
|
|
|
|
<para>The request <literal>http://www.example.com/users/fred</literal> |
|
|
|
|
will bind the userId method parameter to the String value 'fred'.</para> |
|
|
|
|
|
|
|
|
|
<section id="rest-path-variable"> |
|
|
|
|
<title>Mapping RESTful URLs with the @PathVariable annotation</title> |
|
|
|
|
|
|
|
|
|
<para>The <classname>@PathVariable</classname> method parameter |
|
|
|
|
annotation is used to indicate that a method parameter should be bound |
|
|
|
|
to the value of a URI template variable.</para> |
|
|
|
|
|
|
|
|
|
<para>The following code snippet shows the use of a single |
|
|
|
|
<classname>@PathVariable</classname> in a controller method:</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="java">@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET) |
|
|
|
|
public String findOwner(<emphasis role="bold">@PathVariable</emphasis> String ownerId, Model model) { |
|
|
|
|
Owner owner = ownerService.findOwner(ownerId); |
|
|
|
|
model.addAttribute("owner", owner); |
|
|
|
|
return "displayOwner"; |
|
|
|
|
} |
|
|
|
|
</programlisting> |
|
|
|
|
|
|
|
|
|
<para>The URI Template "<literal>/owners/{ownerId}</literal>" |
|
|
|
|
specifies the variable name ownerId. When the controller handles this |
|
|
|
|
request, the value of ownerId is set the value in the request URI. For |
|
|
|
|
example, when a request comes in for /owners/fred, the value 'fred' is |
|
|
|
|
bound to the method parameter <literal>String |
|
|
|
|
ownerId</literal>.</para> |
|
|
|
|
|
|
|
|
|
<para>The matching of method parameter names to URI Template variable |
|
|
|
|
names can only be done if your code is compiled with debugging |
|
|
|
|
enabled. If you do have not debugging enabled, you must specify the |
|
|
|
|
name of the URI Template variable name to bind to in the @PathVariable |
|
|
|
|
annotation. For example</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="java">@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET) |
|
|
|
|
public String findOwner(<emphasis role="bold">@PathVariable</emphasis>("ownerId") String ownerId, Model model) { |
|
|
|
|
// implementation omitted |
|
|
|
|
} |
|
|
|
|
</programlisting> |
|
|
|
|
|
|
|
|
|
<para>The name of the method parameter does not matter in this case, |
|
|
|
|
so you may also use a controller method with the signature shown |
|
|
|
|
below</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="java">@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET) |
|
|
|
|
public String findOwner(<emphasis role="bold">@PathVariable</emphasis>("ownerId") String theOwner, Model model) { |
|
|
|
|
// implementation omitted |
|
|
|
|
}</programlisting> |
|
|
|
|
|
|
|
|
|
<para>Multiple @PathVariable annotations can be used to bind to |
|
|
|
|
multiple URI Template variables as shown below:</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="java">@RequestMapping(value="/owners/{ownerId}/pets/{petId}", method=RequestMethod.GET) |
|
|
|
|
public String findPet(<emphasis role="bold">@PathVariable</emphasis> String ownerId, <emphasis |
|
|
|
|
role="bold">@PathVariable</emphasis> String petId, Model model) { |
|
|
|
|
Owner owner = ownerService.findOwner(ownderId); |
|
|
|
|
Pet pet = owner.getPet(petId); |
|
|
|
|
model.addAttribute("pet", pet); |
|
|
|
|
return "displayPet"; |
|
|
|
|
} |
|
|
|
|
</programlisting> |
|
|
|
|
|
|
|
|
|
<para>The following code snippet shows the use of path variables on a |
|
|
|
|
relative path</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="java">@Controller |
|
|
|
|
@RequestMapping(<emphasis role="bold">"/owners/{ownerId}/**"</emphasis>) |
|
|
|
|
public class RelativePathUriTemplateController { |
|
|
|
|
|
|
|
|
|
@RequestMapping(<emphasis role="bold">"/pets/{petId}"</emphasis>) |
|
|
|
|
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { |
|
|
|
|
// implementation omitted |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
</programlisting> |
|
|
|
|
|
|
|
|
|
<tip> |
|
|
|
|
<para>method parameters that are decorated with the |
|
|
|
|
<interfacename>@PathVariable</interfacename> annotation can be of |
|
|
|
|
<emphasis role="bold">any simple type </emphasis>such as int, long, |
|
|
|
|
Date... Spring automatically converts to the appropriate type and |
|
|
|
|
throws a <classname>TypeMismatchException</classname> if the type is |
|
|
|
|
not correct.</para> |
|
|
|
|
</tip> |
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
<section> |
|
|
|
|
<title>Mapping the request body with the @RequestBody |
|
|
|
|
annotation</title> |
|
|
|
|
|
|
|
|
|
<para>The <classname>@RequestBody</classname> method parameter |
|
|
|
|
annotation is used to indicate that a method parameter should be bound |
|
|
|
|
to the value of the HTTP request body. For example,</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="java">@RequestMapping(value = "/something", method = RequestMethod.PUT) |
|
|
|
|
public void handle(@RequestBody String body, Writer writer) throws IOException { |
|
|
|
|
writer.write(body); |
|
|
|
|
}</programlisting> |
|
|
|
|
|
|
|
|
|
<para>The conversion of the request body to the method argument is |
|
|
|
|
done using a <interfacename>HttpMessageConverter</interfacename>. |
|
|
|
|
<interfacename>HttpMessageConverter</interfacename> is responsible for |
|
|
|
|
converting from the HTTP request message to an object and converting |
|
|
|
|
from an object to the HTTP response body. |
|
|
|
|
<classname>DispatcherServlet</classname> supports annotation based |
|
|
|
|
processing using the |
|
|
|
|
<classname>DefaultAnnotationHandlerMapping</classname> and |
|
|
|
|
<classname>AnnotationMethodHandlerAdapter</classname>. In Spring 3 the |
|
|
|
|
<classname>AnnotationMethodHandlerAdapter</classname> has been |
|
|
|
|
extended to support the <classname>@RequestBody</classname> and has |
|
|
|
|
several <interfacename>HttpMessageConverters</interfacename> |
|
|
|
|
registered by default, these are</para> |
|
|
|
|
|
|
|
|
|
<itemizedlist> |
|
|
|
|
<listitem> |
|
|
|
|
<para><classname>ByteArrayHttpMessageConverter</classname> - |
|
|
|
|
converts byte arrays</para> |
|
|
|
|
</listitem> |
|
|
|
|
|
|
|
|
|
<listitem> |
|
|
|
|
<para><classname>StringHttpMessageConverter</classname> - converts |
|
|
|
|
strings</para> |
|
|
|
|
</listitem> |
|
|
|
|
|
|
|
|
|
<listitem> |
|
|
|
|
<para><classname>FormHttpMessageConverter</classname> - converts |
|
|
|
|
form data to/from a MultiValueMap<String, String></para> |
|
|
|
|
</listitem> |
|
|
|
|
|
|
|
|
|
<listitem> |
|
|
|
|
<para><classname>SourceHttpMessageConverter</classname> - converts |
|
|
|
|
to/from a javax.xml.transform.Source;</para> |
|
|
|
|
</listitem> |
|
|
|
|
|
|
|
|
|
<listitem> |
|
|
|
|
<para><classname>MarshallingHttpMessageConverter</classname> - |
|
|
|
|
converts to/from an object using the |
|
|
|
|
<classname>org.springframework.oxm</classname> package.</para> |
|
|
|
|
</listitem> |
|
|
|
|
</itemizedlist> |
|
|
|
|
|
|
|
|
|
<para>More information on these converters can be found in the section |
|
|
|
|
<link linkend="rest-message-conversion">Message |
|
|
|
|
Converters</link>.</para> |
|
|
|
|
|
|
|
|
|
<para>The <classname>MarshallingHttpMessageConverter</classname> |
|
|
|
|
requires a <interfacename>Marshaller</interfacename> and |
|
|
|
|
<interfacename>Unmarshaller</interfacename> from the |
|
|
|
|
<classname>org.springframework.oxm</classname> package to be |
|
|
|
|
configured on an instance of |
|
|
|
|
<classname>AnnotationMethodHandlerAdapter</classname> in the |
|
|
|
|
application context. For example</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="xml"><bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"> |
|
|
|
|
<property name="messageConverters"> |
|
|
|
|
<util:list id="beanList"> |
|
|
|
|
<ref bean="stringHttpMessageConverter"/> |
|
|
|
|
<ref bean="marshallingHttpMessageConverter"/> |
|
|
|
|
</util:list> |
|
|
|
|
</property |
|
|
|
|
</bean> |
|
|
|
|
|
|
|
|
|
<bean id="stringHttpMessageConverter" |
|
|
|
|
class="org.springframework.http.converter.StringHttpMessageConverter"/> |
|
|
|
|
|
|
|
|
|
<bean id="marshallingHttpMessageConverter" |
|
|
|
|
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"> |
|
|
|
|
<property name="marshaller" ref="castorMarshaller" /> |
|
|
|
|
<property name="unmarshaller" ref="castorMarshaller" /> |
|
|
|
|
</bean> |
|
|
|
|
|
|
|
|
|
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/> |
|
|
|
|
</programlisting> |
|
|
|
|
</section> |
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
<section id="rest-multiple-representations"> |
|
|
|
|
<title>Returning multiple representations</title> |
|
|
|
|
|
|
|
|
|
<para>A RESTful architecture may expose multiple representations of a |
|
|
|
|
resource. There are two strategies for a client to inform the server of |
|
|
|
|
the representation it is interested in receiving.</para> |
|
|
|
|
|
|
|
|
|
<para>The first strategy is to use a distinct URI for each resource. |
|
|
|
|
This is typically done by using a different file extension in the URI. |
|
|
|
|
For example the URI<literal> |
|
|
|
|
http://www.example.com/users/fred.pdf</literal> requests a PDF |
|
|
|
|
representation of the user fred while |
|
|
|
|
<literal>http://www.example.com/users/fred.xml</literal> requests an XML |
|
|
|
|
representation.</para> |
|
|
|
|
|
|
|
|
|
<para>The second strategy is for the client to use the same URI to |
|
|
|
|
locate the resource but set the <literal>Accept</literal> HTTP request |
|
|
|
|
header to list the <ulink |
|
|
|
|
url="http://en.wikipedia.org/wiki/Internet_media_type">media |
|
|
|
|
types</ulink> that it understands. For example, a HTTP request for |
|
|
|
|
<literal>http://www.example.com/users/fred</literal> with an |
|
|
|
|
<literal>Accept</literal> header set to <literal>application/pdf |
|
|
|
|
</literal>requests a PDF representation of the user fred while |
|
|
|
|
<literal>http://www.example.com/users/fred</literal> with an |
|
|
|
|
<literal>Accept</literal> header set to <literal>text/xml</literal> |
|
|
|
|
requests an XML representation. This strategy is known as <ulink |
|
|
|
|
url="http://en.wikipedia.org/wiki/Content_negotiation">content |
|
|
|
|
negotiation</ulink>.</para> |
|
|
|
|
|
|
|
|
|
<note> |
|
|
|
|
<para>One issue with the Accept header is that is impossible to change |
|
|
|
|
it in a web browser, in HTML. For instance, in Firefox, it's fixed |
|
|
|
|
to</para> |
|
|
|
|
|
|
|
|
|
<programlisting>Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 |
|
|
|
|
</programlisting> |
|
|
|
|
|
|
|
|
|
<para>For this reason it is common to see the use of a distinct URI |
|
|
|
|
for each representation.</para> |
|
|
|
|
</note> |
|
|
|
|
|
|
|
|
|
<para>To support multiple representations of a resource Spring provides |
|
|
|
|
the <classname>ContentNegotiatingViewResolver</classname> to resolve a |
|
|
|
|
view based on the file extension or <literal>Accept</literal> header of |
|
|
|
|
the HTTP request. <classname>ContentNegotiatingViewResolver</classname> |
|
|
|
|
does not perform the view resolution itself, but instead delegates to a |
|
|
|
|
list of view resolvers set using the bean property |
|
|
|
|
<literal>ViewResolvers</literal>.</para> |
|
|
|
|
|
|
|
|
|
<para>The <classname>ContentNegotiatingViewResolver</classname> selects |
|
|
|
|
an appropriate <classname>View</classname> to handle the request by |
|
|
|
|
comparing the request media type(s) with the media type (a.k.a. |
|
|
|
|
<literal>Content-Type</literal>) supported by the |
|
|
|
|
<classname>View</classname> associated with each of its |
|
|
|
|
<classname>ViewResolvers</classname>. The first |
|
|
|
|
<classname>View</classname> in the list that has a compatible |
|
|
|
|
<literal>Content-Type</literal> is used to return the representation to |
|
|
|
|
the client. The <literal>Accept</literal> header may include wild cards, |
|
|
|
|
for example 'text/*', in which case a <classname>View</classname> whose |
|
|
|
|
Context-Type was 'text/xml' is a compatible match.</para> |
|
|
|
|
|
|
|
|
|
<para>To support the resolution of a view based on a file extension, |
|
|
|
|
<classname>ContentNegotiatingViewResolver</classname>'s bean property |
|
|
|
|
<literal>MediaTypes</literal> is used to specify a mapping of file |
|
|
|
|
extensions to media types. For more information on the algorithm to |
|
|
|
|
determine the request media type, refer to the API documentation for |
|
|
|
|
<classname>ContentNegotiatingViewResolver</classname>..</para> |
|
|
|
|
|
|
|
|
|
<para>Here is an example configuration of a |
|
|
|
|
<classname>ContentNegotiatingViewResolver</classname></para> |
|
|
|
|
|
|
|
|
|
<programlisting language="xml"> <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> |
|
|
|
|
<property name="mediaTypes"> |
|
|
|
|
<map> |
|
|
|
|
<entry key="atom" value="application/atom+xml"/> |
|
|
|
|
<entry key="html" value="text/html"/> |
|
|
|
|
</map> |
|
|
|
|
</property> |
|
|
|
|
<property name="viewResolvers"> |
|
|
|
|
<list> |
|
|
|
|
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/> |
|
|
|
|
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> |
|
|
|
|
<property name="prefix" value="/WEB-INF/jsp/"/> |
|
|
|
|
<property name="suffix" value=".jsp"/> |
|
|
|
|
</bean> |
|
|
|
|
</list> |
|
|
|
|
</property> |
|
|
|
|
</bean> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<bean id="content" class="com.springsource.samples.rest.SampleContentAtomView"/></programlisting> |
|
|
|
|
|
|
|
|
|
<para>The <classname>InternalResourceViewResolver</classname> handles |
|
|
|
|
the translation of view names and JSP pages while the |
|
|
|
|
<classname>BeanNameViewResolver</classname> returns a view based on the |
|
|
|
|
name of a bean. (See "<link |
|
|
|
|
linkend="mvc-viewresolver-resolver">Resolving views - the ViewResolver |
|
|
|
|
interface</link>" for more details on how Spring looks up and |
|
|
|
|
instantiates a view.) In this example, the <literal>content</literal> |
|
|
|
|
bean is a class that inherits from |
|
|
|
|
<classname>AbstractAtomFeedView</classname> which returns an Atom RSS |
|
|
|
|
feed. For more information on creating an Atom Feed representation see |
|
|
|
|
the section 'Atom Views'.</para> |
|
|
|
|
|
|
|
|
|
<para>In this configuration, if a request is made with a .html extension |
|
|
|
|
the view resolver will look for a view that matches the text/html media |
|
|
|
|
type. The <classname>InternalResourceViewResolver</classname> provides |
|
|
|
|
the matching view for text/html. If the request is made with the file |
|
|
|
|
extension .atom, the view resolver will look for a view that matches the |
|
|
|
|
application/atom+xml media type. This view is provided by the |
|
|
|
|
<classname>BeanNameViewResolver</classname> that maps to the |
|
|
|
|
<classname>SampleContentAtomView</classname> if the view name returned |
|
|
|
|
is 'content'. Alternatively, client requests could be made without a |
|
|
|
|
file extension and setting the Accept header to the preferred media-type |
|
|
|
|
and the same resolution of request to views would occur.</para> |
|
|
|
|
|
|
|
|
|
<note> |
|
|
|
|
<para>If <classname>ContentNegotiatingViewResolver</classname>'s list |
|
|
|
|
of ViewResolvers is not configured explicitly, then it will |
|
|
|
|
automatically use any ViewResolvers defined in the application |
|
|
|
|
context.</para> |
|
|
|
|
</note> |
|
|
|
|
|
|
|
|
|
<para>The corresponding controller code that returns an Atom RSS feed |
|
|
|
|
for a URI of the form <literal>http://localhost/content.atom</literal> |
|
|
|
|
or <literal>http://localhost/content</literal> with an |
|
|
|
|
<literal>Accept</literal> header of application/atom+xml is shown |
|
|
|
|
below</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="java">@Controller |
|
|
|
|
public class ContentController { |
|
|
|
|
|
|
|
|
|
private List<SampleContent> contentList = new ArrayList<SampleContent>(); |
|
|
|
|
|
|
|
|
|
@RequestMapping(value="/content", method=RequestMethod.GET) |
|
|
|
|
public ModelAndView getContent() { |
|
|
|
|
ModelAndView mav = new ModelAndView(); |
|
|
|
|
mav.setViewName("content"); |
|
|
|
|
mav.addObject("sampleContentList", contentList); |
|
|
|
|
return mav; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}</programlisting> |
|
|
|
|
|
|
|
|
|
<para></para> |
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
<section id="rest-views"> |
|
|
|
|
<title>Views</title> |
|
|
|
|
@ -638,333 +276,5 @@ public class SimpleController {
@@ -638,333 +276,5 @@ public class SimpleController {
|
|
|
|
|
<classname>ModelAndView</classname> object. Please refer to the API |
|
|
|
|
documentation for more details.</para> |
|
|
|
|
</section> |
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
<section id="rest-client-access"> |
|
|
|
|
<title>Accessing RESTful services on the Client</title> |
|
|
|
|
|
|
|
|
|
<para>The <classname>RestTemplate</classname> is the core class for |
|
|
|
|
client-side access to RESTful services. It is conceptually similar to |
|
|
|
|
other template classes in Spring, such as |
|
|
|
|
<classname>JdbcTemplate</classname> and <classname>JmsTemplate</classname> |
|
|
|
|
and other template classes found in other Spring portfolio projects. |
|
|
|
|
<classname>RestTemplate</classname>'s behavior is customized by providing |
|
|
|
|
callback methods and configuring the |
|
|
|
|
<interfacename>HttpMessageConverter</interfacename> used to marshal |
|
|
|
|
objects into the HTTP request body and to unmarshall any response back |
|
|
|
|
into an object. As it is common to use XML as a message format, Spring |
|
|
|
|
provides a <classname>MarshallingHttpMessageConverter</classname> that |
|
|
|
|
uses the Object-to-XML framework that is part of the |
|
|
|
|
<classname>org.springframework.oxm</classname> package. This gives you a |
|
|
|
|
wide range of choices of XML to Object mapping technologies to choose |
|
|
|
|
from.</para> |
|
|
|
|
|
|
|
|
|
<para>This section describes how to use the |
|
|
|
|
<classname>RestTemplate</classname> and its associated |
|
|
|
|
<interfacename>HttpMessageConverters</interfacename>.</para> |
|
|
|
|
|
|
|
|
|
<section id="rest-resttemplate"> |
|
|
|
|
<title>RestTemplate</title> |
|
|
|
|
|
|
|
|
|
<para>Invoking RESTful services in Java is typically done using a helper |
|
|
|
|
class such as Jakarta Commons <classname>HttpClient</classname>. For |
|
|
|
|
common REST operations this approach is too low level as shown |
|
|
|
|
below.</para> |
|
|
|
|
|
|
|
|
|
<programlisting>String uri = "http://example.com/hotels/1/bookings"; |
|
|
|
|
|
|
|
|
|
PostMethod post = new PostMethod(uri); |
|
|
|
|
String request = // create booking request content |
|
|
|
|
post.setRequestEntity(new StringRequestEntity(request)); |
|
|
|
|
|
|
|
|
|
httpClient.executeMethod(post); |
|
|
|
|
|
|
|
|
|
if (HttpStatus.SC_CREATED == post.getStatusCode()) { |
|
|
|
|
Header location = post.getRequestHeader("Location"); |
|
|
|
|
if (location != null) { |
|
|
|
|
System.out.println("Created new booking at :" + location.getValue()); |
|
|
|
|
} |
|
|
|
|
}</programlisting> |
|
|
|
|
|
|
|
|
|
<para>RestTemplate provides higher level methods that correspond to each |
|
|
|
|
of the six main HTTP methods that make invoking many RESTful services a |
|
|
|
|
one-liner and enforce REST best practices.</para> |
|
|
|
|
|
|
|
|
|
<table> |
|
|
|
|
<title>Overview of RestTemplate methods</title> |
|
|
|
|
|
|
|
|
|
<tgroup cols="2"> |
|
|
|
|
<tbody> |
|
|
|
|
<row> |
|
|
|
|
<entry><emphasis role="bold">HTTP Method</emphasis></entry> |
|
|
|
|
|
|
|
|
|
<entry><emphasis role="bold">RestTemplate |
|
|
|
|
Method</emphasis></entry> |
|
|
|
|
</row> |
|
|
|
|
|
|
|
|
|
<row> |
|
|
|
|
<entry>DELETE</entry> |
|
|
|
|
|
|
|
|
|
<entry><ulink |
|
|
|
|
url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#delete(String,%20String...)">delete(String |
|
|
|
|
url, String… urlVariables)</ulink></entry> |
|
|
|
|
</row> |
|
|
|
|
|
|
|
|
|
<row> |
|
|
|
|
<entry>GET</entry> |
|
|
|
|
|
|
|
|
|
<entry><ulink |
|
|
|
|
url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#getForObject(String,%20Class,%20String...)">getForObject(String |
|
|
|
|
url, Class<T> responseType, String… |
|
|
|
|
urlVariables)</ulink></entry> |
|
|
|
|
</row> |
|
|
|
|
|
|
|
|
|
<row> |
|
|
|
|
<entry>HEAD</entry> |
|
|
|
|
|
|
|
|
|
<entry><ulink |
|
|
|
|
url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#headForHeaders(String,%20String...)">headForHeaders(String |
|
|
|
|
url, String… urlVariables)</ulink></entry> |
|
|
|
|
</row> |
|
|
|
|
|
|
|
|
|
<row> |
|
|
|
|
<entry>OPTIONS</entry> |
|
|
|
|
|
|
|
|
|
<entry><ulink |
|
|
|
|
url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#optionsForAllow(String,%20String...)">optionsForAllow(String |
|
|
|
|
url, String… urlVariables)</ulink></entry> |
|
|
|
|
</row> |
|
|
|
|
|
|
|
|
|
<row> |
|
|
|
|
<entry>POST</entry> |
|
|
|
|
|
|
|
|
|
<entry><ulink |
|
|
|
|
url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#postForLocation(String,%20Object,%20String...)">postForLocation(String |
|
|
|
|
url, Object request, String… urlVariables)</ulink></entry> |
|
|
|
|
</row> |
|
|
|
|
|
|
|
|
|
<row> |
|
|
|
|
<entry>PUT</entry> |
|
|
|
|
|
|
|
|
|
<entry><ulink |
|
|
|
|
url="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/client/RestTemplate.html#put(String,%20Object,%20String...)">put(String |
|
|
|
|
url, Object request, String…urlVariables)</ulink></entry> |
|
|
|
|
</row> |
|
|
|
|
</tbody> |
|
|
|
|
</tgroup> |
|
|
|
|
</table> |
|
|
|
|
|
|
|
|
|
<para>The names of <classname>RestTemplate</classname> methods follow a |
|
|
|
|
naming convention, the first part indicates what HTTP method is being |
|
|
|
|
invoked and the second part indicates what is returned. For example, the |
|
|
|
|
method <methodname>getForObject</methodname> will perform a GET, convert |
|
|
|
|
the HTTP response into an object type of your choice and return that |
|
|
|
|
object. The method <methodname>postForLocation</methodname> will do a |
|
|
|
|
POST, converting the given object into a HTTP request and return the |
|
|
|
|
response HTTP Location header where the newly created object can be |
|
|
|
|
found In case of an exception processing the HTTP request, an exception |
|
|
|
|
of the type <classname>RestClientException</classname> will be |
|
|
|
|
thrown.</para> |
|
|
|
|
|
|
|
|
|
<para>Objects passed to and returned from these methods are converted to |
|
|
|
|
and from HTTP messages by |
|
|
|
|
<interfacename>HttpMessageConverter</interfacename> instances. |
|
|
|
|
Converters for the main mime types are registered by default, but you |
|
|
|
|
can also write your own converter and register it via the |
|
|
|
|
<methodname>messageConverters</methodname> bean property. The default |
|
|
|
|
converter instances registered with the template are |
|
|
|
|
<classname>ByteArrayHttpMessageConverter</classname>, |
|
|
|
|
<classname>StringHttpMessageConverter</classname>, |
|
|
|
|
<classname>FormHttpMessageConverter</classname> and |
|
|
|
|
<classname>SourceHttpMessageConverter</classname>. You can override |
|
|
|
|
these defaults using the <methodname>messageConverters</methodname> bean |
|
|
|
|
property as would be required if using the |
|
|
|
|
<classname>MarshallingHttpMessageConverter</classname>.</para> |
|
|
|
|
|
|
|
|
|
<para>Each method takes URI template arguments in two forms, either as a |
|
|
|
|
<literal>String</literal> variable length argument or a |
|
|
|
|
<literal>Map<String,String></literal>. For example,</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="java">String result = restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}", |
|
|
|
|
String.class,"42", "21"); |
|
|
|
|
</programlisting> |
|
|
|
|
|
|
|
|
|
<para>using variable length arguments and</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="java">Map<String, String> vars = Collections.singletonMap("hotel", "42"); |
|
|
|
|
String result = |
|
|
|
|
restTemplate.getForObject("http://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars); |
|
|
|
|
</programlisting> |
|
|
|
|
|
|
|
|
|
<para>using a <literal>Map<String,String></literal>.</para> |
|
|
|
|
|
|
|
|
|
<para>To create an instance of <classname>RestTemplate</classname> you |
|
|
|
|
can simply call the default constructor. This will use standard Java |
|
|
|
|
classes from the <literal>java.net</literal> package as the underlying |
|
|
|
|
implementation to create HTTP requests. This can be overridden by |
|
|
|
|
specifying an implementation of |
|
|
|
|
<interfacename>ClientHttpRequestFactory</interfacename>. Spring provides |
|
|
|
|
the implementation |
|
|
|
|
<classname>CommonsClientHttpRequestFactory</classname> that uses the |
|
|
|
|
Jakarta Commons <classname>HttpClient</classname> to create requests. |
|
|
|
|
<classname>CommonsClientHttpRequestFactory</classname> is configured |
|
|
|
|
using an instance of |
|
|
|
|
<classname>org.apache.commons.httpclient.HttpClient</classname> which |
|
|
|
|
can in turn be configured with credentials information or connection |
|
|
|
|
pooling functionality.</para> |
|
|
|
|
|
|
|
|
|
<para>The previous example using Jakarta Commons |
|
|
|
|
<classname>HttpClient</classname> directly rewritten to use the |
|
|
|
|
<classname>RestTemplate</classname> is shown below</para> |
|
|
|
|
|
|
|
|
|
<programlisting>uri = "http://example.com/hotels/{id}/bookings"; |
|
|
|
|
|
|
|
|
|
RestTemplate template = new RestTemplate(); |
|
|
|
|
|
|
|
|
|
Booking booking = // create booking object |
|
|
|
|
|
|
|
|
|
URI location = template.postForLocation(uri, booking, "1"); |
|
|
|
|
</programlisting> |
|
|
|
|
|
|
|
|
|
<para>The general callback interface is |
|
|
|
|
<interfacename>RequestCallback</interfacename> and is called when the |
|
|
|
|
execute method is invoked.</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="java">public <T> T execute(String url, HttpMethod method, RequestCallback requestCallback, |
|
|
|
|
ResponseExtractor<T> responseExtractor, |
|
|
|
|
String... urlVariables) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// also has an overload with urlVariables as a Map<String, String>.</programlisting> |
|
|
|
|
|
|
|
|
|
<para>The <interfacename>RequestCallback</interfacename> interface is |
|
|
|
|
defined as</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="java">public interface RequestCallback { |
|
|
|
|
void doWithRequest(ClientHttpRequest request) throws IOException; |
|
|
|
|
}</programlisting> |
|
|
|
|
|
|
|
|
|
<para>and allows you to manipulate the request headers and write to the |
|
|
|
|
request body. When using the execute method you do not have to worry |
|
|
|
|
about any resource management, the template will always close the |
|
|
|
|
request and handle any errors. Refer to the API documentation for more |
|
|
|
|
information on using the execute method and the meaning of its other |
|
|
|
|
method arguments.</para> |
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
<section id="rest-message-conversion"> |
|
|
|
|
<title>HTTP Message Conversion</title> |
|
|
|
|
|
|
|
|
|
<para>Objects passed to and returned from the methods |
|
|
|
|
<methodname>getForObject</methodname>, |
|
|
|
|
<methodname>postForLocation</methodname>, and |
|
|
|
|
<methodname>put</methodname> are converted to HTTP requests and from |
|
|
|
|
HTTP responses by <interfacename>HttpMessageConverters</interfacename>. |
|
|
|
|
The <interfacename>HttpMessageConverter</interfacename> interface is |
|
|
|
|
shown below to give you a better feel for its functionality</para> |
|
|
|
|
|
|
|
|
|
<programlisting language="java">public interface HttpMessageConverter<T> { |
|
|
|
|
|
|
|
|
|
// Indicate whether the given class is supported by this converter. |
|
|
|
|
boolean supports(Class<? extends T> clazz); |
|
|
|
|
|
|
|
|
|
// Return the list of MediaType objects supported by this converter. |
|
|
|
|
List<MediaType> getSupportedMediaTypes(); |
|
|
|
|
|
|
|
|
|
// Read an object of the given type form the given input message, and returns it. |
|
|
|
|
T read(Class<T> clazz, HttpInputMessage inputMessage) throws IOException, |
|
|
|
|
HttpMessageNotReadableException; |
|
|
|
|
|
|
|
|
|
// Write an given object to the given output message. |
|
|
|
|
void write(T t, HttpOutputMessage outputMessage) throws IOException, |
|
|
|
|
HttpMessageNotWritableException; |
|
|
|
|
|
|
|
|
|
}</programlisting> |
|
|
|
|
|
|
|
|
|
<para>Concrete implementations for the main media (mime) types are |
|
|
|
|
provided in the framework and are registered by default with the |
|
|
|
|
<classname>RestTemplate</classname> on the client-side and with |
|
|
|
|
<classname>AnnotationMethodHandlerAdapter</classname> on the |
|
|
|
|
server-side.</para> |
|
|
|
|
|
|
|
|
|
<para>The implementations of |
|
|
|
|
<classname>HttpMessageConverter</classname>s are described in the |
|
|
|
|
following sections. For all converters a default media type is used but |
|
|
|
|
can be overridden by setting the |
|
|
|
|
<classname>supportedMediaTypes</classname> bean property</para> |
|
|
|
|
|
|
|
|
|
<section id="rest-string-converter"> |
|
|
|
|
<title>StringHttpMessageConverter</title> |
|
|
|
|
|
|
|
|
|
<para>An <interfacename>HttpMessageConverter</interfacename> |
|
|
|
|
implementation that can read and write Strings from the HTTP request |
|
|
|
|
and response. By default, this converter supports all text media types |
|
|
|
|
(<literal>text/*</literal>), and writes with a |
|
|
|
|
<literal>Content-Type</literal> of |
|
|
|
|
<literal>text/plain</literal>.</para> |
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
<section id="rest-form-converter"> |
|
|
|
|
<title>FormHttpMessageConverter</title> |
|
|
|
|
|
|
|
|
|
<para>An <interfacename>HttpMessageConverter</interfacename> |
|
|
|
|
implementation that can read and write form data from the HTTP request |
|
|
|
|
and response. By default, this converter reads and writes the media |
|
|
|
|
type <literal>application/x-www-form-urlencoded</literal>. Form data |
|
|
|
|
is read from and written into a <literal>MultiValueMap<String, |
|
|
|
|
String></literal>.</para> |
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
<section id="rest-byte-converter"> |
|
|
|
|
<title>ByteArrayMessageConverter</title> |
|
|
|
|
|
|
|
|
|
<para>An <interfacename>HttpMessageConverter</interfacename> |
|
|
|
|
implementation that can read and write byte arrays from the HTTP |
|
|
|
|
request and response. By default, this converter supports all media |
|
|
|
|
types (<literal>*/*</literal>), and writes with a |
|
|
|
|
<literal>Content-Type</literal> of |
|
|
|
|
<literal>application/octet-stream</literal>. This can be overridden by |
|
|
|
|
setting the <property>supportedMediaTypes</property> property, and |
|
|
|
|
overriding <literal>getContentType(byte[])</literal>.</para> |
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
<section id="rest-marhsalling-converter"> |
|
|
|
|
<title>MarshallingHttpMessageConverter</title> |
|
|
|
|
|
|
|
|
|
<para>An <interfacename>HttpMessageConverter</interfacename> |
|
|
|
|
implementation that can read and write XML using Spring's |
|
|
|
|
<interfacename>Marshaller</interfacename> and |
|
|
|
|
<interfacename>Unmarshaller</interfacename> abstractions from the |
|
|
|
|
<classname>org.springframework.oxm</classname> package. This converter |
|
|
|
|
requires a <interfacename>Marshaller</interfacename> and |
|
|
|
|
<interfacename>Unmarshaller</interfacename> before it can be used. |
|
|
|
|
These can be injected via constructor or bean properties. By default |
|
|
|
|
this converter supports (<literal>text/xml</literal>) and |
|
|
|
|
(<literal>application/xml</literal>).</para> |
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
<section id="rest-source-converter"> |
|
|
|
|
<title>SourceHttpMessageConverter</title> |
|
|
|
|
|
|
|
|
|
<para>An <interfacename>HttpMessageConverter</interfacename> |
|
|
|
|
implementation that can read and write |
|
|
|
|
<classname>javax.xml.transform.Source</classname> from the HTTP |
|
|
|
|
request and response. Only <classname>DOMSource</classname>, |
|
|
|
|
<classname>SAXSource</classname>, and |
|
|
|
|
<classname>StreamSource</classname> are supported. By default, this |
|
|
|
|
converter supports (<literal>text/xml</literal>) and |
|
|
|
|
(<literal>application/xml</literal>).</para> |
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
<section id="rest-buffered-image-converter"> |
|
|
|
|
<title>BufferedImageHttpMessageConverter</title> |
|
|
|
|
|
|
|
|
|
<para>An <interfacename>HttpMessageConverter</interfacename> |
|
|
|
|
implementation that can read and write |
|
|
|
|
<classname>java.awt.image.BufferedImage</classname> from the HTTP |
|
|
|
|
request and response. This converter reads and writes the media type |
|
|
|
|
supported by the Java I/O API.</para> |
|
|
|
|
</section> |
|
|
|
|
</section> |
|
|
|
|
</section> |
|
|
|
|
</chapter> |
|
|
|
|
|