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平台二维码之生成,扫描 &; 识别
1.二维码的前世今生 “二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的:在代码编制上巧妙地利 ...
-
MySQL之count(*)与count(id)效率比较(转)
优化总结: 1.任何情况下SELECT COUNT(*) FROM tablename是最优选择: 2.尽量减少SELECT COUNT(*) FROM tablename WHERE COL = ’ ...
-
线程join
class ThreadB extends Thread { private String ID="0"; private int time=0; pu ...
-
Linux的nginx环境的vue 部署
1.使用WebStrom编程好的vue 进入到Terminal运行npm run build 2.使用WinSCP进入到nginx 目录配置文件下面,找到nginx.conf文件: ...
-
Solr 06 - Solr中配置使用IK分词器 (配置schema.xml)
目录 1 配置中文分词器 1.1 准备IK中文分词器 1.2 配置schema.xml文件 1.3 重启Tomcat并测试 2 配置业务域 2.1 准备商品数据 2.2 配置商品业务域 2.3 配置s ...
-
【Dubbo源码学习】负载均衡算法(2)-轮询算法的实现
@Overrideprotected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL ur ...
-
JavaWeb基础【1】—— Tomcat
此笔记是学习黑马程序员JavaWeb系列视频的课堂笔记. 感谢黑马程序员. 一.Tomcat概述 Tomcat服务器由Apache提供,开源免费.由于Sun和其他公司参与到了Tomcat的开发中,所以 ...
-
controller,service,repository,component注解的使用对比
项目中的controller层使用@controller注解 @Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象.分发处理器将会扫描使用了 ...
-
SQLServer导入大sql文件报错 对 COM 组件的调用返回了错误 HRESULT E_FAIL。 (mscorlib)
打开cmd执行(d:\script.sql为sql文件位置): sqlcmd -S 127.0.0.1 -U sa -P sa -i d:\script.sql From:https://ww ...
-
HDU 1258 Sum It Up(dfs 巧妙去重)
传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1258 Sum It Up Time Limit: 2000/1000 MS (Java/Others) ...