HttpMime 处理 多部件 POST 请求
HttpMime 处理 多部件 POST 请求
在有的场合例如我们要用到上传文件的时候,就不能使用基本的GET请求和POST 请求了,我们要使用多部件的POST请求。由于Android 附带的 HttpClient 版本暂不支持多部件 POST 请求,所以我们需要用到一个 HttpMime 开源项目,该组件是专门处理与 MIME 类型有关的操作。因为 HttpMime 是包含在 HttpComponents 项目中的,所以我们需要去 apache 官方网站下载 HttpComponents,然后把其中的HttpMime.jar 包放到项目中去。

1 package com.scott.http;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.InputStream;
5
6 import org.apache.http.HttpResponse;
7 import org.apache.http.HttpStatus;
8 import org.apache.http.client.HttpClient;
9 import org.apache.http.client.methods.HttpGet;
10
11 import android.app.Activity;
12 import android.os.Bundle;
13 import android.view.View;
14 import android.widget.Button;
15 import android.widget.Toast;
16
17 public class HttpActivity extends Activity {
18 @Override
19 protected void onCreate(Bundle savedInstanceState) {
20 super.onCreate(savedInstanceState);
21 setContentView(R.layout.main);
22 Button btn = (Button) findViewById(R.id.btn);
23 btn.setOnClickListener(new View.OnClickListener() {
24 @Override
25 public void onClick(View v) {
26 execute();
27 }
28 });
29
30 }
31
32 private void execute() {
33 try {
34 MyApplication app = (MyApplication) this.getApplication(); //获取MyApplication实例
35 HttpClient client = app.getHttpClient(); //获取HttpClient实例
36 HttpGet get = new HttpGet("http://192.168.1.57:8080/web/TestServlet?id=1001&name=john&age=60");
37 HttpResponse response = client.execute(get);
38 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
39 InputStream is = response.getEntity().getContent();
40 String result = inStream2String(is);
41 Toast.makeText(this, result, Toast.LENGTH_LONG).show();
42 }
43 } catch (Exception e) {
44 e.printStackTrace();
45 }
46 }
47
48 //将输入流转换成字符串
49 private String inStream2String(InputStream is) throws Exception {
50 ByteArrayOutputStream baos = new ByteArrayOutputStream();
51 byte[] buf = new byte[1024];
52 int len = -1;
53 while ((len = is.read(buf)) != -1) {
54 baos.write(buf, 0, len);
55 }
56 return new String(baos.toByteArray());
57 }
58 }

在实际应用中,我们不能每次都新建 HttpClient,而是应该只为整个应用创建一个HttpClient,并将其用于所有 HTTP 通信。此外,还应该注意在通过一个 HttpClient 同时发出多个请求时可能发生的多线程问题。针对这两个问题,我们需要改进一下我们的项目:
1、扩展系统默认的 Application,并应用在项目中。
2、使用 HttpClient 类库提供的 ThreadSafeClientManager 来创建和管理 HttpClient。

1 package com.scott.http;
2
3 import org.apache.http.HttpVersion;
4 import org.apache.http.client.HttpClient;
5 import org.apache.http.conn.ClientConnectionManager;
6 import org.apache.http.conn.scheme.PlainSocketFactory;
7 import org.apache.http.conn.scheme.Scheme;
8 import org.apache.http.conn.scheme.SchemeRegistry;
9 import org.apache.http.conn.ssl.SSLSocketFactory;
10 import org.apache.http.impl.client.DefaultHttpClient;
11 import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
12 import org.apache.http.params.BasicHttpParams;
13 import org.apache.http.params.HttpParams;
14 import org.apache.http.params.HttpProtocolParams;
15 import org.apache.http.protocol.HTTP;
16
17 import android.app.Application;
18
19 public class MyApplication extends Application {
20
21 private HttpClient httpClient;
22
23 @Override
24 public void onCreate() {
25 super.onCreate();
26 httpClient = this.createHttpClient();
27 }
28
29 @Override
30 public void onLowMemory() {
31 super.onLowMemory();
32 this.shutdownHttpClient();
33 }
34
35 @Override
36 public void onTerminate() {
37 super.onTerminate();
38 this.shutdownHttpClient();
39 }
40
41 //创建HttpClient实例
42 private HttpClient createHttpClient() {
43 HttpParams params = new BasicHttpParams();
44 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
45 HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
46 HttpProtocolParams.setUseExpectContinue(params, true);
47
48 SchemeRegistry schReg = new SchemeRegistry();
49 schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
50 schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
51
52 ClientConnectionManager connMgr = new ThreadSafeClientConnManager(params, schReg);
53
54 return new DefaultHttpClient(connMgr, params);
55 }
56
57 //关闭连接管理器并释放资源
58 private void shutdownHttpClient() {
59 if (httpClient != null && httpClient.getConnectionManager() != null) {
60 httpClient.getConnectionManager().shutdown();
61 }
62 }
63
64 //对外提供HttpClient实例
65 public HttpClient getHttpClient() {
66 return httpClient;
67 }
68 }

