restlet 学习笔记 -凯发k8网页登录

java, c , linux c, c#.net 技术,软件架构,领域建模,it 项目管理

摘要:网络上对 restlet 的评判褒贬不一,有的说框架封装的很好,很有弹性,有的说 rest 架构风格本身是一种简单的风格,restlet 过设计以使编程过于复杂,其实我倒不觉得 restlet 有什么复杂,相反很简洁明了,不论他的类结构还是整个体系结构,个人很喜欢,昨天晚上匆匆看看他的文档和实例,很不错!
正文:

1. rest简介(摘抄自网络,讲的很到位)

restlet是一个java下的轻量级rest框架。通过拥抱rest(rest是一种web架构风格)它模糊了web站点和web服务之间的界限,从而帮助开发人员构建web应用。每一个主要的rest概念(rest concept)都有一个对应的java类。你的rest化的web设计和你的代码之间的映射是非常简单直接的。为什么有必要创建另一种框架?难道servlet api还不够好用吗?servlet aip在1998年发布,从那个时候起它的核心设计一直没有很大的变化。它是java ee的众多api中最成功的一个,但是它的几个设计缺陷和一些限制损害了它。举个例子,uri模式和它的处理者(handler)之间的映射是受限制的,而且其配置都集中在一个配置文件中。还有,它把socket流的控制直接交给了应用系统开发人员,servlet容器阻碍了我们充分使用nio特性对io操作进行优化。另一个主要问题就是servlet api鼓励应用开发者在应用或者用户会话级别直接将session状态保存于内存中,尽管这看上去不错,但它造成了servlet容器扩展性和高可用性的主要问题。为了克服这些问题,就必须实现复杂的负载均衡、session复制、持久化机制。这导致了可扩展性必然成为灾难。

如何看待别的框架中对rest的支持(例如axis2,或者cxf/xfire)?

这些支持非常有效,但是作用非常有限。我的主要观点是设计这些项目是为了符合ws-*/soap stack,它们与rest世界并不非常契合。在rest世界里,定义了一个全新的范例:面向资源的设计,而非通过远程方法调用这样的范例。例如axis2仅仅支持get和post两种http方法,它需要远程方法的传递需要一个uri参数。这在rest中式不允许的,这种做法也不能被称之为rest化。xfire1.2不支持rest,但是它发布了一个项目用于将pojo映射到rest化的web服务。这有点类似最近发布的jsr-311,此jsr试图基于一套annotation和助手类标准化这种映射。


rest与http协议

rest软件架构是由roy thomas fielding博士在2000年首次提出的。他为我们描绘了开发基于互联网的网络软件的蓝图。rest软件架构是一个抽象的概念,是一种为了实现这一互联网的超媒体分布式系统的行动指南。利用任何的技术都可以实现这种理念。而实现这一软件架构最著名的就是http协议。通常我们把rest也写作为rest/http,在实际中往往把rest理解为基于http的rest软件架构,或者更进一步把rest和http看作为等同的概念。今天,http是互联网上应用最广泛的计算机协议。http不是一个简单的运载数据的协议,而是一个具有丰富内涵的网络软件的协议。它不仅仅能够对于互联网资源进行唯一定位,而且还能告诉我们对于该资源进行怎样运作。这也是rest软件架构当中最重要的两个理念。而rest软件架构理念是真正理解http协议而形成的。有了rest软件架构理念出现,才使得软件业避免了对http协议的片面理解。只有正确的理论指导,才能避免在软件开发的实际工作过程中少走弯路。

rest与uri(资源定位)
rest软件架构之所以是一个超媒体系统,是因为它可以把网络上所有资源进行唯一的定位,不管你的文件是图片、文件word还是视频文件,也不管你的文件是txt文件格式、xml文件格式还是其它文本文件格式。它利用支持http的tcp/ip协议来确定互联网上的资源。

