HttpClient MultipartEntityBuilder 上傳文件

 在HttpCient4.3以後上傳文件主要使用的類是位於org.apache.http.entity.mime下的MultipartEntityBuilder(原先的MultipartEntity已經基本棄用了)。
  1.首先是設置上傳的模式;
  setMode(HttpMultipartMode mode),其中mode主要有BROWSER_COMPATIBLE,RFC6532,STRICT三種,默認值是STRICT。
  2.其次是建立MultipartEntityBuilder對象,並添加須要上傳的數據;
  a.利用MultipartEntityBuilder.create()來建立對象;
  b.addBinaryBody:以二進制的形式添加數據,能夠添加File、InputStream、byte[]類型的數據。
  addBinaryBody(String name, File file, ContentType contentType, String filename)
  addBinaryBody(String name, InputStream stream, ContentType contentType, String filename)
  addBinaryBody(String name, byte[] b, ContentType contentType, String filename)
  c.addTextBody:添加文本數據
  addTextBody(String name, String text, ContentType contentType)
  d.addPart:以Key/Value的形式添加ContentBody類型的數據
  addPart(String name, ContentBody contentBody)
  更多函數能夠參考:https://hc.apache.org/httpcomponents-client-ga/httpmime/apidocs/org/apache/http/entity/mime/MultipartEntityBuilder.html。在GACHA API中,主要是上傳圖片,因此在 測試中選用了addBinaryBody。其中,第一個參數name的值,是服務器已經定義好的,服務器會根據這個字段來讀取咱們上傳的文件流,不匹配則會報錯。關於contentType,能夠參考:http://tool.oschina.net/commons,不一樣文件擴展名所對應的類型。而file/stream和fileName,就是咱們所要上傳文件的信息。當用 瀏覽器的開發者工具查看API請求時,咱們會看到這些/參數基本位於API請求中的 Request Payload字段。
  3.而後是利用build()方法建立一個HttpEntity對象;
  4.最後將HttpEntity對象添加到指定的URL上,採用HttpPost的setEntity的方法;
  5.最後的最後,就是調用HttpClient對象發送請求,並獲取服務器的響應
 

 

 在HttpCient4.3以前上傳文件主要使用MultipartEntity這個類,但如今這個類已經不在推薦使用了。隨之替代它的類是MultipartEntityBuilder。php

 

下面讓咱們瞭解一下MultipartEntityBuilder類:

         MultipartEntityBuilder這個類主要用於建立HttpEntity。它的主要方法有:html

修飾符和類型java

方法和描述android

MultipartEntityBuilderapache

addBinaryBody(String name, byte[] b) api

將字節數組以二進制的形式添加數據。數組

MultipartEntityBuilder瀏覽器

addBinaryBody(String name, byte[] b, ContentType contentType, String filename) 服務器

將字節數組以二進制的形式添加數據。app

MultipartEntityBuilder

addBinaryBody(String name, File file) 

將文件以二進制的形式添加數據。

MultipartEntityBuilder

addBinaryBody(String name, File file, ContentType contentType, String filename) 

將文件以二進制的形式添加數據。

MultipartEntityBuilder

addBinaryBody(String name, InputStream stream) 

MultipartEntityBuilder

addBinaryBody(String name, InputStream stream, ContentType contentType, String filename) 

將輸入流以二進制的形式添加數據。

MultipartEntityBuilder

addPart(String name, ContentBody contentBody) 

添加ContentBody 類型的數據。

MultipartEntityBuilder

addTextBody(String name, String text) 

添加文本數據。

MultipartEntityBuilder

addTextBody(String name, String text, ContentType contentType) 

以指定的內容類型添加文本數據。

HttpEntity

build() 

建立一個HttpEntity。

static MultipartEntityBuilder

create() 

建立一個MultipartEntityBuilder對象。

MultipartEntityBuilder

setBoundary(String boundary) 

設置邊界。

MultipartEntityBuilder

setCharset(Charset charset) 