在 testUpload 测试用例,我们用 HttpMime 提供的 InputStreamBody 处理文件流参数,用 StringBody 处理普通文本参数,最后把所有类型参数都加入到一个 MultipartEntity 的实例中,并将这个 multipartEntity 设置为此次 POST 请求的参数实体,然后执行 POST请求。

1 package com.scot.http.test;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.InputStream;
5 import java.util.ArrayList;
6 import java.util.List;
7
8 import junit.framework.Assert;
9
10 import org.apache.http.HttpEntity;
11 import org.apache.http.HttpResponse;
12 import org.apache.http.HttpStatus;
13 import org.apache.http.NameValuePair;
14 import org.apache.http.client.HttpClient;
15 import org.apache.http.client.entity.UrlEncodedFormEntity;
16 import org.apache.http.client.methods.HttpGet;
17 import org.apache.http.client.methods.HttpPost;
18 import org.apache.http.entity.mime.MultipartEntity;
19 import org.apache.http.entity.mime.content.InputStreamBody;
20 import org.apache.http.entity.mime.content.StringBody;
21 import org.apache.http.impl.client.DefaultHttpClient;
22 import org.apache.http.message.BasicNameValuePair;
23
24 import android.test.AndroidTestCase;
25
26 public class HttpTest extends AndroidTestCase {
27
28 private static final String PATH = "http://192.168.1.57:8080/web";
29
30 public void testGet() throws Exception {
31 HttpClient client = new DefaultHttpClient();
32 HttpGet get = new HttpGet(PATH + "/TestServlet?id=1001&name=john&age=60");
33 HttpResponse response = client.execute(get);
34 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
35 InputStream is = response.getEntity().getContent();
36 String result = inStream2String(is);
37 Assert.assertEquals(result, "GET_SUCCESS");
38 }
39 }
40
41 public void testPost() throws Exception {
42 HttpClient client = new DefaultHttpClient();
43 HttpPost post = new HttpPost(PATH + "/TestServlet");
44 List<NameValuePair> params = new ArrayList<NameValuePair>();
45 params.add(new BasicNameValuePair("id", "1001"));
46 params.add(new BasicNameValuePair("name", "john"));
47 params.add(new BasicNameValuePair("age", "60"));
48 HttpEntity formEntity = new UrlEncodedFormEntity(params);
49 post.setEntity(formEntity);
50 HttpResponse response = client.execute(post);
51 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
52 InputStream is = response.getEntity().getContent();
53 String result = inStream2String(is);
54 Assert.assertEquals(result, "POST_SUCCESS");
55 }
56 }
57
58 public void testUpload() throws Exception {
59 InputStream is = getContext().getAssets().open("books.xml");
60 HttpClient client = new DefaultHttpClient();
61 HttpPost post = new HttpPost(PATH + "/UploadServlet");
62 InputStreamBody isb = new InputStreamBody(is, "books.xml");
63 MultipartEntity multipartEntity = new MultipartEntity();
64 multipartEntity.addPart("file", isb);
65 multipartEntity.addPart("desc", new StringBody("this is description."));
66 post.setEntity(multipartEntity);
67 HttpResponse response = client.execute(post);
68 if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
69 is = response.getEntity().getContent();
70 String result = inStream2String(is);
71 Assert.assertEquals(result, "UPLOAD_SUCCESS");
72 }
73 }
74
75 //将输入流转换成字符串
76 private String inStream2String(InputStream is) throws Exception {
77 ByteArrayOutputStream baos = new ByteArrayOutputStream();
78 byte[] buf = new byte[1024];
79 int len = -1;
80 while ((len = is.read(buf)) != -1) {
81 baos.write(buf, 0, len);
82 }
83 return new String(baos.toByteArray());
84 }
85 }

服务端 Servlet 使用 apache 开源项目 FileUpload 进行处理,所以需要 commons-fileupload 和 commons-io 这两个项目的 jar 包。

1 package com.scott.web.servlet;
2
3 import java.io.FileOutputStream;
4 import java.io.IOException;
5 import java.util.Iterator;
6 import java.util.List;
7
8 import javax.servlet.ServletException;
9 import javax.servlet.http.HttpServlet;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletResponse;
12
13 import org.apache.commons.fileupload.FileItem;
14 import org.apache.commons.fileupload.FileItemFactory;
15 import org.apache.commons.fileupload.FileUploadException;
16 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
17 import org.apache.commons.fileupload.servlet.ServletFileUpload;
18
19 @SuppressWarnings("serial")
20 public class UploadServlet extends HttpServlet {
21
22 @Override
23 @SuppressWarnings("rawtypes")
24 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
25 boolean isMultipart = ServletFileUpload.isMultipartContent(request);
26 if (isMultipart) {
27 FileItemFactory factory = new DiskFileItemFactory();
28 ServletFileUpload upload = new ServletFileUpload(factory);
29 try {
30 List items = upload.parseRequest(request);
31 Iterator iter = items.iterator();
32 while (iter.hasNext()) {
33 FileItem item = (FileItem) iter.next();
34 if (item.isFormField()) {
35 //普通文本信息处理
36 String paramName = item.getFieldName();
37 String paramValue = item.getString();
38 System.out.println(paramName + ":" + paramValue);
39 } else {
40 //上传文件信息处理
41 String fileName = item.getName();
42 byte[] data = item.get();
43 String filePath = getServletContext().getRealPath("/files") + "/" + fileName;
44 FileOutputStream fos = new FileOutputStream(filePath);
45 fos.write(data);
46 fos.close();
47 }
48 }
49 } catch (FileUploadException e) {
50 e.printStackTrace();
51 }
52 }
53 response.getWriter().write("UPLOAD_SUCCESS");
54 }
55 }

