281 lines
13 KiB
XML
281 lines
13 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
|
<chapter id="rest">
|
|
<title>REST support</title>
|
|
|
|
<section id="rest-introduction">
|
|
<title>Introduction</title>
|
|
|
|
<para>The goal of Spring's REST support is to make the development of
|
|
RESTful Web services and applications easier.</para>
|
|
|
|
<para>Client-side access to RESTful resources is greatly simplified using
|
|
Spring <classname>RestTemplate</classname>.
|
|
<classname>RestTemplate</classname> follows in the footsteps of other
|
|
template classes in Spring such as <classname>JdbcTemplate</classname> and
|
|
<classname>JmsTemplate</classname>. Instead of dealing with a verbose
|
|
lower level API such as Apache Commons <classname>HttpClient</classname>
|
|
to create RESTful request, RestTemplate provides one liner methods that
|
|
are purpose built for RESTful programming.</para>
|
|
|
|
<para>On the server-side, Spring's REST support is based upon Spring's
|
|
existing annotation based MVC framework. (For those interested in the
|
|
rational for that decision, and for not implementing JAX-RS, read Arjen
|
|
Poutsma's SpringSource TeamBlog <ulink
|
|
url="http://blog.springsource.com/2009/03/08/rest-in-spring-3-mvc/">entry</ulink>.)
|
|
With little effort, you can marshall data out of a RESTful request using
|
|
<classname>@RequestMapping</classname> and
|
|
<classname>@PathVariable</classname> annotations and return different
|
|
views as determined by the request's <literal>Context-Type</literal>
|
|
header.</para>
|
|
|
|
<para>In this chapter we describe all the features of Spring's REST
|
|
support. It is divided into two main chapters, one for the server-side and
|
|
one for the client-side. For those new to Spring's <link linkend="mvc">MVC
|
|
framework</link>, you may want to read through the reference documentation
|
|
on <link linkend="mvc-annotation">annotation-based controller
|
|
configuration</link> to understand the general programming model.</para>
|
|
</section>
|
|
|
|
|
|
<section id="rest-views">
|
|
<title>Views</title>
|
|
|
|
<para>Several views were added in Spring 3 to help support creating
|
|
RESTful services. They are:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><classname>AbstractAtomFeedView</classname> - returns an Atom
|
|
feed</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><classname>AbstractRssFeedView</classname> - returns a RSS
|
|
feed</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><classname>MarshallingView</classname> - returns an XML
|
|
representation using Spring's Object to XML mapping (OXM)
|
|
functionality</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<note>
|
|
<para>Available separately is the
|
|
<classname>JacksonJsonView</classname> included as part of the Spring
|
|
JavaScript project.</para>
|
|
</note>
|
|
|
|
<section id="rest-feedview">
|
|
<title>Feed Views</title>
|
|
|
|
<para>Both <classname>AbstractAtomFeedView</classname> and
|
|
<classname>AbstractRssFeedView</classname> inherit from the base class
|
|
<classname>AbstractFeedView</classname> and are used to provide Atom
|
|
and RSS Feed views respectfully. They are based on java.net's <ulink
|
|
url="https://rome.dev.java.net">ROME</ulink> project and are located
|
|
in the package
|
|
<literal>org.springframework.web.servlet.view.feed</literal>.</para>
|
|
|
|
<para><classname>AbstractAtomFeedView</classname> requires you to
|
|
implement the <methodname>buildFeedEntries</methodname> method and
|
|
optionally override the <methodname>buildFeedMetadata</methodname>
|
|
method (the default implementation is empty), as shown below</para>
|
|
|
|
<programlisting language="java">public class SampleContentAtomView extends AbstractAtomFeedView {
|
|
|
|
@Override
|
|
protected void buildFeedMetadata(Map<String, Object> model, Feed feed,
|
|
HttpServletRequest request) {
|
|
// implementation omitted
|
|
}
|
|
|
|
@Override
|
|
protected List<Entry> buildFeedEntries(Map<String, Object> model,
|
|
HttpServletRequest request,
|
|
HttpServletResponse response) throws Exception {
|
|
|
|
// implementation omitted
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Similar requirements apply for implementing
|
|
<classname>AbstractRssFeedView</classname>, as shown below</para>
|
|
|
|
<programlisting language="java">public class SampleContentAtomView extends AbstractRssFeedView {
|
|
|
|
@Override
|
|
protected void buildFeedMetadata(Map<String, Object> model, Channel feed,
|
|
HttpServletRequest request) {
|
|
// implementation omitted
|
|
}
|
|
|
|
@Override
|
|
protected List<Item> buildFeedItems(Map<String, Object> model,
|
|
HttpServletRequest request,
|
|
HttpServletResponse response) throws Exception {
|
|
// implementation omitted
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>The <methodname>buildFeedItems</methodname> and
|
|
<methodname>buildFeedEntires</methodname> pass in the HTTP request in
|
|
case you need to access the Locale. The HTTP response is passed in
|
|
only for the setting of cookies or other HTTP headers. The feed will
|
|
automatically be written to the response object after the method
|
|
returns.</para>
|
|
|
|
<para>For an example of creating a Atom view please refer to Alef
|
|
Arendsen's SpringSource TeamBlog <ulink
|
|
url="http://blog.springsource.com/2009/03/16/adding-an-atom-view-to-an-application-using-springs-rest-support/">entry</ulink>.</para>
|
|
</section>
|
|
|
|
<section>
|
|
<title>XML Marshalling View</title>
|
|
|
|
<para>The <classname>MarhsallingView</classname> uses a XML
|
|
<interfacename>Marshaller</interfacename> defined in the
|
|
<classname>org.springframework.oxm</classname> package to render the
|
|
response content as XML. The object to be marshalled can be set
|
|
explicitly using <classname>MarhsallingView</classname>'s
|
|
<property>modelKey</property> bean property. Alternatively, the view
|
|
will iterate over all model properties marhsall only those types that
|
|
are supported by the <interfacename>Marshaller</interfacename>. For
|
|
more information on the functionality in the
|
|
<classname>org.springframework.oxm</classname> package refer to the
|
|
chapter <link linkend="oxm">Marshalling XML using O/X
|
|
Mappers</link>.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="rest-method-conversion">
|
|
<title>HTTP Method Conversion</title>
|
|
|
|
<para>A key principle of REST is the use of the Uniform Interface. This
|
|
means that all resources (URLs) can be manipulated using the same four
|
|
HTTP methods: GET, PUT, POST, and DELETE. For each methods, the HTTP
|
|
specification defines the exact semantics. For instance, a GET should
|
|
always be a safe operation, meaning that is has no side effects, and a
|
|
PUT or DELETE should be idempotent, meaning that you can repeat these
|
|
operations over and over again, but the end result should be the same.
|
|
While HTTP defines these four methods, HTML only supports two: GET and
|
|
POST. Fortunately, there are two possible workarounds: you can either
|
|
use JavaScript to do your PUT or DELETE, or simply do a POST with the
|
|
'real' method as an additional parameter (modeled as a hidden input
|
|
field in an HTML form). This latter trick is what Spring's
|
|
<classname>HiddenHttpMethodFilter</classname> does. This filter is a
|
|
plain Servlet Filter and therefore it can be used in combination with
|
|
any web framework (not just Spring MVC). Simply add this filter to your
|
|
web.xml, and a POST with a hidden _method parameter will be converted
|
|
into the corresponding HTTP method request.</para>
|
|
|
|
<section id="rest-form-tags">
|
|
<title>Supporting Spring form tags</title>
|
|
|
|
<para>To support HTTP method conversion the Spring MVC form tag was
|
|
updated to support setting the HTTP method. For example, the following
|
|
snippet taken from the updated Petclinic sample</para>
|
|
|
|
<programlisting language="xml"><form:form method="delete">
|
|
<p class="submit"><input type="submit" value="Delete Pet"/></p>
|
|
</form:form></programlisting>
|
|
|
|
<para>This will actually perform an HTTP POST, with the 'real' DELETE
|
|
method hidden behind a request parameter, to be picked up by the
|
|
<classname>HiddenHttpMethodFilter</classname>. The corresponding
|
|
@Controller method is shown below</para>
|
|
|
|
<programlisting language="java">@RequestMapping(method = RequestMethod.DELETE)
|
|
public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
|
|
this.clinic.deletePet(petId);
|
|
return "redirect:/owners/" + ownerId;
|
|
}</programlisting>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="rest-etag">
|
|
<title>ETag support</title>
|
|
|
|
<para>An <ulink
|
|
url="http://en.wikipedia.org/wiki/HTTP_ETag">ETag</ulink> (entity tag)
|
|
is an HTTP response header returned by an HTTP/1.1 compliant web server
|
|
used to determine change in content at a given URL. It can be considered
|
|
to be the more sophisticated successor to the
|
|
<literal>Last-Modified</literal> header. When a server returns a
|
|
representation with an ETag header, the client can use this header in
|
|
subsequent GETs, in an <literal>If-None-Match</literal> header. If the
|
|
content has not changed, the server will return <literal>304: Not
|
|
Modified</literal>.</para>
|
|
|
|
<para>Support for ETags is provided by the servlet filter
|
|
<classname>ShallowEtagHeaderFilter</classname>. Since it is a plain
|
|
Servlet Filter, and thus can be used in combination with any web
|
|
framework. The <classname>ShallowEtagHeaderFilter</classname> filter
|
|
creates so-called shallow ETags (as opposed to deep ETags, more about
|
|
that later). The way it works is quite simple: the filter simply caches
|
|
the content of the rendered JSP (or other content), generates an MD5
|
|
hash over that, and returns that as an ETag header in the response. The
|
|
next time a client sends a request for the same resource, it uses that
|
|
hash as the <literal>If-None-Match</literal> value. The filter notices
|
|
this, renders the view again, and compares the two hashes. If they are
|
|
equal, a <literal>304</literal> is returned. It is important to note
|
|
that this filter will not save processing power, as the view is still
|
|
rendered. The only thing it saves is bandwidth, as the rendered response
|
|
is not sent back over the wire.</para>
|
|
|
|
<para>Deep ETags are a bit more complicated. In this case, the ETag is
|
|
based on the underlying domain objects, RDMBS tables, etc. Using this
|
|
approach, no content is generated unless the underlying data has
|
|
changed. Unfortunately, implementing this approach in a generic way is
|
|
much more difficult than shallow ETags. Spring may provide support for
|
|
deep ETags in a later release by relying on JPA's @Version annotation,
|
|
or an AspectJ aspect.</para>
|
|
</section>
|
|
|
|
<section id="rest-exception">
|
|
<title>Exception Handling</title>
|
|
|
|
<para>The <classname>@ExceptionHandler</classname> method annotation is
|
|
used within a controller to specify which method will be invoked when an
|
|
exception of a specific type is thrown during the execution of
|
|
controller methods. For example</para>
|
|
|
|
<programlisting language="java">@Controller
|
|
public class SimpleController {
|
|
|
|
// other controller method omitted
|
|
|
|
@ExceptionHandler(IOException.class)
|
|
public String handleIOException(IOException ex, HttpServletRequest request) {
|
|
return ClassUtils.getShortName(ex.getClass());
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>will invoke the 'handlerIOException' method when a
|
|
<classname>java.io.IOException</classname> is thrown.</para>
|
|
|
|
<para>The <classname>@ExceptionHandler</classname> value can be set to
|
|
an array of Exception types. If an exception is thrown matches one of
|
|
the types in the list, then the method annotated with the matching
|
|
<classname>@ExceptionHandler</classname> will be invoked. If the
|
|
annotation value is not set then the exception types listed as method
|
|
arguments are used.</para>
|
|
|
|
<para>Much like standard controller methods annotated with a
|
|
<classname>@RequestMapping</classname> annotation, the method arguments
|
|
and return values of <classname>@ExceptionHandler</classname> methods
|
|
are very flexible. For example, the
|
|
<classname>HttpServletRequest</classname> can be accessed in Servlet
|
|
environments and the <classname>PortletRequest</classname> in Portlet
|
|
environments. The return type can be a <classname>String</classname>,
|
|
which is interpreted as a view name or a
|
|
<classname>ModelAndView</classname> object. Please refer to the API
|
|
documentation for more details.</para>
|
|
</section>
|
|
|
|
</chapter>
|