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

 

通过构造基于HTTP 协议的传输内容实现图片自动上传到服务器功能 。如果自己编码构造HTTP 协议,那么编写的代码质量肯定不高,建议模仿HttpClient .zip examples \mime\ClientMultipartFormPost.java 来实现,并通过源码来进一步理解如何优雅高效地构造HTTP 协议传输内容。

 

自己构造HTTP 协议传输内容的想法,从何而来呢?灵感启迪于这篇博文“Android下的应用编程——用HTTP协议实现文件上传功能 ”,以前从未想过通过抓取HTTP 请求数据格式,根据协议自己构造数据来实现数据提交。哎,Out 了。因为Apache HttpClient 框架就是通过此方式来实现的,以前从未注意到,看来以后要多多向前人学习啊!结果是:阅读了此框架的源码后,才知道自己编写的代码和人家相比真不是一个档次的。现在已经下定决心了,多读开源框架代码,不但可以熟悉相关业务流程,而且还可以学到设计模式在实际业务需求中的应用,更重要的是领悟其中的思想。业务流程、实践能力、框架思想,一举三得,何乐而不为呢。^_^

 

test.html 部分源码:

 

<form action="Your_Action_Url " method="post" enctype="multipart/form-data " name="form1" id="form1">

  <p>

    <label for="upload_file"></label>

    <input type="file" name="upload_file" id="upload_file " />

  </p>

  <p>

    <input type="submit" name="action" id="action " value="upload " />

  </p>

</form>

 

通过HttpWatch 查看抓取到的包数据格式:

 

 

下面将分别通过按照HttpWatch 抓取下来的协议格式内容构造传输内容实现文件上传功能和基于HttpClient 框架实现文件上传功能。

 

项目配置目录Your_Project/config ,相关文件 如下:

 

actionUrl.properties 文件内容:

 

Your_Action_Url

 

formDataParams.properties 文件内容(对应HTML Form 属性内容):

 

action =upload

 

imageParams.properties 文件内容(这里文件路径已配置死了,不好!建议在程序中动态设置,即通过传入相关参数实现。):

 

upload_file =images/roewe.jpg

 

MIMETypes.properties 文件内容(参考自Multimedia MIME Reference ):

 

jpeg:image/jpeg

jpg:image/jpeg

png:image/png

gif:image/gif

 

 

 

1. 在《Android下的应用编程——用HTTP协议实现文件上传功能 》代码的基础上,通过进一步改进得到如下代码(Java、Android 都可以run):

 

 

Java代码 

/** 

 * 文件名称:UploadImage.java 

 * 

 * 版权信息:Apache License, Version 2.0 

 * 

 * 功能描述:实现图片文件上传。 

 * 

 * 创建日期:2011-5-10 

 * 

 * 作者:Bert Lee 

 */ 

 

/* 

 * 修改历史: 

 */ 

public class UploadImage {  

    String multipart_form_data = "multipart/form-data";  

    String twoHyphens = "--";  

    String boundary = "****************fD4fH3gL0hK7aI6";    // 数据分隔符  

    String lineEnd = System.getProperty("line.separator");    // The value is "\r\n" in Windows.  

      

    /* 

     * 上传图片内容,格式请参考HTTP 协议格式。 

     * 人人网Photos.upload中的”程序调用“http://wiki.dev.renren.com/wiki/Photos.upload#.E7.A8.8B.E5.BA.8F.E8.B0.83.E7.94.A8 

     * 对其格式解释的非常清晰。 

     * 格式如下所示: 

     * --****************fD4fH3hK7aI6 

     * Content-Disposition: form-data; name="upload_file"; filename="apple.jpg" 

     * Content-Type: image/jpeg 

     * 

     * 这儿是文件的内容,二进制流的形式 

     */ 

    private void addImageContent(Image[] files, DataOutputStream output) {  

        for(Image file : files) {  

            StringBuilder split = new StringBuilder();  

            split.append(twoHyphens + boundary + lineEnd);  

            split.append("Content-Disposition: form-data; name=\"" + file.getFormName() + "\"; filename=\"" + file.getFileName() + "\"" + lineEnd);  

            split.append("Content-Type: " + file.getContentType() + lineEnd);  

            split.append(lineEnd);  

            try {  

                // 发送图片数据  

                output.writeBytes(split.toString());  

                output.write(file.getData(), 0, file.getData().length);  

                output.writeBytes(lineEnd);  

            } catch (IOException e) {  

                throw new RuntimeException(e);  

            }  

        }  

    }  

      

