??xml version="1.0" encoding="utf-8" standalone="yes"?>97久久超碰,久久精品亚洲一区二区三区浴池 ,久草视频视频在线播放http://www.aygfsteel.com/rain1102/category/37654.html<br/><font color="green" style="font-family: 华文行楷;font-size:16px;">子曰Q危邦不入,乱邦不居。天下有道则见,无道则隐?lt;/font><font color="#3C1435"></font>zh-cnFri, 25 Dec 2009 00:58:46 GMTFri, 25 Dec 2009 00:58:46 GMT60REST in Spring 3: @MVChttp://www.aygfsteel.com/rain1102/archive/2009/12/24/307201.htmlEric.ZhouEric.ZhouThu, 24 Dec 2009 11:53:00 GMThttp://www.aygfsteel.com/rain1102/archive/2009/12/24/307201.htmlhttp://www.aygfsteel.com/rain1102/comments/307201.htmlhttp://www.aygfsteel.com/rain1102/archive/2009/12/24/307201.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/307201.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/307201.htmlIn 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 – 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.

A Bit of Background

Ok, I lied: there is some background first. If you really want to learn about the new features, feel free to skip to the next section.

For me, work on REST started about two years ago, shortly after reading the highly recommended book RESTful Web Services from O'Reilly, by Leonard Richardson and Sam Ruby. Initially, I was thinking about adding REST support to Spring Web Services, 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 DispatcherServlet over to Spring-WS. Clearly, this was not the way to go forward.

Around the same time we introduced the annotation-based model of Spring MVC. This model was clearly an improvement to the former, inheritance-based model. Another interesting development at that time was the development of the JAX-RS 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 DispatcherServlet. 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.

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 (Jersey, RESTEasy, and Restlet). Adding a fourth to this list did not seem a good use of our valuable time.

RESTful features in Spring MVC 3.0

Now, enough of the background, let's look at the features!

URI Templates

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 proposed RFC.

In Spring 3.0 M1, we introduced the use of URI templates through the @PathVariable annotation. For instance:

 
1.@RequestMapping("/hotels/{hotelId}")
2.public String getHotel(@PathVariable String hotelId, Model model) {
3.    List<Hotel> hotels = hotelService.getHotels();
4.    model.addAttribute("hotels", hotels);
5.    return "hotels";
6.}

When a request comes in for /hotels/1, that 1 will be bound to the hotelId 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.

You can also have more than one path variable, like so:

 
1.@RequestMapping(value="/hotels/{hotel}/bookings/{booking}", method=RequestMethod.GET)
2.public String getBooking(@PathVariable("hotel") long hotelId, @PathVariable("booking") long bookingId, Model model) {
3.    Hotel hotel = hotelService.getHotel(hotelId);
4.    Booking booking = hotel.getBooking(bookingId);
5.    model.addAttribute("booking", booking);
6.    return "booking";
7.}

This would match requests like /hotels/1/bookings/2, for instance.

You can also combine the use of Ant-style paths and path variables, like so:

 
1.@RequestMapping(value="/hotels/*/bookings/{booking}", method=RequestMethod.GET)
2.public String getBooking(@PathVariable("booking") long bookingId, Model model) {
3.    ...
4.}

and you can use data binding, too:

 
01.@InitBinder
02.public void initBinder(WebDataBinder binder) {
03.    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
04.    binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
05.}
06.  
07.@RequestMapping("/hotels/{hotel}/dates/{date}")
08.public void date(@PathVariable("hotel") String hotel, @PathVariable Date date) {
09.    ...
10.}

The above would match /hotels/1/dates/2008-12-18, for instance.

Content Negotiation

In version 2.5, Spring-MVC lets the @Controller decide which view to render for a given request, through its View, view name, and ViewResolver abstractions. In a RESTful scenario, it is common to let the client decide the acceptable representations, via the Accept HTTP header. The server responds with the delivered representation via the Content-Type header. This process is known as content negotiation.

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

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

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, http://example.com/hotels.pdf retrieves the PDF view of the hotel list, as does http://example.com/hotels with an Accept header of application/pdf.

This is what the ContentNegotiatingViewResolver does: it wraps one or more other ViewResolvers, looks at the Accept 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 ContentNegotiatingViewResolver.

Views

We also added some new Views to Spring MVC, particularly:

  • the AbstractAtomFeedView and AbstractRssFeedView, which can be used to return an Atom and RSS feed,
  • the MarshallingView, 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,
  • the JacksonJsonView, 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.

Obviously, these work great in combination with the ContentNegotiatingViewResolver!