rest与crud原则
rest软件架构遵循了crud原则,该原则告诉我们对于资源(包括网络资源)只需要四种行为:创建(create)、获取(read)、更新(update)和销毁(delete)就可以完成对其操作和处理了。其实世界万物都是遵循这一规律:生、变、见、灭。所以计算机世界也不例外。这个原则是源自于我们对于数据库表的数据操作:insert(生)、select(见)、update(变)和delete(灭),所以有时候crud也写作为rudi,其中的i就是insert。这四个操作是一种原子操作,即一种无法再分的操作,通过它们可以构造复杂的操作过程,正如数学上四则运算是数字的最基本的运算一样。

rest与网络服务
尽管在java语言世界中网络服务目前是以soap技术为主,但是rest将是是网络服务的另一选择,并且是真正意义上的网络服务。基于rest思想的网络服务不久的将来也会成为是网络服务的主流技术。rest不仅仅把http作为自己的数据运输协议,而且也作为直接进行数据处理的工具。而当前的网络服务技术都需要使用其它手段来完成数据处理工作,它们完全独立于http协议来进行的,这样增加了大量的复杂软件架构设计工作。rest的思想充分利用了现有的http技术的网络能力。在德国电视台上曾经出现过一个这样的五十万欧元智力题:如何实现网络服务才能充分利用现有的http协议?该问题给出了四个答案:去问微软;wsdl2.0/soap1.2;ws-transfer;根本没有。这个问题告诉我们http并不是一个简单的数据传来传去的协议,而是一个聪明的会表现自己的协议,这也许是rest = representational state transfer的真正含义。实际上目前很多大公司已经采用了rest技术作为网络服务,如google、amazon等。在java语言中重要的两个以soap技术开始的网络服务框架xfire和axis也把rest作为自己的另一种选择。它们的新的项目分别是apache cxf和axis2。java语言也制定关于rest网络服务规范:jax-rs: java api for restful web services (jsr 311)。相信还会出现更多与rest相关的激动人心的信息。

rest与ajax技术
尽管ajax技术的出现才不到两年时间,但是ajax技术遵循了rest的一些重要原则。ajax技术充分利用了http来获取网络资源并且实现了http没有的对于异步数据进行传输的功能。ajax技术还使得软件更好地实现分布性功能,在一个企业内只要一个人下载了ajax引擎,其它企业内部的人员,就可以共享该资源了。ajax技术遵守rest准则的应用程序中简单和可伸缩的架构,凡是采用ajax技术的页面简洁而又丰富,一个页面表现了丰富多彩的形态。ajax技术还使用了一种不同于xml格式的json文件格式,这个意义在哪里呢?在rest软件架构下我们不能对于xml文件进行序列化处理,这样程序员必须要使用自己的xml绑定框架。而以序列化的javascript对象为基础的json已经获得了广泛认可,它被认为能以远比xml更好的方式来序列化和传输简单数据结构,而且它更简洁。这对rest是一个极大贡献和补充。当前的网络应用软件还违背了rest的"无状态服务器"约束。rest服务器只知道自己的状态。rest不关心客户端的状态,客户端的状态自己来管理,这是ajax技术的应用之地。通过ajax技术,可以发挥有状态网络客户机的优势。而rest的服务器关心的是从所有网络客户端发送到服务器操作的顺序。这样使得互联网这样一个巨大的网络得到有序的管理。

rest与rails框架
ruby on rails框架(简称rails或者rails框架)是一个基于ruby语言的越来越流行的网络应用软件开发框架。它提供了关于rest最好的支持,也是当今应用rest最成功的一个软件开发框架。rails框架(从版本1.2.x起)成为了第一个引入rest作为核心思想的主流网络软件开发框架。在rails框架的充分利用了rest软件架构之后,人们更加坚信rest的重要性和必要性。rails利用rest软件架构思想对网络服务也提供了一流的支持。从最直观的角度看待rest,它是网络服务最理想的手段,但是rails框架把rest带到了网络应用软件开发框架。这是一次飞跃,让rest的思想从网络服务的应用提升到了网络应用软件开发。利用rest思想的simply_restful插件已经成为了rails框架的核心内容。