    /* 

     * 构建表单字段内容,格式请参考HTTP 协议格式(用FireBug可以抓取到相关数据)。(以便上传表单相对应的参数值) 

     * 格式如下所示: 

     * --****************fD4fH3hK7aI6 

     * Content-Disposition: form-data; name="action" 

     * // 一空行,必须有 

     * upload 

     */ 

    private void addFormField(Set<Map.Entry<Object,Object>> params, DataOutputStream output) {  

        StringBuilder sb = new StringBuilder();  

        for(Map.Entry<Object, Object> param : params) {  

            sb.append(twoHyphens + boundary + lineEnd);  

            sb.append("Content-Disposition: form-data; name=\"" + param.getKey() + "\"" + lineEnd);  

            sb.append(lineEnd);  

            sb.append(param.getValue() + lineEnd);  

        }  

        try {  

            output.writeBytes(sb.toString());// 发送表单字段数据  

        } catch (IOException e) {  

            throw new RuntimeException(e);  

        }  

    }  

      

    /** 

     * 直接通过HTTP 协议提交数据到服务器,实现表单提交功能。 

     * @param actionUrl 上传路径 

     * @param params 请求参数key为参数名,value为参数值 

     * @param files 上传文件信息 

     * @return 返回请求结果 

     */ 

    public String post(String actionUrl, Set<Map.Entry<Object,Object>> params, Image[] files) {  

        HttpURLConnection conn = null;  

        DataOutputStream output = null;  

        BufferedReader input = null;  

        try {  

            URL url = new URL(actionUrl);  

            conn = (HttpURLConnection) url.openConnection();  

            conn.setConnectTimeout(120000);  

            conn.setDoInput(true);        // 允许输入  

            conn.setDoOutput(true);        // 允许输出  

            conn.setUseCaches(false);    // 不使用Cache  

            conn.setRequestMethod("POST");  

            conn.setRequestProperty("Connection", "keep-alive");  

            conn.setRequestProperty("Content-Type", multipart_form_data + "; boundary=" + boundary);  

              

            conn.connect();  

            output = new DataOutputStream(conn.getOutputStream());  

              

            addImageContent(files, output);    // 添加图片内容  

              

            addFormField(params, output);    // 添加表单字段内容  

              

            output.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);// 数据结束标志  

            output.flush();  

              

            int code = conn.getResponseCode();  

            if(code != 200) {  

                throw new RuntimeException("请求‘" + actionUrl +"’失败!");  

            }  

              

            input = new BufferedReader(new InputStreamReader(conn.getInputStream()));  

            StringBuilder response = new StringBuilder();  

            String oneLine;  

            while((oneLine = input.readLine()) != null) {  

                response.append(oneLine + lineEnd);  

            }  

              

            return response.toString();  

        } catch (IOException e) {  

            throw new RuntimeException(e);  

        } finally {  

            // 统一释放资源  

            try {  

                if(output != null) {  

                    output.close();  

                }  

                if(input != null) {  

                    input.close();  

                }  

            } catch (IOException e) {  

                throw new RuntimeException(e);  

            }  

              

            if(conn != null) {  

                conn.disconnect();  

            }  

        }  

    }  

      

    public static void main(String[] args) {  

        try {  

            String response = "";  

              

            BufferedReader in = new BufferedReader(new FileReader("config/actionUrl.properties"));  

            String actionUrl = in.readLine();  

              

            // 读取表单对应的字段名称及其值  

            Properties formDataParams = new Properties();  

            formDataParams.load(new FileInputStream(new File("config/formDataParams.properties")));  

            Set<Map.Entry<Object,Object>> params = formDataParams.entrySet();  

              

            // 读取图片所对应的表单字段名称及图片路径  

            Properties imageParams = new Properties();  

            imageParams.load(new FileInputStream(new File("config/imageParams.properties")));  

            Set<Map.Entry<Object,Object>> images = imageParams.entrySet();  

            Image[] files = new Image[images.size()];  

            int i = 0;  

            for(Map.Entry<Object,Object> image : images) {  

                Image file = new Image(image.getValue().toString(), image.getKey().toString());  

                files[i++] = file;   

            }  

//            Image file = new Image("images/apple.jpg", "upload_file");  

//            Image[] files = new Image[0];  

//            files[0] = file;  

              

            response = new UploadImage().post(actionUrl, params, files);  

            System.out.println("返回结果:" + response);  

        } catch (IOException e) {  

            e.printStackTrace();  

        }  

    }  

 

