中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
STRUTS2.0影射REST風(fēng)格地址
[摘要]: 介紹如何改寫Struts2的Restful2ActionMapper來(lái)支持REST風(fēng)格的URL映射。

Note: 不 久前寫了一篇文章《使用Restful2ActionMapper讓Struts2支持REST風(fēng)格的URL映射》,但后來(lái)發(fā)現(xiàn)有些不對(duì),Struts2 的Restful2ActionMapper并不按我想的那樣運(yùn)行。因?yàn)樵谖业膶?shí)驗(yàn)項(xiàng)目中,我是改寫了這個(gè)Restful2ActionMapper的。 Struts2自己帶的Restful2ActionMapper稍嫌復(fù)雜,而且我對(duì)它的有些地方的處理不甚滿意,所以自己寫了一個(gè),沒有使用Struts2自己的Restful2ActionMapper進(jìn)行調(diào)試。特此向大家道歉,并修正該文檔。另外,我對(duì)我改寫的這個(gè)Restful2ActionMapper的代碼進(jìn)行了一些刪減調(diào)整,將代碼附于文后。

一、概述

REST是由 Roy Fielding 在他的論文《Architectural Styles and the Design of Network-based Software Architectures》中提出的一個(gè)術(shù)語(yǔ)。關(guān)于REST,請(qǐng)參考:http: //www.redsaga.com/opendoc/REST_cn.pdf
在REST的定義中,一個(gè)Web應(yīng)用總是使用固定的URI向外部世界呈現(xiàn)(或者說暴露)一個(gè)資源,并使用不同的HTTP請(qǐng)求方法來(lái)處理對(duì)資源的CRUD (創(chuàng)建、讀取、更新和刪除)操作。除了我們所熟知的GET和POST這兩種HTTP請(qǐng)求方法,HTTP還有HEAD、PUT、DELETE等請(qǐng)求方法。我 們?cè)赪eb應(yīng)用中處理來(lái)自客戶端的請(qǐng)求時(shí),通常只考慮GET和POST,并使用某種URL映射將URL映射到對(duì)資源的某種操作。而REST架構(gòu)風(fēng)格則要求 使用HTTP的GET、POST、PUT、DELETE來(lái)分別表示資源的讀取、創(chuàng)建、更新、刪除,而URI保持不變。舉例來(lái)說, /article/2007/8/a001這個(gè)URI表示一篇文章,表示形式為:/article/{year}/{month}/{id},對(duì)這個(gè)資源 的CRUD操作如下(下面的表示形式中,我省去了http://host/context/namespace這樣的前綴):
讀?。篏ET /article/2007/8/a001
創(chuàng)建:POST /article/2007/8/a001
更新:PUT /article/2007/8/a001
刪除:DELETE /article/2007/8/a001
如果我們用傳統(tǒng)的struts或webwork的開發(fā)方法,我們可能會(huì)定義一個(gè)ArticleAction,定義好CRUD的method,并使用不同的 URI映射來(lái)表示這幾種操作。比如,我們可能會(huì)使用這樣的URI來(lái)讀取article:/getArticle.action?year= 2007&month=8&id=a001,并使用這樣的URI來(lái)刪除article:/deleteArticle.action? year=2007&month=8&id=a001,或者,把這幾種操作用相同形式的URI來(lái)表示:/article.action? method=get&year=2007&month=8&id=a001。顯然,REST風(fēng)格的URI表示更友好。
Struts2和Webwork2都帶了一個(gè)RestfulActionMapper來(lái)支持REST風(fēng)格的URI映射,但是它的功能太弱了,表現(xiàn)形式也很 呆板。Struts2(我使用的是Struts 2.0.9)中還有一個(gè)Restful2ActionMapper,可以更好地支持REST風(fēng)格。
從struts2的官方文檔中可以找到關(guān)于Restful2ActionMapper的說明: Improved restful action mapper that adds several ReST-style improvements to action mapping, but supports fully-customized URL's via XML.
我查看了Restful2ActionMapper的源碼,對(duì)它有些地方的處理有異議,所以改寫了這個(gè)類。以下的配置中,請(qǐng)使用文后附上的Restful2ActionMapper代替Struts2原來(lái)的類。

二、配置和使用

現(xiàn)在,我們配置struts2使它使用Restful2ActionMapper。在Web項(xiàng)目中,修改struts.properties文件(它最終會(huì)發(fā)布到你的web應(yīng)用的WEB-INF/classes目錄中):
struts.mapper.class=org.apache.struts2.dispatcher.mapper.Restful2ActionMapper
struts.enable.SlashesInActionNames=true
當(dāng)然,你也可以在struts.xml里進(jìn)行配置,請(qǐng)參考struts2的相關(guān)文檔。
(這里,請(qǐng)將struts.mapper.class這行修改為使用我修改后的Restful2ActionMapper)

  這里有個(gè)小建議,許多人在WEB-INF/web.xml里對(duì)struts2的配置是讓struts2處理所有擴(kuò)展名為action的url,也就是設(shè)置url-pattern為*.action。 我的建議是,不要使用擴(kuò)展名來(lái)作為url-pattern,使用基于路徑的匹配形式會(huì)更好,我一般是使用“/app/*”作為url-pattern。至于擴(kuò)展名,我一般是在struts.properties文件中指定:
struts.action.extension=html,xml,json
  或者,不要擴(kuò)展名:
struts.action.extension=
  不過,這些都是題外話。

現(xiàn)在,以上面講到的article為例,我們定義ArticleAction。按照Restful2ActionMapper的規(guī)則,URL與method的對(duì)應(yīng)關(guān)系如下:
GET /article => public String index(); 資源索引;
GET /article/2007/8/a001 => public String view(); 對(duì)應(yīng)于讀取操作;
POST /article/2007/8/a001 => public String create(); 創(chuàng)建資源;
PUT /article/2007/8/a001 => public String update(); 更新資源;
DELETE /article/2007/8/a001 => public String remove(); 刪除資源;
GET /article/2007/8/a001!edit => public String edit(); 請(qǐng)求編輯資源,和REST的四種操作沒有對(duì)應(yīng)關(guān)系;
GET /article/!editNew => public String editNew(); 請(qǐng)求編輯新資源,和REST的四種操作沒有對(duì)應(yīng)關(guān)系。
后兩種方式似乎和REST沒什么關(guān)系,但為傳統(tǒng)的Web應(yīng)用開發(fā)提供了方便。比如edit(),服務(wù)器返回一個(gè)表單頁(yè)面。但是,如果我們讓應(yīng)用服務(wù)器只返 回xml或json,那么這個(gè)edit()是可以不要的,有讀取操作就夠了。(也許把view方法改為read更貼切點(diǎn))。
按照這些規(guī)則,我們?cè)贏rticleAction中定義view()、create()、update()、remove()等method,并在這個(gè)action中定義year、month、id的getter/setter方法:
java 代碼
  1. package app;  
  2.   
  3. public class ArticleAction {  
  4.     private String year, month, id;  
  5.      ...  
  6.      getter/setter methods for year,month,id  
  7.      ...  
  8.     public String view() { ... }  
  9.     public String index() { ... }  
  10.     public String create() { ... }  
  11.     public String update() { ... }  
  12.     public String remove() { ... }  
  13. }  

然后我們需要配置這個(gè)action,使它能與形如/article/{year}/{month}/{id}的URL對(duì)應(yīng)起來(lái)。我們?cè)谙鄳?yīng)的struts2的action配置文件中加入如下幾行:
xml 代碼
  1. <action name="article/*/*/*" className="app.ArticleAction">  
  2.     <param name="year">{1}</param>  
  3.     <param name="month">{2}</param>  
  4.     <param name="id">{3}</param>  
  5.     <result name="..." type="..."/>  
  6. </action>  

OK!現(xiàn)在已經(jīng)可以使用這個(gè)action了。當(dāng)然,這還需要瀏覽器客戶端的支持。當(dāng)你的客戶端以GET來(lái)請(qǐng)求/article/2007/8/a001 時(shí),struts2就會(huì)調(diào)用ArticleAction的view方法,而PUT請(qǐng)求則會(huì)對(duì)應(yīng)到update方法,DELETE請(qǐng)求會(huì)對(duì)應(yīng)到remove 方法...
但是,如果你的客戶端只支持GET和POST怎么辦?Restful2ActionMapper的文檔中提到:To simulate the HTTP methods PUT and DELETE, since they aren't supported by HTML, the HTTP parameter "__http_method" will be used.對(duì)于只支持GET和POST的傳統(tǒng)網(wǎng)頁(yè),我們可以增加一個(gè)"__http_method"參數(shù)來(lái)模擬PUT和DELETE,比如:POST /article/2007/8/a001&__http_method=DELETE。隨著Javascript和Ajax框架的發(fā)展,我們已 經(jīng)可以使用PUT和DELETE等方法。Ajax使用XmlHttpRequest進(jìn)行操作時(shí),在發(fā)送請(qǐng)求之前,可以通過設(shè)置RequestType的方 式來(lái)完成對(duì)請(qǐng)求方法的設(shè)定。

三、不足之處

Restful2ActionMapper對(duì)REST風(fēng)格的支持是不完全的。在REST風(fēng)格中,我們可以使用同一個(gè)URI來(lái)獲取同一個(gè)資源的多種表現(xiàn)形 式。在發(fā)送HTTP請(qǐng)求時(shí),只要我們?cè)谡?qǐng)求頭中指定一個(gè)Accept參數(shù),那么服務(wù)器就可以通過判斷該參數(shù)來(lái)決定返回什么類型的數(shù)據(jù)。如果Accept為 text/xml,服務(wù)器會(huì)返回xml格式的數(shù)據(jù),如果Accept為text/json,則會(huì)返回json格式的數(shù)據(jù),但URI是固定的。而 Restful2ActionMapper只是作了URI的映射,并沒有考慮返回?cái)?shù)據(jù)的格式問題。要讓struts2支持完全的REST風(fēng)格,我們不得不 對(duì)它進(jìn)行改造,或者,等待它的改進(jìn)。
另外,Restful2ActionMapper所定義的URL映射規(guī)則也有一個(gè)小小的“陷阱”。比如,GET /user/1表示讀取id為1的user,但按照Restful2ActionMapper的定義,/user/new會(huì)對(duì)應(yīng)到action的 editNew方法,如果這個(gè)"new"就是某個(gè)用戶的id呢?為了避開這個(gè)陷阱,我寧愿使用/user/!editNew這種丑陋的形式。事實(shí)上,隨著 客戶端技術(shù)的發(fā)展,我們完全可以不使用editNew方法而構(gòu)造輸入頁(yè)面,然后向服務(wù)器發(fā)送POST來(lái)創(chuàng)建資源。同樣,edit方法也不是必要的。
(注:我修改后的Restful2ActionMapper去除了/user/new這種形式的映射)

四、其它

有個(gè)struts2的插件,叫jsonplugin,可以讓struts2很方便地支持json輸出。而Adobe Spry Framework、YUI-ext、DOJO等都能很好地支持json,并能很好地支持HTTP的各種請(qǐng)求方法。我推薦struts2的用戶使用 jsonplugin和Adobe Spry Framework或YUI-ext(或其它UI Framework)。Struts2只輸出json格式的結(jié)果(最好還能輸出xml),而UI和數(shù)據(jù)裝配交給Adobe Spry/YUI-ext等去做。這樣的組合會(huì)讓你更好更方便地使用REST風(fēng)格。

五、修改后的Restful2ActionMapper

這里我附上修改后的Restful2ActionMapper,大家可以在此基礎(chǔ)上進(jìn)行擴(kuò)充。比如,我前面提到Restful2ActionMapper 不能根據(jù)Accept請(qǐng)求頭來(lái)返回不同格式的數(shù)據(jù),其實(shí)也是可以進(jìn)行改進(jìn)的。我看到已經(jīng)有人在讀過我這篇文章后提出一種方案,類似于這樣的:
/user/a001/xml => 返回xml格式的result
/user/a001/json => 返回json格式的result
/user/a001/...
這是一種辦法,另外,根據(jù)url的擴(kuò)展名來(lái)做,也是一種辦法。但是這都不是好方案!我前面已經(jīng)提過,按照REST風(fēng)格,一個(gè)Web應(yīng)用總是使用固定的 URI向外部世界呈現(xiàn)(或者說暴露)一個(gè)資源,而前面這兩種方案只是使URL友好點(diǎn)而已,并不真正符合REST風(fēng)格。當(dāng)然,這樣也不錯(cuò)了,也是不錯(cuò)的方 案,其實(shí)ROR中也有類似的做法。
但我們還有更好的方案,我提個(gè)思路,然后大家自行對(duì)Restful2ActionMapper進(jìn)行改進(jìn):
在Action中可以設(shè)置一個(gè)consumeMime屬性,并寫好對(duì)應(yīng)的getter/setter方法。在Restful2ActionMapper返 回mapping之前,提取request的Accept頭信息,然后將該信息放到mapping.params之中。action的各個(gè)method最 后只返回consumeMime,這樣就可以在action的配置文件中按consumeMime來(lái)配置result了。
下面,附上修改后的Restful2ActionMapper代碼:
java 代碼
  1. import com.opensymphony.xwork2.config.ConfigurationManager;  
  2. import javax.servlet.http.HttpServletRequest;  
  3. import org.apache.commons.logging.Log;  
  4. import org.apache.commons.logging.LogFactory;  
  5. import org.apache.struts2.dispatcher.mapper.ActionMapping;  
  6.   
  7. public class Restful2ActionMapper extends DefaultActionMapper {  
  8.   
  9.     protected static final Log LOG = LogFactory  
  10.              .getLog(Restful2ActionMapper.class);  
  11.     public static final String HTTP_METHOD_PARAM = "__http_method";  
  12.     private static final byte HTTP_METHOD_GET = 1;  
  13.     private static final byte HTTP_METHOD_POST = 2;  
  14.     private static final byte HTTP_METHOD_PUT = 3;  
  15.     private static final byte HTTP_METHOD_DELETE = 4;  
  16.   
  17.     public Restful2ActionMapper() {  
  18.          setSlashesInActionNames("true");  
  19.      }  
  20.   
  21.     /*
  22.       * (non-Javadoc)
  23.       *
  24.       * @see org.apache.struts2.dispatcher.mapper.ActionMapper#getMapping(javax.servlet.http.HttpServletRequest)
  25.       */  
  26.     public ActionMapping getMapping(HttpServletRequest request,  
  27.              ConfigurationManager configManager) {  
  28.   
  29.         if (!isSlashesInActionNames()) {  
  30.             throw new IllegalStateException(  
  31.                     "This action mapper requires the setting 'slashesInActionNames' to be set to 'true'");  
  32.          }  
  33.          ActionMapping mapping = super.getMapping(request, configManager);  
  34.   
  35.         if (mapping == null)  
  36.             return null;  
  37.   
  38.          String actionName = mapping.getName();  
  39.         if ((actionName == null) || (actionName.length() == 0))  
  40.             return mapping;  
  41.   
  42.         // If a method hasn't been explicitly named, try to guess using  
  43.         // ReST-style patterns  
  44.         if (mapping.getMethod() != null)  
  45.             return mapping;  
  46.   
  47.         int lastSlashPos = actionName.lastIndexOf('/');  
  48.         if (lastSlashPos == -1)  
  49.             return mapping;  
  50.          String requestMethod = request.getMethod();  
  51.          String httpMethodParam = request.getParameter(HTTP_METHOD_PARAM);  
  52.         byte requestMethodCode = 0;  
  53.         if ("PUT".equalsIgnoreCase(requestMethod))  
  54.              requestMethodCode = HTTP_METHOD_PUT;  
  55.         else if ("DELETE".equalsIgnoreCase(requestMethod))  
  56.              requestMethodCode = HTTP_METHOD_DELETE;  
  57.         else if ("PUT".equalsIgnoreCase(httpMethodParam))  
  58.              requestMethodCode = HTTP_METHOD_PUT;  
  59.         else if ("DELETE".equalsIgnoreCase(httpMethodParam))  
  60.              requestMethodCode = HTTP_METHOD_DELETE;  
  61.         else if ("GET".equalsIgnoreCase(requestMethod))  
  62.              requestMethodCode = HTTP_METHOD_GET;  
  63.         else if ("POST".equalsIgnoreCase(requestMethod))  
  64.              requestMethodCode = HTTP_METHOD_POST;  
  65.   
  66.         if (requestMethodCode == HTTP_METHOD_GET) {  
  67.             if (lastSlashPos == actionName.length() - 1)  
  68.                  mapping.setMethod("index");  
  69.             else  
  70.                  mapping.setMethod("view");  
  71.          } else if (requestMethodCode == HTTP_METHOD_POST)  
  72.              mapping.setMethod("create");  
  73.         else if (requestMethodCode == HTTP_METHOD_PUT)  
  74.              mapping.setMethod("update");  
  75.         else if (requestMethodCode == HTTP_METHOD_DELETE)  
  76.              mapping.setMethod("remove");  
  77.   
  78.         return mapping;  
  79.      }  
  80. }  
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
漂亮回答面試官struts2的原理
SAP發(fā)布REST/HTTP接口
sturts2運(yùn)行原理
struts2.x的處理流程
org.apache.struts2.dispatcher.FilterDispatche...
delphi datasnap 服務(wù)器 接受 Post Get 方式的參數(shù)
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服