﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-&lt;h3 style="font-family: Comic Sans MS"&gt;&lt;font color="#FA1A0A" size="10"&gt;︻┳═一Java&lt;/font&gt;&lt;/h3&gt;-随笔分类-REST</title><link>http://www.blogjava.net/rain1102/category/37654.html</link><description>&lt;br/&gt;&lt;font color="green" style="font-family: 华文行楷;font-size:16px;"&gt;子曰：危邦不入，乱邦不居。天下有道则见，无道则隐。&lt;/font&gt;&lt;font color="#3C1435"&gt;&lt;/font&gt;</description><language>zh-cn</language><lastBuildDate>Fri, 25 Dec 2009 00:58:46 GMT</lastBuildDate><pubDate>Fri, 25 Dec 2009 00:58:46 GMT</pubDate><ttl>60</ttl><item><title>REST in Spring 3: @MVC</title><link>http://www.blogjava.net/rain1102/archive/2009/12/24/307201.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Thu, 24 Dec 2009 11:53:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/12/24/307201.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/307201.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/12/24/307201.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/307201.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/307201.html</trackback:ping><description><![CDATA[<p>In the last couple of years, REST has emerged as a compelling alternative to SOAP/WSDL/WS-*-based distributed architectures. So when we started to plan our work on the next major release of Spring &#8211; version 3.0, it was quite clear to us that we had to focus on making the development of 'RESTful' Web services and applications easier. Now, what is and isn't 'RESTful' could be the topic of a whole new post all together; in this post I'll take a more practical approach, and focus on the features that we added to the @Controller model of Spring MVC.</p>
<h2>A Bit of Background</h2>
<p><em>Ok, I lied: there is some background first. If you really want to learn about the new features, feel free to skip to the <a href="http://blog.springsource.com/2009/03/08/rest-in-spring-3-mvc/#features">next section</a>.</em></p>
<p>For me, work on REST started about two years ago, shortly after reading the highly recommended book <a onclick="javascript:urchinTracker('/outbound/oreilly.com');" href="http://oreilly.com/catalog/9780596529260/index.html">RESTful Web Services</a> from O'Reilly, by Leonard Richardson and Sam Ruby. Initially, I was thinking about adding REST support to <a onclick="javascript:urchinTracker('/outbound/www.springsource.org');" href="http://www.springsource.org/spring-ws">Spring Web Services</a>, but after working a couple of weeks on a prototype, it became clear to me that this wasn't a very good fit. In particular, I found out that I had to copy most of the logic from the Spring-MVC <tt>DispatcherServlet</tt> over to Spring-WS. Clearly, this was not the way to go forward.</p>
<p>Around the same time we introduced the <a href="http://blog.springsource.com/2007/11/14/annotated-web-mvc-controllers-in-spring-25/">annotation-based model of Spring MVC</a>. This model was clearly an improvement to the former, inheritance-based model. Another interesting development at that time was the development of the <a onclick="javascript:urchinTracker('/outbound/jcp.org');" href="http://jcp.org/en/jsr/detail?id=311">JAX-RS</a> specification. My next attempt was to try and merge these two models: to try and combine the @MVC annotations with the JAX-RS annotations, and to be able to run JAX-RS applications within the <tt>DispatcherServlet</tt>. While I did get a working prototype out of this effort, the result was not satisfactory. There were a number of technical issues which I won't bore you with, but most importantly the approach felt 'clunky' and unnatural for a developer who was already used to Spring MVC 2.5.</p>
<p>Finally, we decided to add the RESTful functionality to features to Spring MVC itself. Obviously, that would mean that there would be some overlap with JAX-RS, but at least the programming model would be satisfactory for Spring MVC developers, both existing and new ones. Additionally, there are already three JAX-RS implementations offering Spring support (<a href="https://jersey.dev.java.net/">Jersey</a>, <a onclick="javascript:urchinTracker('/outbound/www.jboss.org');" href="http://www.jboss.org/resteasy/">RESTEasy</a>, and <a onclick="javascript:urchinTracker('/outbound/www.restlet.org');" href="http://www.restlet.org/">Restlet</a>). Adding a fourth to this list did not seem a good use of our valuable time.</p>
<h2><a name="features" modo="false">RESTful features in Spring MVC 3.0</a></h2>
<p>Now, enough of the background, let's look at the features!</p>
<h3>URI Templates</h3>
<p>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. For more information, see the <a onclick="javascript:urchinTracker('/outbound/bitworking.org');" href="http://bitworking.org/projects/URI-Templates/">proposed RFC</a>.</p>
<p>In Spring 3.0 M1, we introduced the use of URI templates through the <tt>@PathVariable</tt> annotation. For instance:</p>
<div class="syntaxhighlighter " id="highlighter_205437">
<div class="toolbar">&nbsp;</div>
<div class="lines">
<div class="line alt1"><code class="number">1.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="color1">@RequestMapping</code><code class="plain">(</code><code class="string">"/hotels/{hotelId}"</code><code class="plain">) </code></span></span></div>
<div class="line alt2"><code class="number">2.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="keyword">public</code> <code class="plain">String getHotel(</code><code class="color1">@PathVariable</code> <code class="plain">String hotelId, Model model) { </code></span></span></div>
<div class="line alt1"><code class="number">3.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">List&lt;Hotel&gt; hotels = hotelService.getHotels(); </code></span></span></div>
<div class="line alt2"><code class="number">4.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">model.addAttribute(</code><code class="string">"hotels"</code><code class="plain">, hotels); </code></span></span></div>
<div class="line alt1"><code class="number">5.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="keyword">return</code> <code class="string">"hotels"</code><code class="plain">; </code></span></span></div>
<div class="line alt2"><code class="number">6.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">}</code></span></span></div>
</div>
</div>
<p>When a request comes in for <tt>/hotels/1</tt>, that 1 will be bound to the <tt>hotelId</tt> parameter. You can optionally specify the variable name the parameter is bound to, but when you compile your code with debugging enabled that is not necessary: we infer the path variable name from the parameter name.</p>
<p>You can also have more than one path variable, like so:</p>
<div class="syntaxhighlighter " id="highlighter_13061">
<div class="toolbar">&nbsp;</div>
<div class="lines">
<div class="line alt1"><code class="number">1.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="color1">@RequestMapping</code><code class="plain">(value=</code><code class="string">"/hotels/{hotel}/bookings/{booking}"</code><code class="plain">, method=RequestMethod.GET) </code></span></span></div>
<div class="line alt2"><code class="number">2.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="keyword">public</code> <code class="plain">String getBooking(</code><code class="color1">@PathVariable</code><code class="plain">(</code><code class="string">"hotel"</code><code class="plain">) </code><code class="keyword">long</code> <code class="plain">hotelId, </code><code class="color1">@PathVariable</code><code class="plain">(</code><code class="string">"booking"</code><code class="plain">) </code><code class="keyword">long</code> <code class="plain">bookingId, Model model) { </code></span></span></div>
<div class="line alt1"><code class="number">3.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">Hotel hotel = hotelService.getHotel(hotelId); </code></span></span></div>
<div class="line alt2"><code class="number">4.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">Booking booking = hotel.getBooking(bookingId); </code></span></span></div>
<div class="line alt1"><code class="number">5.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">model.addAttribute(</code><code class="string">"booking"</code><code class="plain">, booking); </code></span></span></div>
<div class="line alt2"><code class="number">6.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="keyword">return</code> <code class="string">"booking"</code><code class="plain">; </code></span></span></div>
<div class="line alt1"><code class="number">7.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">}</code></span></span></div>
</div>
</div>
<p>This would match requests like <tt>/hotels/1/bookings/2</tt>, for instance.</p>
<p>You can also combine the use of Ant-style paths and path variables, like so:</p>
<div class="syntaxhighlighter " id="highlighter_8191">
<div class="toolbar">&nbsp;</div>
<div class="lines">
<div class="line alt1"><code class="number">1.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="color1">@RequestMapping</code><code class="plain">(value=</code><code class="string">"/hotels/*/bookings/{booking}"</code><code class="plain">, method=RequestMethod.GET) </code></span></span></div>
<div class="line alt2"><code class="number">2.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="keyword">public</code> <code class="plain">String getBooking(</code><code class="color1">@PathVariable</code><code class="plain">(</code><code class="string">"booking"</code><code class="plain">) </code><code class="keyword">long</code> <code class="plain">bookingId, Model model) { </code></span></span></div>
<div class="line alt1"><code class="number">3.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">... </code></span></span></div>
<div class="line alt2"><code class="number">4.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">}</code></span></span></div>
</div>
</div>
<p>and you can use data binding, too:</p>
<div class="syntaxhighlighter " id="highlighter_311065">
<div class="toolbar">&nbsp;</div>
<div class="lines">
<div class="line alt1"><code class="number">01.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="color1">@InitBinder</code></span></span></div>
<div class="line alt2"><code class="number">02.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="keyword">public</code> <code class="keyword">void</code> <code class="plain">initBinder(WebDataBinder binder) { </code></span></span></div>
<div class="line alt1"><code class="number">03.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">SimpleDateFormat dateFormat = </code><code class="keyword">new</code> <code class="plain">SimpleDateFormat(</code><code class="string">"yyyy-MM-dd"</code><code class="plain">); </code></span></span></div>
<div class="line alt2"><code class="number">04.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">binder.registerCustomEditor(Date.</code><code class="keyword">class</code><code class="plain">, </code><code class="keyword">new</code> <code class="plain">CustomDateEditor(dateFormat, </code><code class="keyword">false</code><code class="plain">)); </code></span></span></div>
<div class="line alt1"><code class="number">05.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">} </code></span></span></div>
<div class="line alt2"><code class="number">06.</code><span class="content"><code class="spaces">&nbsp;</code><span class="block" style="margin-left: 7px! important">&nbsp;</span></span></div>
<div class="line alt1"><code class="number">07.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="color1">@RequestMapping</code><code class="plain">(</code><code class="string">"/hotels/{hotel}/dates/{date}"</code><code class="plain">) </code></span></span></div>
<div class="line alt2"><code class="number">08.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="keyword">public</code> <code class="keyword">void</code> <code class="plain">date(</code><code class="color1">@PathVariable</code><code class="plain">(</code><code class="string">"hotel"</code><code class="plain">) String hotel, </code><code class="color1">@PathVariable</code> <code class="plain">Date date) { </code></span></span></div>
<div class="line alt1"><code class="number">09.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">... </code></span></span></div>
<div class="line alt2"><code class="number">10.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">}</code></span></span></div>
</div>
</div>
<p>The above would match <tt>/hotels/1/dates/2008-12-18</tt>, for instance.</p>
<h3>Content Negotiation</h3>
<p>In version 2.5, Spring-MVC lets the @Controller decide which view to render for a given request, through its <tt>View</tt>, view name, and <tt>ViewResolver</tt> abstractions. In a RESTful scenario, it is common to let the client decide the acceptable representations, via the <tt>Accept</tt> HTTP header. The server responds with the delivered representation via the <tt>Content-Type</tt> header. This process is known as <a onclick="javascript:urchinTracker('/outbound/en.wikipedia.org');" href="http://en.wikipedia.org/wiki/Content_negotiation">content negotiation</a>.</p>
<p>One issue with the <tt>Accept</tt> header is that is impossible to change it in a web browser, in HTML. For instance, in Firefox, it's fixed to</p>
<div class="codesnip-container">Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8</div>
<p>So what if you want to link to a PDF version of a particular resource? Looking at the file extension is a good workaround. For example, <tt>http://example.com/hotels.pdf</tt> retrieves the PDF view of the hotel list, as does <tt>http://example.com/hotels</tt> with an Accept header of <tt>application/pdf</tt>.</p>
<p>This is what the <tt>ContentNegotiatingViewResolver</tt> does: it wraps one or more other <tt>ViewResolver</tt>s, looks at the <tt>Accept</tt> header or file extension, and resolves a view corresponding to these. In an upcoming blog post, Alef Arendsen will show you how to use the <tt>ContentNegotiatingViewResolver</tt>.</p>
<h3>Views</h3>
<p>We also added some new Views to Spring MVC, particularly:</p>
<ul>
    <li>the <a onclick="javascript:urchinTracker('/outbound/static.springsource.org');" href="http://static.springsource.org/spring/docs/3.0.0.M1/javadoc-api/org/springframework/web/servlet/view/feed/AbstractAtomFeedView.html"><tt>AbstractAtomFeedView</tt></a> and <a onclick="javascript:urchinTracker('/outbound/static.springsource.org');" href="http://static.springsource.org/spring/docs/3.0.0.M1/javadoc-api/org/springframework/web/servlet/view/feed/AbstractRssFeedView.html"><tt>AbstractRssFeedView</tt></a>, which can be used to return an Atom and RSS feed,
    <li>the <a onclick="javascript:urchinTracker('/outbound/static.springframework.org');" href="http://static.springframework.org/spring/docs/3.0.0.M2/javadoc-api/org/springframework/web/servlet/view/xml/MarshallingView.html"><tt>MarshallingView</tt></a>, which can be used to return an XML representation. This view is based on the Object/XML Mapping module, which has been copied from the Spring Web Services project. This module wraps XML marshalling technologies such as JAXB, Castor, JiBX, and more, and makes it easier to configure these within a Spring application context,
    <li>the <tt>JacksonJsonView</tt>, for JSON representations of objects in your model. This view is actually part of the Spring JavaScript project, which we'll talk about more in a future blog post. </li>
</ul>
<p>Obviously, these work great in combination with the <tt>ContentNegotiatingViewResolver</tt>!</p>
<h3>HTTP Method Conversion</h3>
<p>Another key principle of REST is the use of the Uniform Interface. Basically, this means that all resources (URLs) can be manipulated using the same four HTTP method: GET, PUT, POST, and DELETE. For each of methods, the HTTP specification defines 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.</p>
<p>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 the <tt>HiddenHttpMethodFilter</tt> does. This filter was introduced in Spring 3.0 M1, and is a plain Servlet Filter. As such, it can be used in combination with any web framework (not just Spring MVC). Simply add this filter to your <tt>web.xml</tt>, and a POST with a hidden <tt>_method</tt> parameter will be converted into the corresponding HTTP method request.</p>
<p>As an extra bonus, we've also added support for method conversion in the Spring MVC form tags. For example, the following snippet taken from the updated Petclinic sample:</p>
<div class="syntaxhighlighter " id="highlighter_354227">
<div class="toolbar">&nbsp;</div>
<div class="lines">
<div class="line alt1"><code class="number">1.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">&lt;</code><code class="keyword">form:form</code> <code class="color1">method</code><code class="plain">=</code><code class="string">"delete"</code><code class="plain">&gt; </code></span></span></div>
<div class="line alt2"><code class="number">2.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="plain">&lt;</code><code class="keyword">p</code> <code class="color1">class</code><code class="plain">=</code><code class="string">"submit"</code><code class="plain">&gt;&lt;</code><code class="keyword">input</code> <code class="color1">type</code><code class="plain">=</code><code class="string">"submit"</code> <code class="color1">value</code><code class="plain">=</code><code class="string">"Delete Pet"</code><code class="plain">/&gt;&lt;/</code><code class="keyword">p</code><code class="plain">&gt; </code></span></span></div>
<div class="line alt1"><code class="number">3.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">&lt;/</code><code class="keyword">form:form</code><code class="plain">&gt;</code></span></span></div>
</div>
</div>
<p>will actually perform an HTTP POST, with the 'real' DELETE method hidden behind a request parameter, to be picked up by the <tt>HiddenHttpMethodFilter</tt>. The corresponding @Controller method is therefore:</p>
<div class="syntaxhighlighter " id="highlighter_172114">
<div class="toolbar">&nbsp;</div>
<div class="lines">
<div class="line alt1"><code class="number">1.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="color1">@RequestMapping</code><code class="plain">(method = RequestMethod.DELETE) </code></span></span></div>
<div class="line alt2"><code class="number">2.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="keyword">public</code> <code class="plain">String deletePet(</code><code class="color1">@PathVariable</code> <code class="keyword">int</code> <code class="plain">ownerId, </code><code class="color1">@PathVariable</code> <code class="keyword">int</code> <code class="plain">petId) { </code></span></span></div>
<div class="line alt1"><code class="number">3.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="keyword">this</code><code class="plain">.clinic.deletePet(petId); </code></span></span></div>
<div class="line alt2"><code class="number">4.</code><span class="content"><code class="spaces">&nbsp;&nbsp;&nbsp;&nbsp;</code><span class="block" style="margin-left: 28px! important"><code class="keyword">return</code> <code class="string">"redirect:/owners/"</code> <code class="plain">+ ownerId; </code></span></span></div>
<div class="line alt1"><code class="number">5.</code><span class="content"><span class="block" style="margin-left: 0px! important"><code class="plain">}</code></span></span></div>
</div>
</div>
<h3>ETag support</h3>
<p>An <a onclick="javascript:urchinTracker('/outbound/en.wikipedia.org');" href="http://en.wikipedia.org/wiki/HTTP_ETag">ETag</a> (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 <tt>Last-Modified</tt> header. When a server returns a representation with an ETag header, client can use this header in subsequent GETs, in a <tt>If-None-Match</tt> header. If the content has not changed, the server will return <tt>304: Not Modified</tt>.</p>
<p>In Spring 3.0 M1, we introduced the <tt>ShallowEtagHeaderFilter</tt>. This is a plain Servlet Filter, and thus can be used in combination any web framework. As the name indicates, the filter creates so-called <em>shallow</em> ETags (as opposed to a 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 a MD5 hash over that, and returns that as a <tt>ETag</tt> header in the response. The next time a client sends a request for the same resource, it use that hash as the <tt>If-None-Match</tt> value. The filter notices this, renders the view again, and compares the two hashes. If they are equal, a 304 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 <strong>bandwith</strong>, as the rendered response is not sent back over the wire.</p>
<p><em>Deep</em> 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. We might add support for deep ETags in a later version of Spring, by relying on JPA's @Version annotation, or an AspectJ aspect for instance.</p>
<h2>And more!</h2>
<p>In a following post, I will conclude my RESTful journey, and talk about the <tt>RestTemplate</tt>, which was also introduced in Spring 3.0 M2. This class gives you client-side access to RESTful resources in a fashion similar to the <tt>JdbcTemplate</tt>, <tt>JmsTemplate</tt>, etc.<br />
</p>
<h2>Similar Posts</h2>
<ul class="similar-posts">
    <li><a title="March 27, 2009" href="http://blog.springsource.com/2009/03/27/rest-in-spring-3-resttemplate/" rel="bookmark">REST in Spring 3: RestTemplate</a>
    <li><a title="March 16, 2009" href="http://blog.springsource.com/2009/03/16/adding-an-atom-view-to-an-application-using-springs-rest-support/" rel="bookmark">Adding an Atom view to an application using Spring's REST support</a>
    <li><a title="July 10, 2009" href="http://blog.springsource.com/2009/07/10/pluggable-styling-with-springsource-slices/" rel="bookmark">Pluggable styling with SpringSource Slices</a>
    <li><a title="March 29, 2007" href="http://blog.springsource.com/2007/03/29/aop-context-binding/" rel="bookmark">AOP Context Binding With Named Pointcuts</a>
    <li><a title="November 14, 2007" href="http://blog.springsource.com/2007/11/14/annotated-web-mvc-controllers-in-spring-25/" rel="bookmark">Annotated Web MVC Controllers in Spring 2.5</a> </li>
</ul>
<br />
<br />
原文地址：http://blog.springsource.com/2009/03/08/rest-in-spring-3-mvc/<img src ="http://www.blogjava.net/rain1102/aggbug/307201.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2009-12-24 19:53 <a href="http://www.blogjava.net/rain1102/archive/2009/12/24/307201.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring MVC Annotation &amp; Convention Over Configuration</title><link>http://www.blogjava.net/rain1102/archive/2009/01/07/250410.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Wed, 07 Jan 2009 13:43:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2009/01/07/250410.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/250410.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2009/01/07/250410.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/250410.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/250410.html</trackback:ping><description><![CDATA[<p>Spring MVC在使用annotation进行配置controller时候要注意：两种urlmapping的模式不能同时使用，如果使用annotation就不能再配置urlmapping了。</p>
&lt;action&gt;-servlet.xml如下：<br />
<p><span style="color: #008000">&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />
&lt;beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />
&nbsp;&nbsp;xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"<br />
&nbsp;&nbsp;xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd<br />
&nbsp;&nbsp;&nbsp;&nbsp;http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"&gt;</span></p>
<p><span style="color: #008000">&nbsp;&lt;!--&nbsp;对com.founder.action包中的所有类进行扫描，以完成Bean创建和自动依赖注入的功能 --&gt;<br />
&nbsp;&lt;context:component-scan base-package="com.founder.action"/&gt;<br />
&nbsp;<br />
&lt;!--&nbsp;启动Spring MVC的注解功能，完成请求和注解POJO的映射 --&gt;<br />
&nbsp;&lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/&gt;<br />
&nbsp;<br />
&lt;!--把请求的URL映射到Controller的name上面 --&gt;<br />
&nbsp;&lt;bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/&gt;&nbsp; <br />
&nbsp;&nbsp; <br />
&nbsp;&lt;!-- 对模型视图名称的解析，即在模型视图名称添加前后缀--&gt;<br />
&nbsp;&lt;bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;<br />
&nbsp;&nbsp;&lt;property name="viewClass"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;value&gt;org.springframework.web.servlet.view.JstlView&lt;/value&gt;<br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&nbsp;&lt;property name="prefix"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;/jsp/&lt;/value&gt; <br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&nbsp;&lt;property name="suffix"&gt;<br />
&nbsp;&nbsp;&nbsp;&lt;value&gt;.jsp&lt;/value&gt;<br />
&nbsp;&nbsp;&lt;/property&gt;<br />
&nbsp;&lt;/bean&gt;<br />
<br />
&lt;/beans&gt;</span></p>
<br />
<p>package com.founder.action;</p>
<p>import org.springframework.stereotype.Controller;<br />
import org.springframework.web.bind.annotation.RequestMapping;<br />
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;<br />
</p>
<p><br />
@Controller<br />
@RequestMapping<br />
public class HelloController{<br />
&nbsp;@RequestMapping<br />
&nbsp;public String world(){<br />
&nbsp;&nbsp;String name = "Eric";<br />
&nbsp;&nbsp;System.out.println("name is = " + name);<br />
&nbsp;&nbsp;return "hello";<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;@RequestMapping<br />
&nbsp;public String test() {<br />
&nbsp;&nbsp;String name = "test";<br />
&nbsp;&nbsp;System.out.println("name is = " + name);<br />
&nbsp;&nbsp;return "test";<br />
&nbsp;}<br />
&nbsp;<br />
}<br />
</p><img src ="http://www.blogjava.net/rain1102/aggbug/250410.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2009-01-07 21:43 <a href="http://www.blogjava.net/rain1102/archive/2009/01/07/250410.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入浅出REST[转载]</title><link>http://www.blogjava.net/rain1102/archive/2008/11/27/243016.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Thu, 27 Nov 2008 08:05:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2008/11/27/243016.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/243016.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2008/11/27/243016.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/243016.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/243016.html</trackback:ping><description><![CDATA[<p>作者 <strong>Stefan Tilkov</strong>译者 <strong>苑永凯</strong> 发布于 2007年12月25日 下午10时10分 </p>
<p>不知你是否意识到，围绕着什么才是实现异构的应用到应用通信的&#8220;正确&#8221;方式，一场争论正进行的如火如荼：虽然当前主流的方式明显地集中在基于SOAP、WSDL和WS-*规范的Web Services领域，但也有少数人用细小但洪亮的声音主张说更好的方式是REST，表述性状态转移（REpresentational State Transfer）的简称。在本文中，我不会涉及争论的话题，而是尝试对REST和RESTful HTTP应用集成做实用性的介绍。以我的经验，有些话题一旦触及就会引来众多的讨论，当涉及到这方面话题的时候，我会深入详细地阐述。</p>
<h2>REST关键原则</h2>
<p>大部分对REST的介绍是以其正式的定义和背景作为开场的。但这儿且先按下不表，我先提出一个简单扼要的定义：REST定义了应该如何正确地使用（这和大多数人的实际使用方式有很大不同）Web标准，例如HTTP和URI。如果你在设计应用程序时能坚持REST原则，那就预示着你将会得到一个使用了优质Web架构（这将让你受益）的系统。总之，五条关键原则列举如下：</p>
<ul>
    <li>为所有&#8220;事物&#8221;定义ID
    <li>将所有事物链接在一起
    <li>使用标准方法
    <li>资源多重表述
    <li>无状态通信 </li>
</ul>
<p>下面让我们进一步审视这些原则。</p>
<h2>为所有&#8220;事物&#8221;定义ID </h2>
<p>在这里我使用了&#8220;事物&#8221;来代替更正式准确的术语&#8220;资源&#8221;，因为一条如此简单的原则，不应该被淹没在术语当中。思考一下人们构建的系统，通常会找到一系列值得被标识的关键抽象。每个事物都应该是可标识的，都应该拥有一个明显的ID——在Web中，代表ID的统一概念是：URI。URI构成了一个全局命名空间，使用URI标识你的关键资源意味着它们获得了一个唯一、全局的ID。 </p>
<p>对事物使用一致的命名规则（naming scheme）最主要的好处就是你不需要提出自己的规则——而是依靠某个已被定义，在全球范围中几乎完美运行，并且能被绝大多数人所理解的规则。想一下你构建的上一个应用（假设它不是采用RESTful方式构建的）中的任意一个高级对象（high-level object），那就很有可能看到许多从使用唯一标识中受益的用例。比如，如果你的应用中包含一个对顾客的抽象，那么我可以相当肯定，用户会希望将一个指向某个顾客的链接，能通过电子邮件发送到同事那里，或者加入到浏览器的书签中，甚至写到纸上。更透彻地讲：如果在一个类似于Amazon.com的在线商城中，没有用唯一的ID（一个URI）标识它的每一件商品，可想而知这将是多么可怕的业务决策。</p>
<p>当面对这个原则时，许多人惊讶于这是否意味着需要直接向外界暴露数据库记录（或者数据库记录ID）——自从多年以来面向对象的实践告诫我们，要将持久化的信息作为实现细节隐藏起来之后，哪怕是刚有点想法都常会使人惊恐。但是这条原则与隐藏实现细节两者之间并没有任何冲突：通常，值得被URI标识的事物——资源——要比数据库记录抽象的多。例如，一个定单资源可以由定单项、地址以及许多其它方面（可能不希望作为单独标识的资源暴露出来）组成。标识所有值得标识的事物，领会这个观念可以进一步引导你创造出在传统的应用程序设计中不常见的资源：一个流程或者流程步骤、一次销售、一次谈判、一份报价请求——这都是应该被标识的事物的示例。同样，这也会导致创建比非RESTful设计更多的持久化实体。 </p>
<p>下面是一些你可能想到的URI的例子：</p>
<pre>http://example.com/customers/1234<br />
http://example.com/orders/2007/10/776654<br />
http://example.com/products/4554<br />
http://example.com/processes/salary-increase-234 </pre>
<p>正如我选择了创建便于阅读的URI——这是个有用的观点，尽管不是RESTful设计所必须的——应该能十分容易地推测出URI的含义：它们明显地标识着单一&#8220;数据项&#8221;。但是再往下看：</p>
<pre>http://example.com/orders/2007/11<br />
http://example.com/products?color=green </pre>
<p>首先，这两个URI看起来与之前的稍有不同——毕竟，它们不是对一件事物的标识，而是对一类事物集合的标识（假定第一个URI标识了所有在2007年11月份提交的定单，第二个则是绿颜色产品的集合）。但是这些集合自身也是事物（资源），也应该被标识。</p>
<p>注意，使用唯一、全局统一的命名规则的好处，既适用于浏览器中的Web应用，也适用于机对机（machine-to-machine，m2m）通信。</p>
<p>来对第一个原则做下总结：使用URI标识所有值得标识的事物，特别是应用中提供的所有&#8220;高级&#8221;资源，无论这些资源代表单一数据项、数据项集合、虚拟亦或实际的对象还是计算结果等。</p>
<h2>将所有事物链接在一起 </h2>
<p>接下来要讨论的原则有一个有点令人害怕的正式描述：&#8220;超媒体被当作应用状态引擎（Hypermedia as the engine of application state）&#8221;，有时简写为HATEOAS。（严格地说，这不是我说的。）这个描述的核心是<strong>超媒体</strong>概念，换句话说：是<strong>链接</strong>的思想。链接是我们在HTML中常见的概念，但是它的用处绝不局限于此（用于人们网络浏览）。考虑一下下面这个虚构的XML片段： </p>
<pre><order self="http://example.com/customers/1234">&lt;order self="http://example.com/customers/1234"&gt; <br />
&nbsp;&lt;amount&gt;23&lt;/amount&gt;<br />
&nbsp;&lt;product ref="http://example.com/products/4554"&gt;<br />
&nbsp; &lt;customer ref="http://example.com/customers/1234"&gt;<br />
&nbsp; &lt;/customer&gt;<br />
&nbsp;&lt;/product&gt;<br />
&lt;/order&gt;   <customer ref="http://example.com/customers/1234"> <br />
</customer> </pre>
如果你观察文档中product和customer的链接，就可以很容易地想象到，应用程序（已经检索过文档）如何&#8220;跟随&#8221;链接检索更多的信息。当然，如果使用一个遵守专用命名规范的简单&#8220;id&#8221;属性作为链接，
也是可行的——<strong>但是仅限于应用环境之内</strong>。使用URI表示链接的优雅之处在于，链接可以指向由不同应用、不同服务器甚至位于另一个大陆上的不同公司提供的资源——因为URI命名规范是全球标准，构成Web的所有资源都可以互联互通。
<p>超媒体原则还有一个更重要的方面——应用&#8220;状态&#8221;。简而言之，实际上服务器端（如果你愿意，也可以叫服务提供者）为客户端（服务消费者）提供一组链接，使客户端能通过链接将应用从一个状态改变为另一个状态。稍后我们会在另一篇文章中探究这个方面的影响；目前，只需要记住：链接是构成动态应用的非常有效的方式。</p>
<p>对此原则总结如下：任何可能的情况下，使用链接指引可以被标识的事物（资源）。也正是超链接造就了现在的Web。</p>
<h2>使用标准方法 </h2>
<p>在前两个原则的讨论中暗含着一个假设：接收URI的应用程序可以通过URI明确地<strong>做</strong>一些有意义的事情。如果你在公共汽车上看到一个URI，你可以将它输入浏览器的地址栏中并回车——但是你的浏览器如何知道需要对这个URI做些什么呢？</p>
<p>它知道如何去处理URI的原因在于所有的资源都支持同样的接口，一套同样的方法（只要你乐意，也可以称为操作）集合。在HTTP中这被叫做动词（verb），除了两个大家熟知的（GET和POST）之外，标准方法集合中还包含PUT、DELETE、HEAD和OPTIONS。这些方法的含义连同行为许诺都一起定义在HTTP规范之中。如果你是一名OO开发人员，就可以想象到RESTful HTTP方案中的所有资源都继承自类似于这样的一个类（采用类Java、C#的伪语法描述，请注意关键的方法）：</p>
<pre>class Resource {<br />
Resource(URI u);<br />
Response get();<br />
Response post(Request r);<br />
Response put(Request r);<br />
Response delete();<br />
} </pre>
<p>由于所有资源使用了同样的接口，你可以依此使用GET方法检索一个<strong>表述</strong>（representation）——也就是对资源的描述。因为规范中定义了GET的语义，所以可以肯定当你调用它的时候不需要对后果负责——这就是为什么可以&#8220;安全&#8221;地调用此方法。GET方法支持非常高效、成熟的缓存，所以在很多情况下，你甚至不需要向服务器发送请求。还可以肯定的是，GET方法具有<strong>幂等性</strong>[译注：指多个相同请求返回相同的结果]——如果你发送了一个GET请求没有得到结果，你可能不知道原因是请求未能到达目的地，还是响应在反馈的途中丢失了。幂等性保证了你可以简单地再发送一次请求解决问题。幂等性同样适用于PUT（基本的含义是&#8220;更新资源数据，如果资源不存在的话，则根据此URI创建一个新的资源&#8221;）和DELETE（你完全可以一遍又一遍地操作它，直到得出结论——删除不存在的东西没有任何问题）方法。POST方法，通常表示&#8220;创建一个新资源&#8221;，也能被用于调用任意过程，因而它既不安全也不具有幂等性。</p>
<p>如果你采用RESTful的方式暴露应用功能（如果你乐意，也可以称为服务功能），<strong>那这条原则和它的约束同样也适用于你</strong>。如果你已经习惯于另外的设计方式，则很难去接受这条原则——毕竟，你很可能认为你的应用包含了超出这些操作表达范围的逻辑。请允许我花费一些时间来让你相信不存在这样的情况。 </p>
<p>来看下面这个简单的采购方案例子： </p>
<p><img alt="Sample Scenario" src="http://www.infoq.com/resource/articles/rest-introduction/zh/resources/figure1.jpg" width="200" _href="img://figure1.jpg" /></p>
<p>可以看到，例子中定义了两个服务程序（没有包含任何实现细节）。这些服务程序的接口都是为了完成任务（正是我们讨论的OrderManagement和CustomerManagement服务）而定制的。如果客户端程序试图使用这些服务，那它必须针对这些特定接口进行编码——不可能在这些接口定义之前，使用客户程序去有目的地和接口协作。这些接口定义了服务程序的应用协议（application protocol）。</p>
<p>在RESTful HTTP方式中，你将通过组成<strong>HTTP应用协议</strong>的通用接口访问服务程序。你可能会想出像这样的方式：</p>
<p><img alt="Sample Scenario, done RESTfully" src="http://www.infoq.com/resource/articles/rest-introduction/zh/resources/figure2.jpg" width="400" _href="img://figure2.jpg" /></p>
<p>可以看到，服务程序中的特定操作被映射成为标准的HTTP方法——为了消除歧义，我创建了一组全新的资源。&#8220;这是骗人的把戏&#8221;，我听见你叫嚷着。不，这不是欺骗。标识一个顾客的URI上的GET方法正好相当于getCustomerDetails操作。有人用三角形形象化地说明了这一点：</p>
<p><img alt="Knobs one can turn" src="http://www.infoq.com/resource/articles/rest-introduction/zh/resources/figure3.jpg" width="200" _href="img://figure3.jpg" /></p>
<p>把三个顶点想象为你可以调节的按钮。可以看到在第一种方法中，你拥有许多操作，许多种类的数据以及固定数量的&#8220;实例&#8221;（本质上和你拥有的服务程序数量一致）。在第二种方法中，你拥有固定数量的操作，许多种类的数据和许多调用固定方法的对象。它的意义在于，证明了通过这两种方式，你基本上可以表示任何你喜欢的事情。</p>
<p>为什么使用标准方法如此重要？从根本上说，它使你的应用成为Web的一部分——应用程序为Web变成Internet上最成功的应用所做的贡献，与它添加到Web中的资源数量成比例。采用RESTful方式，一个应用可能会向Web中添加数以百万计的客户URI；如果采用CORBA技术并维持应用的原有设计方式，那它的贡献大抵只是一个&#8220;端点（endpoint）&#8221;——就好比一个非常小的门，仅仅允许有钥匙的人进入其中的资源域。</p>
<p>统一接口也使得所有理解HTTP应用协议的组件能与你的应用交互。通用客户程序（generic client）就是从中受益的组件的例子，例如curl、wget、代理、缓存、HTTP服务器、网关还有Google、Yahoo!、MSN等等。 </p>
<p>总结如下：为使客户端程序能与你的资源相互协作，资源应该正确地实现默认的应用协议（HTTP），也就是使用标准的GET、PUT、POST和DELETE方法。</p>
<h2>资源多重表述 </h2>
<p>到目前为止我们一直忽略了一个稍微复杂的问题：客户程序如何知道该怎样处理检索到的数据，比如作为GET或者POST请求的结果？原因是，HTTP采取的方式是允许数据处理和操作调用之间关系分离的。换句话说，如果客户程序知道如何处理一种特定的数据格式，那就可以与所有提供这种表述格式的资源交互。让我们再用一个例子来阐明这个观点。利用HTTP内容协商（content negotiation），客户程序可以请求一种特定格式的表述：</p>
<pre>GET /customers/1234 HTTP/1.1<br />
Host: example.com <br />
Accept: application/vnd.mycompany.customer+xml  </pre>
<p>请求的结果可能是一些由公司专有的XML格式表述的客户信息。假设客户程序发送另外一个不同的请求，就如下面这样：</p>
<pre>GET /customers/1234 HTTP/1.1<br />
Host: example.com <br />
Accept: text/x-vcard </pre>
<p>结果则可能是VCard格式的客户地址。（在这里我没有展示响应的内容，在其HTTP Content-type头中应该包含着关于数据类型的元数据。）这说明为什么理想的情况下，资源表述应该采用标准格式——如果客户程序对HTTP应用协议和一组数据格式都有所&#8220;了解&#8221;，那么它就可以用一种有意义的方式<strong>与世界上任意一个RESTful HTTP应用交互</strong>。不幸的是，我们不可能拿到所有东西的标准格式，但是，或许我们可以想到在公司或者一些合作伙伴中使用标准格式来营造一个小环境。当然以上情况不仅适用于从服务器端到客户端的数据，反之既然——倘若从客户端传来的数据符合应用协议，那么服务器端就可以使用特定的格式处理数据，而不去关心客户端的类型。 </p>
<p id="scroll_to_here">在实践中，资源多重表述还有着其它重要的好处：如果你为你的资源提供HTML和XML两种表述方式，那这些资源不仅可以被你的应用所用，还可以被任意标准Web浏览器所用——也就是说，你的应用信息可以被所有会使用Web的人获取到。</p>
<p>资源多重表述还有另外一种使用方式：你可以将应用的Web UI纳入到Web API中——毕竟，API的设计通常是由UI可以提供的功能驱动的，而UI也是通过API执行动作的。将这两个任务合二为一带来了令人惊讶的好处，这使得使用者和调用程序都能得到更好的Web接口。</p>
<p>总结：针对不同的需求提供资源多重表述。</p>
<h2>无状态通信</h2>
<p><strong>无状态通信</strong>是我要讲到的最后一个原则。首先，需要着重强调的是，虽然REST包含无状态性（statelessness）的观念，但这并不是说暴露功能的应用不能有状态——<br />
事实上，在大部分情况下这会导致整个做法没有任何用处。REST要求状态要么被放入资源状态中，要么保存在客户端上。或者换句话说，服务器端不能保持除了单次请求之外的，任何与其通信的客户端的通信状态。这样做的最直接的理由就是可伸缩性—— 如果服务器需要保持客户端状态，那么大量的客户端交互会严重影响服务器的内存可用空间（footprint）。（注意，要做到无状态通信往往需要需要一些重新设计——不能简单地将一些session状态绑缚在URI上，然后就宣称这个应用是RESTful。）</p>
<p>但除此以外，其它方面可能显得更为重要：无状态约束使服务器的变化对客户端是不可见的，因为在两次连续的请求中，客户端并不依赖于同一台服务器。一个客户端从某台服务器上收到一份包含链接的文档，当它要做一些处理时，这台服务器宕掉了，可能是硬盘坏掉而被拿去修理，可能是软件需要升级重启——如果这个客户端访问了从这台服务器接收的链接，它不会察觉到后台的服务器已经改变了。</p>
<h2>理论上的REST</h2>
<p>我承认：以上我所说的REST不是真正的REST，而且我可能有点过多地热衷于简单化。但因为我想有一个与众不同的开场，所以没有在一开始就介绍其正式的定义和背景。现在就让我们稍微简要地介绍一下这方面的内容。</p>
<p>首先，先前我并没有明确地区分HTTP、RESTful HTTP和REST。要理解这些不同方面之间的关系，我们要先来看看REST的历史。</p>
<p><a title="Roy T. Fielding" href="http://www.ics.uci.edu/~fielding/">Roy T. Fielding</a>在他的<a id="ewd-" title="博士学位论文" href="http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm">博士学位论文</a>（实际上你应该访问这个链接——至少对于一篇学术论文来说，它是相当易读的。此论文已被翻译成<a id="nev8" title="中文" href="http://www.redsaga.com/opendoc/REST_cn.pdf">中文</a>）中定义了术语REST。Roy曾是许多基本Web协议的主要设计者，其中包括HTTP和URIs，并且他在论文中对这些协议提出了很多想法。（这篇论文被誉为&#8220;REST圣经&#8221;，这是恰当的——毕竟，是作者发明了这个术语，所以在定义上，他写的任何内容都被认为是权威的。）在论文中，Roy首先定义一种方法论来谈论<strong>架构风格</strong>——高级、抽象的模式，来表达架构方法背后的核心理念。每一个架构风格由一系列的<strong>约束</strong>（constraints）定义形成。架构风格的例子包括&#8220;没有风格&#8221;（根本没有任何约束）、管道和过滤器（pipe and filter）、客户端/服务器、分布式对象以及——你猜到它了——REST。</p>
<p>如果对你来说这些听起来都太抽象了，那就对了——REST在本质上是一个可以被许多不同技术实现的高层次的风格，而且可以被实例化——通过为它的抽象特性赋上不同的值。比如，REST中包含资源和统一接口的概念——也就是说，所有资源都应该对这些相同的方法作出反应。但是REST并没有说明是哪些方法，或者有多少方法。</p>
<p>REST风格的一个&#8220;化身&#8221;便是HTTP（以及一套相关的一套标准，比如URI），或者稍微抽象一些：Web架构自身。接着上面的例子，HTTP使用HTTP动词作为REST统一接口的&#8220;实例&#8221;。由于Fielding是在Web已经（或者至少是大部分）&#8220;完善&#8221;了之后才定义的REST风格，有人可能会争论两者是不是100%的匹配。但是无论如何，整体上来说Web、HTTP和URI仅仅是REST风格的一个主要实现。不过，由于Roy Fielding即是REST论文的作者，又对Web架构设计有过深远的影响，两者相似也在情理之中。</p>
<p>最后，我在前面一次又一次地使用着术语&#8220;RESTful HTTP&#8221;，原因很简单：许多使用HTTP的应用因为一些理由并没有遵循REST原则，有人会说使用HTTP而不遵循REST原则就等同于滥用HTTP。当然这听起来有点狂热——事实上违反REST约束的原因通常是，仅仅因为每个约束带来的设计权衡可能不适合于一些特殊情况。但通常，违背REST约束的原因可归咎于对其好处认知的缺乏。来看一个明显的反面案例：使用HTTP GET调用类似于删除对象的操作，这违反了REST的安全约束和一般性常识（客户程序不应为此负责，服务器端开发人员大概不是有意而为之）。但在随后的文章中，我会提及更多这样或那样的对HTTP的滥用。</p>
<h2>总结 </h2>
<p>本文试图对REST（Web架构）背后的概念提供快速的介绍。RESTful HTTP暴露功能的方式与RPC、分布式对象以及Web Services是不相同的；要真正理解这些不同是需要一些心态的转变。不管你构建的应用是仅仅想暴露Web UI还是想把API变成Web的一份子，了解下REST的原则还是有好处的。</p>
<p><a href="http://www.innoq.com/blog/st/"><strong>Stefan Tilkov</strong></a><strong>是InfoQ SOA社区的首席编辑，并且是位于德国和瑞士的</strong><a id="hdph" title="innoQ" href="http://www.innoq.com/"><strong>innoQ</strong></a><strong>公司的共同创始人、首席顾问和REST狂热分子首领。</strong> </p>
<strong>查看英文原文</strong>：<a id="mxm5" title="A Brief Introduction to REST" href="http://www.infoq.com/articles/rest-introduction">A Brief Introduction to REST</a><img src ="http://www.blogjava.net/rain1102/aggbug/243016.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2008-11-27 16:05 <a href="http://www.blogjava.net/rain1102/archive/2008/11/27/243016.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于REST的一点想法[转载]</title><link>http://www.blogjava.net/rain1102/archive/2008/11/25/242524.html</link><dc:creator>Eric.Zhou</dc:creator><author>Eric.Zhou</author><pubDate>Tue, 25 Nov 2008 05:29:00 GMT</pubDate><guid>http://www.blogjava.net/rain1102/archive/2008/11/25/242524.html</guid><wfw:comment>http://www.blogjava.net/rain1102/comments/242524.html</wfw:comment><comments>http://www.blogjava.net/rain1102/archive/2008/11/25/242524.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/rain1102/comments/commentRss/242524.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/rain1102/services/trackbacks/242524.html</trackback:ping><description><![CDATA[这阵子正打算用Rails做个东东，所以开始系统地学习起了Rails。巧合的是，大概两周前，dlee邀请我加入Fielding博士关于REST的那篇论文的翻译团队。可以说Rails和REST这两个最热门的词汇几乎同时挤入了我的生活。随着我对Rails的学习和对[Fielding]的翻译，我也开始对REST产生了一些不太成熟的想法，写在这里与大家分享，同时也起到抛砖引玉的作用，欢迎大家讨论。<br />
<br />
先复习一下REST的基本思想。[Fielding]把REST形式化地定义为一种架构风格（architecture style），它有架构元素（element）和架构约束（constraint）组成。这些概念比较晦涩难懂，而且我们做工程的往往并不需要形而上的理解。我们只知道，REST是一种针对网络应用的设计和开发方式，可以降低开发的复杂性，提高系统的可伸缩性。REST提出了一些设计概念和准则：<br />
<ol>
    <li>网络上的所有事物都被抽象为资源（resource）；
    <li>每个资源对应一个唯一的资源标识（resource identifier）；
    <li>通过通用的连接器接口（generic connector interface）对资源进行操作；
    <li>对资源的各种操作不会改变资源标识；
    <li>所有的操作都是无状态的（stateless）。 </li>
</ol>
对于当今最常见的网络应用来说，resource identifier是url，generic connector interface是HTTP，第4条准则就是我们常说的url不变性。这些概念中的resouce最容易使人产生误解。resouce所指的并不是数据，而是数据+特定的表现形式（representation），这也是为什么REST的全名是Representational State Transfer的原因。举个例子来说，&#8220;本月卖得最好的10本书&#8221;和&#8220;你最喜欢的10本书&#8221;在数据上可能有重叠（有一本书即卖得好，你又喜欢），甚至完全相同。但是它们的representation不同，因此是不同的resource。<br />
<br />
REST之所以能够简化开发，是因为其引入的架构约束，比如Rails 1.2中对REST的实现默认把controller中的方法限制在7个：index、show、new、edit、create、update和destory，这实际上就是对CURD的实现。更进一步讲，Rails（也是当今大部分网络应用）使用HTTP作为generic connector interface，HTTP则把对一个url的操作限制在了4个之内：GET、POST、PUT和DELETE。<br />
<br />
REST之所以能够提高系统的可伸缩性，是因为它强制所有操作都是stateless的，这样就没有context的约束，如果要做分布式、做集群，就不需要考虑context的问题了。同时，它令系统可以有效地使用pool。REST对性能的另一个提升来自其对client和server任务的分配：server只负责提供resource以及操作resource的服务，而client要根据resource中的data和representation自己做render。这就减少了服务器的开销。<br />
<br />
既然REST有这样的好处，那我们应该义无反顾地拥抱它啊！目前一些大牛（像DHH）都已经开始投入到了REST的世界，那我们这些人应该做什么或者说思考写什么你呢？我觉得我们应该思考两个问题：<br />
<ol>
    <li>如何使用REST；
    <li>REST和MVC的关系。 </li>
</ol>
<p>第一个问题假设REST是我们应该采用的架构，然后讨论如何使用；第二个问题则要说明REST和当前最普遍应用的MVC是什么关系，互补还是取代？<br />
<br />
我们先来谈谈第一个问题，如何使用REST。我感觉，REST除了给我们带来了一个崭新的架构以外，还有一个重要的贡献是在开发系统过程中的一种新的思维方式：通过url来设计系统的结构。根据REST，每个url都代表一个resource，而整个系统就是由这些resource组成的。因此，如果url是设计良好的，那么系统的结构就也应该是设计良好的。对于非高手级的开发人员来说，考虑一个系统如何架构总是一个很抽象的问题。敏捷开发所提倡的Test Driven Development，其好处之一（我觉得是最大的好处）就是可以通过testcase直观地设计系统的接口。比如在还没有创建一个class的时候就编写一个testcase，虽然设置不能通过编译，但是testcase中的方法调用可以很好地从class使用者的角度反映出需要的接口，从而为class的设计提供了直观的表现。这与在REST架构中通过url设计系统结构非常类似。虽然我们连一个功能都没有实现，但是我们可以先设计出我们认为合理的url，这些url甚至不能连接到任何page或action，但是它们直观地告诉我们：系统对用户的访问接口就应该是这样。根据这些url，我们可以很方便地设计系统的结构。<br />
<br />
让我在这里重申一遍：<strong>REST允许我们通过url设计系统，就像Test Driven Development允许我们使用testcase设计class接口一样。<br />
<br />
</strong>OK，既然url有这样的好处，那我们就着重讨论一下如何设计url。网络应用通常都是有hierarchy的，像棵大树。我们通常希望url也能反映出资源的层次性。比如对于一个blog应用：/articles表示所有的文章，/articles/1表示id为1的文章，这都比较直观。遗憾的是，网络应用的资源结构永远不会如此简单。因此人们常常会问这样一个问题：RESTful的url能覆盖所有的用户请求吗？比如，login如何RESTful？search如何RESTful？<br />
<br />
从REST的概念上来看，所有可以被抽象为资源的东东都可以使用RESTful的url。因此对于上面的两个问题，如果login和search可以被抽象为资源，那么就可以使用RESTful的url。search比较简单，因为它会返回搜索结果，因此可以被抽象为资源，并且只实现index方法就可以了（只需要显示搜索结果，没有create、destory之类的东西）。然而这里面也有一个问题：search的关键字如何传给server？index方法显然应该使用HTTP GET，这会把关键字加到url后面，当然不符合REST的风格。要解决这个问题，可以把每次search看作一个资源，因此要创建create和index方法，create用来在用户点击&#8220;搜索&#8221;按钮是通过HTTP POST把关键字传给server，然后index则用来显示搜索结果。这样一来，我们还可以记录用户的搜索历史。使用同样的方法，我们也可以对login应用REST，即每次login动作是一个资源。<br />
<br />
现在，我们来复杂一些的东东。如何用url表达&#8220;category为ruby的article&#8221;？一开始可能想到的是/category/ruby/articles，这种想法很直观。但是我觉得里面的category是不需要的，我们可以直接把&#8220;/ruby&#8221;理解为&#8220;category是ruby&#8221;，也就是说&#8220;ruby&#8221;出现的位置说明了它指的就是category。OK，/ruby/articles，单单从这个url上看，我们能获得多少关于category的信息呢？显然category隐藏在了url后面，这样做到底好不好，应该是仁者见仁，智者见智了。对于如何表达category这样的东西，我还没想出很好的方式，大家有什么好idea，可以一起讨论。<br />
<br />
另外还有一种url形式，它对应到程序中的继承关系。比如product是一个父类，book和computer是其子类。那么所有产品的url应该是/products，所有书籍的url应该是/books，所有电脑的url应该是/computers。这一想法就比较直观了，而且再次验证了url可以帮助我们进行设计的论点。<br />
<br />
让我再说明一下我的想法：<strong>如果每个用户需求都可以抽象为资源，那么就可以完全使用REST。</strong><br />
<br />
由此看来，使用REST的关键是如何抽象资源，抽象得越精确，对REST的应用就越好。因此，如何改变我们目前根深蒂固的基于action的思想是最重要的。<br />
<br />
有了对第一个问题的讨论，第二个问题就容易讨论多了。REST会取代MVC吗？还是彼此是互补关系（就像AOP对于OOP）？答案是It depends！如果我们可以把所有的用户需求都可以抽象为资源，那么MVC就可以退出历史的舞台了。如果情况相反，那么我们就需要混合使用REST和MVC。<br />
<br />
当然，这是非常理想的论断。可能我们无法找到一种方法可以把所有的用户需求都抽象为资源，因为保证这种抽象的完整性（即真的是所有需求都可以）需要形式化的证明。而且即使被证明出来了，由于开发人员的能力和喜好不同，MVC肯定也会成为不少人的首选。但是对于希望拥抱REST的人来说，这些都没有关系。只要你开发的系统所设计的问题域可以被合理地抽象为资源，那么REST就会成为你的开发利器。<br />
<br />
<strong>所以，所有希望拥抱REST的朋友们，赶快训练自己如何带上资源的眼镜看世界吧，这才是REST的核心所在。</strong>&nbsp;</p>
<p>转载自javaeye论坛　作者：AllenYoung</p>
<p>原文地址：<a href="http://www.javaeye.com/topic/70113">http://www.javaeye.com/topic/70113</a></p><img src ="http://www.blogjava.net/rain1102/aggbug/242524.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/rain1102/" target="_blank">Eric.Zhou</a> 2008-11-25 13:29 <a href="http://www.blogjava.net/rain1102/archive/2008/11/25/242524.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>