• Android网络编程—同时上传参数和文件到服务器 [转载]


    转自http://blog.csdn.net/carterjin/article/details/7571915

    的三种方法为:

    第一种:形如 "http://host:port/xxx/xxx/xxx/param?param1=xxx&param2=xxx"的形式

    Params:

          param1

          param2

    Data:

          file:要上传的文件

    第二种:形如“http://host:port/xxx/xxx/xxx”的形式

    Part1:

          param1

    Part2:

          param2

    Part3:

          file:要上传的文件

    第三种:形如“http://host:port/xxx/xxx/xxx”的形式

    Part1:

          param1

    Part2:

          param2

    Part3:

          file:要上传的文件

    利用Socket方法来发送

    三种方法,首先搞得我头晕脑胀,纠结了整整一天,后来终于理顺了一些,现在把这些方法陈列出来,大家来批评指正,有不对的地方及时通知我来进行修改,大家共勉。

    第一种和第二种都是模拟HTTP协议来发送的,使用HttpURLConnection类来发送,第三种使用Socket方法来发送。

    首先我定义了一个上传工具类:UploadUtil.java,里面只是定义了一个Static的服务器地址,INTERNAL_HOST。

    代码如下

    [java] view plaincopy
     
    1. public class UploadUtil {  
    2.       
    3.     static String INTERNAL_HOST = "http://host:port/xxx/xxx/xxx/upload/";  
    4.       
    5. }  


    这个主机是在第一种方法的地址中,位于“param?”前面的部分。

    完成第一种方法:

    第一种方法的“http://host:port/xxx/xxx/xxx/param?param1=xxx&param2=xxx”,其实已经给出了POST的参数,param1和param2,我为了弄着方便,就直接写死了参数键值。其实也可以在方法内部,通过传入的参数,进行循环拼装,最后只要能组出类似“http://host:port/xxx/xxx/xxx/param?param1=xxx&param2=xxx”的字符串就行,最后通过URL来生成一个url对象即可。

    [java] view plaincopy
     
    1. public static void queryParam(String fileName)  
    2.     {  
    3.         String BOUNDARY = "---------------------------7db1c523809b2";//数据分割线  
    4.         File file = new File(fileName);   // 要上传的文件  
    5.         String host = INTERNAL_HOST + "param?param1=xxx¶m2=xxx"; // 这个字符串就是要上传的带参数的服务器地址  
    6.           
    7.           
    8.         try   
    9.         {  
    10.             byte[] after = ("--" + BOUNDARY + "-- ").getBytes("UTF-8");  
    11.               
    12.             // 构造URL和Connection  
    13.             URL url = new URL(host);              
    14.             HttpURLConnection conn = (HttpURLConnection)url.openConnection();  
    15.               
    16.             // 设置HTTP协议的头属性  
    17.             conn.setRequestMethod("POST");  
    18.             conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);  
    19.             conn.setRequestProperty("Content-Length", String.valueOf(file.length()));  
    20.             conn.setRequestProperty("HOST", url.getHost());  
    21.             conn.setDoOutput(true);  
    22.               
    23.             // 得到Connection的OutputStream流,准备写数据  
    24.             OutputStream out = conn.getOutputStream();  
    25.             InputStream in = new FileInputStream(file);  
    26.               
    27.               
    28.             // 写文件数据。因为服务器地址已经带有参数了,所以这里只要直接写入文件部分就可以了。  
    29.             byte[] buf = new byte[1024];  
    30.             int len;  
    31.             while ((len = in.read(buf)) != -1)  
    32.             {  
    33.                 out.write(buf, 0, len);  
    34.             }               
    35.   
    36.             // 数据结束标志,整个HTTP报文就构造结束了。  
    37.             //out.write(after);  
    38.   
    39.             in.close();  
    40.             out.close();  
    41.               
    42.             Log.d("carter", "queryParam 返回码为: " + conn.getResponseCode());  
    43.             Log.d("carter", "queryParam 返回信息为: " + conn.getResponseMessage());  
    44.               
    45.         }  
    46.         catch (MalformedURLException e) {  
    47.             // TODO Auto-generated catch block  
    48.             e.printStackTrace();  
    49.         } catch (IOException e) {  
    50.             // TODO Auto-generated catch block  
    51.             e.printStackTrace();  
    52.         }  
    53.     }  

    大概的步骤:

    1.先构造好URL服务器地址

    2.初始化一个URL对象,得到里面的HttpURLConnection对象

    3.设置connection对象的头部信息,包括POST方法、HOST、Content-Type、Content-Length等属性

    4.写入要上传的文件内容

    完成第二种方法:

    第二种的方法,不想第一种方法那样简单,但基本语法结构都相似,因为都是模仿HTTP协议的形式。

    第二种方法,在服务器地址上,只提供了上传的HOST和PATH,具体的参数没有提供,所以要通过在HTTP报文中添加来实现。

    [java] view plaincopy
     
    1. public static void multiPart(String fileName)  
    2.     {  
    3.         String BOUNDARY = "---------------------------7db1c523809b2";//数据分割线  
    4.         File file = new File(fileName);   // 要上传的文件  
    5.           
    6.         // 构造param参数部分的数据内容,格式都是相同的,依次添加param1和param2  
    7.         StringBuilder sb = new StringBuilder();  
    8.         sb.append("--" + BOUNDARY + " ");  
    9.         sb.append("Content-Disposition: form-data; name="param1"" + " ");  
    10.         sb.append(" ");  
    11.         sb.append("xxx" + " ");  
    12.   
    13.         sb.append("--" + BOUNDARY + " ");  
    14.         sb.append("Content-Disposition: form-data; name="param2"" + " ");  
    15.         sb.append(" ");  
    16.         sb.append("xxx" + " ");  
    17.   
    18.                 // 构造要上传文件的前段参数内容,和普通参数一样,在这些设置后就可以紧跟文件内容了。  
    19.         sb.append("--" + BOUNDARY + " ");  
    20.         sb.append("Content-Disposition: form-data; name="data"; filename="" + fileName + """ + " ");  
    21.         sb.append("Content-Type: text/plain" + " ");  
    22.         sb.append(" ");  
    23.           
    24.         try   
    25.         {  
    26.             byte[] before = sb.toString().getBytes("UTF-8");  
    27.             byte[] after = ("--" + BOUNDARY + "-- ").getBytes("UTF-8");  
    28.             URL url = new URL(INTERNAL_HOST);  
    29.               
    30.             // 得到HttpURLConnection对象,设置一些头信息基本属性  
    31.             HttpURLConnection conn = (HttpURLConnection) url.openConnection();  
    32.             conn.setRequestMethod("POST");  
    33.             conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);  
    34.             conn.setRequestProperty("Content-Length", String.valueOf(before.length + file.length() + after.length));  
    35.             conn.setRequestProperty("HOST", url.getHost());  
    36.             conn.setDoOutput(true);  
    37.               
    38.             OutputStream out = conn.getOutputStream();  
    39.             InputStream in = new FileInputStream(file);  
    40.               
    41.             // 写入参数信息  
    42.             out.write(before);  
    43.   
    44.             // 写入文件数据  
    45.             byte[] buf = new byte[1024];  
    46.             int len;  
    47.             while ((len = in.read(buf)) != -1)  
    48.             {  
    49.                 out.write(buf, 0, len);  
    50.             }               
    51.   
    52.             // 写结束符,代表该HTTP组包完毕  
    53.             out.write(after);  
    54.               
    55.             // 发送出去  
    56.             out.flush();  
    57.   
    58.             // 关闭流  
    59.             in.close();  
    60.             out.close();  
    61.               
    62.             Log.d("carter", "multipart 返回码为: " + conn.getResponseCode());  
    63.             Log.d("carter", "multipart 返回信息为: " + conn.getResponseMessage());  
    64.         }  
    65.         catch (MalformedURLException e) {  
    66.             // TODO Auto-generated catch block  
    67.             e.printStackTrace();  
    68.         } catch (UnsupportedEncodingException e) {  
    69.             // TODO Auto-generated catch block  
    70.             e.printStackTrace();  
    71.         } catch (IOException e) {  
    72.             // TODO Auto-generated catch block  
    73.             e.printStackTrace();  
    74.         }  
    75.     }  


    具体步骤为:

    1.分别把param1等参数通过格式组织起来

    2.得到HttpURLConnection对象,设置一些基本头属性,其中的Content-Length是所有param和文件加上尾标志的总长度。

    3.发送outputStream。

    完成第三种方法:

    第三种方法和第二种方法很相似,只是使用了Socket对象,而不是HttpURLConnection方法。

    [java] view plaincopy
     
    1. public static void socket(String fileName)  
    2.   {  
    3.       String BOUNDARY = "---------------------------7db1c523809b2";//数据分割线  
    4.       File file = new File(fileName);   // 要上传的文件  
    5.         
    6.       // 构造参数内容字符串  
    7.       StringBuilder textParam = new StringBuilder();  
    8.       textParam.append("--" + BOUNDARY + " ");  
    9.       textParam.append("Content-Disposition: form-data; name="param1"" + " ");  
    10.       textParam.append(" ");  
    11.       textParam.append("xxx" + " ");  
    12.   
    13.       textParam.append("--" + BOUNDARY + " ");  
    14.       textParam.append("Content-Disposition: form-data; name="param2"" + " ");  
    15.       textParam.append(" ");  
    16.       textParam.append("xxx" + " ");  
    17.         
    18.       // 构造文件内容字符串  
    19.       int fileDataLen = 0;    // 文件内容的长度  
    20.       StringBuilder fileParam = new StringBuilder();  
    21.       fileParam.append("--" + BOUNDARY + " ");  
    22.       fileParam.append("Content-Disposition: form-data;name="data";" + "filename="" + fileName + """ + " ");  
    23.       fileParam.append("Content-Type: text/plain" + " ");  
    24.       fileParam.append(" ");  
    25.         
    26.       // 得到文件内容前的声明信息长度  
    27.       fileDataLen += fileParam.length();  
    28.       // 得到声明信息和文件内容总长度  
    29.       fileDataLen += file.length();  
    30.         
    31.       // HTTP报文数据总长度  
    32.       int totalDataLen = 0;  
    33.         
    34.       try   
    35.       {  
    36.           byte[] textEntity = textParam.toString().getBytes();  
    37.           byte[] after = ("--" + BOUNDARY + "-- ").getBytes();  
    38.           // 得到报文内数据总长度,参数声明信息+文件信息+报文尾标志信息  
    39.           totalDataLen = textEntity.length + fileDataLen + after.length;  
    40.             
    41.           // 得到Socket  
    42.           URL url = new URL(INTERNAL_HOST);              
    43.           Socket socket = new Socket(url.getHost(), 80);  
    44.           socket.setSoTimeout(60000);   // 设置Socket超时时间  
    45.             
    46.           // 得到输出流,靠它去发送报文  
    47.           OutputStream out = socket.getOutputStream();  
    48.             
    49.           // 设置请求方法  
    50.           String requestMethod = "POST " + url.getPath() + " HTTP/1.1 ";  
    51.           out.write(requestMethod.getBytes());  
    52.             
    53.           // 设置接收类型  
    54.           String accept = "Accept: image/gif, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml," +  
    55.                 "application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, " +  
    56.                 "application/vnd.ms-powerpoint, application/msword, */* ";  
    57.           out.write(accept.getBytes());  
    58.             
    59.           // 设置语言  
    60.           String language = "Accept-Language: zh-CN ";  
    61.           out.write(language.getBytes());  
    62.             
    63.           // 设置内容类型  
    64.           String contentType = "Content-Type: multipart/form-data; boundary=" + BOUNDARY + " ";  
    65.           out.write(contentType.getBytes());  
    66.             
    67.           // 设置报文长度  
    68.           String contentLength = "Content-Length: " + totalDataLen + " ";  
    69.           out.write(contentLength.getBytes());  
    70.             
    71.           // 设置活动  
    72.           String alive = "Connection: Keep-Alive ";  
    73.           out.write(alive.getBytes());  
    74.             
    75.           // 设置主机  
    76.           String host = "Host: " + url.getHost() + ":80 ";  
    77.           out.write(host.getBytes());  
    78.             
    79.           // 设置一个回车换行  
    80.           out.write(" ".getBytes());  
    81.             
    82.             
    83.           // 添加所有文本类型数据  
    84.           out.write(textEntity);  
    85.             
    86.             
    87.           // 添加所有文件类型数据  
    88.           StringBuilder fileEntity = new StringBuilder();  
    89.           fileEntity.append("--" + BOUNDARY + " ");  
    90.           fileEntity.append("Content-Disposition: form-data;name="data";" + "filename="" + fileName + """ + " ");  
    91.           fileEntity.append("Content-Type: text/plain" + " ");  
    92.           out.write(fileEntity.toString().getBytes());  
    93.             
    94.           // 将文件内容写入报文  
    95.           FileInputStream fis = new FileInputStream(file);    // 以后记得加null判断  
    96.           byte[] buffer = new byte[1024];  
    97.           int len = 0;  
    98.           while( (len=fis.read(buffer))!=-1 )  
    99.           {  
    100.               out.write(buffer, 0, len);  
    101.           }  
    102.           fis.close();  
    103.           out.write(" ".getBytes());  
    104.             
    105.           // 数据结束标志,代表数据已经结束  
    106.           out.write(after);  
    107.             
    108.             
    109.           // 输出处理结果  
    110.           BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));  
    111.           String line = "";  
    112.           while( (line=reader.readLine())!=null)  
    113.           {  
    114.               Log.d("carter", line);  
    115.           }  
    116.            
    117.           // 发送报文  
    118.           out.flush();  
    119.             
    120.           // 关闭流  
    121.           out.close();  
    122.           reader.close();  
    123.           socket.close();              
    124.       }  
    125.       catch (MalformedURLException e) {  
    126.           // TODO Auto-generated catch block  
    127.           e.printStackTrace();  
    128.       }   
    129.       catch (UnsupportedEncodingException e) {  
    130.           // TODO Auto-generated catch block  
    131.           e.printStackTrace();  
    132.       }   
    133.       catch (IOException e) {  
    134.           // TODO Auto-generated catch block  
    135.           e.printStackTrace();  
    136.       }  
    137.   }  


    具体步骤:

    1.构造参数信息

    2.构造文件信息

    3.构造尾信息

    4.通过URL和端口得到一个Socket对象

    5.设置Socket的属性

    6.得到一个输出流,将所有信息输出

    7.输出传送结果

  • 相关阅读:
    [转]来扯点ionic3[2] 页面一线牵 珍惜这段缘
    [转]ionic工作原理
    [转]禁止浏览器自动保存密码弹框
    [转]git提交代码时遇到代码库有更新以及本地有更新的解决方法
    [转]Angular 4 *ngIf/Else
    [转]Angular4 引用 material dialog时自定义对话框/deep/.mat-dialog-container
    ES之五:ElasticSearch聚合
    Logstash之四:配置说明
    Logstash之三:命令行中常用的命令
    Logstash之二:原理
  • 原文地址:https://www.cnblogs.com/chyl411/p/4380887.html
Copyright © 2020-2023  润新知