RESTFUL概念及实践

一:定义:
REST是英文representational state transfer(表象性状态转变)或者表述性状态转移;Rest是web服务的一种架构风格;使用HTTP,URI,XML,JSON,HTML等广泛流行的标准和协议;轻量级,跨平台,跨语言的架构设计;它是一种设计风格,不是一种标准,是一种思想。
对应的中文是rest式的;Restful web service是一种常见的rest的应用,是遵守了rest风格的web服务;rest式的web服务是一种ROA(The Resource-Oriented Architecture)(面向资源的架构)。

二:概述:
1. Rest架构的主要原则:
网络上的所有事物都被抽象为资源
每个资源都有一个唯一的资源标识符
同一个资源具有多种表现形式(xml,json等)
对资源的各种操作不会改变资源标识符
所有的操作都是无状态的
REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。
2.分层系统:
另一个重要的 REST 原则是分层系统,这表示组件无法了解它与之交互的中间层以外的组件。通过将系统知识限制在单个层,可以限制整个系统的复杂性,促进了底层的独立性。
当 REST 架构的约束条件作为一个整体应用时,将生成一个可以扩展到大量客户端的应用程序。它还降低了客户端和服务器之间的交互延迟。统一界面简化了整个系统架构,改进了子系统之间交互的可见性。REST 简化了客户端和服务器的实现。
三:实现:
1. RESTful的实现:RESTful Web 服务与 RPC 样式的 Web 服务
了解了什么是REST,我们再看看RESTful的实现。使用 RPC 样式架构构建的基于 SOAP(指简易对象访问协议:对于应用程序开发来说,使程序之间进行因特网通信是很重要的。目前的应用程序通过使用远程过程调用(RPC)在诸如 DCOM 与 CORBA 等对象之间进行通信,但是 HTTP 不是为此设计的。RPC 会产生兼容性以及安全问题;防火墙和代理服务器通常会阻止此类流量。通过 HTTP 在应用程序间通信是更好的方法,因为 HTTP 得到了所有的因特网浏览器及服务器的支持。SOAP 就是被创造出来完成这个任务的。SOAP 提供了一种标准的方法,使得运行在不同的操作系统并使用不同的技术和编程语言的应用程序可以互相进行通信。) 的 Web 服务成为实现 SOA 最常用的方法。RPC 样式的 Web 服务客户端将一个装满数据的信封(包括方法和参数信息)通过 HTTP 发送到服务器。服务器打开信封并使用传入参数执行指定的方法。方法的结果打包到一个信封并作为响应发回客户端。客户端收到响应并打开信封。每个对象都有自己独特的方法以及仅公开一个 URI 的 RPC 样式 Web 服务,URI 表示单个端点。它忽略 HTTP 的大部分特性且仅支持 POST 方法。
由于轻量级以及通过 HTTP 直接传输数据的特性,Web 服务的 RESTful 方法已经成为最常见的替代方法。可以使用各种语言(比如 Java 程序、Perl、Ruby、Python、PHP 和 Javascript[包括 Ajax])实现客户端。RESTful Web 服务通常可以通过自动客户端或代表用户的应用程序访问。但是,这种服务的简便性让用户能够与之直接交互,使用它们的 Web 浏览器构建一个 GET URL 并读取返回的内容。
在 REST 样式的 Web 服务中,每个资源都有一个地址。资源本身都是方法调用的目标,方法列表对所有资源都是一样的。这些方法都是标准方法,包括 HTTP GET、POST、PUT、DELETE,还可能包括 HEADER 和 OPTIONS。
在 RPC 样式的架构中,关注点在于方法,而在 REST 样式的架构中,关注点在于资源 —— 将使用标准方法检索并操作信息片段(使用表示的形式)。资源表示形式在表示形式中使用超链接互联。
Leonard Richardson 和 Sam Ruby 在他们的著作 RESTful Web Services 中引入了术语 REST-RPC 混合架构。REST-RPC 混合 Web 服务不使用信封包装方法、参数和数据,而是直接通过 HTTP 传输数据,这与 REST 样式的 Web 服务是类似的。但是它不使用标准的 HTTP 方法操作资源。它在 HTTP 请求的 URI 部分存储方法信息。好几个知名的 Web 服务,比如 Yahoo 的 Flickr API 和 Delicious API 都使用这种混合架构。
2.RESTful的实现:构建 RESTful Web 服务的多层架构
RESTful Web 服务和动态 Web 应用程序在许多方面都是类似的。有时它们提供相同或非常类似的数据和函数,尽管客户端的种类不同。例如,在线电子商务分类网站为用户提供一个浏览器界面,用于搜索、查看和订购产品。如果还提供 Web 服务供公司、零售商甚至个人能够自动订购产品,它将非常有用。与大部分动态 Web 应用程序一样,Web 服务可以从多层架构的关注点分离中受益。业务逻辑和数据可以由自动客户端和 GUI 客户端共享。惟一的不同点在于客户端的本质和中间层的表示层。此外,从数据访问中分离业务逻辑可实现数据库独立性,并为各种类型的数据存储提供插件能力。
自动化 Web 服务客户端在 Web 层向 Resource Request Handler 发送 HTTP 响应。客户端的无状态请求在头部包含方法信息,即 POST、GET、PUT 和 DELETE,这又将映射到 Resource Request Handler 中资源的相应操作。每个请求都包含所有必需的信息,包括 Resource Request Handler 用来处理请求的凭据。
从 Web 服务客户端收到请求之后,Resource Request Handler 从业务逻辑层请求服务。Resource Request Handler 确定所有概念性的实体,系统将这些实体作为资源公开,并为每个资源分配一个惟一的 URI。但是,概念性的实体在该层是不存在的。它们存在于业务逻辑层。可以使用 Jersey 或其他框架(比如 Restlet)实现 Resource Request Handler,它应该是轻量级的,将大量职责工作委托给业务层。
Ajax 和 RESTful Web 服务本质上是互为补充的。它们都可以利用大量 Web 技术和标准,比如 HTML、JavaScript、浏览器对象、XML/JSON 和 HTTP。当然也不需要购买、安装或配置任何主要组件来支持 Ajax 前端和 RESTful Web 服务之间的交互。RESTful Web 服务为 Ajax 提供了非常简单的 API 来处理服务器上资源之间的交互。
业务规则可以集中到业务逻辑层,该层充当表示层和数据访问层之间的数据交换的中间层。数据以域对象或值对象的形式提供给表示层。从业务逻辑层中解耦 Browser Request Handler 和 Resource Request Handler 有助于促进代码重用,并能实现灵活和可扩展的架构。此外,由于将来可以使用新的 REST 和 MVC 框架,实现它们变得更加容易,无需重写业务逻辑层。
数据访问层提供与数据存储层的交互,可以使用 DAO 设计模式或者对象-关系映射解决方案(如 Hibernate、OJB 或 iBatis(随着开发团队转投Google Code旗下,ibatis3.x正式更名为Mybatis))实现。作为替代方案,业务层和数据访问层中的组件可以实现为 EJB 组件,并取得 EJB 容器的支持,该容器可以为组件生命周期提供便利,管理持久性、事务和资源配置。但是,这需要一个遵从 Java EE 的应用服务器(比如 JBoss),并且可能无法处理 Tomcat。该层的作用在于针对不同的数据存储技术,从业务逻辑中分离数据访问代码。数据访问层还可以作为连接其他系统的集成点,可以成为其他 Web 服务的客户端。
数据存储层包括数据库系统、LDAP 服务器、文件系统和企业信息系统(包括遗留系统、事务处理系统和企业资源规划系统)。使用该架构,您可以开始看到 RESTful Web 服务的力量,它可以灵活地成为任何企业数据存储的统一 API,从而向以用户为中心的 Web 应用程序公开垂直数据,并自动化批量报告脚本。
什么是REST:结束语
REST 描述了一个架构样式的互联系统(如 Web 应用程序)。REST 约束条件作为一个整体应用时,将生成一个简单、可扩展、有效、安全、可靠的架构。由于它简便、轻量级以及通过 HTTP 直接传输数据的特性,RESTful Web 服务成为基于 SOAP 服务的一个最有前途的替代方案。用于 web 服务和动态 Web 应用程序的多层架构可以实现可重用性、简单性、可扩展性和组件可响应性的清晰分离。开发人员可以轻松使用 Ajax 和 RESTful Web 服务一起创建丰富的界面。
RESTful的关键
RESTful的关键是定义可表示流程元素/资源的对象。在REST中,每一个对象都是通过URL来表示的,对象用户负责将状态信息打包进每一条消息内,以便对象的处理总是无状态的。
RESTful的第二大问题是组合管理及流程绑定。企业对正规的(基于SOAP)SOA最大的反对声之一便是,这种等级的发现和绑定灵活性不足以适应复杂性。[1]
四:应用实例:

