ivaneeo's blog

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

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            669 Posts :: 0 Stories :: 64 Comments :: 0 Trackbacks

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

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

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

          1.     public void doPost(HttpServletRequest request, HttpServletResponse response)
          2.  
          3.            throws ServletException, IOException {
          4.  
          5.  
          6.  
          7.        //獲取輸入流,是HTTP協議中的實體內容
          8.  
          9.        ServletInputStream  sis=request.getInputStream();
          10.  
          11.      
          12.  
          13.        //緩沖區
          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.        //把流里的信息循環讀入到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.  

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

          1. <form action="servlet/ReceiveFile" method="post" enctype="multipart/form-data">
          2.  
          3.     第一個參數<input type="text" name="name1"/> <br/>
          4.  
          5.     第二個參數<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,才可以實現附件的上傳。

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

          —————————–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–

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

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

                 結合16進制數據和記事本顯示的數據可知上傳參數部分的格式規律:

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

          2.       第二行

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

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

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

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

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

          由觀察可得,表單上傳的每個參數都是按照以上1—4的格式構造HTTP協議中的參數部分。

          結合16進制數據和記事本顯示的數據可知上傳文件部分的格式規律:

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

          2.       第二行:

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

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

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

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

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

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

          5.       第五行開始:上傳的內容的二進制數。

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

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

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

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

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

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

          1. public class FormFile {
          2.  /* 上傳文件的數據 */
          3.  private byte[] data;
          4.  /* 文件名稱 */
          5.  private String filname;
          6.  /* 表單字段名稱*/
          7.  private String formname;
          8.  /* 內容類型 */
          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.  

           
          實現文件上傳的代碼如下:

          /** 
           * 直接通過HTTP協議提交數據到服務器,實現表單提交功能 
           * @param actionUrl 上傳路徑 
           * @param params 請求參數 key為參數名,value為參數值 
           * @param file 上傳文件 
           */ 
          public static String post(String actionUrl, Map<String, String> params, FormFile[] files) {  
              try {             
                  String BOUNDARY = “———7d4a6d158c9″; //數據分隔線  
                  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();  
                    
                  //上傳的表單參數部分,格式請參考文章  
                  for (Map.Entry<String, String> entry : params.entrySet()) {//構建表單字段內容  
                      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());//發送表單字段數據  
                   
                  //上傳的文件部分,格式請參考文章  
                  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();//數據結束標志           
                  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魔力
          主站蜘蛛池模板: 东光县| 谢通门县| 台江县| 信丰县| 武穴市| 鄂州市| 桑日县| 洛扎县| 霍林郭勒市| 平山县| 元阳县| 大港区| 沧州市| 柏乡县| 舞钢市| 远安县| 察雅县| 斗六市| 巴马| 三江| 和政县| 堆龙德庆县| 新乐市| 吉首市| 临沭县| 句容市| 襄汾县| 通城县| 巴彦县| 麦盖提县| 大竹县| 榆社县| 开远市| 太和县| 平陆县| 桦甸市| 紫金县| 延川县| 深州市| 新河县| 柳河县|