rest安全性
我们把现有基于soap的网络服务和基于rest/http网络服务作个比喻,前者是一种传统的寄信方式,而后者是现代网络的电子邮件方式。要是是寄信和电子邮件都有病毒存在的话,传统的寄信被送到对方就很危险,而电子邮件是开发的,电子邮件供应商比如google为我们检查了电子邮件是否有病毒。这里并不是说明soap网络服务消息包含义病毒,而是说明http是无法处理soap信息包究竟好不好,需要额外的软件工具解决这一问题,包括防火墙也用不上和管不了。
rest/http网络服务的信息包可以被防火墙理解和控制。你可以按照操作和链接进行过滤信息包,如你可以规定从外部来的只能读取(get操作)自己服务器的资源。这样对于系统管理员而言使得软件管理更为简单。rest的安全性还可以利用传输安全协议ssl/tls、基本和摘要式认证(basic und digest authentication)。除了这些rest自身的安全性功能外,还可以利用像基于信息的web services security(jsr 155)作为rest不错的补充。

2. restlet 类结构

uniform 是一个 abstract 类,定义了和 httpmethod 对应的方法如 get,post,delete,put 等等。子类 restlet 应该是这个框架的核心类了,restlet 有些像 servlet api,可以得到 application和 context 两个对象,其子类分别为链接器,应用,路由器,查找器,组件和过滤器。在看他的表述类结构

3. 脱离 web server 的 restlet

其实说脱离,只是 restlet 自己做了端口监听和 http 协议解析和封装的功能,restlet 设计是以资源设计为中心的,有些像 struts,webwork之 mvc 风格但又不同,他完全符合 rest 体系架构风格,可以很好的和现有的领域模型结合,一个简单的分层结构如图 资源层是对需要显示的领域模型做了显示封装,对表示层提供资源,而对领域层中需要持久化的模型借助 orm 映射器持久化。个人觉得 restlet 的应用核心在于服务,像 axis2和xfire 等都有支持 rest 风格,restlet结合 json 应该是个比较好的实践。

且看下面简单的代码(代码为官方文档里的例子):

对 resource 封装一下 baseresource 以方便应用程序使用:

 1package org.blogjava.restlet;
 2

 3import
 java.util.map;
 4

 5import
 org.restlet.context; 
 6import
 org.restlet.data.request; 
 7import
 org.restlet.data.response; 
 8import
 org.restlet.resource.resource; 
 9import
 org.restlet.application;
10

11
/** 
12
* base resource class that supports common behaviours or attributes shared by 
13
* all resources. 
14

15*/
 
16public abstract class baseresource extends resource 
{
17

18public baseresource(context context, request request, response response) 

19super
(context, request, response); 
20}

21
22
/** 
23
* returns the map of items managed by this application. 
24

25@return
 the map of items managed by this application. 
26*/
 
27protected map<string, item> getitems() 

28return
 ((firstresourceapplication) getcontext().getattributes().get( 
29
application.key)).getitems(); 
30}
 
31}

32
33


实现 application 类,定义路由(uri ->resource 的映射)

 

 1package org.blogjava.restlet;
 2

 3import
 java.util.map; 
 4import
 java.util.concurrent.concurrenthashmap;
 5

 6import
 org.restlet.application; 
 7import
 org.restlet.context; 
 8import
 org.restlet.restlet; 
 9import
 org.restlet.router;
10

11public class firstresourceapplication extends application 
{
12

13/** the list of items is persisted in memory. */
 
14private final map<string, item>
 items;
15

16public firstresourceapplication(context parentcontext) 

17super
(parentcontext); 
18// we make sure that this attribute will support concurrent access. 

19items = new concurrenthashmap<string, item>(); 
20}

21
22
/** 
23
* creates a root restlet that will receive all incoming calls. 
24*/
 
25
@override 
26public synchronized restlet createroot() 

27// create a router restlet that defines routes. 

28router router = new router(getcontext());
29

30// defines a route for the resource "list of items" 