設置請求的編碼格式。

MultipartEntityBuilder

setLaxMode() 

MultipartEntityBuilder

setMode(HttpMultipartMode mode) 

設置模式。

MultipartEntityBuilder

setStrictMode() 

         

主要方法說明:

addBinaryBody、addPart、addTextBody方法用於添加要上傳的數據,從上面的表格中能夠發現用於添加數據的方法,都是key-value類型。因此在服務器端咱們能夠經過request.getPart("keyname")方式獲取對應key的數據。也能夠經過request.getParts()方式獲取客戶端經過以上三種方法提交全部數據。

1.經過addBinaryBody方法直接能夠添加File、InputStream、byte[]類型的數據。

2.經過addPart方法只能添加ContentBody類型的數據,在org.apache.http.entity.mime.content包中已經提供了String、File以及InputStream對應的ContentBody類型的子類,如FileBody、InputStreamBody、StringBody,經過這些類咱們能夠將String、File以及InputStream類型的數據轉換成ContentBody類型的數據。

3.經過addTextBody方法咱們能夠很方便的添加文本數據。

 

2.經過HttpCient上傳文件


Android端須要添加httpcore-4.3.2.jarhttpmime-4.3.5.jar兩個包。兩個包缺一不可。

在這裏我用的是最新版的HttpCient,你們能夠從http://hc.apache.org/downloads.cgi上下載所須要的jar包,若是上面的網站打不開,你們也不用擔憂,我已經將項目中所須要的jar包上傳到CSDN上《httpcomponents-client-4.3.5-bin.zip》須要的朋友能夠去下載。

      Android端項目核心代碼:

[java]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. HttpClient client=new DefaultHttpClient();// 開啓一個客戶端 HTTP 請求   
  2. HttpPost post = new HttpPost(url);//建立 HTTP POST 請求    
  3. MultipartEntityBuilder builder = MultipartEntityBuilder.create();  
  4. //      builder.setCharset(Charset.forName("uft-8"));//設置請求的編碼格式  
  5. builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);//設置瀏覽器兼容模式  
  6. int count=0;  
  7. for (File file:files) {  
  8. //          FileBody fileBody = new FileBody(file);//把文件轉換成流對象FileBody  
  9. //          builder.addPart("file"+count, fileBody);  
  10.     builder.addBinaryBody("file"+count, file);  
  11.     count++;  
  12. }         
  13. builder.addTextBody("method", params.get("method"));//設置請求參數  
  14. builder.addTextBody("fileTypes", params.get("fileTypes"));//設置請求參數  
  15. HttpEntity entity = builder.build();// 生成 HTTP POST 實體        
  16. post.setEntity(entity);//設置請求參數  
  17. HttpResponse response = client.execute(post);// 發起請求 並返回請求的響應  
  18. if (response.getStatusLine().getStatusCode()==200) {  
  19.     return true;  
  20. }  
  21. return false;         
[java]  view plain  copy
  1. HttpClient client=new DefaultHttpClient();// 開啓一個客戶端 HTTP 請求   
  2. HttpPost post = new HttpPost(url);//建立 HTTP POST 請求    
  3. MultipartEntityBuilder builder = MultipartEntityBuilder.create();  
  4. //      builder.setCharset(Charset.forName("uft-8"));//設置請求的編碼格式  
  5. builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);//設置瀏覽器兼容模式  
  6. int count=0;  
  7. for (File file:files) {  
  8. //          FileBody fileBody = new FileBody(file);//把文件轉換成流對象FileBody  
  9. //          builder.addPart("file"+count, fileBody);  
  10.     builder.addBinaryBody("file"+count, file);  
  11.     count++;  
  12. }         
  13. builder.addTextBody("method", params.get("method"));//設置請求參數  
  14. builder.addTextBody("fileTypes", params.get("fileTypes"));//設置請求參數  
  15. HttpEntity entity = builder.build();// 生成 HTTP POST 實體        
  16. post.setEntity(entity);//設置請求參數  
  17. HttpResponse response = client.execute(post);// 發起請求 並返回請求的響應  
  18. if (response.getStatusLine().getStatusCode()==200) {  
  19.     return true;  
  20. }  
  21. return false;         

