摘要:網(wǎng)絡(luò)上對(duì) restlet 的評(píng)判褒貶不一,,有的說(shuō)框架封裝的很好,,很有彈性,,有的說(shuō) rest 架構(gòu)風(fēng)格本身是一種簡(jiǎn)單的風(fēng)格,,restlet 過(guò)設(shè)計(jì)以使編程過(guò)于復(fù)雜,,其實(shí)我倒不覺(jué)得 restlet 有什么復(fù)雜,,相反很簡(jiǎn)潔明了,,不論他的類(lèi)結(jié)構(gòu)還是整個(gè)體系結(jié)構(gòu),個(gè)人很喜歡,,昨天晚上匆匆看看他的文檔和實(shí)例,,很不錯(cuò)!文章例子代碼,! 1. Rest簡(jiǎn)介(摘抄自網(wǎng)絡(luò),,講的很到位) Restlet是一個(gè)Java下的輕量級(jí)REST框架,。通過(guò)擁抱REST(REST是一種Web架構(gòu)風(fēng)格)它模糊了Web站點(diǎn)和Web服務(wù)之間的界限,從而幫助開(kāi)發(fā)人員構(gòu)建Web應(yīng)用,。每一個(gè)主要的REST概念(REST concept)都有一個(gè)對(duì)應(yīng)的Java類(lèi),。你的REST化的Web設(shè)計(jì)和你的代碼之間的映射是非常簡(jiǎn)單直接的。為什么有必要?jiǎng)?chuàng)建另一種框架,?難道Servlet API還不夠好用嗎,?Servlet AIP在1998年發(fā)布,從那個(gè)時(shí)候起它的核心設(shè)計(jì)一直沒(méi)有很大的變化,。它是Java EE的眾多API中最成功的一個(gè),,但是它的幾個(gè)設(shè)計(jì)缺陷和一些限制損害了它。舉個(gè)例子,,URI模式和它的處理者(handler)之間的映射是受限制的,,而且其配置都集中在一個(gè)配置文件中。還有,,它把socket流的控制直接交給了應(yīng)用系統(tǒng)開(kāi)發(fā)人員,,Servlet容器阻礙了我們充分使用NIO特性對(duì)IO操作進(jìn)行優(yōu)化。另一個(gè)主要問(wèn)題就是Servlet API鼓勵(lì)應(yīng)用開(kāi)發(fā)者在應(yīng)用或者用戶(hù)會(huì)話級(jí)別直接將session狀態(tài)保存于內(nèi)存中,,盡管這看上去不錯(cuò),,但它造成了Servlet容器擴(kuò)展性和高可用性的主要問(wèn)題。為了克服這些問(wèn)題,,就必須實(shí)現(xiàn)復(fù)雜的負(fù)載均衡,、session復(fù)制、持久化機(jī)制,。這導(dǎo)致了可擴(kuò)展性必然成為災(zāi)難,。 如何看待別的框架中對(duì)REST的支持(例如Axis2,或者CXF/XFire),? 這些支持非常有效,,但是作用非常有限。我的主要觀點(diǎn)是設(shè)計(jì)這些項(xiàng)目是為了符合WS-*/SOAP Stack,,它們與REST世界并不非常契合,。在REST世界里,,定義了一個(gè)全新的范例:面向資源的設(shè)計(jì),,而非通過(guò)遠(yuǎn)程方法調(diào)用這樣的范例。例如Axis2僅僅支持GET和POST兩種HTTP方法,,它需要遠(yuǎn)程方法的傳遞需要一個(gè)URI參數(shù),。這在REST中式不允許的,這種做法也不能被稱(chēng)之為REST化,。XFire1.2不支持REST,,但是它發(fā)布了一個(gè)項(xiàng)目用于將POJO映射到REST化的Web服務(wù),。這有點(diǎn)類(lèi)似最近發(fā)布的JSR-311,此JSR試圖基于一套annotation和助手類(lèi)標(biāo)準(zhǔn)化這種映射,。
REST軟件架構(gòu)是由Roy Thomas Fielding博士在2000年首次提出的,。他為我們描繪了開(kāi)發(fā)基于互聯(lián)網(wǎng)的網(wǎng)絡(luò)軟件的藍(lán)圖。REST軟件架構(gòu)是一個(gè)抽象的概念,,是一種為了實(shí)現(xiàn)這一互聯(lián)網(wǎng)的超媒體分布式系統(tǒng)的行動(dòng)指南,。利用任何的技術(shù)都可以實(shí)現(xiàn)這種理念。而實(shí)現(xiàn)這一軟件架構(gòu)最著名的就是HTTP協(xié)議,。通常我們把REST也寫(xiě)作為REST/HTTP,,在實(shí)際中往往把REST理解為基于HTTP的REST軟件架構(gòu),或者更進(jìn)一步把REST和HTTP看作為等同的概念,。今天,,HTTP是互聯(lián)網(wǎng)上應(yīng)用最廣泛的計(jì)算機(jī)協(xié)議。HTTP不是一個(gè)簡(jiǎn)單的運(yùn)載數(shù)據(jù)的協(xié)議,,而是一個(gè)具有豐富內(nèi)涵的網(wǎng)絡(luò)軟件的協(xié)議,。它不僅僅能夠?qū)τ诨ヂ?lián)網(wǎng)資源進(jìn)行唯一定位,而且還能告訴我們對(duì)于該資源進(jìn)行怎樣運(yùn)作,。這也是REST軟件架構(gòu)當(dāng)中最重要的兩個(gè)理念,。而REST軟件架構(gòu)理念是真正理解HTTP協(xié)議而形成的。有了REST軟件架構(gòu)理念出現(xiàn),,才使得軟件業(yè)避免了對(duì)HTTP協(xié)議的片面理解,。只有正確的理論指導(dǎo),才能避免在軟件開(kāi)發(fā)的實(shí)際工作過(guò)程中少走彎路,。 REST與URI(資源定位) REST與CRUD原則 REST與AJAX技術(shù) REST與Rails框架 REST安全性 2. Restlet 類(lèi)結(jié)構(gòu)
Uniform 是一個(gè) Abstract 類(lèi),,定義了和 HTTPMethod 對(duì)應(yīng)的方法如 get,post,delete,put 等等,。子類(lèi) Restlet 應(yīng)該是這個(gè)框架的核心類(lèi)了,restlet 有些像 servlet API,,可以得到 application和 context 兩個(gè)對(duì)象,,其子類(lèi)分別為鏈接器,應(yīng)用,,路由器,,查找器,組件和過(guò)濾器,。在看他的表述類(lèi)結(jié)構(gòu)
3. 脫離 web server 的 restlet 其實(shí)說(shuō)脫離,,只是 restlet 自己做了端口監(jiān)聽(tīng)和 http 協(xié)議解析和封裝的功能,restlet 設(shè)計(jì)是以資源設(shè)計(jì)為中心的,,有些像 struts,,webwork之 MVC 風(fēng)格但又不同,他完全符合 rest 體系架構(gòu)風(fēng)格,,可以很好的和現(xiàn)有的領(lǐng)域模型結(jié)合,,一個(gè)簡(jiǎn)單的分層結(jié)構(gòu)如圖 資源層是對(duì)需要顯示的領(lǐng)域模型做了顯示封裝,對(duì)表示層提供資源,,而對(duì)領(lǐng)域?qū)又行枰志没哪P徒柚?orm 映射器持久化,。個(gè)人覺(jué)得 restlet 的應(yīng)用核心在于服務(wù),,像 Axis2和XFire 等都有支持 rest 風(fēng)格,restlet結(jié)合 json 應(yīng)該是個(gè)比較好的實(shí)踐,。 且看下面簡(jiǎn)單的代碼(代碼為官方文檔里的例子): 對(duì) Resource 封裝一下 BaseResource 以方便應(yīng)用程序使用: 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( 29Application.KEY)).getItems(); 30} 31} 32 33
實(shí)現(xiàn) Application 類(lèi),,定義路由(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. */ 4Item item; 5 6/** The sequence of characters that identifies the resource. */ 7String 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( 63MediaType.TEXT_XML); 64Document d = representation.getDocument(); 65 66Element eltItem = d.createElement("item"); 67d.appendChild(eltItem); 68Element eltName = d.createElement("name"); 69eltName.appendChild(d.createTextNode(item.getName())); 70eltItem.appendChild(eltName); 71 72Element eltDescription = d.createElement("description"); 73eltDescription.appendChild(d.createTextNode(item 74.getDescription())); 75eltItem.appendChild(eltDescription); 76 77d.normalizeDocument(); 78 79// Returns the XML representation of this document. 80return representation; 81} catch (IOException e) { 82e.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) { 110getResponse().setStatus(Status.SUCCESS_CREATED); 111} else { 112getResponse().setStatus(Status.SUCCESS_OK); 113} 114} 115 116} 117 118 客戶(hù)端和服務(wù)器類(lèi),服務(wù)器類(lèi)代替 web server 做監(jiān)聽(tīng)和 Http 協(xié)議處理,。
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"); 35updateItem(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) { 75e.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()) { 99response.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) { 128e.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) { 150e.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.和現(xiàn)有 servlet 容器結(jié)合的例子 配置 web.xml
1<context-param>
2<param-name>org.restlet.application</param-name> 3<param-value> 4org.blogjava.helloworld.FirstStepsApplication 5</param-value> 6</context-param> 7<!-- Restlet adapter --> 8<servlet> 9<servlet-name>RestletServlet</servlet-name> 10<servlet-class> 11com.noelios.restlet.ext.servlet.ServerServlet 12</servlet-class> 13</servlet> 14<!-- Catch all requests --> 15<servlet-mapping> 16<servlet-name>RestletServlet</servlet-name> 17<url-pattern>/*</url-pattern> 18</servlet-mapping> 19 20 實(shí)現(xiàn) Application 和 Resource 資源類(lèi)
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 參考資料
本博客為學(xué)習(xí)交流用,,凡未注明引用的均為本人作品,,轉(zhuǎn)載請(qǐng)注明出處,,如有版權(quán)問(wèn)題請(qǐng)及時(shí)通知。由于博客時(shí)間倉(cāng)促,,錯(cuò)誤之處敬請(qǐng)諒解,,有任何意見(jiàn)可給我留言,愿共同學(xué)習(xí)進(jìn)步,。 |
|
來(lái)自: 開(kāi)心豆豆2010 > 《技術(shù)》