ivaneeo's blog

          自由的力量,自由的生活。

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            669 Posts :: 0 Stories :: 64 Comments :: 0 Trackbacks

          在Android的客戶端編程中(特別是SNS 類型的客戶端),經(jīng)常需要實現(xiàn)注冊功能Activity,要用戶輸入用戶名,密碼,郵箱,照片后注冊。但這時就有一個問題,在HTML中用form表單就 能實現(xiàn)如上的注冊表單,需要的信息會自動封裝為完整的HTTP協(xié)議,但在Android中如何把這些參數(shù)和需要上傳的文件封裝為HTTP協(xié)議呢?

          我們可以先做個試驗,看一下form表單到底封裝了什么樣的信息。

          第一步:編寫一個Servlet,把接收到的HTTP信息保存在一個文件中,代碼如下:

          1.     public void doPost(HttpServletRequest request, HttpServletResponse response)
          2.  
          3.            throws ServletException, IOException {
          4.  
          5.  
          6.  
          7.        //獲取輸入流,是HTTP協(xié)議中的實體內(nèi)容
          8.  
          9.        ServletInputStream  sis=request.getInputStream();
          10.  
          11.      
          12.  
          13.        //緩沖區(qū)
          14.  
          15.        byte buffer[]=new byte[1024];
          16.  
          17.       
          18.  
          19.        FileOutputStream fos=new FileOutputStream("d:\\file.log");
          20.  
          21.       
          22.  
          23.        int len=sis.read(buffer, 0, 1024);
          24.  
          25.       
          26.  
          27.        //把流里的信息循環(huán)讀入到file.log文件中
          28.  
          29.        while( len!=-1 )
          30.  
          31.        {
          32.  
          33.            fos.write(buffer, 0, len);
          34.  
          35.            len=sis.readLine(buffer, 0, 1024);
          36.  
          37.        }
          38.  
          39.       
          40.  
          41.        fos.close();
          42.  
          43.        sis.close();
          44.  
          45.       
          46.  
          47.     }
          48.  
          49.  

          第二步:實現(xiàn)如下一個表單頁面, 詳細的代碼如下:

          1. <form action="servlet/ReceiveFile" method="post" enctype="multipart/form-data">
          2.  
          3.     第一個參數(shù)<input type="text" name="name1"/> <br/>
          4.  
          5.     第二個參數(shù)<input type="text" name="name2"/> <br/>
          6.  
          7.     第一個上傳的文件<input type="file" name="file1"/> <br/>
          8.  
          9.     第二個上傳的文件<input type="file" name="file2"/> <br/>
          10.  
          11.     <input type="submit" value="提交">
          12.  
          13. </form>

          注意了,由于要上傳附件,所以一定要設置enctype為multipart/form-data,才可以實現(xiàn)附件的上傳。

          第三步:填寫完信息后按“提交”按鈕后,在D盤下查找file.log文件用記事本打開,數(shù)據(jù)如下:

          —————————–7d92221b604bc

          Content-Disposition: form-data; name=”name1″

          hello

          —————————–7d92221b604bc

          Content-Disposition: form-data; name=”name2″

          world

          —————————–7d92221b604bc

          Content-Disposition: form-data; name=”file1″; filename=”C:\2.GIF”

          Content-Type: image/gif

          GIF89a

                €   € €€   €€ € €€€€€覽?                                                                                     3  f       3  33 3f 3 3 3 f  f3 ff f f f   ? 檉 櫃 櫶 ?   ? 蘤 虣 燙 ?   3 f   3  3 33 f3 ? ? 33 33333f33?3?33f 3f33ff3f?f?f3 3?3檉3櫃3櫶3?3 3?3蘤3虣3燙3?3 333f3??f  f 3f ff 檉 蘤 f3 f33f3ff3檉3蘤3ff ff3fffff檉f蘤ff f?f檉f櫃f櫶f?f f?f蘤f虣f燙f?f f3fff檉蘤   3 f 櫃 虣 ? ?3?f?櫃3虣3檉 檉3檉f檉櫃f虣f櫃 櫃3櫃f櫃櫃櫶櫃櫶 櫶3櫶f櫶櫃燙櫶? ?3?f?櫃虣   3 f 櫶 燙 ? ?3?f?櫶3燙3蘤 蘤3蘤f蘤櫶f燙f虣 虣3虣f虣櫶櫶虣燙 燙3燙f燙櫶燙燙? ?3?f?櫶燙   3 f ? ? 3 333f3?3?3f f3fff?f?f ?檉櫃櫶??蘤虣燙? 3f??!?   ,   

            e   ??羵Q鸚M!C囑lH馉脝遠5荑p釩?3R?R愣?MV39V5?談re琷?試   3??qn?薵Q燚c?獖i鄲EW艗赥戟j ;

          —————————–7d92221b604bc

          Content-Disposition: form-data; name=”file2″; filename=”C:\2.txt”

          Content-Type: text/plain

          hello everyone!!!

          —————————–7d92221b604bc–

                 從表單源碼可知,表單上傳的數(shù)據(jù)有4個:參數(shù)name1和name2,文件file1和file2

          首先從file.log觀察兩個參數(shù)name1和name2的情況。這時候使用UltraEdit打開file.log(因為有些字符在記事本里顯示不出來,所以要用16進制編輯器)

                 結(jié)合16進制數(shù)據(jù)和記事本顯示的數(shù)據(jù)可知上傳參數(shù)部分的格式規(guī)律:

          1.       第一行是“—————————–7d92221b604bc”作為分隔符,然后是“\r\n”(即16進制編輯器顯示的0D 0A)回車換行符。

          2.       第二行

          (1)       首先是HTTP中的擴展頭部分“Content-Disposition: form-data;”,表示上傳的是表單數(shù)據(jù)。

          (2)       “name=”name1″”參數(shù)的名稱。

          (3)       “\r\n”(即16進制編輯器顯示的0D 0A)回車換行符。

          3.       第三行:“\r\n”(即16進制編輯器顯示的0D 0A)回車換行符。

          4.       第四行:參數(shù)的值,最后是“\r\n”(即16進制編輯器顯示的0D 0A)回車換行符。

          由觀察可得,表單上傳的每個參數(shù)都是按照以上1—4的格式構(gòu)造HTTP協(xié)議中的參數(shù)部分。

          結(jié)合16進制數(shù)據(jù)和記事本顯示的數(shù)據(jù)可知上傳文件部分的格式規(guī)律:

          1.       第一行是“—————————–7d92221b604bc”作為分隔符,然后是“\r\n”(即16進制編輯器顯示的0D 0A)回車換行符。

          2.       第二行:

          a)         首先是HTTP中的擴展頭部分“Content-Disposition: form-data;”,表示上傳的是表單數(shù)據(jù)。

          b)        “name=”file2″;”參數(shù)的名稱。

          c)        “filename=”C:\2.txt””參數(shù)的值。

          d)        “\r\n”(即16進制編輯器顯示的0D 0A)回車換行符。

          3.       第三行:HTTP中的實體頭部分“Content-Type: text/plain”:表示所接收到得實體內(nèi)容的文件格式。計算機的應用中有多種多種通用的文件格式,人們?yōu)槊糠N通用格式都定義了一個名稱,稱為 MIME,MIME的英文全稱是”Multipurpose Internet Mail Extensions” (多功能Internet 郵件擴充服務)

          4.       第四行:“\r\n”(即16進制編輯器顯示的0D 0A)回車換行符。

          5.       第五行開始:上傳的內(nèi)容的二進制數(shù)。

          6.       最后是結(jié)束標志“—————————–7d92221b604bc–”,注意:這個結(jié)束標志和分隔符的區(qū)別是最后多了“–”部分。

          但現(xiàn)在還有一個問題,就是分隔符“—————————–7d92221b604bc”是怎么確定的呢?是不是一定要“7d92221b604bc”這串數(shù)字?

                  我們以前的分析只是觀察了HTTP請求的實體部分,可以借用工具觀察完整的HTTP請求看一看有沒有什么線索?

            在IE下用HttpWatch,在Firefox下用Httpfox這個插件,可以實現(xiàn)網(wǎng)頁數(shù)據(jù)的抓包,從圖4可看出,原來在Content-Type部分指定了分隔符所用的字符串。

           
          根據(jù)以上總結(jié)的注冊表單中的參數(shù)傳遞和文件上傳的規(guī)律,我們可以能寫出Android中實現(xiàn)一個用戶注冊功能(包括個人信息填寫和上傳圖片部分)的工具類,

          首先,要有一個javaBean類FormFile封裝文件的信息:

          1. public class FormFile {
          2.  /* 上傳文件的數(shù)據(jù) */
          3.  private byte[] data;
          4.  /* 文件名稱 */
          5.  private String filname;
          6.  /* 表單字段名稱*/
          7.  private String formname;
          8.  /* 內(nèi)容類型 */
          9.  private String contentType = "application/octet-stream"; //需要查閱相關的資料
          10.  
          11.  public FormFile(String filname, byte[] data, String formname, String contentType) {
          12.   this.data = data;
          13.   this.filname = filname;
          14.   this.formname = formname;
          15.   if(contentType!=null) this.contentType = contentType;
          16.  }
          17.  
          18.  public byte[] getData() {
          19.   return data;
          20.  }
          21.  
          22.  public void setData(byte[] data) {
          23.   this.data = data;
          24.  }
          25.  
          26.  public String getFilname() {
          27.   return filname;
          28.  }
          29.  
          30.  public void setFilname(String filname) {
          31.   this.filname = filname;
          32.  }
          33.  
          34.  public String getFormname() {
          35.   return formname;
          36.  }
          37.  
          38.  public void setFormname(String formname) {
          39.   this.formname = formname;
          40.  }
          41.  
          42.  public String getContentType() {
          43.   return contentType;
          44.  }
          45.  
          46.  public void setContentType(String contentType) {
          47.   this.contentType = contentType;
          48.  }
          49.  
          50. }
          51.  

           
          實現(xiàn)文件上傳的代碼如下:

          /** 
           * 直接通過HTTP協(xié)議提交數(shù)據(jù)到服務器,實現(xiàn)表單提交功能 
           * @param actionUrl 上傳路徑 
           * @param params 請求參數(shù) key為參數(shù)名,value為參數(shù)值 
           * @param file 上傳文件 
           */ 
          public static String post(String actionUrl, Map<String, String> params, FormFile[] files) {  
              try {             
                  String BOUNDARY = “———7d4a6d158c9″; //數(shù)據(jù)分隔線  
                  String MULTIPART_FORM_DATA = “multipart/form-data”;  
                    
                  URL url = new URL(actionUrl);  
                  HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
                  conn.setDoInput(true);//允許輸入  
                  conn.setDoOutput(true);//允許輸出  
                  conn.setUseCaches(false);//不使用Cache  
                  conn.setRequestMethod(”POST”);            
                  conn.setRequestProperty(”Connection”, “Keep-Alive”);  
                  conn.setRequestProperty(”Charset”, “UTF-8″);  
                  conn.setRequestProperty(”Content-Type”, MULTIPART_FORM_DATA + “; boundary=” + BOUNDARY);  
           
                  StringBuilder sb = new StringBuilder();  
                    
                  //上傳的表單參數(shù)部分,格式請參考文章  
                  for (Map.Entry<String, String> entry : params.entrySet()) {//構(gòu)建表單字段內(nèi)容  
                      sb.append(”–”);  
                      sb.append(BOUNDARY);  
                      sb.append(”\r\n”);  
                      sb.append(”Content-Disposition: form-data; name=\”"+ entry.getKey() + “\”\r\n\r\n”);  
                      sb.append(entry.getValue());  
                      sb.append(”\r\n”);  
                  }  
                  DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());  
                  outStream.write(sb.toString().getBytes());//發(fā)送表單字段數(shù)據(jù)  
                   
                  //上傳的文件部分,格式請參考文章  
                  for(FormFile file : files){  
                      StringBuilder split = new StringBuilder();  
                      split.append(”–”);  
                      split.append(BOUNDARY);  
                      split.append(”\r\n”);  
                      split.append(”Content-Disposition: form-data;name=\”"+ file.getFormname()+”\”;filename=\”"+ file.getFilname() + “\”\r\n”);  
                      split.append(”Content-Type: “+ file.getContentType()+”\r\n\r\n”);  
                      outStream.write(split.toString().getBytes());  
                      outStream.write(file.getData(), 0, file.getData().length);  
                      outStream.write(”\r\n”.getBytes());  
                  }  
                  byte[] end_data = (”–” + BOUNDARY + “–\r\n”).getBytes();//數(shù)據(jù)結(jié)束標志           
                  outStream.write(end_data);  
                  outStream.flush();  
                  int cah = conn.getResponseCode();  
                  if (cah != 200) throw new RuntimeException(”請求url失敗”);  
                  InputStream is = conn.getInputStream();  
                  int ch;  
                  StringBuilder b = new StringBuilder();  
                  while( (ch = is.read()) != -1 ){  
                      b.append((char)ch);  
                  }  
                  outStream.close();  
                  conn.disconnect();  
                  return b.toString();  
              } catch (Exception e) {  
                  throw new RuntimeException(e);  
              }  

          posted on 2011-06-09 16:26 ivaneeo 閱讀(3325) 評論(0)  編輯  收藏 所屬分類: java魔力
          主站蜘蛛池模板: 大名县| 大丰市| 祁门县| 桂平市| 福建省| 咸阳市| 扬中市| 新邵县| 鸡东县| 天峨县| 祥云县| 乌拉特后旗| 贡嘎县| 贡山| 石林| 晋州市| 辛集市| 屯留县| 云龙县| 高州市| 惠安县| 卢龙县| 永福县| 寻乌县| 库尔勒市| 黄大仙区| 平乡县| 余干县| 苗栗县| 平湖市| 贵定县| 建湖县| 丹寨县| 丰台区| 常山县| 桓台县| 偃师市| 贺州市| 浦县| 怀集县| 德保县|