代碼分析: 

     上面代碼主要實現了多文件上傳,爲了方便服務器端保存文件,上面代碼設置了名稱爲fileTypes的參數,fileTypes是由上傳的文件類型名拼接成的字符串,如」.jpg.png.docx「;

     服務器端能夠經過獲取名爲fileTypes的參數,而後將其拆分紅字符數組,便可獲得要保存文件的類型。

 

服務器端項目核心代碼:

服務器段主要用到Servlet3.0的API,主要用到的方法有:

1.      request.getParameter("");//獲取客戶端經過addTextBody方法添加的String類型的數據。

2.      request.getPart("");//獲取客戶端經過addBinaryBody、addPart、addTextBody方法添加的指定數據,返回Part類型的對象。

3.      request.getParts();//獲取客戶端經過addBinaryBody、addPart、addTextBody方法添加的全部數據,返回Collection<Part>類型的對象。

4.      part.getName();//獲取上傳文件的名稱即上傳時指定的key。

5.      part.getSize()//獲取上傳文件的大小單位爲字節。

 

[java]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. String fileTypes=request.getParameter("fileTypes");//獲取客戶端上傳的全部文件類型  
  2. String[]typeArray=fileTypes.substring(1).split("\\.");//將文件類型字符串拆分紅String數組  
  3. try {  
  4.     Iterator<Part>iterator=request.getParts().iterator();  
  5.     int count=0;  
  6.     while (iterator.hasNext()) {//遍歷客戶端上傳的全部文件                
  7.         if (count>=typeArray.length)break;//若是超出文件類型數組的大小則跳出循環         
  8.         Part part = (Part) iterator.next();               
  9. //              System.out.println("part.getSize()"+part.getSize());//獲取上傳文件的大小  
  10. //              System.out.println("part.getName()"+part.getName());//獲取上傳文件的名及添加數據時的key名  
  11.         File file=new File("E:\\upload\\"+count+"."+typeArray[count++]);  
  12.         InputStream inputStream=part.getInputStream();  
  13.         FileOutputStream fos=new FileOutputStream(file);  
  14.         byte[]buffer=new byte[1024];  
  15.         int len=0;  
  16.         while ((len=inputStream.read(buffer))!=-1) {  
  17.             fos.write(buffer,0, len);  
  18.         }  
  19.         inputStream.close();  
  20.         fos.close();                      
  21.     }  
  22. }catch (Exception e) {  
  23.     // TODO Auto-generated catch block  
  24.     e.printStackTrace();  
  25. }  
[java]  view plain  copy
  1. String fileTypes=request.getParameter("fileTypes");//獲取客戶端上傳的全部文件類型  
  2. String[]typeArray=fileTypes.substring(1).split("\\.");//將文件類型字符串拆分紅String數組  
  3. try {  
  4.     Iterator<Part>iterator=request.getParts().iterator();  
  5.     int count=0;  
  6.     while (iterator.hasNext()) {//遍歷客戶端上傳的全部文件                
  7.         if (count>=typeArray.length)break;//若是超出文件類型數組的大小則跳出循環         
  8.         Part part = (Part) iterator.next();               
  9. //              System.out.println("part.getSize()"+part.getSize());//獲取上傳文件的大小  
  10. //              System.out.println("part.getName()"+part.getName());//獲取上傳文件的名及添加數據時的key名  
  11.         File file=new File("E:\\upload\\"+count+"."+typeArray[count++]);  
  12.         InputStream inputStream=part.getInputStream();  
  13.         FileOutputStream fos=new FileOutputStream(file);  
  14.         byte[]buffer=new byte[1024];  
  15.         int len=0;  
  16.         while ((len=inputStream.read(buffer))!=-1) {  
  17.             fos.write(buffer,0, len);  
  18.         }  
  19.         inputStream.close();  
  20.         fos.close();                      
  21.     }  
  22. }catch (Exception e) {  
  23.     // TODO Auto-generated catch block  
  24.     e.printStackTrace();  
  25. }  

 