HTTP Method Conversion

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.

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 HiddenHttpMethodFilter 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 web.xml, and a POST with a hidden _method parameter will be converted into the corresponding HTTP method request.

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:

 
1.<form:form method="delete">
2.    <p class="submit"><input type="submit" value="Delete Pet"/></p>
3.</form:form>

will actually perform an HTTP POST, with the 'real' DELETE method hidden behind a request parameter, to be picked up by the HiddenHttpMethodFilter. The corresponding @Controller method is therefore:

 
1.@RequestMapping(method = RequestMethod.DELETE)
2.public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
3.    this.clinic.deletePet(petId);
4.    return "redirect:/owners/" + ownerId;
5.}

ETag support

An ETag (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 Last-Modified header. When a server returns a representation with an ETag header, client can use this header in subsequent GETs, in a If-None-Match header. If the content has not changed, the server will return 304: Not Modified.

In Spring 3.0 M1, we introduced the ShallowEtagHeaderFilter. 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 shallow 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 ETag header in the response. The next time a client sends a request for the same resource, it use that hash as the If-None-Match 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 bandwith, as the rendered response is not sent back over the wire.

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. 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.

And more!

In a following post, I will conclude my RESTful journey, and talk about the RestTemplate, 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 JdbcTemplate, JmsTemplate, etc.

Similar Posts



原文地址Qhttp://blog.springsource.com/2009/03/08/rest-in-spring-3-mvc/

Eric.Zhou 2009-12-24 19:53 发表评论
]]>
Spring MVC Annotation & Convention Over Configurationhttp://www.aygfsteel.com/rain1102/archive/2009/01/07/250410.htmlEric.ZhouEric.ZhouWed, 07 Jan 2009 13:43:00 GMThttp://www.aygfsteel.com/rain1102/archive/2009/01/07/250410.htmlhttp://www.aygfsteel.com/rain1102/comments/250410.htmlhttp://www.aygfsteel.com/rain1102/archive/2009/01/07/250410.html#Feedback1http://www.aygfsteel.com/rain1102/comments/commentRss/250410.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/250410.htmlSpring MVC在用annotationq行配置controller时候要注意Q两Uurlmapping的模式不能同时用,如果使用annotation׃能再配置urlmapping了?/p> <action>-servlet.xml如下Q?br />

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

 <!-- 对com.founder.action包中的所有类q行扫描Q以完成Bean创徏和自动依赖注入的功能 -->
 <context:component-scan base-package="com.founder.action"/>
 
<!-- 启动Spring MVC的注解功能,完成h和注解POJO的映?-->
 <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
 
<!--把请求的URL映射到Controller的name上面 -->
 <bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/> 
  
 <!-- Ҏ型视囑֐U的解析Q即在模型视囑֐U添加前后缀-->
 <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass">
   <value>org.springframework.web.servlet.view.JstlView</value>
  </property>
  <property name="prefix">
     <value>/jsp/</value>
  </property>
  <property name="suffix">
   <value>.jsp</value>
  </property>
 </bean>

</beans>


package com.founder.action;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;


@Controller
@RequestMapping
public class HelloController{
 @RequestMapping
 public String world(){
  String name = "Eric";
  System.out.println("name is = " + name);
  return "hello";
 }
 
 @RequestMapping
 public String test() {
  String name = "test";
  System.out.println("name is = " + name);
  return "test";
 }
 
}



Eric.Zhou 2009-01-07 21:43 发表评论
]]>
深入出REST[转蝲]http://www.aygfsteel.com/rain1102/archive/2008/11/27/243016.htmlEric.ZhouEric.ZhouThu, 27 Nov 2008 08:05:00 GMThttp://www.aygfsteel.com/rain1102/archive/2008/11/27/243016.htmlhttp://www.aygfsteel.com/rain1102/comments/243016.htmlhttp://www.aygfsteel.com/rain1102/archive/2008/11/27/243016.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/243016.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/243016.html作?Stefan Tilkov译?苑永?/strong> 发布?2007q?2?5?下午10?0?

不知你是否意识到Q围l着什么才是实现异构的应用到应用通信?#8220;正确”方式Q一Z论正q行的如火如|虽然当前L的方式明昑֜集中在基于SOAP、WSDL和WS-*规范的Web Services领域Q但也有数人用l小但洪亮的声音d说更好的方式是RESTQ表q性状态{U(REpresentational State TransferQ的U。在本文中,我不会涉及争论的话题Q而是试对REST和RESTful HTTP应用集成做实用性的介绍。以我的l验Q有些话题一旦触及就会引来众多的讨论Q当涉及到这斚w话题的时候,我会深入详细地阐q?/p>

