Android利用网络编程HttpClient批量上传(一个)

请尊重他人的劳动成果。转载请注明出处:Android网络编程之使用HttpClient批量上传文件


我曾在《Android网络编程之使用HTTP訪问网络资源》一文中介绍过HttpCient的使用,这里就不在累述了,感兴趣的朋友能够去看一下。在这里主要介绍怎样通过HttpClient实现文件上传。


1.预备知识:


          HttpCient4.3之前上传文件主要使用MultipartEntity这个类,但如今这个类已经不在推荐使用了。

随之替代它的类是MultipartEntityBuilder


以下让我们了解一下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() 

         

主要方法说明:

addBinaryBodyaddPartaddTextBody方法用于加入要上传的数据,从上面的表格中能够发现用于加入数据的方法,都是key-value类型。所以在server端我们能够通过request.getPart("keyname")方式获取相应key的数据。也能够通过request.getParts()方式获取client通过以上三种方法提交全部数据。

1.通过addBinaryBody方法直接能够加入FileInputStreambyte[]类型的数据。

2.通过addPart方法仅仅能加入ContentBody类型的数据,在org.apache.http.entity.mime.content包中已经提供了StringFile以及InputStream相应的ContentBody类型的子类。如FileBodyInputStreamBodyStringBody通过这些类我们能够将StringFile以及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端项目核心代码:

HttpClient client=new DefaultHttpClient();// 开启一个客户端 HTTP 请求 
HttpPost post = new HttpPost(url);//创建 HTTP POST 请求  
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
//		builder.setCharset(Charset.forName("uft-8"));//设置请求的编码格式
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);//设置浏览器兼容模式
int count=0;
for (File file:files) {
//			FileBody fileBody = new FileBody(file);//把文件转换成流对象FileBody
//			builder.addPart("file"+count, fileBody);
	builder.addBinaryBody("file"+count, file);
	count++;
}		
builder.addTextBody("method", params.get("method"));//设置请求參数
builder.addTextBody("fileTypes", params.get("fileTypes"));//设置请求參数
HttpEntity entity = builder.build();// 生成 HTTP POST 实体  	
post.setEntity(entity);//设置请求參数
HttpResponse response = client.execute(post);// 发起请求 并返回请求的响应
if (response.getStatusLine().getStatusCode()==200) {
	return true;
}
return false;		

代码分析: 

     上面代码主要实现了多文件上传。为了方便server端保存文件,上面代码设置了名称为fileTypes的參数,fileTypes是由上传的文件类型名拼接成的字符串,如”.jpg.png.docx“

     server端能够通过获取名为fileTypes的參数。然后将其拆分成字符数组,就可以得到要保存文件的类型。


server端项目核心代码:

server段主要用到Servlet3.0API,主要用到的方法有:

1.      request.getParameter("");//获取client通过addTextBody方法加入的String类型的数据。

2.      request.getPart("");//获取client通过addBinaryBodyaddPartaddTextBody方法加入的指定数据,返回Part类型的对象。

3.      request.getParts();//获取client通过addBinaryBodyaddPartaddTextBody方法加入的全部数据,返回Collection<Part>类型的对象。

4.      part.getName();//获取上传文件的名称即上传时指定的key

5.      part.getSize()//获取上传文件的大小单位为字节。