代碼分析: 

         服務器端是經過Servlet實現的,經過調用request.getParameter("fileTypes")方法來獲取客戶端上傳的全部文件類型,而後將文件類型字符串拆分紅String數組。經過request.getParts()方法取出客戶端經過addBinaryBody、addPart、addTextBody上傳的全部數據,而後遍歷數據集合便可進行文件的保存。

因爲事先和客戶端協定,添加上傳文件的順序在添加請求參數以前,因此能夠根據拆分出的文件類型數組的長度判斷出客戶端上傳文件的個數,所以當上面代碼遍歷超出了類型數組的長度時程序跳出循環,再也不進行文件的保存,由於下面的Part都是些參數,而不是要保存的文件了。

 

程序運行效果圖:


Android使用HttpClient上傳數據
 

 

3.完成項目代碼:


MainActivity.java
[java]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
  1. package com.jph.ufh.activity;  
  2.   
  3. import java.io.File;  
  4. import java.util.ArrayList;  
  5. import java.util.HashMap;  
  6. import java.util.Map;  
  7. import com.jph.ufh.R;  
  8. import com.jph.ufh.service.UploadService;  
  9. import android.app.Activity;  
  10. import android.os.Bundle;  
  11. import android.os.Environment;  
  12. import android.os.Handler;  
  13. import android.os.Message;  
  14. import android.view.View;  
  15. import android.widget.Toast;  
  16.   
  17. /** 
  18.  * 經過httpClient批量上傳文件 
  19.  * @author jph 
  20.  * Date:2014.10.09   
  21.  */  
  22. public class MainActivity extends Activity {  
  23.     private ArrayList<File>files;  
  24.     private Map<String, String>params;  
  25.     Handler mHandler=new Handler(){  
  26.         @Override  
  27.         public void handleMessage(Message msg) {  
  28.             // TODO Auto-generated method stub  
  29.             switch (msg.what) {  
  30.             case UploadService.UPLOAD_SUCCESS:  
  31.                 Toast.makeText(MainActivity.this, "上傳成功", Toast.LENGTH_LONG).show();  
  32.                 break;            
  33.             }  
  34.             super.handleMessage(msg);  
  35.         }         
  36.     };  
  37.     @Override  
  38.     protected void onCreate(Bundle savedInstanceState) {  
  39.         super.onCreate(savedInstanceState);  
  40.         setContentView(R.layout.activity_main);       
  41.         files=new ArrayList<File>();  
  42.         params=new HashMap<String, String>();  
  43.           
  44.     }  
  45.     public void upload(View v) {  
  46.         files.clear();  
  47.         params.clear();  
  48.         File file=new File(Environment.getExternalStorageDirectory(),"kaola.jpg");  
  49.         File file2=new File(Environment.getExternalStorageDirectory(),"test.docx");  
  50.         File file3=new File(Environment.getExternalStorageDirectory(),"test.jpg");  
  51.         files.add(file);  
  52.         files.add(file2);  
  53.         files.add(file3);  
  54.         StringBuffer sbFileTypes=new StringBuffer();  
  55.         for (File tempFile:files) {  
  56.             String fileName=tempFile.getName();  
  57.             sbFileTypes.append(getFileType(fileName));            
  58.         }  
  59.         params.put("fileTypes",sbFileTypes.toString());  
  60.         params.put("method", "upload");  
  61.         UploadService uploadService=new UploadService(mHandler);  
  62.         uploadService.uploadFileToServer(params, files);  
  63.     }  
  64.     /** 
  65.      * 獲取文件的類型 
  66.      * @param fileName :文件名 
  67.      * @return 文件類型 
  68.      */  
  69.     private String getFileType(String fileName) {  
  70.         // TODO Auto-generated method stub  
  71.         return fileName.substring(fileName.lastIndexOf("."), fileName.length());  
  72.     }  
  73. }  
