REST架构风格

REST的几条关键原则列举如下:

 

1.为所有“事物”定义ID

对事物使用一致的命名规则(naming scheme)最主要的好处就是你不需要提出自己的规则——而是依靠某个已被定义,在全球范围中几乎完美运行,并且能被绝大多数人所理解的规则。如果在一个类似于Amazon.com的在线商城中,没有用唯一的ID(一个URI)标识它的每一件商品,可想而知这将是多么可怕的业务决策。 下面是一些你可能想到的URI的例子:

http://example.com/customers/1234
http://example.com/orders/2007/10/776654
http://example.com/orders/2007/11

2.将所有事物链接在一起
任何可能的情况下,使用链接指引可以被标识的事物(资源)。也正是超链接造就了现在的Web。
3.使用标准方法
GET、POST、DELETE、PUT
4.资源多重表述
针对不同的需求提供资源多重表述,客户端可以请求返回指定格式的资源如xml
上面的内容来源于http://www.infoq.com/cn/articles/rest-introduction
英文地址http://www.infoq.com/articles/rest-introduction

还有一篇文章Build RESTful web services using Spring 3介绍了如何利用spring 3构建REST风格应用。

下面借用下上篇文章的例子介绍下如何在Spring3下搭建REST应用,首先在web.xml
配置contextConfigLocation

 

 