String fileTypes=request.getParameter("fileTypes");//获取client上传的全部文件类型
String[]typeArray=fileTypes.substring(1).split("\.");//将文件类型字符串拆分成String数组
try {
	Iterator<Part>iterator=request.getParts().iterator();
	int count=0;
	while (iterator.hasNext()) {//遍历client上传的全部文件				
		if (count>=typeArray.length)break;//假设超出文件类型数组的大小则跳出循环		
		Part part = (Part) iterator.next();				
//				System.out.println("part.getSize()"+part.getSize());//获取上传文件的大小
//				System.out.println("part.getName()"+part.getName());//获取上传文件的名及加入数据时的key名
		File file=new File("E:\upload\"+count+"."+typeArray[count++]);
		InputStream inputStream=part.getInputStream();
		FileOutputStream fos=new FileOutputStream(file);
		byte[]buffer=new byte[1024];
		int len=0;
		while ((len=inputStream.read(buffer))!=-1) {
			fos.write(buffer,0, len);
		}
		inputStream.close();
		fos.close();					
	}
}catch (Exception e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

代码分析: 

         server端是通过Servlet实现的,通过调用request.getParameter("fileTypes")方法来获取client上传的全部文件类型,然后将文件类型字符串拆分成String数组。通过request.getParts()方法取出client通过addBinaryBodyaddPartaddTextBody上传的全部数据,然后遍历数据集合就可以进行文件的保存。

由于事先和client协定。加入上传文件的顺序在加入请求參数之前,所以能够依据拆分出的文件类型数组的长度推断出client上传文件的个数,因此当上面代码遍历超出了类型数组的长度时程序跳出循环。不再进行文件的保存,由于以下的Part都是些參数,而不是要保存的文件了。


程序执行效果图:


Android使用HttpClient上传数据

3.完毕项目代码:


MainActivity.java
package com.jph.ufh.activity;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import com.jph.ufh.R;
import com.jph.ufh.service.UploadService;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Toast;

/**
 * 通过httpClient批量上传文件
 * @author jph
 * Date:2014.10.09  
 */
public class MainActivity extends Activity {
	private ArrayList<File>files;
	private Map<String, String>params;
	Handler mHandler=new Handler(){
		@Override
		public void handleMessage(Message msg) {
			// TODO Auto-generated method stub
			switch (msg.what) {
			case UploadService.UPLOAD_SUCCESS:
				Toast.makeText(MainActivity.this, "上传成功", Toast.LENGTH_LONG).show();
				break;			
			}
			super.handleMessage(msg);
		}		
	};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);		
		files=new ArrayList<File>();
		params=new HashMap<String, String>();
		
	}
	public void upload(View v) {
		files.clear();
		params.clear();
		File file=new File(Environment.getExternalStorageDirectory(),"kaola.jpg");
		File file2=new File(Environment.getExternalStorageDirectory(),"test.docx");
		File file3=new File(Environment.getExternalStorageDirectory(),"test.jpg");
		files.add(file);
		files.add(file2);
		files.add(file3);
		StringBuffer sbFileTypes=new StringBuffer();
		for (File tempFile:files) {
			String fileName=tempFile.getName();
			sbFileTypes.append(getFileType(fileName));			
		}
		params.put("fileTypes",sbFileTypes.toString());
		params.put("method", "upload");
		UploadService uploadService=new UploadService(mHandler);
		uploadService.uploadFileToServer(params, files);
	}
	/**
	 * 获取文件的类型
	 * @param fileName :文件名称
	 * @return 文件类型
	 */
	private String getFileType(String fileName) {
		// TODO Auto-generated method stub
		return fileName.substring(fileName.lastIndexOf("."), fileName.length());
	}
}
UploadService.java
package com.jph.ufh.service;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.DefaultHttpClient;

import android.os.Handler;
 
/**
 * 採用HttpClient上传文件,支持多文件上传
 * @author jph
 * Date:2014.10.09
 */
public class UploadService {
	private static String url="http://10.219.57.16:8080/ServerForUpload/ServletForUpload";
//	private static String url="http://10.110.6.58:8080/ServerForUpload/ServletForUpload";
	public static final int UPLOAD_SUCCESS=0x123;
	public static final int UPLOAD_FAIL=0x124;
	private Handler handler;
	public UploadService(Handler handler) {
		// TODO Auto-generated constructor stub
		this.handler=handler;
	}	
	/**
	 * @param params 请求參数。包含请求的的方法參数method如:“upload”,
	 * 请求上传的文件类型fileTypes如:“.jpg.png.docx”
	 * @param files 要上传的文件集合
	 */
	public void uploadFileToServer(final Map<String, String> params, final ArrayList<File>files) {
		// TODO Auto-generated method stub	
		new Thread(new Runnable() {			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				try {
					 if (uploadFiles(url,params,files)) {
						handler.sendEmptyMessage(UPLOAD_SUCCESS);//通知主线程数据发送成功
					}else {
						//将数据发送给server失败
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}				
			}
		}).start();
	}
	/**
	 * @param url servlet的地址
	 * @param params 要传递的參数
	 * @param files 要上传的文件
	 * @return true if upload success else false
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	private boolean uploadFiles(String url,Map<String, String>params,ArrayList<File>files) throws ClientProtocolException, IOException {
		HttpClient client=new DefaultHttpClient();// 开启一个客户端 HTTP 请求 
		HttpPost post = new HttpPost(url);//创建 HTTP POST 请求  
		MultipartEntityBuilder builder = MultipartEntityBuilder.create();
//		builder.setCharset(Charset.forName("uft-8"));//设置请求的编码格式
		builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);//设置浏览器兼容模式
		int count=0;
		for (File file:files) {
//			FileBody fileBody = new FileBody(file);//把文件转换成流对象FileBody
//			builder.addPart("file"+count, fileBody);
			builder.addBinaryBody("file"+count, file);
			count++;
		}		
		builder.addTextBody("method", params.get("method"));//设置请求參数
		builder.addTextBody("fileTypes", params.get("fileTypes"));//设置请求參数
		HttpEntity entity = builder.build();// 生成 HTTP POST 实体  	
		post.setEntity(entity);//设置请求參数
		HttpResponse response = client.execute(post);// 发起请求 并返回请求的响应
		if (response.getStatusLine().getStatusCode()==200) {
			return true;
		}
		return false;		
	}
}



版权声明:本文博客原创文章。博客,未经同意,不得转载。

原文地址:https://www.cnblogs.com/yxwkf/p/4643719.html