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 ...
随机推荐
- 两张图解读Java异常与断言
两张图解读Java异常与断言 --转载请注明出处:coder-pig 本节引言: 前天公布的"七张图解析Java多线程&quo ...
- ABAP 常用FUNCTION集锦(转)
此文章从网上抄摘,目的用于自己记录 DYNP_VALUES_READ – 读取SCREEN字段的值,也可以用来读取报表SELECTION SCREEN. DYNP_VALUES_UPDATE – 更新 ...
- Delphi的DLL里如何实现定时器功能?
一,首先引入“mmsystem”单元. 二,启动定时器: var MMTimerID: Integer; // 定时器ID MMTimerID := timeSetEvent(1000, 0, @Ti ...
- 我觉得主要靠积累,难度不是问题,主要靠时间积累,以及兴趣带来的学习能力(我觉得至少5年全职Qt开发经验,才能算精通)
顺便想请教一下,你用QT有几年了? 3年不到 那感觉怎么样?是比较难,还是不难但需要时间才能掌握全部? 很多东西真的要拿来做项目了,才会懂.要靠积累.一开始看看理论貌似都很简单. 但是QT和C++本身 ...
- vc2010下使用64位控件
最近把我的控件(ST_Curve www.st-curve.cn)升级到了64位,2010编译,本来以为很简单的问题,结果折腾了两天(也有可能我多年没做过界面和vc相关的东西了吧),于是把我遇到的问题 ...
- Android四大组件--Broadcast Receiver具体解释
本文主要讲述了: 一.BroadcastReceiver概述: 二.BroadcastReceiver事件分类 三.BroadcastReceiver事件的编程流程 四.两类BroadcastRece ...
- [Android学习笔记]try-catch
private boolean test() { boolean result = true; String str = null; try { Log.d("test",&quo ...
- centos7 opera济览器安装
网网下rpm安装包: http://www.opera.com/computer/thanks?partner=www&par=id%3D39136%26amp;location%3D403& ...
- 文顶顶 iOS开发UI篇—UITabBarController简单介绍 iOS开发UI篇—UITabBarController简单介绍
一.简单介绍 UITabBarController和UINavigationController类似,UITabBarController也可以轻松地管理多个控制器,轻松完成控制器之间的切换,典型的例 ...
- [C#基础] 委托
什么是委托 委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有 ...