[xhtml] view plaincopy
 
  1. <context-param>  
  2. <param-name>contextConfigLocation</param-name>  
  3. <param-value>  
  4.     /WEB-INF/rest-context.xml  
  5. </param-value>  
  6. </context-param>  
  7.       
  8. <!-- This listener will load other application context file in addition to   
  9.             rest-servlet.xml -->  
  10. <listener>  
  11. <listener-class>  
  12.     org.springframework.web.context.ContextLoaderListener  
  13. </listener-class>  
  14. </listener>  
  15.       
  16. <servlet>  
  17. <servlet-name>rest</servlet-name>  
  18. <servlet-class>  
  19.     org.springframework.web.servlet.DispatcherServlet  
  20. </servlet-class>  
  21. <load-on-startup>1</load-on-startup>  
  22. </servlet>  
  23. <servlet-mapping>  
  24. <servlet-name>rest</servlet-name>  
  25. <url-pattern>/service/*</url-pattern>  
  26. </servlet-mapping>  

 

 

下面是在rest-servlet.xml中配置Spring MVC

 

 

[xhtml] view plaincopy
 
  1. <context:component-scan base-package="dw.spring3.rest.controller" />  
  2. <!--To enable @RequestMapping process on type level and method level-->  
  3. <bean class="org.springframework.web.servlet.mvc.annotation  
  4.         .DefaultAnnotationHandlerMapping" />  
  5. <bean class="org.springframework.web.servlet.mvc.annotation  
  6.         .AnnotationMethodHandlerAdapter" />  
  7. <!--Use JAXB OXM marshaller to marshall/unmarshall following class-->  
  8. <bean id="jaxbMarshaller"  
  9. class="org.springframework.oxm.jaxb.Jaxb2Marshaller">  
  10. <property name="classesToBeBound">  
  11.     <list>  
  12.         <value>dw.spring3.rest.bean.Employee</value>  
  13.         <value>dw.spring3.rest.bean.EmployeeList</value>  
  14.     </list>  
  15. </property>  
  16. </bean>  
  17. <bean id="employees" class=  
  18.     "org.springframework.web.servlet.view.xml.MarshallingView">  
  19. <constructor-arg ref="jaxbMarshaller" />  
  20. </bean>  
  21. <bean id="viewResolver" class=  
  22. "org.springframework.web.servlet.view.BeanNameViewResolver" />  

  

 

 

Listing 3. EmployeeController控制器类

 

 

[java] view plaincopy
 
  1. @Controller  
  2. public class EmployeeController {  
  3. @RequestMapping(method=RequestMethod.GET, value="/employee/{id}")  
  4. public ModelAndView getEmployee(@PathVariable String id) {  
  5.     Employee e = employeeDS.get(Long.parseLong(id));  
  6.     return new ModelAndView(XML_VIEW_NAME, "object", e);  
  7. }  
  8. }  

 

 

 

Listing 4. EmployeeController in dw.spring3.rest.controller

 

[java] view plaincopy
 
  1. @RequestMapping(method=RequestMethod.POST, value="/employee")  
  2. public ModelAndView addEmployee(@RequestBody String body) {  
  3.     Source source = new StreamSource(new StringReader(body));  
  4.     Employee e = (Employee) jaxb2Mashaller.unmarshal(source);  
  5.     employeeDS.add(e);  
  6.     return new ModelAndView(XML_VIEW_NAME, "object", e);  
  7. }  
  8. @RequestMapping(method=RequestMethod.PUT, value="/employee/{id}")  
  9. public ModelAndView updateEmployee(@RequestBody String body) {  
  10.     Source source = new StreamSource(new StringReader(body));  
  11.     Employee e = (Employee) jaxb2Mashaller.unmarshal(source);  
  12.     employeeDS.update(e);  
  13.     return new ModelAndView(XML_VIEW_NAME, "object", e);  
  14. }  
  15. @RequestMapping(method=RequestMethod.DELETE, value="/employee/{id}")  
  16. public ModelAndView removeEmployee(@PathVariable String id) {  
  17.     employeeDS.remove(Long.parseLong(id));  
  18.     List<Employee> employees = employeeDS.getAll();  
  19.     EmployeeList list = new EmployeeList(employees);  
  20.     return new ModelAndView(XML_VIEW_NAME, "employees", list);  
  21. }  

 

 

 

 

 

Listing 5. getAllEmployees in EmployeeController

 

[java] view plaincopy
 
  1. @RequestMapping(method=RequestMethod.GET, value="/employees")  
  2. public ModelAndView getEmployees() {  
  3.     List<Employee> employees = employeeDS.getAll();  
  4.     EmployeeList list = new EmployeeList(employees);  
  5.     return new ModelAndView(XML_VIEW_NAME, "employees", list);  
  6. }   

 

 

Listing 6. EmployeeList class in dw.spring3.rest.bean

 

 

[java] view plaincopy
 
  1. @XmlRootElement(name="employees")  
  2. public class EmployeeList {  
  3.     private int count;  
  4.     private List<Employee> employees;  
  5.     public EmployeeList() {}  
  6.       
  7.     public EmployeeList(List<Employee> employees) {  
  8.         this.employees = employees;  
  9.         this.count = employees.size();  
  10.     }  
  11.     public int getCount() {  
  12.         return count;  
  13.     }  
  14.     public void setCount(int count) {  
  15.         this.count = count;  
  16.     }  
  17.       
  18.     @XmlElement(name="employee")  
  19.     public List<Employee> getEmployees() {  
  20.         return employees;  
  21.     }  
  22.     public void setEmployees(List<Employee> employees) {  
  23.         this.employees = employees;  
  24.     }  
  25.       
  26. }  


 


Listing 7. Define content negotiation

 

 

[xhtml] view plaincopy
 
  1. <bean class="org.springframework.web.servlet.view  
  2.         .ContentNegotiatingViewResolver">  
  3. <property name="mediaTypes">  
  4.     <map>  
  5.     <entry key="xml" value="application/xml"/>  
  6.     <entry key="html" value="text/html"/>  
  7.     </map>  
  8. </property>  
  9. <property name="viewResolvers">  
  10.     <list>  
  11.     <bean class="org.springframework.web.servlet.view  
  12.             .BeanNameViewResolver"/>  
  13.     <bean class="org.springframework.web.servlet.view  
  14.             .UrlBasedViewResolver">  
  15.         <property name="viewClass" value=  
  16.         "org.springframework.web.servlet.view.JstlView"/>  
  17.         <property name="prefix" value="/WEB-INF/jsp/"/>  
  18.         <property name="suffix" value=".jsp"/>  
  19.     </bean>  
  20.     </list>  
  21. </property>  
  22. </bean>  

 

 

Listing 8. employees.jsp in /WEB-INF/jsp

 

 

[xhtml] view plaincopy
 
  1. <table border=1>  
  2.     <thead><tr>  
  3.         <th>ID</th>  
  4.         <th>Name</th>  
  5.         <th>Email</th>  
  6.     </tr></thead>  
  7.     <c:forEach var="employee" items="${employees.employees}">  
  8.     <tr>  
  9.         <td>${employee.id}</td>  
  10.         <td>${employee.name}</td>  
  11.         <td>${employee.email}</td>  
  12.     </tr>  
  13.     </c:forEach>  
  14. </table>  

 

 

下面演示Clients如何与 REST services交互

 

curl –HAccept:application/xml http://localhost:8080/rest/service/employees

 

下面返回的xml包含employees

 

Figure 2. 用浏览器打开的HTML展示

 

 

 

下面演示创建一个新的employee到服务端,

 

[java] view plaincopy
 
  1. curl -X POST -HContent-type:application/xml --data  
  2. "<employee><id>3</id><name>guest</name><email>guest@ibm.com</employee>"  
  3. http://localhost:8080/rest/service/employee  

 

 

这样一个新的employee注册好了. 可以用第一个例子的 employee 列表验证下.

PUT 和POST方法类似.

 

 

[java] view plaincopy
 
  1. curl -X PUT -HContent-type:application/xml --data  
  2. "<employee><id>3</id><name>guest3</name><email>guest3@ibm.com</employee>"   
  3. http://localhost:8080/rest/service/employee/3  
  4.               

 

 

上面代码更新了编号为3的 employee 数据。

 

现在spring3的mvc层以及完全支持REST了,你可以很轻松的用Spring APIs和注解去构建RESTful web services.

posted @ 2015-06-24 18:41  曹刚  阅读(335)  评论(0编辑  收藏  举报