|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
轮性能微软曾做过一个例子,就是同一个项目用java和.net网页编程来作,结果开发周期,.net网页编程是java的一半,性能java是.net网页编程的十分之一,代码量java是.net网页编程的三倍。呵呵,这说明了什么,.net网页编程的全方位比java好。但是有的人说.net网页编程不能跨平台,这个问题我和我同学曾讨论过,都认为微软的.net网页编程很可能早都可以跨平台了,但是微软为了保护他们的操作系统,所以才没有推出跨平台的.net网页编程,只是推出了跨语言的.net网页编程,Restlet项目(http://www.restlet.org)为“创建REST观点与Java类之间的映照”供应了一个轻量级而周全的框架。它可用于完成任何品种的REST式体系,而不单单是REST式Web服务;并且,现实证实它自从2005年出生之时起,就是一个牢靠的软件。
Restlet项目遭到ServletAPI、JSP(JavaServerPages)、HttpURLConnection及Struts等Web开辟手艺的影响。该项目标次要方针是:在供应一律功效的同时,只管恪守RoyFielding博士论文中所论述的REST的方针。它的另外一个次要方针是:提出一个既适于客户端使用又适于服务真个使用的、一致的Web视图。
Restlet的头脑是:HTTP客户端与HTTP服务器之间的不同,对架构来讲无所谓。一个软件应能够既充任Web客户端又充任Web服务器,而不必接纳两套完整分歧的APIs。
Restlet包含RestletAPI和NoeliosRestletEngine(NRE)两部分,NRE是对RestletAPI的一种参考完成。这类分别,使得分歧完成能够具有一样的API。NRE包含多少HTTP服务器毗连器(HTTPserverconnector),它们都是基于Mortbay的Jetty、Codehaus的AsyncWeb,和Simple框架这些盛行的HTTPJava开源项目标。它乃至供应一个适配器(adapter),使你能够在尺度Servlet容器(如ApacheTomcat)外部署一个Restlet使用。
Restlet还供应两个HTTP客户端毗连器(HTTPclientconnector)。它们一个是基于官方的HttpURLConnection类,一个是基于Apache的HTTP客户端库。另有一个毗连器同意你简单地按REST作风经由过程XML文档来处置JDBC源(source);别的,一个基于JavaMailAPI的SMTP毗连器同意你发送内容为XML的Email。
RestletAPI包含一些可以创立基于字符串、文件、流(stream)、通道(channel)及XML文档的暗示(representation),它撑持SAX、DOM及XSLT。利用FreeMaker或ApacheVelocity模板引擎,你能够很简单地创立基于JSP式模板的暗示(representations)。你乃至能够像一般Web服务器那样,用一个撑持内容协商(contentnegotiation)的Directory类来前往静态文件与目次。
复杂性(simplicity)和天真性(flexibility)是贯串全部框架的计划准绳。RestletAPI旨在把HTTP、URI及REST的观点笼统成一系列类(classes),同时又不把低层信息(如原始HTTP报头)完整埋没起来。
基础观点
Restlet在术语上参照了RoyFielding博士论文在解说REST时接纳的术语,如:资本(resource)、暗示(representation)、毗连器(connector)、组件(component)、媒体范例(mediatype)、言语(language),等等。这些术语你应当不会生疏。Restlet增添了一些专门的类(如Application、Filter、Finder、Router和Route),用以简化restlets的相互分离,和简化把收到的哀求(incomingrequests)映照为处置它们的资本。
<br>
2-1:Restlet的类条理布局
笼统类Uniform及其详细子类Restlet,是Restlet的中心观点。正如其称号所表示的,Uniform表露一个切合REST划定的一致接口(uniforminterface)。固然该接口是按HTTP一致接口界说的,但它也可用于其他协定(如FTP和SMTP)。
handle是一个主要的办法,它承受两个参数:Request和Response。正如你能够从2-1中看到的,每一个表露于网上的挪用处置者(callhandler)(不管作为客户端仍是服务端)都是Restlet的一个子类——也就是说,它是一个restlets——并恪守这个一致接口。因为有一致接口,restlets能够十分庞大的体例组合在一同。
Restlet撑持的每个协定都是经由过程handle办法表露的。这就是说,HTTP(服务器和客户端)、HTTPS、SMTP,和JDBC、文件体系,乃至类加载器(classloaders)都是经由过程挪用handle办法来操纵的。这削减了开辟者需把握的APIs的数目。
过滤、平安、数据转换及路由是“经由过程把Restlet的子类链起来”举行处置的。Filters能够在处置下个restlet挪用之前或以后举行处置。Filters实例的事情体例与Rails过滤器差未几,只不外Filters实例跟其他Restlet类一样呼应handle办法,而不是具有一个专门的API。
一个Routerrestlet有很多从属的Restlet对象,它把每一个收到的协定挪用(incomingprotocolcall)路由给得当的Restlet处置器。路由(routing)一般是依据方针URI举行的。跟Rails分歧的是,Restlet没有对资本条理布局(resourcehierarchy)作URI划定规矩限制,以是能够随便设置想要的URI,只需对Routers作响应编程就好了。
除这一罕见用处,Router还可用于其他用处。你能够用一个Router在多台远程呆板之间以静态负载平衡的体例来转发挪用。即便在这类庞大的情形下,它也一样呼应Restlet的一致接口,而且可成为一个更亨衢由体系中的一个组件。VirtualHost类(Router的一个子类)使我们能够在统一台物理主机上运转多个具有分歧域名的使用。在已往,你要引进一个前端Web服务器(如Apache的httpd)才干完成此功效;而用Restlet的话,它只是另外一个呼应一致接口的Router完成。
一个Application对象可以办理一组restlets,并供应罕见的服务,例如说对紧缩的哀求举行通明解码,大概使用method查询参数在重载的POST(overloadedPOST)之上完成PUT和DELETE哀求。最初,Component对象能够包括并编配(orchestrate)一组Connectors、VirtualHosts及Applications(作为自力Java使用运转的,大概嵌进在一个更年夜体系(如J2EE情况)中的)。
在第6章,我向你先容了“把一个成绩分别为一组呼应HTTP一致接口的资本”的步骤。在第7章,为了处置RubyonRails的复杂化假定(simplifyingassumptions),我对该步骤作了响应的调剂。由于Restlet没有做复杂化假定(simplifyingassumptions),以是我们不必对此步骤举行修正。它能够完成任何REST式体系。假如你恰好想完成一个REST式面向资本的Web服务,能够按乐意的体例来构造和完成这些资本。Restlet的确供应了一些便于创立面向资本的使用的类。个中出格值得一提的是Resource类,它可作为你一切使用资本的基本。
我在本书中一向用URI模板作为一组URIs的简化表达(见第9章)。Restlet用URI模板来举行URI与资本的映照。假设用Restlet来完成第7章谁人社会性书签服务的话,它大概要指定一个代表特定书签的URI:- /users/{username}/bookmarks/{URI}
复制代码 你能够在把Resource子类附加到Router上时利用这类语法。假设你不信任真会这么好的话,能够比及下一节,当时我会实践完成部分书签服务。
编写Restlet客户端
在示例2-1中,你看到的是一个从Yahoo!搜刮服务猎取XML搜刮了局的Ruby客户端。示例12-3是一个用Java参照Restlet1.0完成的具有一样功效的客户端。要确保把以下JAR包写在你的classpath中,才干乐成编译并运转接上去的例子:
- org.restlet.jar(RestletAPI)
- com.noelios.restlet.jar(NoeliosRestletEngine中心)
- com.noelios.restlet.ext.net.jar(基于JDK的HttpURLConnection的HTTP客户端毗连器)
这些JAR包能够在Restlet公布包中的lib目次里找到。要确保你的Java情况撑持JavaSE5.0(或更高)版本。假如你的确必要的话,能够用Retrotranslator(http://retrotranslator.sourceforge.net/)容易地把Restlet代码反移植(backport)到J2SE4.0版上往。
示例12-3:Yahoo!搜刮服务的一个Restlet客户端- //YahooSearch.javaimportorg.restlet.Client;importorg.restlet.data.Protocol;importorg.restlet.data.Reference;importorg.restlet.data.Response;importorg.restlet.resource.DomRepresentation;importorg.w3c.dom.Node;/***用前往XML的Yahoo!搜刮服务来搜刮Web*/publicclassYahooSearch{staticfinalStringBASE_URI="http://api.search.yahoo.com/WebSearchService/V1/webSearch";publicstaticvoidmain(String[]args)throwsException{if(args.length!=1){System.err.println("Youneedtopassatermtosearch");}else{//猎取一个资本,即一个包括搜刮了局的XML文档Stringterm=Reference.encode(args[0]);Stringuri=BASE_URI+"?appid=restbook&query="+term;Responseresponse=newClient(Protocol.HTTP).get(uri);DomRepresentationdocument=response.getEntityAsDom();//用XPath找出数据布局中主要部分Stringexpr="/ResultSet/Result/Title";for(Nodenode:document.getNodes(expr)){System.out.println(node.getTextContent());}}}}
复制代码 跟示例2-1一样,你能够在实行这个类时把一个搜刮关头字作为命令行参数传给它。好比像上面如许:- $javaYahooSearchxsltXSLTransformations(XSLT)TheExtensibleStylesheetLanguageFamily(XSL)XSLTTutorial...
复制代码 该示例证实了“用Restlet从Web服务猎取XML数据,并用尺度工具处置它”是极为复杂的事。Yahoo!资本的URI是用一个常量和用户供应的搜刮关头字机关而成的。客户端毗连器(clientconnector)是用HTTP协定来初始化的。XML文档是经由过程get办法取得的,该办法对应于HTTP一致接口的GET办法。当挪用前往时,程序将失掉一个DOM暗示。跟后面的Ruby例子一样,XPath是对XML举行查询的最复杂体例。
跟后面的Ruby例子一样,这个程序也疏忽了XML文档里的XML称号空间(namespaces)。Yahoo!为全部文档接纳称号空间urn:yahoo:srch,但我是间接援用标签的,例如说,我用ResultSet,而不是urn:yahoo:srch:ResultSet。后面的Ruby例子疏忽称号空间,是由于Ruby的默许XML剖析器不撑持称号空间。Java的XML剖析器撑持称号空间,并且RestletAPI令阃确处置称号空间变得加倍简单。固然对下面谁人复杂例子来讲,它们区分不年夜,但撑持称号空间能够制止一些因称号空间而招致的奇妙的成绩。
固然,若一向用urn:yahoo:srch:ResultSet,是对照烦人的。RestletAPI能够简单地把一个冗长前缀跟一个称号空间举行联系关系,然后就能够在XPath表达式中利用这个冗长前缀而不是全部称号空间了。示例12-4对示例12-3后半部分代码作了修改,它利用了带称号空间的Xpath,如许就不会把来自Yahoo!的ResultSet标签与来自其他称号空间的标签弄混了。
示例12-4:撑持称号空间的文档处置代码- DomRepresentationdocument=response.getEntityAsDom();//把该称号空间与前缀‘y’联系关系起来document.setNamespaceAware(true);document.putNamespace("y","urn:yahoo:srch");//用XPath找出数据布局中主要部分Stringexpr="/y:ResultSet/y:Result/y:Title/text()";for(Nodenode:document.getNodes(expr)){System.out.println(node.getTextContent());}
复制代码 示例2-15是Yahoo!搜刮服务的另外一个Ruby客户端。它哀求的是JSON格局(而不是XML格局)的搜刮数据。示例12-5是一个与之功效等价的Restlet客户端。它经由过程Restlet里的另两个JAR文件猎取JSON撑持:
- org.restlet.ext.json_2.0.jar(用于JSON的Restlet扩大)
- org.json_2.0/org.json.jar(JSON官方程序库)
示例12-5:Yahoo!的JSON搜刮服务的一个Restlet客户端- //YahooSearchJSON.javaimportorg.json.JSONArray;importorg.json.JSONObject;importorg.restlet.Client;importorg.restlet.data.Protocol;importorg.restlet.data.Reference;importorg.restlet.data.Response;importorg.restlet.ext.json.JsonRepresentation;/***用前往JSON的Yahoo!搜刮服务来搜刮Web*/publicclassYahooSearchJSON{staticfinalStringBASE_URI="http://api.search.yahoo.com/WebSearchService/V1/webSearch";publicstaticvoidmain(String[]args)throwsException{if(args.length!=1){System.err.println("Youneedtopassatermtosearch");}else{//猎取一个资本,即一个包括搜刮了局的JSON文档Stringterm=Reference.encode(args[0]);Stringuri=BASE_URI+"?appid=restbook&output=json&query="+term;Responseresponse=newClient(Protocol.HTTP).get(uri);JSONObjectjson=newJsonRepresentation(response.getEntity()).toJsonObject();//在JSON文档中寻觅并显现题目JSONObjectresultSet=json.getJSONObject("ResultSet");JSONArrayresults=resultSet.getJSONArray("Result");for(inti=0;i<results.length();i++){System.out.println(results.getJSONObject(i).getString("Title"));}}}}
复制代码 当你为Yahoo!的Web服务编写客户端时,能够选择暗示格局(representationformat)。Restlet中心API撑持XML,别的还能够经由过程扩大撑持JSON。正如你所意料的那样,这两个例子的区分仅仅在于对呼应的处置上。JsonRepresentation类能够把呼应实体主体(responseentity-body)转换成一个JSONObject实例(而Ruby的JSON库是把JSON数据布局转换成一个当地数据布局)。该数据布局只能举行野生遍历,由于今朝JSON中还没有相似XPath的查询言语。
编写Restlet服务
接上去的例子会略微庞大一些。我将向你展现怎样计划并完成一个服务端使用。在第7章,我用RubyonRails完成了一个书签办理使用,如今我用Restlet来从头完成其部分功效。为了复杂起见,该使用只撑持对用户及其书签举行平安的(safe)操纵。
Java包布局是如许的:- orgrestletexamplebookrestch7-Application-ApplicationTest-Bookmark-BookmarkResource-BookmarksResource-User-UserResource
复制代码 也就是说,Bookmark等类都在org.restlet.example.book.rest.ch7包里。
我不盘算在此展现完全的代码。假如必要,你能够往本书的官方网站(http://www.oreilly.com/catalog/9780596529260),那边供应了本书的一切示例程序代码。你也能够在restlet.org(http://www.restlet.org)上找到本例的完全代码。假如你已下载了Restlet的话,那末也能够在src/org/restlet.example/org/restlet/example/book/rest目次里找到本节的示例代码。
我将从一些复杂的代码入手下手。示例12-6是Application.main办法,它用来创建Web服务器,并入手下手处置哀求。
示例12-6:Application.main办法:创建Web服务器- publicstaticvoidmain(String...args)throwsException{//用HTTP服务器毗连器创立一个组件Componentcomp=newComponent();comp.getServers().add(Protocol.HTTP,3000);//把使用附加到默许主机上,并启动comp.getDefaultHost().attach("/v1",newApplication());comp.start();}
复制代码 资本与URI计划
因为Restlet未对资本计划作出格的限定,以是你完整能够依据ROA的计划准绳来举行资本类(resourceclasses)及URIs的计划。在第7章,我要环绕“Rails的基于把持器的架构”来举行计划;而这里,我不必要环绕Restlet架构来举行计划。2-2展现了URI是怎样经过Router映照到资本,再映照到上层restlet类的。
<br>
2-2:社会性书签使用的Restlet架构
为了了解怎样用Java代码完成这些映照,我们来看一下Application类及它的createRoot办法(见教例12-7)。它跟示例7-3所示的Railsroutes.rb文件在功效上是等价的。
示例12-7:Application.createRoot办法:完成URI模板到restlet的映照- publicRestletcreateRoot(){Routerrouter=newRouter(getContext());//为用户资本增添路由router.attach("/users/{username}",UserResource.class);//为用户的书签资本增添路由router.attach("/users/{username}/bookmarks",BookmarksResource.class);//为书签资本增添路由RouteuriRoute=router.attach("/users/{username}/bookmarks/{URI}",BookmarkResource.class);uriRoute.getTemplate().getVariables().put("URI",newVariable(Variable.TYPE_URI_ALL));}
复制代码 在我创立一个Application对象(好比像示例12-6中的那样)时,这段代码便会运转。它会在资本类UserResource与URI模板“/users/(username)”之间创建起明晰而直不雅的映照干系。Router先拿哀求的方针URI跟URI模板(URItemplates)举行对照,然后把哀求转发给一个新建的响应的资本类实例。模板变量的值被寄存在哀求的属性舆图(attributesmap)里(跟Rails例子中的params舆图相似),以便于在Resource代码中利用。这既无效,又易于了解;当你事隔好久再回忆代码时,这很有匡助。
哀求处置和暗示
假定一个客户端向URIhttp://localhost:3000/v1/users/jerome收回GET哀求。我有一个监听当地主机3000端口的Component对象,和一个从属于/v1的Application对象。该Application有一个Router和一组Route对象,这些Route对象正守候着跟各个URI模板婚配的哀求。URI路径片断“/users/jerome”跟模板“/users/{username}”相婚配,而该模板的Route是与UserResource类(大抵等价于RailsUsersController类)相干联的。
Restlet经由过程初始化一个新的UserResource对象,并挪用它的handleGet办法来处置该哀求。示例12-8是UserResource类的机关办法。
示例12-8:UserResource类的机关办法- /***机关办法**@paramcontext*下级高低文*@paramrequest*要处置的哀求*@paramresponse*要前往的呼应*/publicUserResource(Contextcontext,Requestrequest,Responseresponse){super(context,request,response);this.userName=(String)request.getAttributes().get("username");ChallengeResponsecr=request.getChallengeResponse();this.login=(cr!=null)?cr.getIdentifier():null;this.password=(cr!=null)?cr.getSecret():null;this.user=findUser();if(user!=null){getVariants().add(newVariant(MediaType.TEXT_PLAIN));}}
复制代码 至此,这个架构已创建了一个Request对象,它包括了我所必要的关于哀求的一切信息。username属性来自URI,认证证书来自哀求的Authorization报头。我还挪用findUser办法来依据认证证书在数据库中查找用户(为节俭篇幅,我就不在此展现findUser办法的代码了)。这些事情在第7章都是由Rails过滤器完成的。
在框架把一个UserResource实例化后,它会对资本对象挪用得当的handle办法。HTTP一致接口中的每个办法,都有一个对应handle办法。在这个例子中,Restlet架构最初的义务是挪用UserResource.handleGet。
因为我没有界说UserResource.handleGet这个办法,以是它将具有承继Resource.handleGet办法的举动。HandleGet的默许举动是找到最切合客户端请求的资本的暗示。客户端经由过程内容协商(content-negotiation)来表达它的请求。Restlet经由过程Accept报头的值来决意前往哪一个暗示。因为这里只要一个暗示格局,以是客户真个请求不起感化。这是由getVariants和getRepresentation办法处置的。因为在上述机关办法中把text/plain界说为独一撑持的暗示格局,以是我的getRepresentation办法的完成是很复杂的(见教例12-9)。
示例12-9:UserResoure.getRepresentation:机关一个用户的暗示- @OverridepublicRepresentationgetRepresentation(Variantvariant){Representationresult=null;if(variant.getMediaType().equals(MediaType.TEXT_PLAIN)){//创立一个文本暗示StingBuildersb=newStringBuilder();sb.append("------------");sb.append("Userdetails");sb.append("------------");sb.append("Name:").append(this.user.getFullName()).append("");sb.append("Email:").append(this.user.getEmail()).append("");result=newStringRepresentation(sb);}returnresult;}
复制代码 固然这只是一个资本的一个办法,但其他资本,和UserResource的其他HTTP办法的事情道理都差未几,好比:对用户的PUT哀求将被路由给UserResource.handlePut,等等。正如我后面所提到的,这里的代码只是社会性书签使用一切代码的一部分;以是,假如你有乐趣进一步进修的话,能够往下载一个完全的示例代码来浏览。
如今,你应当懂得Restlet架构是怎样把收到的(incoming)HTTP哀求路由给特定的Resource类,然后再路由给该类的特定办法了。你也应当晓得怎样由资本形态来机关暗示(representations)了。一样平常,只需存眷Application和Router代码一次就行,由于一个Router可用于你的一切资本。
编译、运转与测试
Application类完成了运转社会性书签服务的HTTP服务器。你必要在classpath中到场以下JAR文件:
- org.restlet.jar
- com.noelios.restlet.jar
- com.noelios.restlet.ext.net.jar
- org.simpleframework_3.1/org.simpleframework.jar
- com.noelios.restlet.ext.simple_3.1.jar
- com.db4o_6.1/com.db4o.jar
这些JAR包能够在Restlet公布包中的lib目次里找到。有两点必要注重:第一,Web服务器的实践事情是由一个十分松散的、基于Simple框架的HTTP服务器毗连器来处置的;第二,我们是用壮大的db4o对象数据库(而不是干系数据库)来存储范畴对象(用户和书签)的。在编译好一切示例文件后,运转org.restlet.example.book.rest.ch7.Application,它将作为服务器的端点(endpoint)。
ApplicationTest类为服务供应了一个客户端接口。它接纳上节形貌的Restlet客户端类来增加和删除用户和书签。它是经由过程HTTP一致接口举行事情的:用PUT哀求创立用户和书签,用DELETE哀求删除用户和书签。
在命令行下运转ApplicationTest类,你将失掉以下动静:- //YahooSearch.javaimportorg.restlet.Client;importorg.restlet.data.Protocol;importorg.restlet.data.Reference;importorg.restlet.data.Response;importorg.restlet.resource.DomRepresentation;importorg.w3c.dom.Node;/***用前往XML的Yahoo!搜刮服务来搜刮Web*/publicclassYahooSearch{staticfinalStringBASE_URI="http://api.search.yahoo.com/WebSearchService/V1/webSearch";publicstaticvoidmain(String[]args)throwsException{if(args.length!=1){System.err.println("Youneedtopassatermtosearch");}else{//猎取一个资本,即一个包括搜刮了局的XML文档Stringterm=Reference.encode(args[0]);Stringuri=BASE_URI+"?appid=restbook&query="+term;Responseresponse=newClient(Protocol.HTTP).get(uri);DomRepresentationdocument=response.getEntityAsDom();//用XPath找出数据布局中主要部分Stringexpr="/ResultSet/Result/Title";for(Nodenode:document.getNodes(expr)){System.out.println(node.getTextContent());}}}}0
复制代码 你能够用这个程序来增加一些用户,并增添一些书签。然后,你就能够在Web扫瞄器中经由过程会见得当的URI(如http://localhost:3000/v1/users/jerome等)来扫瞄用户书签的HTML暗示了。
小结
Restlet项目在2007岁首公布了1.0正式版。它只用了12个多月的开辟工夫。今朝,该项目具有一个昌盛的开辟与用户群体。Restlet邮件列表很友爱,不管是老手,仍是有履历的开辟者,它都接待。作为该项目标创立者,Noelios征询公司是次要的开辟力气,他们也供应专业的撑持企图与培训。
在本书编写之时,1.0版处于保护中,新的1.1版已入手下手开辟了。该项目企图未来把RestletAPI提交给JCP(JavaCommunityProcess)。另有一个用于REST式Web服务的高层API,它已由Sun公司提交给JCP(JSR311)。这个高层API使得“把Java范畴对象表露为REST式资本”加倍简单。这将是对RestletAPI(特别是其Resource类)的一个很好的增补。Noelios征询公司是最后的专家构成员,他们将依据尺度的停顿来对Restlet引擎作响应的更新。
本文节选自博文视点出书公司行将推出的典范著作《RESTfulWebServices中文版》中的第12章《REST式服务框架》。
《RESTfulWebServices中文版》向读者先容了甚么是REST、甚么是面向资本的架构(Resource-OrientedArchitecture,ROA)、REST式计划的长处、REST式Web服务的实在案例剖析、怎样用各类盛行的编程言语编写Web服务客户端、怎样用三种盛行的框架(RubyonRails、Restlet和Django)完成REST式服务等。不但解说REST与面向资本的架构(ROA)的观点与道理,还向读者先容怎样编写切合REST作风的Web2.0使用。本书详确、易懂,实战性强,供应了大批RESTfulWeb服务开辟的最好理论和引导,合适宽大的Web开辟职员、Web架构师及对Web开辟或Web架构感乐趣的宽大手艺职员与先生浏览。
与此同时,博文视点还受权InfoQ中文站独家为人人供应分外的样章举行试读:接待下载第3章《REST式服务有甚么分歧》
来自:http://www.infoq.com/cn/articles/restlet-for-restful-service
唉!都是钱闹的1.Swing和.net网页编程开发比较------从市场份额看.net网页编程开发主要占据大部分的中小型和中型的的桌面开发,原因是它封装了很多工具 |
|