[java]  view plain  copy
  1. package com.jph.ufh.activity;  
  2.   
  3. import java.io.File;  
  4. import java.util.ArrayList;  
  5. import java.util.HashMap;  
  6. import java.util.Map;  
  7. import com.jph.ufh.R;  
  8. import com.jph.ufh.service.UploadService;  
  9. import android.app.Activity;  
  10. import android.os.Bundle;  
  11. import android.os.Environment;  
  12. import android.os.Handler;  
  13. import android.os.Message;  
  14. import android.view.View;  
  15. import android.widget.Toast;  
  16.   
  17. /** 
  18.  * 經過httpClient批量上傳文件 
  19.  * @author jph 
  20.  * Date:2014.10.09   
  21.  */  
  22. public class MainActivity extends Activity {  
  23.     private ArrayList<File>files;  
  24.     private Map<String, String>params;  
  25.     Handler mHandler=new Handler(){  
  26.         @Override  
  27.         public void handleMessage(Message msg) {  
  28.             // TODO Auto-generated method stub  
  29.             switch (msg.what) {  
  30.             case UploadService.UPLOAD_SUCCESS:  
  31.                 Toast.makeText(MainActivity.this, "上傳成功", Toast.LENGTH_LONG).show();  
  32.                 break;            
  33.             }  
  34.             super.handleMessage(msg);  
  35.         }         
  36.     };  
  37.     @Override  
  38.     protected void onCreate(Bundle savedInstanceState) {  
  39.         super.onCreate(savedInstanceState);  
  40.         setContentView(R.layout.activity_main);       
  41.         files=new ArrayList<File>();  
  42.         params=new HashMap<String, String>();  
  43.           
  44.     }  
  45.     public void upload(View v) {  
  46.         files.clear();  
  47.         params.clear();  
  48.         File file=new File(Environment.getExternalStorageDirectory(),"kaola.jpg");  
  49.         File file2=new File(Environment.getExternalStorageDirectory(),"test.docx");  
  50.         File file3=new File(Environment.getExternalStorageDirectory(),"test.jpg");  
  51.         files.add(file);  
  52.         files.add(file2);  
  53.         files.add(file3);  
  54.         StringBuffer sbFileTypes=new StringBuffer();  
  55.         for (File tempFile:files) {  
  56.             String fileName=tempFile.getName();  
  57.             sbFileTypes.append(getFileType(fileName));            
  58.         }  
  59.         params.put("fileTypes",sbFileTypes.toString());  
  60.         params.put("method", "upload");  
  61.         UploadService uploadService=new UploadService(mHandler);  
  62.         uploadService.uploadFileToServer(params, files);  
  63.     }  
  64.     /** 
  65.      * 獲取文件的類型 
  66.      * @param fileName :文件名 
  67.      * @return 文件類型 
  68.      */  
  69.     private String getFileType(String fileName) {  
  70.         // TODO Auto-generated method stub  
  71.         return fileName.substring(fileName.lastIndexOf("."), fileName.length());  
  72.     }  
  73. }  