在Restful之前的操作:
http://127.0.0.1/user/query/1 GET  根据用户id查询用户数据
http://127.0.0.1/user/save POST 新增用户
http://127.0.0.1/user/update POST 修改用户信息
http://127.0.0.1/user/delete GET/POST 删除用户信息

RESTful用法:
http://127.0.0.1/user/1 GET  根据用户id查询用户数据
http://127.0.0.1/user  POST 新增用户
http://127.0.0.1/user  PUT 修改用户信息
http://127.0.0.1/user  DELETE 删除用户信息

之前的操作是没有问题的,大神认为是有问题的,有什么问题呢?你每次请求的接口或者地址,都在做描述,例如查询的时候用了query,新增的时候用了save,其实完全没有这个必要,我使用了get请求,就是查询.使用post请求,就是新增的请求,我的意图很明显,完全没有必要做描述,这就是为什么有了restful.

如何使用:



SpringMVC实现restful服务:

SpringMVC原生态的支持了REST风格的架构设计

所涉及到的注解:

–@RequestMapping

—@PathVariable

—@ResponseBody

  1. package cn.itcast.mybatis.controller;  
  2.   
  3. import org.springframework.beans.factory.annotation.Autowired;  
  4. import org.springframework.http.HttpStatus;  
  5. import org.springframework.http.ResponseEntity;  
  6. import org.springframework.stereotype.Controller;  
  7. import org.springframework.web.bind.annotation.PathVariable;  
  8. import org.springframework.web.bind.annotation.RequestMapping;  
  9. import org.springframework.web.bind.annotation.RequestMethod;  
  10. import org.springframework.web.bind.annotation.RequestParam;  
  11. import org.springframework.web.bind.annotation.ResponseBody;  
  12.   
  13. import cn.itcast.mybatis.pojo.User;  
  14. import cn.itcast.mybatis.service.NewUserService;  
  15.   
  16. @RequestMapping(“restful/user”)  
  17. @Controller  
  18. public class RestUserController {  
  19.   
  20.     @Autowired  
  21.     private NewUserService newUserService;  
  22.   
  23.     /** 
  24.      * 根据用户id查询用户数据 
  25.      *  
  26.      * @param id 
  27.      * @return 
  28.      */  
  29.     @RequestMapping(value = “{id}”, method = RequestMethod.GET)  
  30.     @ResponseBody  
  31.     public ResponseEntity<User> queryUserById(@PathVariable(“id”) Long id) {  
  32.         try {  
  33.             User user = this.newUserService.queryUserById(id);  
  34.             if (null == user) {  
  35.                 // 资源不存在,响应404  
  36.                 return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);  
  37.             }  
  38.             // 200  
  39.             // return ResponseEntity.status(HttpStatus.OK).body(user);  
  40.             return ResponseEntity.ok(user);  
  41.         } catch (Exception e) {  
  42.             e.printStackTrace();  
  43.         }  
  44.         // 500  
  45.         return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);  
  46.     }  
  47.   
  48.     /** 
  49.      * 新增用户 
  50.      *  
  51.      * @param user 
  52.      * @return 
  53.      */  
  54.     @RequestMapping(method = RequestMethod.POST)  
  55.     public ResponseEntity<Void> saveUser(User user) {  
  56.         try {  
  57.             this.newUserService.saveUser(user);  
  58.             return ResponseEntity.status(HttpStatus.CREATED).build();  
  59.         } catch (Exception e) {  
  60.             // TODO Auto-generated catch block  
  61.             e.printStackTrace();  
  62.         }  
  63.         // 500  
  64.         return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);  
  65.     }  
  66.   
  67.     /** 
  68.      * 更新用户资源 
  69.      *  
  70.      * @param user 
  71.      * @return 
  72.      */  
  73.     @RequestMapping(method = RequestMethod.PUT)  
  74.     public ResponseEntity<Void> updateUser(User user) {  
  75.         try {  
  76.             this.newUserService.updateUser(user);  
  77.             return ResponseEntity.status(HttpStatus.NO_CONTENT).build();  
  78.         } catch (Exception e) {  
  79.             e.printStackTrace();  
  80.         }  
  81.         // 500  
  82.         return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);  
  83.     }  
  84.   
  85.     /** 
  86.      * 删除用户资源 
  87.      *  
  88.      * @param user 
  89.      * @return 
  90.      */  
  91.     @RequestMapping(method = RequestMethod.DELETE)  
  92.     public ResponseEntity<Void> deleteUser(@RequestParam(value = “id”, defaultValue = “0”) Long id) {  
  93.         try {  
  94.             if (id.intValue() == 0) {  
  95.                 // 请求参数有误  
  96.                 return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();  
  97.             }  
  98.             this.newUserService.deleteUserById(id);  
  99.             // 204  
  100.             return ResponseEntity.status(HttpStatus.NO_CONTENT).build();  
  101.         } catch (Exception e) {  
  102.             e.printStackTrace();  
  103.         }  
  104.         // 500  
  105.         return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);  
  106.     }  
  107. }  