/**

 * 文件名称:UploadImage.java

 *

 * 版权信息:Apache License, Version 2.0

 *

 * 功能描述:实现图片文件上传。

 *

 * 创建日期:2011-5-10

 *

 * 作者:Bert Lee

 */

 

/*

 * 修改历史:

 */

public class UploadImage {

    String multipart_form_data = "multipart/form-data";

    String twoHyphens = "--";

    String boundary = "****************fD4fH3gL0hK7aI6";    // 数据分隔符

    String lineEnd = System.getProperty("line.separator");    // The value is "\r\n" in Windows.

   

    /*

     * 上传图片内容,格式请参考HTTP 协议格式。

     * 人人网Photos.upload中的”程序调用“http://wiki.dev.renren.com/wiki/Photos.upload#.E7.A8.8B.E5.BA.8F.E8.B0.83.E7.94.A8

     * 对其格式解释的非常清晰。

     * 格式如下所示:

     * --****************fD4fH3hK7aI6

     * Content-Disposition: form-data; name="upload_file"; filename="apple.jpg"

     * Content-Type: image/jpeg

     *

     * 这儿是文件的内容,二进制流的形式

     */

    private void addImageContent(Image[] files, DataOutputStream output) {

        for(Image file : files) {

            StringBuilder split = new StringBuilder();

            split.append(twoHyphens + boundary + lineEnd);

            split.append("Content-Disposition: form-data; name=\"" + file.getFormName() + "\"; filename=\"" + file.getFileName() + "\"" + lineEnd);

            split.append("Content-Type: " + file.getContentType() + lineEnd);

            split.append(lineEnd);

            try {

                // 发送图片数据

                output.writeBytes(split.toString());

                output.write(file.getData(), 0, file.getData().length);

                output.writeBytes(lineEnd);

            } catch (IOException e) {

                throw new RuntimeException(e);

            }

        }

    }

   

    /*

     * 构建表单字段内容,格式请参考HTTP 协议格式(用FireBug可以抓取到相关数据)。(以便上传表单相对应的参数值)

     * 格式如下所示:

     * --****************fD4fH3hK7aI6

     * Content-Disposition: form-data; name="action"

     * // 一空行,必须有

     * upload

     */

    private void addFormField(Set<Map.Entry<Object,Object>> params, DataOutputStream output) {

        StringBuilder sb = new StringBuilder();

        for(Map.Entry<Object, Object> param : params) {

            sb.append(twoHyphens + boundary + lineEnd);

            sb.append("Content-Disposition: form-data; name=\"" + param.getKey() + "\"" + lineEnd);

            sb.append(lineEnd);

            sb.append(param.getValue() + lineEnd);

        }

        try {

            output.writeBytes(sb.toString());// 发送表单字段数据

        } catch (IOException e) {

            throw new RuntimeException(e);

        }

    }

   

    /**

     * 直接通过HTTP 协议提交数据到服务器,实现表单提交功能。

     * @param actionUrl 上传路径

     * @param params 请求参数key为参数名,value为参数值

     * @param files 上传文件信息

     * @return 返回请求结果

     */

