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 ...
随机推荐
- Android中View绘制优化之一---- 优化布局层次
本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning 前言,竟然是翻译,当然得弄的有板有眼. 照着大作家格式来咯 , - - . 译序 最近一直在做锁屏界面,之前也 ...
- JQuery - 留言之后,不重新加载数据,直接显示发表内容
留言板中,发表信息的时候,使用Ajax存储到后台数据库,如果存储成功,不重新加载数据库,直接显示发表内容. 代码: var Nicehng = ''; var kkimgpath = ''; var ...
- 14.8.1 Enabling File Formats
14.8 InnoDB File-Format Management 14.8.1 Enabling File Formats 14.8.2 Verifying File Format Compati ...
- Delphi图像处理 -- 最小值
阅读提示: <Delphi图像处理>系列以效率为侧重点,一般代码为PASCAL,核心代码采用BASM. <C++图像处理>系列以代码清晰,可读性为主,全部使用C ...
- “新浪UC”的后江湖时代------易名新浪SHOW重出江湖
说到新浪UC,相信很多老网民应该并不陌生,当年QQ放号收费让新浪UC火爆了好一阵子,而随着QQ的崛起,UC也就渐渐退出了即时通信市场,不过,这并不意味着新浪UC退出了历史舞台,因为目前炙手可热 ...
- Lucene.Net 2.3.1开发介绍 —— 简介
原文:Lucene.Net 2.3.1开发介绍 -- 简介 Lucene.Net是Lucene在dot net平台上的移植版本.它的功能与Lucene一样,都是用来提供一组API,让我们能快速开发自己 ...
- windows下RabbitMQ 监控
RabbitMQ的监控很简单,网上也有很多资料,但是大都不详细,让人云里雾里,我这里详细总结下. RabbitMQ本身提供了一个web的监控页面,只需要简单的几部命令行就可以访问这个页面了. 1.打开 ...
- thinkphp模版调用函数方法
原文:thinkphp模版调用函数方法 {变量|函数1|函数2|函数3=参数1,参数2,参数3,###} ###为第4个参数,代表变量替换为第4个参数 举例: {$username|substr=0, ...
- spice for openstack
nova.conf vnc_enabled=False [Spice] agent_enabled=True enabled=True html5proxy_base_url=http://x.x.x ...
- ThinkPHP 3.2 开发过程
原文:ThinkPHP 3.2 开发过程 设置所有项目的公共配置Application\Common\Conf\config.php,SAE模式下配置文件为config_sae.php 配置默认的模块 ...