<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢(mèng)蝶

    生活、程序、未來(lái)
       :: 首頁(yè) ::  ::  :: 聚合  :: 管理
    ??? REST這個(gè)名詞已經(jīng)聽(tīng)過(guò)許久,在javaeye的ruby版上也看到不少的討論,一開(kāi)始是搞不明白的,似乎跟webservice有關(guān)。今天讀了《RESTfull Rails Development》和幾篇介紹REST的文章開(kāi)始有點(diǎn)明白。REST 是英文 Representational State Transfer 的縮寫,有中文翻譯為“具象狀態(tài)傳輸”。讀這篇文章《學(xué)習(xí)REST》對(duì)于初次接觸REST的人來(lái)說(shuō)更好理解。

    ??? 我們?cè)?Web 應(yīng)用中處理來(lái)自客戶端的請(qǐng)求時(shí),通常只考慮 GET 和 POST 這兩種 HTTP 請(qǐng)求方法。實(shí)際上,HTTP 還有 HEAD、PUT、DELETE 等請(qǐng)求方法。而在 REST 架構(gòu)中,用不同的 HTTP 請(qǐng)求方法來(lái)處理對(duì)資源的 CRUD(創(chuàng)建、讀取、更新和刪除)操作:

    • POST: 創(chuàng)建
    • GET: 讀取
    • PUT: 更新
    • DELETE: 刪除

    經(jīng)過(guò)這樣的一番擴(kuò)展,我們對(duì)一個(gè)資源的 CRUD 操作就可以通過(guò)同一個(gè) URI 完成了。需要注意的是REST的核心就是資源(resources)這個(gè)概念。我們所說(shuō)的webservice是一種建立在http協(xié)議上的遠(yuǎn)程調(diào)用,而REST就是把遠(yuǎn)程調(diào)用抽象成對(duì)遠(yuǎn)程資源的CRUD的操作,正好可以用HTTP的PUT GET POST DELETE來(lái)對(duì)應(yīng),而不是重新發(fā)明一個(gè)協(xié)議(比如soap,簡(jiǎn)單對(duì)象訪問(wèn)協(xié)議)。REST與AJAX的流行,甚至遠(yuǎn)至設(shè)計(jì)模式的興起,都充分說(shuō)明一個(gè)現(xiàn)象,在成熟的應(yīng)用的基礎(chǔ)上創(chuàng)新而非擴(kuò)展出復(fù)雜所謂“創(chuàng)新性”架構(gòu)在軟件行業(yè)是更為可靠。

    ??? 實(shí)戰(zhàn)體驗(yàn)REST可以從IBM Developer的這篇文章開(kāi)始《跨越邊界:Rest On Rails》。這篇文章是在Rails1.2發(fā)布之前出來(lái)的,有些地方已經(jīng)可以修改的更簡(jiǎn)練,我把我的練習(xí)過(guò)程記錄下,并添加了C#調(diào)用REST風(fēng)格web service的例子。

    ??? 首先,你的機(jī)器上需要安裝rails1.2,并且假設(shè)你對(duì)rails有基本的了解,建立一個(gè)應(yīng)用叫service,命令行執(zhí)行:

    ??
    ?rails?service

    rails自動(dòng)幫你生成應(yīng)用的基本結(jié)構(gòu)和基礎(chǔ)代碼,然后編輯config下面的database.yml設(shè)置數(shù)據(jù)庫(kù),并建立數(shù)據(jù)service_development,我用的是mysql數(shù)據(jù)庫(kù)。

    create.bmp

    利用rails1.2新的scaffold命令:

    ruby?script/generate?scaffold_resource?person

    這個(gè)命令將自動(dòng)生成ActiveRecord,Controller以及View,在\app\models下可以發(fā)現(xiàn)自動(dòng)生成的Model——person.rb。打開(kāi)service\db\migrate下面的001_create_people.rb,編輯如下:

    class?CreatePeople?<?ActiveRecord::Migration
    ??def?self
    .up
    ????create_table?
    :people?do?|t|
    ?????t
    .column?:first_name,?:string,?:limit?=>?40
    ?????t
    .column?:last_name,?:string,?:limit?=>?40
    ?????t
    .column?:email,?:string,?:limit?=>?40
    ?????t
    .column?:phone,?:string,?:limit?=>?15
    ????end
    ??end

    ??def?self
    .down
    ????drop_table?
    :people
    ??end
    end

    利用rake命令自動(dòng)建表,執(zhí)行
    rake?db:migrate
    rails默認(rèn)表明是Model的復(fù)數(shù)形式,也就是這里將自動(dòng)建立一張名叫people的表。

    OK,一切就緒,啟動(dòng)WEBric,訪問(wèn)http://localhost:3000/people,顯示:
    rest1.bmp

    scaffold已經(jīng)幫我們自動(dòng)生成了一個(gè)對(duì)person資源的crud操作,增刪改查似乎跟傳統(tǒng)的rails沒(méi)有什么不同嘛。如果你認(rèn)真觀察在操作過(guò)程中URL的變化情況就會(huì)發(fā)現(xiàn)在操作過(guò)程中URL的變化很小,而且與傳統(tǒng)rails的URL路由相比,省去了action名稱。出現(xiàn)的變化在/people、/people/1、/people/1;edit和/people/new這幾個(gè)之中。在/people的URL中隱藏這可能是http的POST或者GET的方法,前者用于create操作,而GET用于show操作,具體你可以查看app/controllers/目錄下的PeopleController類,每個(gè)action的前面都注釋了它們將對(duì)應(yīng)哪個(gè)HTTP方法。而/people/1中的1指的是資源的標(biāo)志符,比如這里person的id,通過(guò)這個(gè)ID來(lái)進(jìn)行資源的操作,也許是PUT方法(更新),也許是DELETE方法(刪除)。rails實(shí)現(xiàn)PUT和Delete是通過(guò)隱藏字段來(lái)實(shí)現(xiàn)的,查看編輯頁(yè)面生成的html源代碼,你將發(fā)現(xiàn)一個(gè)_method的隱藏字段,值為PUT。而另外兩個(gè)URL:/people/1;edit和/people/new,這兩個(gè)并非嚴(yán)格意義上的RESTful URL,它們只是為了顯示用,顯示form表單用于新建和編輯。關(guān)于RESTful風(fēng)格的URL的詳細(xì)討論請(qǐng)見(jiàn)《RESTfull Rails Development》文檔。

    ??? 如果rails只是這樣的威力,那就有點(diǎn)小提大做了,看看PeopleController的show action,它對(duì)應(yīng)于http的GET請(qǐng)求,返回people列表:
    #?GET?/people/1
    ??#?GET?/people/1.xml

    ??def?show
    ????
    @person?=?Person.find(params[:id])

    ????respond_to?
    do?|format|
    ??????
    format.html?#?show.rhtml
    ??????format.xml??{?render?:xml?=>?@person.to_xml?}
    ????end
    ??end

    神奇的地方在respond_to方法中,根據(jù)請(qǐng)求文件類型(http Header的ContentType),顯示html格式,或者xml格式(還有其他支持,比如json、RSS、Atom等等)。比如你添加了一個(gè)person,通過(guò)http://localhost:3000/people/1訪問(wèn),可以看到這個(gè)人員的具體信息:
    rest2.bmp
    我們?cè)偻ㄟ^(guò)http://localhost:3000/people/3.xml訪問(wèn)看到的卻是一個(gè)xml文件:

    rest3.bmp

    不僅如此,我們也可以通過(guò)其他語(yǔ)言編寫客戶端來(lái)調(diào)用http://localhost:3000/people/1這個(gè)url,慢著,這不正是web service遠(yuǎn)程調(diào)用嗎?沒(méi)錯(cuò),REST風(fēng)格的web service相比于wsdl、soap定義的web service簡(jiǎn)單了太多太多,也更加實(shí)用。我們來(lái)編寫一個(gè)java類調(diào)用http://localhost:3000/people獲得所有的人員列表:
    package?example;

    import?java.io.BufferedReader;
    import?java.io.InputStreamReader;
    import?java.io.OutputStreamWriter;
    import?java.net.HttpURLConnection;
    import?java.net.URL;
    import?java.net.URLConnection;

    public?class?RESTDemo?{

    ????
    /**
    ?????*?
    @param?args
    ?????
    */
    ????
    public?static?void?main(String[]?args)?{
    ????????RESTDemo?restDemo?
    =?new?RESTDemo();
    ????????????restDemo.get();
    ????????
    ????}

    ????
    void?get()?{

    ????????
    try?{
    ????????????URL?url?
    =?new?URL("http://localhost:3000/people");
    ????????????URLConnection?urlConnection?
    =?url.openConnection();
    ????????????urlConnection.setRequestProperty(
    "accept",?"text/xml");
    ????????????BufferedReader?in?
    =?new?BufferedReader(new?InputStreamReader(
    ????????????????????urlConnection.getInputStream()));
    ????????????String?str;

    ????????????
    while?((str?=?in.readLine())?!=?null)?{
    ????????????????System.out.println(str);
    ????????????}

    ????????????in.close();
    ????????}?
    catch?(Exception?e)?{
    ????????????System.out.println(e);
    ????????}
    ????}
    }

    我們沒(méi)有什么服務(wù)端接口class,我們也不用生成什么stub,我們調(diào)用的最常見(jiàn)最常見(jiàn)的http協(xié)議,發(fā)送的是默認(rèn)的GET請(qǐng)求,rails自動(dòng)將該請(qǐng)求轉(zhuǎn)發(fā)給show action。注意,我們這里把accept設(shè)置為text/xml,show方法根據(jù)此格式返回一個(gè)xml文檔,下面是輸出:
    <?xml?version="1.0"?encoding="UTF-8"?>
    <people>
    ??
    <person>
    ????
    <email>killme2008@gmail.com</email>
    ????
    <first-name>dennis</first-name>
    ????
    <id?type="integer">1</id>
    ????
    <last-name>zane</last-name>
    ????
    <phone>1355XXXXXXX</phone>
    ??
    </person>
    </people>

    如果僅僅是GET請(qǐng)求是不夠的,我們說(shuō)過(guò),把遠(yuǎn)程調(diào)用抽象成對(duì)遠(yuǎn)程資源的CRUD操作,那么如何create、delete和update遠(yuǎn)程資源呢?同樣很簡(jiǎn)單,比如我們通過(guò)C#遠(yuǎn)程調(diào)用,創(chuàng)建一個(gè)新person,還記的我說(shuō)過(guò)嗎?/people可以是POST請(qǐng)求,他將調(diào)用PeopleController的create方法:
    using?System;
    using?System.Net;
    using?System.IO;
    using?System.Text;
    namespace?demo
    {
    ????
    class?RESTDemo
    ????{
    ????????
    static?void?Main(string[]?args)
    ????????{
    ????????????
    string?xmlText?=?"<person>?"?+?"<first-name>jordan</first-name>"
    ????????????????????
    +?"<last-name>jordan</last-name>"
    ????????????????????
    +?"<email>maggie@tate.com</email>"
    ????????????????????
    +?"<phone>010-XXXXXXXX</phone>"?+?"</person>";
    ????????????Uri?address?
    =?new?Uri("http://localhost:3000/people");??
    ???
    ????????????
    //?創(chuàng)建web請(qǐng)求
    ????????????HttpWebRequest?request?=?WebRequest.Create(address)?as?HttpWebRequest;??
    ???
    ????????????
    //?設(shè)置請(qǐng)求類型為POST,調(diào)用create?action
    ????????????request.Method?=?"POST";??
    ????????????request.ContentType?
    =?"application/xml";

    ????????????
    byte[]?xmlBytes?=?Encoding.ASCII.GetBytes(xmlText);

    ????????????
    using?(Stream?reqStream?=?request.GetRequestStream())
    ????????????{
    ????????????????reqStream.Write(xmlBytes,?
    0,?xmlBytes.Length);
    ????????????}
    ????????????
    using?(WebResponse?wr?=?request.GetResponse())
    ????????????{
    ????????????????wr.
    ????????????????
    //打印返回的http頭
    ????????????????Console.WriteLine(wr.Headers.ToString());
    ???????????????
    ????????????}??????????????
    ???????????

    ????????}
    ????}
    }

    執(zhí)行此程序,刷新http://localhost:3000/people,可以看到新建了一個(gè)人員如下

    rest4.bmp

    好極了,GET和POST都有了,那么PUT對(duì)應(yīng)的更新和DELETE對(duì)應(yīng)的刪除又該怎么做呢,唯一的區(qū)別就是設(shè)置請(qǐng)求類型不同而已,java調(diào)用如下:
    ????void?put()?{
    ????????
    try?{
    ????????????String?xmlText?
    =?"<person>?"?+?"<first-name>test</first-name>"
    ????????????????????
    +?"<last-name>test</last-name>"
    ????????????????????
    +?"<email>maggie@tate.com</email>"
    ????????????????????
    +?"<phone>010-XXXXXXXX</phone>"?+?"</person>";

    ????????????URL?url?
    =?new?URL("http://localhost:3000/people/1");
    ????????????HttpURLConnection?conn?
    =?(HttpURLConnection)?url.openConnection();
    ????????????conn.setDoOutput(
    true);
    ??????????? //設(shè)置請(qǐng)求為PUT
    ????????????conn.setRequestMethod(
    "PUT");
    ????????????conn.setRequestProperty(
    "Content-Type",?"text/xml");
    ????????????OutputStreamWriter?wr?
    =?new?OutputStreamWriter(conn
    ????????????????????.getOutputStream());
    ????????????wr.write(xmlText);
    ????????????wr.flush();
    ????????????wr.close();
    ????????}?
    catch?(Exception?e)?{
    ????????????System.out.println(
    "Error"?+?e);
    ????????}
    ????}

    ????
    void?delete()?{
    ????????
    try?{
    ????????????URL?url?
    =?new?URL("http://localhost:3000/people/2");
    ????????????HttpURLConnection?conn?
    =?(HttpURLConnection)?url.openConnection();
    ????????????conn.setDoOutput(
    true);
    ??????????? //設(shè)置請(qǐng)求為DELETE
    ????????????conn.setRequestMethod(
    "DELETE");
    ????????????conn.setRequestProperty(
    "Content-Type",?"text/xml");
    ????????????
    if(conn.getResponseCode()==200)
    ????????????????System.out.println(
    "刪除成功!");
    ????????}
    catch?(Exception?e)?{
    ????????????System.out.println(
    "Error"?+?e);
    ????????}
    ????}

    這里的put方法將第一個(gè)人員的名字改了,而delete方法干脆將剛才C#添加的人員刪除掉。異構(gòu)系統(tǒng)的遠(yuǎn)程調(diào)用變的如此簡(jiǎn)單很輕松,把什么EJB、CORBA、SOAP統(tǒng)統(tǒng)忘掉吧。想象這樣的場(chǎng)景,所有的網(wǎng)站都提供REST風(fēng)格的API,這個(gè)世界將是什么模樣?

    ??? REST帶來(lái)的不僅僅是web service的改變,對(duì)MVC架構(gòu)同樣具有很重要的意義,過(guò)去我們的復(fù)用通常在MODEL層,我們一直希望復(fù)用業(yè)務(wù)邏輯層,卻沒(méi)有想過(guò)是否能復(fù)用Controller甚至View呢?REST為我們提供了可能,比如以一個(gè)很經(jīng)常被提到的例子來(lái)說(shuō),用戶加入某個(gè)圈子這個(gè)操作跟圈子的管理員將用戶加入圈子的操作是一樣,但是操作成功后的跳轉(zhuǎn)顯示的頁(yè)面也許不同,過(guò)去也許我們是通過(guò)寫兩個(gè)不同的Action來(lái)實(shí)現(xiàn),而現(xiàn)在,同一個(gè)Action(加入圈子這個(gè)操作)只負(fù)責(zé)發(fā)送數(shù)據(jù)(XML格式的文檔),而頁(yè)面的展示將留給客戶端去選擇,從而復(fù)用了Controller,減少了Action和View層的代碼量。進(jìn)一步,請(qǐng)你想象,REST與AJAX的技術(shù)結(jié)合產(chǎn)生多么有趣的畫(huà)面。REST僅用于提供數(shù)據(jù),展現(xiàn)更多的交給了客戶端。

    ??? 本文僅僅是我接觸REST這兩天的學(xué)習(xí)總結(jié),對(duì)于REST的應(yīng)用才剛剛起步,需要更多的探討和實(shí)踐。其實(shí)java實(shí)現(xiàn)REST也是相當(dāng)簡(jiǎn)單的,servlet本身就是很好的模型,恐怕沒(méi)有多人注意到HttpServlet類中的doPut和doDelete方法,我們過(guò)去太強(qiáng)調(diào)GET和POST,反而忽視了PUT和DELETE可能帶來(lái)的改變。java開(kāi)源世界中已經(jīng)有了REST風(fēng)格的框架,比如cetia4,這是一個(gè)servlet-base的REST框架,值的關(guān)注。
    主站蜘蛛池模板: 一级一级一片免费高清| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 亚洲乱亚洲乱妇24p| 亚洲国产精品无码久久SM| 国产免费无遮挡精品视频 | 亚洲av日韩av不卡在线观看| 91亚洲自偷在线观看国产馆| 亚洲国产精品自产在线播放| 97无码免费人妻超级碰碰夜夜| 日韩精品免费视频| 手机永久免费的AV在线电影网| 亚洲色大成网站WWW国产| 亚洲成色999久久网站| 亚洲人成无码www久久久| 在线免费观看国产视频| 手机在线看永久av片免费| 一级成人a毛片免费播放| 精精国产www视频在线观看免费| 国产精品亚洲lv粉色| 亚洲依依成人亚洲社区| 亚洲国产成人精品青青草原| 亚洲国产女人aaa毛片在线| 亚洲精品国精品久久99热一| 亚洲国产黄在线观看| 四虎1515hm免费国产| 日韩人妻无码免费视频一区二区三区 | 久久精品国产亚洲AV无码偷窥 | 一日本道a高清免费播放| 男女超爽视频免费播放| 亚洲AV一区二区三区四区| 2019亚洲午夜无码天堂| 亚洲av无码久久忘忧草| 亚洲一级免费视频| 亚洲香蕉在线观看| 国产99在线|亚洲| 亚洲中文字幕无码爆乳app| 亚洲AV日韩综合一区尤物| 91丁香亚洲综合社区| 亚洲精品国产精品| 国产成人高清亚洲一区久久 | 免费一级做a爰片性色毛片|