    public String post(String actionUrl, Set<Map.Entry<Object,Object>> params, Image[] files) {

        HttpURLConnection conn = null;

        DataOutputStream output = null;

        BufferedReader input = null;

        try {

            URL url = new URL(actionUrl);

            conn = (HttpURLConnection) url.openConnection();

            conn.setConnectTimeout(120000);

            conn.setDoInput(true);        // 允许输入

            conn.setDoOutput(true);        // 允许输出

            conn.setUseCaches(false);    // 不使用Cache

            conn.setRequestMethod("POST");

            conn.setRequestProperty("Connection", "keep-alive");

            conn.setRequestProperty("Content-Type", multipart_form_data + "; boundary=" + boundary);

           

            conn.connect();

            output = new DataOutputStream(conn.getOutputStream());

           

            addImageContent(files, output);    // 添加图片内容

           

            addFormField(params, output);    // 添加表单字段内容

           

            output.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);// 数据结束标志

            output.flush();

           

            int code = conn.getResponseCode();

            if(code != 200) {

                throw new RuntimeException("请求‘" + actionUrl +"’失败!");

            }

           

            input = new BufferedReader(new InputStreamReader(conn.getInputStream()));

            StringBuilder response = new StringBuilder();

            String oneLine;

            while((oneLine = input.readLine()) != null) {

                response.append(oneLine + lineEnd);

            }

           

            return response.toString();

        } catch (IOException e) {

            throw new RuntimeException(e);

        } finally {

            // 统一释放资源

            try {

                if(output != null) {

                    output.close();

                }

                if(input != null) {

                    input.close();

                }

            } catch (IOException e) {

                throw new RuntimeException(e);

            }

           

            if(conn != null) {

                conn.disconnect();

            }

        }

    }

   

    public static void main(String[] args) {

        try {

            String response = "";

           

            BufferedReader in = new BufferedReader(new FileReader("config/actionUrl.properties"));

            String actionUrl = in.readLine();

           

            // 读取表单对应的字段名称及其值

            Properties formDataParams = new Properties();

            formDataParams.load(new FileInputStream(new File("config/formDataParams.properties")));

            Set<Map.Entry<Object,Object>> params = formDataParams.entrySet();

            

            // 读取图片所对应的表单字段名称及图片路径

            Properties imageParams = new Properties();

            imageParams.load(new FileInputStream(new File("config/imageParams.properties")));

            Set<Map.Entry<Object,Object>> images = imageParams.entrySet();

            Image[] files = new Image[images.size()];

            int i = 0;

            for(Map.Entry<Object,Object> image : images) {

                Image file = new Image(image.getValue().toString(), image.getKey().toString());

                files[i++] = file;

            }

//            Image file = new Image("images/apple.jpg", "upload_file");

//            Image[] files = new Image[0];

//            files[0] = file;

            

            response = new UploadImage().post(actionUrl, params, files);

            System.out.println("返回结果:" + response);

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

}

2. 基于HttpClient 框架实现文件上传,实例代码如下:

 

Java代码 

/** 

 * 文件名称:ClientMultipartFormPost.java 

 * 

 * 版权信息:Apache License, Version 2.0 

 * 

 * 功能描述:通过HttpClient 4.1.1 实现文件上传。 

 * 

 * 创建日期:2011-5-15 

 * 

 * 作者:Bert Lee 

 */ 

 

/* 

 * 修改历史: 

 */ 

public class ClientMultipartFormPost {  

    /** 

     * 直接通过HttpMime's MultipartEntity 提交数据到服务器,实现表单提交功能。 

     * @return Post 请求所返回的内容 

     */ 

    public static String filePost() {  

        HttpClient httpclient = new DefaultHttpClient();  

          

        try {  

            BufferedReader in = new BufferedReader(new FileReader("config/actionUrl.properties"));  

            String actionUrl;  

            actionUrl = in.readLine();  

            HttpPost httppost = new HttpPost(actionUrl);  

              

            // 通过阅读源码可知,要想实现图片上传功能,必须将MultipartEntity 的模式设置为BROWSER_COMPATIBLE 。  

            MultipartEntity multiEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);  

//            MultipartEntity multiEntity = new MultipartEntity();  

               

            // 读取图片的MIME Type 类型集  

            Properties mimeTypes = new Properties();  

            mimeTypes.load(new FileInputStream(new File("config/MIMETypes.properties")));  

              

            // 构造图片数据  

            Properties imageParams = new Properties();  

            imageParams.load(new FileInputStream(new File("config/imageParams.properties")));  

            String fileType;  

            for(Map.Entry<Object,Object> image : imageParams.entrySet()) {  

                String path = image.getValue().toString();  

                fileType = path.substring(path.lastIndexOf(".") + 1);  

                FileBody binaryContent = new FileBody(new File(path), mimeTypes.get(fileType).toString());  

//                FileBody binaryContent = new FileBody(new File(path));  

                multiEntity.addPart(image.getKey().toString(), binaryContent);  

            }  

              

            // 构造表单参数数据  

            Properties formDataParams = new Properties();  

            formDataParams.load(new FileInputStream(new File("config/formDataParams.properties")));  

            for(Entry<Object, Object> param : formDataParams.entrySet()) {  

                multiEntity.addPart(param.getKey().toString(), new StringBody(param.getValue().toString()));  

            }  

              

            httppost.setEntity(multiEntity);  

//            Out.println("executing request " + httppost.getRequestLine());  

              

            HttpResponse response = httpclient.execute(httppost);  

            HttpEntity resEntity = response.getEntity();  

              

//            Out.println("-------------------");  

//            Out.println(response.getStatusLine());  

            if(resEntity != null) {  

                String returnContent = EntityUtils.toString(resEntity);  

                EntityUtils.consume(resEntity);  

                  

                return returnContent; // 返回页面内容  

            }  

        } catch (IOException e) {  

            e.printStackTrace();  

        } finally {  

            // 释放资源  

            httpclient.getConnectionManager().shutdown();  

        }  

        return null;  

    }  

 

    // 测试  

    public static void main(String[] args) {  

        Out.println("Response content: " + ClientMultipartFormPost.filePost());  

    }  

 

 

/**

 * 文件名称:ClientMultipartFormPost.java

 *

 * 版权信息:Apache License, Version 2.0

 *

 * 功能描述:通过HttpClient 4.1.1 实现文件上传。

 *

 * 创建日期:2011-5-15

 *

 * 作者:Bert Lee

 */

 

/*

 * 修改历史:

 */

public class ClientMultipartFormPost {

    /**

     * 直接通过HttpMime's MultipartEntity 提交数据到服务器,实现表单提交功能。

     * @return Post 请求所返回的内容

     */

    public static String filePost() {

        HttpClient httpclient = new DefaultHttpClient();

       

        try {

            BufferedReader in = new BufferedReader(new FileReader("config/actionUrl.properties"));

            String actionUrl;

            actionUrl = in.readLine();

            HttpPost httppost = new HttpPost(actionUrl);

           

            // 通过阅读源码可知,要想实现图片上传功能,必须将MultipartEntity 的模式设置为BROWSER_COMPATIBLE 。

            MultipartEntity multiEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);

//            MultipartEntity multiEntity = new MultipartEntity();

           

            // 读取图片的MIME Type 类型集

            Properties mimeTypes = new Properties();

            mimeTypes.load(new FileInputStream(new File("config/MIMETypes.properties")));

            

            // 构造图片数据

            Properties imageParams = new Properties();

            imageParams.load(new FileInputStream(new File("config/imageParams.properties")));

            String fileType;

            for(Map.Entry<Object,Object> image : imageParams.entrySet()) {

                String path = image.getValue().toString();

                fileType = path.substring(path.lastIndexOf(".") + 1);

                FileBody binaryContent = new FileBody(new File(path), mimeTypes.get(fileType).toString());

//                FileBody binaryContent = new FileBody(new File(path));

                multiEntity.addPart(image.getKey().toString(), binaryContent);

            }

           

            // 构造表单参数数据

            Properties formDataParams = new Properties();

            formDataParams.load(new FileInputStream(new File("config/formDataParams.properties")));

            for(Entry<Object, Object> param : formDataParams.entrySet()) {

                multiEntity.addPart(param.getKey().toString(), new StringBody(param.getValue().toString()));

            }

           

            httppost.setEntity(multiEntity);

//            Out.println("executing request " + httppost.getRequestLine());

           

            HttpResponse response = httpclient.execute(httppost);

            HttpEntity resEntity = response.getEntity();

           

//            Out.println("-------------------");

//            Out.println(response.getStatusLine());

            if(resEntity != null) {

                String returnContent = EntityUtils.toString(resEntity);

                EntityUtils.consume(resEntity);

               

                return returnContent; // 返回页面内容

            }

        } catch (IOException e) {

            e.printStackTrace();

        } finally {

            // 释放资源

            httpclient.getConnectionManager().shutdown();

        }

        return null;

    }

 

    // 测试

    public static void main(String[] args) {

        Out.println("Response content: " + ClientMultipartFormPost.filePost());

    }

 

}   




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值