UploadService.java
[java]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. package com.jph.ufh.service;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.util.ArrayList;  
  6. import java.util.Map;  
  7. import org.apache.http.HttpEntity;  
  8. import org.apache.http.HttpResponse;  
  9. import org.apache.http.client.ClientProtocolException;  
  10. import org.apache.http.client.HttpClient;  
  11. import org.apache.http.client.methods.HttpPost;  
  12. import org.apache.http.entity.mime.HttpMultipartMode;  
  13. import org.apache.http.entity.mime.MultipartEntityBuilder;  
  14. import org.apache.http.impl.client.DefaultHttpClient;  
  15.   
  16. import android.os.Handler;  
  17.    
  18. /** 
  19.  * 採用HttpClient上傳文件,支持多文件上傳 
  20.  * @author jph 
  21.  * Date:2014.10.09 
  22.  */  
  23. public class UploadService {  
  24.     private static String url="http://10.219.57.16:8080/ServerForUpload/ServletForUpload";  
  25. //  private static String url="http://10.110.6.58:8080/ServerForUpload/ServletForUpload";  
  26.     public static final int UPLOAD_SUCCESS=0x123;  
  27.     public static final int UPLOAD_FAIL=0x124;  
  28.     private Handler handler;  
  29.     public UploadService(Handler handler) {  
  30.         // TODO Auto-generated constructor stub  
  31.         this.handler=handler;  
  32.     }     
  33.     /** 
  34.      * @param params 請求參數,包括請求的的方法參數method如:「upload」, 
  35.      * 請求上傳的文件類型fileTypes如:「.jpg.png.docx」 
  36.      * @param files 要上傳的文件集合 
  37.      */  
  38.     public void uploadFileToServer(final Map<String, String> params, final ArrayList<File>files) {  
  39.         // TODO Auto-generated method stub    
  40.         new Thread(new Runnable() {           
  41.             @Override  
  42.             public void run() {  
  43.                 // TODO Auto-generated method stub  
  44.                 try {  
  45.                      if (uploadFiles(url,params,files)) {  
  46.                         handler.sendEmptyMessage(UPLOAD_SUCCESS);//通知主線程數據發送成功  
  47.                     }else {  
  48.                         //將數據發送給服務器失敗  
  49.                     }  
  50.                 } catch (Exception e) {  
  51.                     // TODO Auto-generated catch block  
  52.                     e.printStackTrace();  
  53.                 }                 
  54.             }  
  55.         }).start();  
  56.     }  
  57.     /** 
  58.      * @param url servlet的地址 
  59.      * @param params 要傳遞的參數 
  60.      * @param files 要上傳的文件 
  61.      * @return true if upload success else false 
  62.      * @throws ClientProtocolException 
  63.      * @throws IOException 
  64.      */  
  65.     private boolean uploadFiles(String url,Map<String, String>params,ArrayList<File>files) throws ClientProtocolException, IOException {  
  66.         HttpClient client=new DefaultHttpClient();// 開啓一個客戶端 HTTP 請求   
  67.         HttpPost post = new HttpPost(url);//建立 HTTP POST 請求    
  68.         MultipartEntityBuilder builder = MultipartEntityBuilder.create();  
  69. //      builder.setCharset(Charset.forName("uft-8"));//設置請求的編碼格式  
  70.         builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);//設置瀏覽器兼容模式  
  71.         int count=0;  
  72.         for (File file:files) {  
  73. //          FileBody fileBody = new FileBody(file);//把文件轉換成流對象FileBody  
  74. //          builder.addPart("file"+count, fileBody);  
  75.             builder.addBinaryBody("file"+count, file);  
  76.             count++;  
  77.         }         
  78.         builder.addTextBody("method", params.get("method"));//設置請求參數  
  79.         builder.addTextBody("fileTypes", params.get("fileTypes"));//設置請求參數  
  80.         HttpEntity entity = builder.build();// 生成 HTTP POST 實體        
  81.         post.setEntity(entity);//設置請求參數  
  82.         HttpResponse response = client.execute(post);// 發起請求 並返回請求的響應  
  83.         if (response.getStatusLine().getStatusCode()==200) {  
  84.             return true;  
  85.         }  
  86.         return false;         
  87.     }  
  88. }  

轉載於: :http://blog.csdn.net/fengyuzhengfan/article/details/39941851

 

如下待研究:http://blog.csdn.net/zhouzme/article/details/18940279htp://my.oschina.net/weichou/blog/352753

        

        http://topmanopensource.iteye.com/blog/1605238(使用HttpurlConnection上傳文件)

相關文章
相關標籤/搜索