REST关键原则

大部分对REST的介l是以其正式的定义和背景作ؓ开场的。但q儿且先按下不表Q我先提Z个简单扼要的定义QREST定义了应该如何正地使用Q这和大多数人的实际使用方式有很大不同)Web标准Q例如HTTP和URI。如果你在设计应用程序时能坚持REST原则Q那预C着你将会得C个用了优质Web架构Q这让你受益)的系l。MQ五条关键原则列丑֦下:

  • 为所?#8220;事物”定义ID
  • 所有事物链接在一?
  • 使用标准Ҏ
  • 资源多重表述
  • 无状态通信

下面让我们进一步审视这些原则?/p>

为所?#8220;事物”定义ID

在这里我使用?#8220;事物”来代替更正式准确的术?#8220;资源”Q因Z条如此简单的原则Q不应该被没在术语当中。思考一下h们构建的pȝQ通常会找Cpd值得被标识的关键抽象。每个事物都应该是可标识的,都应该拥有一个明昄ID——在Web中,代表ID的统一概念是:URI。URI构成了一个全局命名I间Q用URI标识你的关键资源意味着它们获得了一个唯一、全局的ID?

对事物用一致的命名规则Qnaming schemeQ最主要的好处就是你不需要提q规则——而是依靠某个已被定义Q在全球范围中几乎完运行,q且能被l大多数人所理解的规则。想一下你构徏的上一个应用(假设它不是采用RESTful方式构徏的)中的L一个高U对象(high-level objectQ,那就很有可能看到许多从用唯一标识中受益的用例。比如,如果你的应用中包含一个对֮的抽象,那么我可以相当肯定,用户会希望将一个指向某个顾客的链接Q能通过电子邮g发送到同事那里Q或者加入到览器的书签中,甚至写到U怸。更透彻地讲Q如果在一个类gAmazon.com的在U商城中Q没有用唯一的IDQ一个URIQ标识它的每一件商品,可想而知q将是多么可怕的业务决策?/p>

当面对这个原则时Q许多h惊讶于这是否意味着需要直接向外界暴露数据库记录(或者数据库记录IDQ——自从多q以来面向对象的实践告诫我们Q要持久化的信息作为实现细节隐藏v来之后,哪怕是刚有Ҏ法都怼使h惊恐。但是这条原则与隐藏实现l节两者之间ƈ没有M冲突Q通常Q值得被URI标识的事物——资源——要比数据库记录抽象的多。例如,一个定单资源可以由定单V地址以及许多其它斚wQ可能不希望作ؓ单独标识的资源暴露出来)l成。标识所有值得标识的事物,领会q个观念可以q一步引g创造出在传l的应用E序设计中不常见的资源:一个流E或者流E步骤、一ơ销售、一ơ谈判、一份报仯求——这都是应该被标识的事物的示例。同Pq也会导致创建比非RESTful设计更多的持久化实体?

下面是一些你可能惛_的URI的例子:

http://example.com/customers/1234
http://example.com/orders/2007/10/776654
http://example.com/products/4554
http://example.com/processes/salary-increase-234

正如我选择了创Z于阅ȝURI——这是个有用的观点,管不是RESTful设计所必须的——应该能十分Ҏ地推出URI的含义:它们明显地标识着单一“数据?#8221;。但是再往下看Q?/p>

http://example.com/orders/2007/11
http://example.com/products?color=green

首先Q这两个URI看v来与之前的稍有不同——毕竟,它们不是对一件事物的标识Q而是对一cM物集合的标识Q假定第一个URI标识了所有在2007q?1月䆾提交的定单,W二个则是绿颜色产品的集合)。但是这些集合自w也是事物(资源Q,也应该被标识?/p>

注意Q用唯一、全局l一的命名规则的好处Q既适用于浏览器中的Web应用Q也适用于机ҎQmachine-to-machineQm2mQ通信?/p>

来对W一个原则做下ȝQ用URI标识所有值得标识的事物,特别是应用中提供的所?#8220;高”资源Q无些资源代表单一数据V数据项集合、虚拟亦或实际的对象q是计算l果{?/p>

所有事物链接在一?

接下来要讨论的原则有一个有点o人害怕的正式描述Q?#8220;媒体被当作应用状态引擎(Hypermedia as the engine of application stateQ?#8221;Q有时简写ؓHATEOAS。(严格地说Q这不是我说的。)q个描述的核心是媒?/strong>概念Q换句话_?strong>链接的思想。链接是我们在HTML中常见的概念Q但是它的用处绝不局限于此(用于Z|络览Q。考虑一下下面这个虚构的XML片段Q?

<order self="http://example.com/customers/1234"> 
 <amount>23</amount>
 <product ref="http://example.com/products/4554">
  <customer ref="http://example.com/customers/1234">
  </customer>
 </product>
</order>
如果你观察文档中product和customer的链接,可以很Ҏ地想象到Q应用程序(已经索过文档Q如?#8220;跟随”链接索更多的信息。当Ӟ如果使用一个遵守专用命名规范的?#8220;id”属性作为链接, 也是可行的—?strong>但是仅限于应用环境之?/strong>。用URI表示链接的优雅之处在于,链接可以指向׃同应用、不同服务器甚至位于另一个大陆上的不同公司提供的资源——因为URI命名规范是全球标准,构成Web的所有资源都可以互联互通?

媒体原则还有一个更重要的方面——应?#8220;状?#8221;。简而言之,实际上服务器端(如果你愿意,也可以叫服务提供者)为客LQ服务消费者)提供一l链接,使客L能通过链接应用从一个状态改变ؓ另一个状态。稍后我们会在另一文章中探究q个斚w的媄响;目前Q只需要记住:链接是构成动态应用的非常有效的方式?/p>

Ҏ原则ȝ如下QQ何可能的情况下,使用链接指引可以被标识的事物Q资源)。也正是链接造就了现在的Web?/p>

使用标准Ҏ

在前两个原则的讨Z暗含着一个假设:接收URI的应用程序可以通过URI明确?strong>?/strong>一些有意义的事情。如果你在公共汽车上看到一个URIQ你可以它输入览器的地址栏中q回车——但是你的浏览器如何知道需要对q个URI做些什么呢Q?/p>

它知道如何去处理URI的原因在于所有的资源都支持同L接口Q一套同LҎQ只要你乐意Q也可以UCؓ操作Q集合。在HTTP中这被叫做动词(verbQ,除了两个大家熟知的(GET和POSTQ之外,标准Ҏ集合中还包含PUT、DELETE、HEAD和OPTIONS。这些方法的含义q同行ؓ许诺都一起定义在HTTP规范之中。如果你是一名OO开发h员,可以想象到RESTful HTTPҎ中的所有资源都l承自类gq样的一个类Q采用类Java、C#的伪语法描述Q请注意关键的方法)Q?/p>

class Resource {
Resource(URI u);
Response get();
Response post(Request r);
Response put(Request r);
Response delete();
}

׃所有资源用了同样的接口,你可以依此用GETҎ索一?strong>表述QrepresentationQ——也是对资源的描述。因范中定义了GET的语义,所以可以肯定当你调用它的时候不需要对后果负责——这是Z么可?#8220;安全”地调用此Ҏ。GETҎ支持非常高效、成熟的~存Q所以在很多情况下,你甚至不需要向服务器发送请求。还可以肯定的是QGETҎhq等?/strong>[译注Q指多个相同hq回相同的结果]——如果你发送了一个GETh没有得到l果Q你可能不知道原因是h未能到达目的圎ͼq是响应在反馈的途中丢失了。幂{性保证了你可以简单地再发送一ơ请求解决问题。幂{性同样适用于PUTQ基本的含义?#8220;更新资源数据Q如果资源不存在的话Q则Ҏ此URI创徏一个新的资?#8221;Q和DELETEQ你完全可以一遍又一遍地操作它,直到得出l论——删除不存在的东西没有Q何问题)Ҏ。POSTҎQ通常表示“创徏一个新资源”Q也能被用于调用Lq程Q因而它既不安全也不hq等性?/p>

如果你采用RESTful的方式暴露应用功能(如果你乐意,也可以称为服务功能)Q?strong>那这条原则和它的U束同样也适用于你。如果你已经习惯于另外的设计方式Q则很难L受这条原则——毕竟,你很可能认ؓ你的应用包含了超些操作表达范围的逻辑。请允许我花费一些时间来让你怿不存在这L情况?

来看下面q个单的采购Ҏ例子Q?

Sample Scenario

可以看到Q例子中定义了两个服务程序(没有包含M实现l节Q。这些服务程序的接口都是Z完成dQ正是我们讨论的OrderManagement和CustomerManagement服务Q而定制的。如果客LE序试图使用q些服务Q那它必针对这些特定接口进行编码——不可能在这些接口定义之前,使用客户E序L目的地和接口协作。这些接口定义了服务E序的应用协议(application protocolQ?/p>

在RESTful HTTP方式中,你将通过l成HTTP应用协议的通用接口讉K服务E序。你可能会想出像q样的方式:

Sample Scenario, done RESTfully

可以看到Q服务程序中的特定操作被映射成ؓ标准的HTTPҎ——ؓ了消除歧义,我创Z一l全新的资源?#8220;q是骗h的把?#8221;Q我听见你叫L。不Q这不是ƺ骗。标识一个顾客的URI上的GETҎ正好相当于getCustomerDetails操作。有人用三角形Ş象化地说明了q一点:

Knobs one can turn

把三个顶Ҏ象ؓ你可以调节的按钮。可以看到在W一U方法中Q你拥有许多操作Q许多种cȝ数据以及固定数量?#8220;实例”Q本质上和你拥有的服务程序数量一_。在W二U方法中Q你拥有固定数量的操作,许多U类的数据和许多调用固定Ҏ的对象。它的意义在于,证明了通过q两U方式,你基本上可以表示M你喜Ƣ的事情?/p>

Z么用标准方法如此重要?从根本上_它你的应用成ؓWeb的一部分——应用程序ؓWeb变成Internet上最成功的应用所做的贡献Q与它添加到Web中的资源数量成比例。采用RESTful方式Q一个应用可能会向Web中添加数以百万计的客户URIQ如果采用CORBA技术ƈl持应用的原有设计方式,那它的A献大抵只是一?#8220;端点QendpointQ?#8221;——就好比一个非常小的门Q仅仅允许有钥匙的hq入其中的资源域?/p>

l一接口也得所有理解HTTP应用协议的组件能与你的应用交互。通用客户E序Qgeneric clientQ就是从中受益的lg的例子,例如curl、wget、代理、缓存、HTTP服务器、网兌有Google、Yahoo!、MSN{等?

ȝ如下Qؓ使客LE序能与你的资源怺协作Q资源应该正地实现默认的应用协议(HTTPQ,也就是用标准的GET、PUT、POST和DELETEҎ?/p>

资源多重表述

到目前ؓ止我们一直忽略了一个稍微复杂的问题Q客L序如何知道该怎样处理索到的数据,比如作ؓGET或者POSTh的结果?原因是,HTTP采取的方式是允许数据处理和操作调用之间关pdȝ。换句话_如果客户E序知道如何处理一U特定的数据格式Q那可以与所有提供这U表q格式的资源交互。让我们再用一个例子来阐明q个观点。利用HTTP内容协商Qcontent negotiationQ,客户E序可以h一U特定格式的表述Q?/p>

GET /customers/1234 HTTP/1.1
Host: example.com
Accept: application/vnd.mycompany.customer+xml

h的结果可能是一些由公司专有的XML格式表述的客户信息。假讑֮L序发送另外一个不同的hQ就如下面这P

GET /customers/1234 HTTP/1.1
Host: example.com
Accept: text/x-vcard

l果则可能是VCard格式的客户地址。(在这里我没有展示响应的内容,在其HTTP Content-type头中应该包含着关于数据cd的元数据。)q说明ؓ什么理想的情况下,资源表述应该采用标准格式——如果客L序对HTTP应用协议和一l数据格式都有所“了解”Q那么它可以用一U有意义的方?strong>与世界上L一个RESTful HTTP应用交互。不q的是,我们不可能拿到所有东西的标准格式Q但是,或许我们可以惛_在公司或者一些合作伙伴中使用标准格式来营造一个小环境。当然以上情况不仅适用于从服务器端到客L的数据,反之既然——倘若从客L传来的数据符合应用协议,那么服务器端可以用特定的格式处理数据Q而不d心客L的类型?

在实践中Q资源多重表q还有着其它重要的好处:如果你ؓ你的资源提供HTML和XML两种表述方式Q那q些资源不仅可以被你的应用所用,q可以被L标准Web览器所用——也是_你的应用信息可以被所有会使用Web的h获取到?/p>

资源多重表述q有另外一U用方式:你可以将应用的Web UIU_到Web API中——毕竟,API的设计通常是由UI可以提供的功能驱动的Q而UI也是通过API执行动作的。将q两个Q务合二ؓ一带来了o人惊讶的好处Q这使得使用者和调用E序都能得到更好的Web接口?/p>

ȝQ针对不同的需求提供资源多重表q?/p>

无状态通信

无状态通信是我要讲到的最后一个原则。首先,需要着重强调的是,虽然REST包含无状态性(statelessnessQ的观念Q但qƈ不是说暴露功能的应用不能有状态—?br /> 事实上,在大部分情况下这会导致整个做法没有Q何用处。REST要求状态要么被攑օ资源状态中Q要么保存在客户端上。或者换句话_服务器端不能保持除了单次h之外的,M与其通信的客L的通信状态。这样做的最直接的理由就是可伸羃性—?如果服务器需要保持客L状态,那么大量的客L交互会严重媄响服务器的内存可用空_footprintQ。(注意Q要做到无状态通信往往需要需要一些重新设计——不能简单地一些session状态绑~在URI上,然后宣U这个应用是RESTful。)

但除此以外,其它斚w可能昑־更ؓ重要Q无状态约束服务器的变化对客L是不可见的,因ؓ在两ơ连l的h中,客户端ƈ不依赖于同一台服务器。一个客L从某台服务器上收C份包含链接的文档Q当它要做一些处理时Q这台服务器宕掉了,可能是硬盘坏掉而被拿去修理Q可能是软g需要升U重启——如果这个客L讉K了从q台服务器接收的链接Q它不会察觉到后台的服务器已l改变了?/p>

理论上的REST

我承认:以上我所说的REST不是真正的RESTQ而且我可能有点过多地热衷于简单化。但因ؓ我想有一个与众不同的开场,所以没有在一开始就介绍其正式的定义和背景。现在就让我们稍微简要地介绍一下这斚w的内宏V?/p>

首先Q先前我q没有明地区分HTTP、RESTful HTTP和REST。要理解q些不同斚w之间的关p,我们要先来看看REST的历双Ӏ?/p>

Roy T. Fielding在他?a id="ewd-" title="博士学位论文" >博士学位论文Q实际上你应该访问这个链接——至对于一学术论文来_它是相当易读的。此论文已被译?a id="nev8" title="中文" >中文Q中定义了术语REST。Roy曾是许多基本Web协议的主要设计者,其中包括HTTP和URIsQƈ且他在论文中对这些协议提Z很多x。(q篇论文被誉?#8220;REST圣经”Q这是恰当的——毕竟,是作者发明了q个术语Q所以在定义上,他写的Q何内定w被认为是权威的。)在论文中QRoy首先定义一U方法论来谈?strong>架构风格——高U、抽象的模式Q来表达架构Ҏ背后的核心理c每一个架构风格由一pd?strong>U束QconstraintsQ定义Ş成。架构风格的例子包括“没有风格”Q根本没有Q何约束)、管道和qo器(pipe and filterQ、客L/服务器、分布式对象以及——你猜到它了——REST?/p>

如果对你来说q些听v来都太抽象了Q那对了——REST在本质上是一个可以被许多不同技术实现的高层ơ的风格Q而且可以被实例化——通过为它的抽象特性赋上不同的倹{比如,REST中包含资源和l一接口的概念——也是_所有资源都应该对这些相同的Ҏ作出反应。但是RESTq没有说明是哪些ҎQ或者有多少Ҏ?/p>

REST风格的一?#8220;化n”便是HTTPQ以及一套相关的一套标准,比如URIQ,或者稍微抽象一些:Web架构自n。接着上面的例子,HTTP使用HTTP动词作ؓRESTl一接口?#8220;实例”。由于Fielding是在Web已经Q或者至是大部分)“完善”了之后才定义的REST风格Q有人可能会争论两者是不是100%的匹配。但是无论如何,整体上来说Web、HTTP和URI仅仅是REST风格的一个主要实现。不q,׃Roy FieldingxREST论文的作者,又对Web架构设计有过p的媄响,两者相g在情理之中?/p>

最后,我在前面一ơ又一ơ地使用着术语“RESTful HTTP”Q原因很单:许多使用HTTP的应用因Z些理由ƈ没有遵@REST原则Q有Z说用HTTP而不遵@REST原则q同于滥用HTTP。当然这听v来有点狂热——事实上q反RESTU束的原因通常是,仅仅因ؓ每个U束带来的设计权衡可能不适合于一些特D情c但通常Q违背RESTU束的原因可归咎于对其好处认知的~Z。来看一个明昄反面案例Q用HTTP GET调用cM于删除对象的操作Q这q反了REST的安全约束和一般性常识(客户E序不应为此负责Q服务器端开发h员大概不是有意而ؓ之)。但在随后的文章中,我会提及更多q样或那L对HTTP的滥用?/p>

ȝ

本文试图对RESTQWeb架构Q背后的概念提供快速的介绍。RESTful HTTP暴露功能的方式与RPC、分布式对象以及Web Services是不相同的;要真正理解这些不同是需要一些心态的转变。不你构徏的应用是仅仅x露Web UIq是xAPI变成Web的一份子Q了解下REST的原则还是有好处的?/p>

Stefan Tilkov是InfoQ SOAC֌的首席编辑,q且是位于d国和瑞士?/strong>innoQ公司的共同创始h、首席顾问和REST狂热分子首领?/strong>

查看英文原文Q?a id="mxm5" title="A Brief Introduction to REST" >A Brief Introduction to REST

Eric.Zhou 2008-11-27 16:05 发表评论
]]>
关于REST的一Ҏ法[转蝲]http://www.aygfsteel.com/rain1102/archive/2008/11/25/242524.htmlEric.ZhouEric.ZhouTue, 25 Nov 2008 05:29:00 GMThttp://www.aygfsteel.com/rain1102/archive/2008/11/25/242524.htmlhttp://www.aygfsteel.com/rain1102/comments/242524.htmlhttp://www.aygfsteel.com/rain1102/archive/2008/11/25/242524.html#Feedback0http://www.aygfsteel.com/rain1102/comments/commentRss/242524.htmlhttp://www.aygfsteel.com/rain1102/services/trackbacks/242524.html
先复习一下REST的基本思想。[Fielding]把REST形式化地定义ZU架构风|architecture styleQ,它有架构元素QelementQ和架构U束QconstraintQ组成。这些概忉|较晦涩难懂,而且我们做工E的往往q不需要Ş而上的理解。我们只知道QREST是一U针对网l应用的设计和开发方式,可以降低开发的复杂性,提高pȝ的可伸羃性。REST提出了一些设计概念和准则Q?br />
  1. |络上的所有事物都被抽象ؓ资源QresourceQ;
  2. 每个资源对应一个唯一的资源标识(resource identifierQ;
  3. 通过通用的连接器接口Qgeneric connector interfaceQ对资源q行操作Q?
  4. 对资源的各种操作不会改变资源标识Q?
  5. 所有的操作都是无状态的QstatelessQ?
对于当今最常见的网l应用来_resource identifier是urlQgeneric connector interface是HTTPQ第4条准则就是我们常说的url不变性。这些概念中的resouce最Ҏ使h产生误解。resouce所指的q不是数据,而是数据+特定的表现Ş式(representationQ,q也是ؓ什么REST的全名是Representational State Transfer的原因。D个例子来_“本月卖得最好的10本书”?#8220;你最喜欢?0本书”在数据上可能有重叠(有一本书卛_得好Q你又喜Ƣ)Q甚臛_全相同。但是它们的representation不同Q因此是不同的resource?br />
REST之所以能够简化开发,是因为其引入的架构约束,比如Rails 1.2中对REST的实现默认把controller中的Ҏ限制?个:index、show、new、edit、create、update和destoryQ这实际上就是对CURD的实现。更q一步讲QRailsQ也是当今大部分|络应用Q用HTTP作ؓgeneric connector interfaceQHTTP则把对一个url的操作限制在?个之内:GET、POST、PUT和DELETE?br />
REST之所以能够提高系l的可׾~性,是因为它强制所有操作都是stateless的,q样没有context的约束,如果要做分布式、做集群Q就不需要考虑context的问题了。同Ӟ它opȝ可以有效C用pool。RESTҎ能的另一个提升来自其对client和serverd的分配:server只负责提供resource以及操作resource的服务,而client要根据resource中的data和representation自己做render。这减了服务器的开销?br />
既然REST有这L好处Q那我们应该义无反顾地拥抱它啊!目前一些大牛(像DHHQ都已经开始投入到了REST的世界,那我们这些h应该做什么或者说思考写什么你呢?我觉得我们应该思考两个问题:
  1. 如何使用RESTQ?
  2. REST和MVC的关pR?

W一个问题假设REST是我们应该采用的架构Q然后讨论如何用;W二个问题则要说明REST和当前最普遍应用的MVC是什么关p,互补q是取代Q?br />
我们先来谈谈W一个问题,如何使用REST。我感觉QREST除了l我们带来了一个崭新的架构以外Q还有一个重要的贡献是在开发系l过E中的一U新的思维方式Q通过url来设计系l的l构。根据RESTQ每个url都代表一个resourceQ而整个系l就是由q些resourcel成的。因此,如果url是设计良好的Q那么系l的l构׃应该是设计良好的。对于非高手U的开发h员来_考虑一个系l如何架构L一个很抽象的问题。敏捷开发所提倡的Test Driven DevelopmentQ其好处之一Q我觉得是最大的好处Q就是可以通过testcase直观地设计系l的接口。比如在q没有创Z个class的时候就~写一个testcaseQ虽然设|不能通过~译Q但是testcase中的Ҏ调用可以很好Cclass使用者的角度反映出需要的接口Q从而ؓclass的设计提供了直观的表现。这与在REST架构中通过url设计pȝl构非常cM。虽然我们连一个功能都没有实现Q但是我们可以先设计出我们认为合理的urlQ这些url甚至不能q接CQ何page或actionQ但是它们直观地告诉我们Q系l对用户的访问接口就应该是这栗根据这些urlQ我们可以很方便地设计系l的l构?br />
让我在这里重申一遍:REST允许我们通过url设计pȝQ就像Test Driven Development允许我们使用testcase设计class接口一栗?br />
OKQ既然url有这L好处Q那我们q重讨Z下如何设计url。网l应用通常都是有hierarchy的,像棵大树。我们通常希望url也能反映源的层次性。比如对于一个blog应用Q?articles表示所有的文章Q?articles/1表示id?的文章,q都比较直观。遗憄是,|络应用的资源结构永q不会如此简单。因此h们常怼问这样一个问题:RESTful的url能覆盖所有的用户h吗?比如Qlogin如何RESTfulQsearch如何RESTfulQ?br />
从REST的概念上来看Q所有可以被抽象源的东东都可以用RESTful的url。因此对于上面的两个问题Q如果login和search可以被抽象ؓ资源Q那么就可以使用RESTful的url。search比较单,因ؓ它会q回搜烦l果Q因此可以被抽象源,q且只实现indexҎ可以了Q只需要显C搜索结果,没有create、destory之类的东西)。然而这里面也有一个问题:search的关键字如何传给serverQindexҎ昄应该使用HTTP GETQ这会把关键字加到url后面Q当然不W合REST的风根{要解决q个问题Q可以把每次search看作一个资源,因此要创建create和indexҎQcreate用来在用L?#8220;搜烦”按钮是通过HTTP POST把关键字传给serverQ然后index则用来显C搜索结果。这样一来,我们q可以记录用L搜烦历史。用同LҎQ我们也可以对login应用RESTQ即每次login动作是一个资源?br />
现在Q我们来复杂一些的东东。如何用url表达“category为ruby的article”Q一开始可能想到的?category/ruby/articlesQ这U想法很直观。但是我觉得里面的category是不需要的Q我们可以直接把“/ruby”理解?#8220;category是ruby”Q也是?#8220;ruby”出现的位|说明了它指的就是category。OKQ?ruby/articlesQ单单从q个url上看Q我们能获得多少关于category的信息呢Q显然category隐藏在了url后面Q这样做到底好不好,应该是仁者见仁,见Z。对于如何表达categoryq样的东西,我还没想出很好的方式Q大家有什么好ideaQ可以一赯论?br />
另外q有一Uurl形式Q它对应到程序中的承关pR比如product是一个父c,book和computer是其子类。那么所有品的url应该?productsQ所有书c的url应该?booksQ所有电脑的url应该?computers。这一x比较直观了Q而且再次验证了url可以帮助我们q行设计的论炏V?br />
让我再说明一下我的想法:如果每个用户需求都可以抽象源,那么可以完全用REST?/strong>

由此看来Q用REST的关键是如何抽象资源Q抽象得精,对REST的应用就好。因此,如何改变我们目前Ҏ蒂固的基于action的思想是最重要的?br />
有了对第一个问题的讨论Q第二个问题容易讨论多了。REST会取代MVC吗?q是彼此是互补关p(像AOP对于OOPQ?{案是It dependsQ如果我们可以把所有的用户需求都可以抽象源,那么MVC可以退出历史的舞台了。如果情늛反,那么我们需要؜合用REST和MVC?br />
当然Q这是非常理想的论断。可能我们无法找CU方法可以把所有的用户需求都抽象源,因ؓ保证q种抽象的完整性(即真的是所有需求都可以Q需要Ş式化的证明。而且即被证明出来了Q由于开发h员的能力和喜好不同,MVC肯定也会成ؓ不少人的首选。但是对于希望拥抱REST的h来说Q这些都没有关系。只要你开发的pȝ所设计的问题域可以被合理地抽象源,那么REST׃成ؓ你的开发利器?br />
所以,所有希望拥抱REST的朋友们Q赶快训l自己如何带上资源的眼镜看世界吧Q这才是REST的核心所在?/strong> 

转蝲自javaeye论坛 作者:AllenYoung

原文地址Q?a >http://www.javaeye.com/topic/70113



Eric.Zhou 2008-11-25 13:29 发表评论
]]>
վ֩ģ壺 | ֯| | ;| | °Ͷ| ɽ| пǰ| | ƽ| ͤ| | | ʡ| ÷| ຣʡ| ͨ| | | | | ˷| | ߮| | Դ| | ˮ| | | | Ž| ¡| | | | ͨ| | ԭ| Դ| |