package cn.itcast.mybatis.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import cn.itcast.mybatis.pojo.User;
import cn.itcast.mybatis.service.NewUserService;

@RequestMapping("restful/user")
@Controller
public class RestUserController {

    @Autowired
    private NewUserService newUserService;

    /**
     * 根据用户id查询用户数据
     * 
     * @param id
     * @return
     */
    @RequestMapping(value = "{id}", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<User> queryUserById(@PathVariable("id") Long id) {
        try {
            User user = this.newUserService.queryUserById(id);
            if (null == user) {
                // 资源不存在,响应404
                return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
            }
            // 200
            // return ResponseEntity.status(HttpStatus.OK).body(user);
            return ResponseEntity.ok(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 500
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
    }

    /**
     * 新增用户
     * 
     * @param user
     * @return
     */
    @RequestMapping(method = RequestMethod.POST)
    public ResponseEntity<Void> saveUser(User user) {
        try {
            this.newUserService.saveUser(user);
            return ResponseEntity.status(HttpStatus.CREATED).build();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 500
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
    }

    /**
     * 更新用户资源
     * 
     * @param user
     * @return
     */
    @RequestMapping(method = RequestMethod.PUT)
    public ResponseEntity<Void> updateUser(User user) {
        try {
            this.newUserService.updateUser(user);
            return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 500
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
    }

    /**
     * 删除用户资源
     * 
     * @param user
     * @return
     */
    @RequestMapping(method = RequestMethod.DELETE)
    public ResponseEntity<Void> deleteUser(@RequestParam(value = "id", defaultValue = "0") Long id) {
        try {
            if (id.intValue() == 0) {
                // 请求参数有误
                return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
            }
            this.newUserService.deleteUserById(id);
            // 204
            return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 500
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
    }
}



HTTP相应状态码:



总结:

restful就是旧技术,新风格.之前写过一篇关于restful接口的博客:【Restful接口】restful接口的两种使用方式

            </div>
                </div>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值