31router.attach("/items", itemsresource.class); 
32// defines a route for the resource "item" 

33router.attach("/items/{itemname}", itemresource.class);
34

35return
 router; 
36}

37
38
/** 
39
* returns the list of registered items. 
40

41@return
 the list of registered items. 
42*/
 
43public map<string, item> getitems() 

44return
 items; 
45}
 
46}
 
47


资源类实现:

 

  1public class itemresource extends baseresource {
  2

  3/** the underlying item object. */
 
  4
item item;
  5

  6/** the sequence of characters that identifies the resource. */
 
  7
string itemname;
  8

  9public itemresource(context context, request request, response response) 

 10super
(context, request, response);
 11

 12//
 get the "itemname" attribute value taken from the uri template 
 13// /items/{itemname}. 

 14this.itemname = (string) getrequest().getattributes().get("itemname");
 15

 16// get the item directly from the "persistence layer". 

 17this.item = getitems().get(itemname);
 18

 19if (this.item != null

 20// define the supported variant. 

 21getvariants().add(new variant(mediatype.text_xml)); 
 22}
 
 23}

 24
 25
/** 
 26
* this resource supports delete requests. 
 27*/
 
 28
@override 
 29public boolean allowdelete() 

 30return true

 31}

 32
 33
/** 
 34
* this resource supports put requests. 
 35*/
 
 36
@override 
 37public boolean allowput() 

 38return true

 39}

 40
 41
/** 
 42
* handle delete requests. 
 43*/
 
 44
@override 
 45public void delete() 

 46if (item != null

 47// remove the item from the list. 

 48getitems().remove(item.getname()); 
 49}

 50
 51// tells the client that the request has been successfully fulfilled. 

 52getresponse().setstatus(status.success_no_content); 
 53}

 54
 55
@override 
 56public representation getrepresentation(variant variant) 
{
 57

 58if (mediatype.text_xml.equals(variant.getmediatype())) 

 59// generate the xml representation of this resource. 

 60try 
 61// generate a dom document representing the item. 

 62domrepresentation representation = new domrepresentation( 
 63
mediatype.text_xml); 
 64document d =
 representation.getdocument();
 65

 66element eltitem = d.createelement("item"
); 
 67
d.appendchild(eltitem); 
 68element eltname = d.createelement("name"
); 
 69
eltname.appendchild(d.createtextnode(item.getname())); 
 70
eltitem.appendchild(eltname);
 71

 72element eltdescription = d.createelement("description"
); 
 73
eltdescription.appendchild(d.createtextnode(item 
 74
.getdescription())); 
 75
eltitem.appendchild(eltdescription);
 76

 77
d.normalizedocument();
 78

 79// returns the xml representation of this document. 

 80return representation; 
 81}
 catch (ioexception e) 
 82
e.printstacktrace(); 
 83}
 
 84}

 85
 86return null

 87}

 88
 89
/** 
 90
* handle put requests. 
 91*/
 
 92
@override 
 93public void put(representation entity) 

 94// tells if the item is to be created of not. 

 95boolean creation = (item == null);
 96

 97// the put request updates or creates the resource. 

 98if (item == null
 99item = new
 item(itemname); 
100}

101
102// update the description. 

103form form = new form(entity); 
104item.setdescription(form.getfirstvalue("description"
));
105

106// update the item in the list. 

107getitems().put(item.getname(), item);
108

109if (creation) 

110
getresponse().setstatus(status.success_created); 
111}
 else 
112
getresponse().setstatus(status.success_ok); 
113}
 
114}

115
116}
 
117

118

