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 }
 
                    
                
 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号