Android模拟 HTTP multipart/form-data 请求协议信息实现图片上传

来源:互联网 发布:淘宝网一元秒杀在哪里 编辑:程序博客网 时间:2024/05/18 02:41
Android应用中,当遇到填写用户信息、发表评论等操作,不可避免会遇到“form表单操作”(类似web form操作)上传图片的功能。
在这种情况下,使用Android的HTTPConnection/ ApacheHTTP 通过POST 和GET的方式就实现不了。

解决方法:

Android客户端通过模拟 HTTP multipart/form-data 请求协议信息实现图片上传。
  1. /**  
  2. * 文件名称:UploadImage.java  
  3. *  
  4. * 版权信息:Apache License, Version 2.0  
  5. *  
  6. * 功能描述:实现图片文件上传。  
  7. *  
  8. * 创建日期:2011-5-10  
  9. *  
  10. * 作者:Bert Lee  
  11. */   
  12.    
  13. /*  
  14. * 修改历史:  
  15. */   
  16. public class UploadImage {   
  17.     String multipart_form_data = "multipart/form-data";   
  18.     String twoHyphens = "--";   
  19.     String boundary = "****************fD4fH3gL0hK7aI6";    // 数据分隔符   
  20.     String lineEnd = System.getProperty("line.separator");    // The value is "\r\n" in Windows.   
  21.       
  22.     /*  
  23.      * 上传图片内容,格式请参考HTTP 协议格式。  
  24.      * 人人网Photos.upload中的”程序调用“http://wiki.dev.renren.com/wiki/Photos.upload#.E7.A8.8B.E5.BA.8F.E8.B0.83.E7.94.A8  
  25.      * 对其格式解释的非常清晰。  
  26.      * 格式如下所示:  
  27.      * --****************fD4fH3hK7aI6  
  28.      * Content-Disposition: form-data; name="upload_file"; filename="apple.jpg"  
  29.      * Content-Type: image/jpeg  
  30.      *  
  31.      * 这儿是文件的内容,二进制流的形式  
  32.      */   
  33.     private void addImageContent(Image[] files, DataOutputStream output) {   
  34.         for(Image file : files) {   
  35.             StringBuilder split = new StringBuilder();   
  36.             split.append(twoHyphens + boundary + lineEnd);   
  37.             split.append("Content-Disposition: form-data; name=\"" + file.getFormName() + "\"; filename=\"" + file.getFileName() + "\"" + lineEnd);   
  38.             split.append("Content-Type: " + file.getContentType() + lineEnd);   
  39.             split.append(lineEnd);   
  40.             try {   
  41.                 // 发送图片数据   
  42.                 output.writeBytes(split.toString());   
  43.                 output.write(file.getData(), 0, file.getData().length);   
  44.                 output.writeBytes(lineEnd);   
  45.             } catch (IOException e) {   
  46.                 throw new RuntimeException(e);   
  47.             }   
  48.         }   
  49.     }   
  50.       
  51.     /*  
  52.      * 构建表单字段内容,格式请参考HTTP 协议格式(用FireBug可以抓取到相关数据)。(以便上传表单相对应的参数值)  
  53.      * 格式如下所示:  
  54.      * --****************fD4fH3hK7aI6  
  55.      * Content-Disposition: form-data; name="action"  
  56.      * // 一空行,必须有  
  57.      * upload  
  58.      */   
  59.     private void addFormField(Set<Map.Entry<Object,Object>> params, DataOutputStream output) {   
  60.         StringBuilder sb = new StringBuilder();   
  61.         for(Map.Entry<Object, Object> param : params) {   
  62.             sb.append(twoHyphens + boundary + lineEnd);   
  63.             sb.append("Content-Disposition: form-data; name=\"" + param.getKey() + "\"" + lineEnd);   
  64.             sb.append(lineEnd);   
  65.             sb.append(param.getValue() + lineEnd);   
  66.         }   
  67.         try {   
  68.             output.writeBytes(sb.toString());// 发送表单字段数据   
  69.         } catch (IOException e) {   
  70.             throw new RuntimeException(e);   
  71.         }   
  72.     }   
  73.       
  74.     /**  
  75.      * 直接通过 HTTP 协议提交数据到服务器,实现表单提交功能。  
  76.      * @param actionUrl 上传路径  
  77.      * @param params 请求参数key为参数名,value为参数值  
  78.      * @param files 上传文件信息  
  79.      * @return 返回请求结果  
  80.      */   
  81.     public String post(String actionUrl, Set<Map.Entry<Object,Object>> params, Image[] files) {   
  82.         HttpURLConnection conn = null;   
  83.         DataOutputStream output = null;   
  84.         BufferedReader input = null;   
  85.         try {   
  86.             URL url = new URL(actionUrl);   
  87.             conn = (HttpURLConnection) url.openConnection();   
  88.             conn.setConnectTimeout(120000);   
  89.             conn.setDoInput(true);        // 允许输入   
  90.             conn.setDoOutput(true);        // 允许输出   
  91.             conn.setUseCaches(false);    // 不使用Cache   
  92.             conn.setRequestMethod("POST");   
  93.             conn.setRequestProperty("Connection", "keep-alive");   
  94.             conn.setRequestProperty("Content-Type", multipart_form_data + "; boundary=" + boundary);   
  95.                
  96.             conn.connect();   
  97.             output = new DataOutputStream(conn.getOutputStream());   
  98.                
  99.             addImageContent(files, output);    // 添加图片内容   
  100.                
  101.             addFormField(params, output);    // 添加表单字段内容   
  102.                
  103.             output.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);// 数据结束标志   
  104.             output.flush();   
  105.                
  106.             int code = conn.getResponseCode();   
  107.             if(code != 200) {   
  108.                 throw new RuntimeException("请求‘" + actionUrl +"’失败!");   
  109.             }   
  110.                
  111.             input = new BufferedReader(new InputStreamReader(conn.getInputStream()));   
  112.             StringBuilder response = new StringBuilder();   
  113.             String oneLine;   
  114.             while((oneLine = input.readLine()) != null) {   
  115.                 response.append(oneLine + lineEnd);   
  116.             }   
  117.                
  118.             return response.toString();   
  119.         } catch (IOException e) {   
  120.             throw new RuntimeException(e);   
  121.         } finally {   
  122.             // 统一释放资源   
  123.             try {   
  124.                 if(output != null) {   
  125.                     output.close();   
  126.                 }   
  127.                 if(input != null) {   
  128.                     input.close();   
  129.                 }   
  130.             } catch (IOException e) {   
  131.                 throw new RuntimeException(e);   
  132.             }   
  133.                
  134.             if(conn != null) {   
  135.                 conn.disconnect();   
  136.             }   
  137.         }   
  138.     }   
  139.       
  140.     public static void main(String[] args) {   
  141.         try {   
  142.             String response = "";   
  143.                
  144.             BufferedReader in = new BufferedReader(new FileReader("config/actionUrl.properties"));   
  145.             String actionUrl = in.readLine();   
  146.                
  147.             // 读取表单对应的字段名称及其值   
  148.             Properties formDataParams = new Properties();   
  149.             formDataParams.load(new FileInputStream(new File("config/formDataParams.properties")));   
  150.             Set<Map.Entry<Object,Object>> params = formDataParams.entrySet();   
  151.                
  152.             // 读取图片所对应的表单字段名称及图片路径   
  153.             Properties imageParams = new Properties();   
  154.             imageParams.load(new FileInputStream(new File("config/imageParams.properties")));   
  155.             Set<Map.Entry<Object,Object>> images = imageParams.entrySet();   
  156.             Image[] files = new Image[images.size()];   
  157.             int i = 0;   
  158.             for(Map.Entry<Object,Object> image : images) {   
  159.                 Image file = new Image(image.getValue().toString(), image.getKey().toString());   
  160.                 files[i++] = file;   
  161.             }   
  162. //            Image file = new Image("images/apple.jpg", "upload_file");   
  163. //            Image[] files = new Image[0];   
  164. //            files[0] = file;   
  165.                
  166.             response = new UploadImage().post(actionUrl, params, files);   
  167.             System.out.println("返回结果:" + response);   
  168.         } catch (IOException e) {   
  169.             e.printStackTrace();   
  170.         }   
  171.     }   
  172. }
复制代码