客户端和服务器类,服务器类代替 web server 做监听和 http 协议处理。

 

  1package org.blogjava.restlet;
  2

  3import
 java.io.ioexception;
  4

  5import
 org.restlet.client; 
  6import
 org.restlet.data.form; 
  7import
 org.restlet.data.protocol; 
  8import
 org.restlet.data.reference; 
  9import
 org.restlet.data.response; 
 10import
 org.restlet.resource.representation;
 11

 12public class firstresourceclientmain 
{
 13

 14public static void main(string[] args) throws ioexception 

 15// define our restlet http client. 

 16client client = new client(protocol.http);
 17

 18// the uri of the resource "list of items". 

 19reference itemsuri = new reference( 
 20"http://localhost:8182/firstresource/items"
);
 21

 22// create a new item 

 23item item = new item("item1""this is an item."); 
 24reference itemuri =
 createitem(item, client, itemsuri); 
 25if (itemuri != null

 26// prints the representation of the newly created resource. 

 27get(client, itemuri); 
 28}

 29
 30// prints the list of registered items. 

 31get(client, itemsuri);
 32

 33// update the item 

 34item.setdescription("this is an other description"); 
 35
updateitem(item, client, itemuri);
 36

 37// prints the list of registered items. 

 38get(client, itemsuri);
 39

 40// delete the item 

 41deleteitem(client, itemuri);
 42

 43// print the list of registered items. 

 44get(client, itemsuri); 
 45}

 46
 47
/** 
 48
* try to create a new item. 
 49

 50@param
 item 
 51
* the new item. 
 52@param
 client 
 53
* the restlet http client. 
 54@param
 itemsuri 
 55
* where to post the data. 
 56@return
 the reference of the new resource if the creation succeeds, null 
 57
* otherwise. 
 58*/
 
 59public static
 reference createitem(item item, client client, 
 60reference itemsuri) 

 61// gathering informations into a web form. 

 62form form = new form(); 
 63form.add("name"
, item.getname()); 
 64form.add("description"
, item.getdescription()); 
 65representation rep =
 form.getwebrepresentation();
 66

 67// launch the request 

 68response response = client.post(itemsuri, rep); 
 69if (response.getstatus().issuccess()) 

 70if (response.isentityavailable()) 

 71try 

 72// always consume the response's entity, if available. 

 73response.getentity().write(system.out); 
 74}
 catch (ioexception e) 
 75
e.printstacktrace(); 
 76}
 
 77}

 78
 79return
 response.getentity().getidentifier(); 
 80}

 81
 82return null

 83}

 84
 85
/** 
 86
* prints the resource's representation. 
 87

 88@param
 client 
 89
* client restlet. 
 90@param
 reference 
 91
* the resource's uri 
 92@throws
 ioexception 
 93*/
 
 94public static void
 get(client client, reference reference) 
 95throws ioexception 

 96response response =
 client.get(reference); 
 97if (response.getstatus().issuccess()) 

 98if (response.isentityavailable()) 

 99
response.getentity().write(system.out); 
100}
 
101}
 
102}

103
104
/** 
105
* try to update an item. 
106

107@param
 item 
108
* the item. 
109@param
 client 
110
* the restlet http client. 
111@param
 itemuri 
112
* the resource's uri. 
113*/
 
114public static boolean updateitem(item item, client client, reference itemuri) 

115// gathering informations into a web form. 

116form form = new form(); 
117form.add("name"
, item.getname()); 
118form.add("description"
, item.getdescription()); 
119representation rep =
 form.getwebrepresentation();
120

121// launch the request 

122response response = client.put(itemuri, rep); 
123if (response.isentityavailable()) 

124try 

125// always consume the response's entity, if available. 

126response.getentity().write(system.out); 
127}
 catch (ioexception e) 
128
e.printstacktrace(); 
129}
 
130}
 
131return
 response.getstatus().issuccess(); 
132}

133
134
/** 
135
* try to delete an item. 
136

137@param
 client 
138
* the restlet http client. 
139@param
 itemuri 
140
* the resource's uri. 
141*/
 
142public static boolean deleteitem(client client, reference itemuri) 

143// launch the request 

144response response = client.delete(itemuri); 
145if (response.isentityavailable()) 

146try 

147// always consume the response's entity, if available. 

148response.getentity().write(system.out); 
149}
 catch (ioexception e) 
150
e.printstacktrace(); 
151}
 
152}

