HttpClient使用MultipartEntityBuilder實現多文件上傳

1、MultipartEntityBuilder 實現文件上傳步驟  

 在HttpCient4.3以後上傳文件主要使用的類是位於org.apache.http.entity.mime下的MultipartEntityBuilder(原先的MultipartEntity已經基本棄用了)基本實現步驟以下: php

  1.設置上傳的模式;java

  setMode(HttpMultipartMode mode),其中mode主要有BROWSER_COMPATIBLE,RFC6532,STRICT三種,默認值是STRICT。android

  2.建立MultipartEntityBuilder對象,並添加須要上傳的數據;apache

  a.利用MultipartEntityBuilder.create()來建立對象;json

  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)app

  c.addTextBody:添加文本數據ide

  addTextBody(String name, String text, ContentType contentType)

  d.addPart:以Key/Value的形式添加ContentBody類型的數據

  addPart(String name, ContentBody contentBody)

  測試中選用了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。

2、MultipartEntityBuilder類介紹

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

修飾符和類型

方法和描述

MultipartEntityBuilder

addBinaryBody(String name, byte[] b) 

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

MultipartEntityBuilder

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

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

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包中已經提供了StringFile以及InputStream對應的ContentBody類型的子類,如FileBody、InputStreamBody、StringBody,經過這些類咱們能夠將String、File以及InputStream類型的數據轉換成ContentBody類型的數據。

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


3、.經過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》須要的朋友能夠去下載。

3.1 Android端項目核心代碼:

 

 
  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. builder.addBinaryBody("file"+count, file);

  9. count++;

  10. }

  11. builder.addTextBody("method", params.get("method"));//設置請求參數

  12. builder.addTextBody("fileTypes", params.get("fileTypes"));//設置請求參數

  13. HttpEntity entity = builder.build();// 生成 HTTP POST 實體

  14. post.setEntity(entity);//設置請求參數

  15. HttpResponse response = client.execute(post);// 發起請求 並返回請求的響應

  16. if (response.getStatusLine().getStatusCode()==200) {

  17. return true;

  18. }

  19. return false;

代碼分析: 

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

3.2 服務器端項目核心代碼:

       服務器端能夠經過獲取名爲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()//獲取上傳文件的大小單位爲字節。

 

 
  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都是些參數,而不是要保存的文件了。

3.3 程序運行效果圖:

Android使用HttpClient上傳數據


4、項目代碼

MainActivity.java

 
  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. }

  74.  


 

UploadService.java

 
  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. builder.addBinaryBody("file"+count, file);

  74. count++;

  75. }

  76. builder.addTextBody("method", params.get("method"));//設置請求參數

  77. builder.addTextBody("fileTypes", params.get("fileTypes"));//設置請求參數

  78. HttpEntity entity = builder.build();// 生成 HTTP POST 實體

  79. post.setEntity(entity);//設置請求參數

  80. HttpResponse response = client.execute(post);// 發起請求 並返回請求的響應

  81. if (response.getStatusLine().getStatusCode()==200) {

  82. return true;

  83. }

  84. return false;

  85. }

 

 

public static boolean codeLogin(String telNum,String vcode) throws Exception{
		String postUrl = "https://";
		HttpClient httpClient = HttpClients.createDefault();
		MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
		multipartEntityBuilder.setContentType(ContentType.DEFAULT_BINARY);
		
		multipartEntityBuilder.setBoundary("3ArYfORhtTPEefj3q2f");
		multipartEntityBuilder
		       .addTextBody("cmversion", "")
		       .addTextBody("vcode", vcode);
		       
		HttpPost httpPost = new HttpPost(postUrl);
		
		httpPost.setHeader("User-Agent", "aaa");
		
		httpPost.setHeader("Accept-Language", "zh_CN");
	
		httpPost.setEntity(multipartEntityBuilder.build());
		
		for(Header header:httpPost.getAllHeaders()) {
			System.out.println(header.getName()+"="+header.getValue());
		}
		ByteArrayOutputStream out = new ByteArrayOutputStream((int) httpPost.getEntity().getContentLength());
		// write content to stream
		httpPost.getEntity().writeTo(out);
		// either convert stream to string
		String string = out.toString();
		
		System.out.println(string);
		
		org.apache.http.HttpResponse httpResponse = httpClient.execute(httpPost);
		HttpEntity httpEntity =  httpResponse.getEntity();
		String content = EntityUtils.toString(httpEntity);
		System.out.println(content);
		JSONObject jsonObject = JSONObject.parseObject(content);
		
		String ret = jsonObject.getString("msg");		
		if("1".equals(ret)) {
			return true;
		}

		return false;
	}
相關文章
相關標籤/搜索