HttpMime 处理 多部件 POST 请求的更多相关文章
- Android中使用HTTP服务
在Android中,除了使用java.net包下的API访问HTTP服务之外,我们还可以换一种途径去完成工作.Android SDK附带了Apache的HttpClient API.Apache Ht ...
- HttpClient 4.5.x 工具类设计与实现
最近,业务需要在java服务端发起http请求,需要实现"GET","POST","PUT"等基本方法.于是想以 "HttpCli ...
- Composite模式
1 意图:将对象组成树形结构,以表示“部分——整体”的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. 2 动机:同意处理图元对象和包含图元的容器对象.Composite通过 ...
- ASP.NET Core重写个人博客站点小结
今天用ASP.NET Core重写了个人博客站点,原来是基于ASP.NET 4.5开发的.重写工作总体很顺利,最后成功发布到Ubunt+Nginx平台上.效果如下: 右边的Header信息里可以看到已 ...
- MEF 编程指南(十二):批量组合
MEF 容器实例并非不可变的.如果目录支持改变(像监控目录变动)或者在运行时添加/移除部件都可能发生改变.以前,你不得不做出改动并且调用 CompositionContainer 上的 Compose ...
- NET Core个人博客
NET Core重写个人博客站点小结 今天用ASP.NET Core重写了个人博客站点,原来是基于ASP.NET 4.5开发的.重写工作总体很顺利,最后成功发布到Ubunt+Nginx平台上.效果如下 ...
- Java解析导入Excel文件后台代码实现
使用MultipartFile上传Excel文件后端代码实现:(springmvc下的spring-webmvc (MultipartFile )上传) 由于POST一个包含文件上传的Form会以mu ...
- Odoo Javascript 参考
本文介绍了odoo javascript框架.从代码行的角度来看,这个框架不是一个大的应用程序,但它是非常通用的,因为它基本上是一个将声明性接口描述转换为活动应用程序的机器,能够与数据库中的每个模型和 ...
- Sentry(v20.12.1) K8S 云原生架构探索,JavaScript Enriching Events(丰富事件信息)
系列 Sentry-Go SDK 中文实践指南 一起来刷 Sentry For Go 官方文档之 Enriching Events Snuba:Sentry 新的搜索基础设施(基于 ClickHous ...
随机推荐
- 怎样将Emoj表情插入mysql5.6数据库__python+mysqldb
废话不多说,相信看到这里的看客已经看过非常多配置文件的设置方法.可是问题还是没有解决.本文就具体记录一下我的解决方法吧. 我的环境:mysql5.6+python2.7.3+MySQLdb1.2.4 ...
- AFNetwork学习(二)——GET/POST请求
为了学习AFNetwork,自己搭建整理了一下AFNetwork向后台发送请求和后台返回json数据的整个处理过程.利用Struts2搭建了一个后台,提供Action并返回json数据 环境:Xcod ...
- p类型最大可定义范围
t7(16) TYPE p DECIMALS 14,
- win32 sdk绘制ListBox控件
1>产生: // HWND CreateLB(HWND parentWnd) { HWND hListBox=0; hListBox = CreateWindow("LISTBOX&q ...
- delpi中的RTTI初试
java中的反射机制使我们能够在运行期间获取运行期类的信息,那么在delphi中有没有这样的功能呢?答案是有,实现这种功能的机制在delphi中叫做RTTI,废话少说,先来一段demo: 1.先定义一 ...
- [置顶] oracle 快速查询数据库各种信息、及转换对应java代码
1 查询表中数据量 select 'select '||''''||t.TABLE_NAME||''''||' as table_name, count(*) from '|| t.TABLE_NAM ...
- 设置静态IP
设定IP $sudo vi/etc/network/interfaces autolo iface lo inet loopback 加入下面内容 autoeth0 iface eth0inet st ...
- 谈谈Ext JS的组件——布局的用法续二
绝对布局(Ext.layout.container.Absolute) 绝对布局让我回忆到了使用Foxpro开发的时候,哪时候的界面布局就是这样.通过设置控件的左上角坐标(x.y)和宽度来进行的,由于 ...
- 将n进制的数组压缩成字符串(0-9 a-z)同一时候解压
比如一个3进制的数组: [1 1 2 2 2 0 0] 用一个字符串表示... 此类题目要明白两点: 1. 打表:用数组下标索引字符.同一时候注意假设从字符相应回数字: int index = (st ...
- dwz框架---(2)表单回调函数
dwz中的表单回调函数大概有下面几种: /** * 普通ajax表单提交 * @param {Object} form * @param {Object} callback * @param {Str ...