153
154return
 response.getstatus().issuccess(); 
155}

156
157}
 
158package
 org.blogjava.restlet; 
159import
 org.restlet.component; 
160import
 org.restlet.data.protocol;
161

162public class firstresourceservermain 
{
163

164public static void main(string[] args) throws exception 

165// create a new component. 

166component component = new component();
167

168// add a new http server listening on port 8182. 

169component.getservers().add(protocol.http, 8182);
170

171// attach the sample application. 

172component.getdefaulthost().attach("/firstresource"
173new
 firstresourceapplication(component.getcontext()));
174

175// start the component. 

176component.start(); 
177}

178
179}
 
180

181

 

4.和现有 servlet 容器结合的例子

配置 web.xml

 1<context-param> 
 2<param-name>org.restlet.applicationparam-name>
 
 3<param-value>
 
 4
org.blogjava.helloworld.firststepsapplication 
 5param-value>
 
 6context-param>
 
 7
 
 8<servlet>
 
 9<servlet-name>restletservletservlet-name>
 
10<servlet-class>
 
11
com.noelios.restlet.ext.servlet.serverservlet 
12servlet-class>
 
13servlet>
 
14
 
15<servlet-mapping>
 
16<servlet-name>restletservletservlet-name>
 
17<url-pattern>/*url-pattern>
 
18servlet-mapping>

19
20

实现 application 和 resource 资源类

 

 1
 2public class firststepsapplication extends application {
 3

 4public firststepsapplication(context parentcontext) 

 5super
(parentcontext); 
 6}

 7
 8
/** 
 9
* creates a root restlet that will receive all incoming calls. 
10*/
 
11
@override 
12public synchronized restlet createroot() 

13//
 create a router restlet that routes each call to a 
14// new instance of helloworldresource. 

15router router = new router(getcontext());
16

17// defines only one route 

18router.attachdefault(helloworldresource.class);
19

20return
 router; 
21}
 
22}
 
23

24

25package
 org.blogjava.helloworld;
26

27import
 org.restlet.context; 
28import
 org.restlet.data.mediatype; 
29import
 org.restlet.data.request; 
30import
 org.restlet.data.response; 
31import
 org.restlet.resource.representation; 
32import
 org.restlet.resource.resource; 
33import
 org.restlet.resource.stringrepresentation; 
34import
 org.restlet.resource.variant;
35

36
/** 
37
* resource which has only one representation. 
38

39*/
 
40public class helloworldresource extends resource 
{
41

42public
 helloworldresource(context context, request request, 
43response response) 

44super
(context, request, response);
45

46// this representation has only one type of representation. 

47getvariants().add(new variant(mediatype.text_plain)); 
48}

49
50
/** 
51
* returns a full representation for a given variant. 
52*/
 
53
@override 
54public representation getrepresentation(variant variant) 

55representation representation = new
 stringrepresentation( 
56"hello, world,just a simple example!"
, mediatype.text_plain); 
57return
 representation; 
58}
 
59}

60
61

参考资料

(官方手册)





本博客为学习交流用,凡未注明引用的均为本人作品,转载请注明出处,如有凯发k8网页登录的版权问题请及时通知。由于博客时间仓促,错误之处敬请谅解,有任何意见可给我留言,愿共同学习进步。
posted on 2008-10-08 10:40 jack.wang 阅读(29517) 评论(4)     所属分类: 开发技术架构师篇领域建模
# re: restlet 学习笔记 2008-10-08 11:41
字体看不清啦,特别是代码  回复  
  

# re: restlet 学习笔记 2008-10-08 11:48 jack.wang
@reviewer
不好意思,改了!  回复  
  

# re: restlet 学习笔记 2009-11-17 15:07
第二张图有问题
file:///h:/zoundry raven/profiles/my profile/resourcestore/representations[1].png  回复  
  

# re: restlet 学习笔记 2011-12-13 11:01
中文字体好难看,看得眼痛。。不要用font-family: 楷体_gb2312  回复  
  

网站地图