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

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

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

    L遷客

    技術博客
    隨筆 - 1, 文章 - 12, 評論 - 1, 引用 - 0
    數據加載中……

    為網站建立數據接口

    為網站建立數據接口

    文章覆蓋知識點:HttpWatch抓包,HttpClient模擬POST請求,Jsoup解析HTML代碼,動態更新ListView

         背景介紹:客戶端(Client)或稱為用戶端,是指與服務器相對應,為客戶提供本地服務的程序。而android系統上的90%客戶端軟件都有一個共性,就是為了改善網頁在android系統上體驗不佳而生,最具有影響力的軟件有:新浪微博、人人網、淘寶等,這類軟件最突出的特點就是,先有網站再有軟件。

    由于網絡技術發展的多樣性,手機瀏覽器往往無法跟隨它的步伐,為改善用戶體驗,網站客戶端軟件印運而生。

    開發Android網站客戶端通常有兩種方法:第一種,通過服務端的開放平臺,調用提供的API接口來開發,比如說open sina;第二種,服務端沒有提供任何接口,你也沒有服務端任何數據庫訪問權限,就是一個純純粹粹的網站,要你做客戶端。今天,我要和大家分享的正是第二種情況。
       

        這是一個簡單的示意圖,告訴我們,數據是由網頁從數據庫中取出,我們要為這個系統做客戶端,我們就應該這樣去改造它。

         

    通過這樣間接的方法來訪問數據庫,只要網頁能看到的內容,我們的客戶端都能獲取到,而UI是由你自行制作,就可以使使用體驗上一個臺階。

    既然網頁是我們的數據樞紐,我們就從網頁分析著手。

    該教程來自本人項目-掌上民大-真實經驗,所以用項目中的掌上圖書館板塊來示范。

    該項目任務為中南民族大學圖書館圖書查詢功能制作客戶端。

    首先打開該網址http://www.lib.scuec.edu.cn/,我們會看到主界面
        

    正中間就是查詢入口,我們輸入”android”進行查詢
        

    得到結果的網頁,但我們能發現,這個頁面是ILAS圖書管理系統,所以真正的入口并不是上面紅圈的地方。
    所以我繼續找,經過短暫的觀察,發現入口在這里
        

    我們點擊進入

    果然就是這貨,我們點擊書目查詢

         

    就是它了。真正的入口就在這里,這時我們打開Http Watch軟件,點”Record”,在搜索框里輸入”android”,點擊查詢,抓取以”android”為關鍵字搜索時瀏覽器的所有包。待結果界面載入完成后,HttpWatch上就會出現如下信息
         

    我們先看Summary選項卡,我們可以初步了解,這是一個POST請求(Http請求中的一種,另一種是GET)POST到的網址是http://coin.lib.scuec.edu.cn/cgi-bin/IlaswebBib
       
    這樣我們的思路就清晰了,我們的客戶端需要模擬瀏覽器,向上述地址POST一個包,那個地址肯定會返回一個Content給我們,不出意外的話,Content里面就是我們要的書目信息。那么,瀏覽器POST上去的內容是什么呢?我們點擊這條POST請求,看詳細信息,
        

    由于是POST請求,我們先看POST DATA,里面是以鍵值對的形式存儲的,這里顯示了我們瀏覽器在我們搜索”android”時,POST的所有數據。那這些鍵值對又代表了什么呢,我們打開這個網頁的源碼來一探究竟。
        

    從這段可以看出v_index是表示查找途徑的它有TITLE,AUTHOR,SUBJECT,CLASSNO,ISBN,CALLNO六種值

    FLD_DAT_BEGFLD_DAT_END分別是開始和結束年份

    v_value表示用戶在搜索框中輸入的內容

      
    v_paggnum
    表示每頁顯示的書目條數,有10 15 20三種

       

    v_seldatabases
    是檢索庫  0 1 2三種值v_LogicSrch是檢索方式   0 1兩種值

        Submit是查詢或重填,有 兩種值至此,我們弄清楚了POST,Data里所有內容的含義和取值可能。但我們模擬POST請求為什么,其實就是為了得到搜索的書目信息,所以我們看一下返回的Content是不是我們要的東西

    果然,就是我們搜到的書目信息,就以String的形式放在Content里面。最后我們查看一下Stream,截圖,以防等下我們需要這里面的東西
        

    好了,這個頁面的工作原理我們已經弄清楚了:用戶在網頁中輸入搜索內容后,點擊查詢,瀏覽器會POST一個Data到目標網址,該網址的返回信息就是搜到的書目。 
       
    我們開始編寫代碼,模擬這個過程,先打開eclipse建立一個Java項目(注意是Java項目,因為Java項目可以完美移植到Android項目中且調試方便,并且模擬Http請求這一過程沒有用到任何Android功能)。
    導入HttpClient4個包commons-codeccommons-httpclientcommons-logginglog4j

    ?

    //實例化HttpClient

    HttpClient client = new HttpClient();

    //Stream頁面里面有Host地址 端口是80

    client.getHostConfiguration().setHost("http://coin.lib.scuec.edu.cn", 80);

    //用目標地址 實例一個POST方法

    PostMethod post = new PostMethod("http://coin.lib.scuec.edu.cn/cgi-bin/IlaswebBib");

    //將需要的鍵值對寫出來

    NameValuePair beg = new NameValuePair("FLD_DAT_BEG" , “”);

    NameValuePair end = new NameValuePair("FLD_DAT_END" , “”);

    NameValuePair submit = new NameValuePair("submit" , "查 詢"));

    NameValuePair vIndex = new NameValuePair("v_index" , “TITLE”);

    NameValuePair vLogicSrch = new NameValuePair("v_LogicSrch" , "0");

    NameValuePair vPagenum = new NameValuePair("v_pagenum" , "10");

    NameValuePair vSeldatabase = new NameValuePair("v_seldatabase" , "0");

    NameValuePair vValue = new NameValuePair("v_value" ,”android”);

     

    //給POST方法加入上述鍵值對

    post.setRequestBody(new NameValuePair[] {beg , end , submit , vIndex , vLogicSrch , vPagenum , vSeldatabase , vValue});

    //執行POST方法

    client.executeMethod(post);

    //將POST返回的數據以流的形式讀入,再把輸入流流至一個buff緩沖字節數組

    //StreamTool類是我自己寫的一個工具類,其內容將在下文附出

    byte[] buff = StreamTool.readInputStream(post.getResponseBodyAsStream());

    //將返回的內容格式化為String存在html中

    String html = new String(buff);

    //任務完成了,釋放連接

    post.releaseConnection();

      

    ?

    //StreamTool類如下

    public class StreamTool {

            /**

             * 從輸入流中獲取數據

             * @param inputStream 輸入流

             * @return 字節數組

             * @throws Exception

             */

      public static byte[] readInputStream(InputStream inputStream) throws Exception

            {

    //實例化一個輸出流

             ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    //一個1024字節的緩沖字節數組

             byte[] buffer = new byte[1024];

             int len = 0;

    //讀流的基本知識

             while ((len=inputStream.read(buffer)) != -1) {

                 outputStream.write(buffer, 0, len);

                    }

    //用完要關,大家都懂的

             inputStream.close();

             return outputStream.toByteArray();

            }

    }

      現在,我們得到了POST方法返回的String,我們輸出到控制臺看看是什么

    ?

    System.out.println(html);

      

    沒錯,就是我們上文看到的HttpWatch 抓到的返回Content,也就是一段HTML代碼,這說明,我們模擬瀏覽器POST請求成功了!
    我們再試試別的搜索內容,來一個”Android開發”(即將v_value鍵值對的值改成”android開發”),這時運行后,我們卻從控制臺得到了這樣的結果:


       
    經過幾次試驗后,發現一個規律,只要搜索內容中包括中文,就搜不到。
    所以可以判定是中文編碼的問題,(在開發這類客戶端時候,中文編碼往往是個很具困難的問題。安卓巴士開發3群的某群友提到:服務器交流用的編碼是”ISO-8859-1”,跟我起初用到的編碼一致,但真實性仍需考證)所以我們修改上面的代碼,將代表搜索內容的v_value對應的值編碼為”ISO-8859-1”

    就將上段代碼中的

    ?

    NameValuePair vValue = new NameValuePair("v_value" ,”android”);

      改為

    ?

    NameValuePair vValue = new NameValuePair("v_value" , new String(“android開發”.getBytes(),"ISO-8859-1"));

      這時再運行,控制臺成功輸出以” android開發為關鍵字的Content

    至此,我們POST請求才真正完成。 觀察控制臺的HTML后發現,我們需要的書目信息就在里面,只不過被一些HTML標簽包裹住了,下一步我們就要解放這些信息,存儲到容器里。
    這里我們要用到Jsoup,一個Java開源HTML解析器(來自org.jsoup)
    我們直接上代碼,逐行解釋(大家最好對應上面的HTML代碼來理解)
    首先我們建一個容器來裝這些解析到的數據,由于我的項目是將這些數據以ListView呈現給用戶,而ListView的數據是由Adapter提供,Adapter需要傳一個特殊容器-包含HashMapArrayList(Android基礎知識)

    ?

    //所以有

    List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();

    //開始使用Jsoup

    //Jsoup支援一個Document類將剛才的html轉化成Document

    Document document = Jsoup.parse(html);

    //一個Document又由elements組成 我們選擇”tr”開頭的標簽,存入 trs元素群中

    Elements trs = document.select("tr");

    //得到整個HTML中包含tr的標簽的個數

    int totalTrs = trs.size();

    //我們可以觀察上面沒有搜索結果的那個HTML。發現,如果totalTrs<=3就表示沒結果。

    //只要有書目結果totalTrs必定大于3,于是

    if(totalTrs > 3)

    for(int i = 0;i < totalTrs - 3;i++)

    {

    //觀察HTML,從第i+2個tr開始,包含的才是我們要的書目信息

    //我們從每個tr中選出td標簽元素群

     Elements tds = trs.get(i + 2).select("td");

    //得到每個tr中td的個數

     int totalTds = tds.size();

    //一個臨時的HashMap,里面是String-Object鍵值對

     Map<String,Object> map = new HashMap<String,Object>();

    //j是一個標識數

      for(int j =0;j < totalTds ;j++)

       {

        switch (j) {

    //0表示第一個,即書名

    //put方法即向map加入一條鍵值對

    //html()方法就得到標簽括起來的內容

           case 0:

            map.put("book_title",tds.get(j).html().toString());

            break;

           case 1:

    //1表示第二個,即作者

            map.put("book_author", tds.get(j).html().toString());

            break;

           case 2:

    //2表示第三個,即出版信息

            map.put("book_press", tds.get(j).html().toString());

            break;

           case 3:

    //3表示第四個,即頁數

            map.put("book_page", tds.get(j).html().toString());

            break;

           case 4:

    //4表示第五個,即價格

            map.put("book_price", tds.get(j).html().toString());

            break;

           case 5:

    //5表示第六個,即索取號

            map.put("book_noFor", tds.get(j).html().toString());

            break;

           case 6:

    //6表示第七個,即那段網址

    //那段網址td中又包含一個a標簽,a標簽的href屬性的值就是網址

    //attr(“href”)可以返回href屬性的值

            map.put("book_detail",tds.get(j).select("a").attr("href").toString());

            break;

           default:

            break;

               }

          }

         list.add(map);

    }

      list就是我們需要的ArrayList
      
    上面所有代碼調通后,我們只需一些簡單的復制粘貼,就可以放在我們的Android工程中,加上一段簡單的代碼就可以讓ListView顯示這個ArrayList(由于沒有任何技術含量,以及該項目暫未上線,此段代碼不予以展示,敬請諒解
       
    接下來,我們一個頁面最多只包含10個書目信息,而我們校圖書館,光以”Java”為關鍵字的書就超過1000本,怎么來顯示完全呢,一次顯示所有的書肯定不現實。首先數據量太大,手機無法承受;消耗流量過大,用戶體驗極差。所以,我們就需要ListView能夠動態加載數據,即一開始顯示十項,如果用戶此時拉動ListView顯示完十項之后,自動聯網,再加載十項(如果還有十項的話),這樣的用戶體驗會非常順暢。
       
    這個功能的核心是,我們的ListView需要實現OnScrollListener接口。
    如果你的ListView所在的Activity繼承的是ListActivity的話,只需在extends ListActivity后面加上implements OnScrollListener,這時你需要復寫onScrollonScrollStateChanged。如果你的ListView是從XMLgetView 得到的,你只需為它setOnScrollListener,也會需要你復寫onScrollonScrollStateChanged

    不管你用哪種方法,我們只用修改onScroll方法

    ?

    @Override

    public void onScroll(AbsListView view, int firstVisibleItem,

              int visibleItemCount,int totalItemCount) {

                    // TODO Auto-generated method stub

    //關鍵的判斷代碼,這句話表示用戶將ListView拉至最底部

          if(firstVisibleItem + visibleItemCount ==totalItemCount)

    //你只需要把繼續得到下面十項的代碼寫在這里,就可以實現上述功能了。

    //同樣再使用一次POST方法,不再贅述

    //代碼由于同樣原因不予以展示,敬請諒解

     

      項目成品展示:

     
    這些信息就是上面用網頁以"android"為關鍵字搜索到的。

    【至此,文章開頭的幾個知識點已經全部講解完畢,時間倉促,事物繁忙,可能會影響文章質量,還請大家多多包涵。 如果有問題,可以直接回帖、發論壇信息或通過Email:anliupeinye@gmail.com聯系我。】

    posted on 2013-02-24 17:10 L遷客 閱讀(1585) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 大陆一级毛片免费视频观看| 美女视频黄a视频全免费网站一区 美女视频黄a视频全免费网站色 | 美女被爆羞羞网站在免费观看| 永久免费av无码网站韩国毛片 | 亚洲国产成人VA在线观看| 毛片亚洲AV无码精品国产午夜| 大香人蕉免费视频75| 欧美亚洲精品一区二区| 国产在线19禁免费观看国产 | 亚洲国产成人手机在线观看| 69式国产真人免费视频| 亚洲w码欧洲s码免费| 成人免费毛片内射美女APP| va天堂va亚洲va影视中文字幕| 麻豆国产精品免费视频| 亚洲综合色7777情网站777| 女人让男人免费桶爽30分钟| 亚洲av无码一区二区三区天堂| 国产精品嫩草影院免费| 一个人免费观看www视频| 亚洲精品成人无限看| 99精品视频在线视频免费观看| 亚洲成A∨人片在线观看无码| 青春禁区视频在线观看直播免费 | 亚洲中文字幕伊人久久无码| 中国国产高清免费av片| 亚洲噜噜噜噜噜影院在线播放| 日韩免费a级在线观看| 在线播放免费人成视频网站| 精品久久久久久亚洲| 131美女爱做免费毛片| 亚洲AV噜噜一区二区三区| 久久青青草原亚洲av无码| 91香蕉国产线观看免费全集| 亚洲乱码在线卡一卡二卡新区| 又黄又爽一线毛片免费观看| 中文字幕无码免费久久| 色天使亚洲综合在线观看| 国产AV无码专区亚洲AV手机麻豆| 黄在线观看www免费看| 亚洲国产成人AV网站|