热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

Android使用Volley框架定制PostUploadRequest上传文件

这篇文章主要为大家详细介绍了Android使用Volley框架定制PostUploadRequest上传文件或图片,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

发现问题

项目中有发表动态的功能,该功能可以将文本和图片上传至服务器。
Volley通过定制PostUploadRequest实现文件上传的功能,本文以一张图片上传为例。

数据格式

以下为项目中图片上传实例的数据格式
多张图片上传可通过添加——WebKitFormBoundary 内容实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
POST /CloudLife/user/social HTTP/1.1
Host: localhost
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://localhost
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryzayymBT8Owg2UzBR
Referer: http://localhost/CloudLife/upload.jsp
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8
COOKIE: CLOUD_LIFE=03F21B9A9D9B4FF2BF443290A9CD8E2C; USER=18060506304; JSESSIOnID=C4AB532929FA43230FA193A98197F962
Content-Length: 12444
 
------WebKitFormBoundaryzayymBT8Owg2UzBR
Content-Disposition: form-data; name="text"
 
发表的圈子内容
------WebKitFormBoundaryzayymBT8Owg2UzBR
Content-Disposition: form-data; name="file"; filename="这里是文件名"
Content-Type: image/png
这里空一行 接下来是二进制图片文件内容
------WebKitFormBoundaryzayymBT8Owg2UzBR--
这里为空白的一行

总共有加上结尾行,有五行,图片的二进制数,整个算一行;下面来分析下:

1、第一行:”–” + boundary + “\r\n” ;
文件上传在提交数据的开始标志不变;

2、第二行:Content-Disposition: form-data; name=”参数的名称”; filename=”上传的文件名” + “\r\n”

3、第三行:Content-Type: 文件的 mime 类型 + “\r\n”
这一行是文件上传必须要的,而普通的文字提交可有可无,mime 类型需要根据文档查询;

4、第四行:”\r\n”

5、第五行文件的二进制数据 + “\r\n”:
结尾行:”–” + boundary + “–” + “\r\n”
可以同时上传多个文件,上传多个文件的时候重复1、2、3、4、5步,在最后的一个文件的末尾加上统一的结束行。

上传的图像实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import java.io.ByteArrayOutputStream;
import android.graphics.Bitmap;
 
/*
 * 上传的图像实体类
 * */
public class FormImage {
 
 // 参数的名称
 private String mName;
 
 // 文件名
 private String mFileName;
 
 // 文件的 mime,需要根据文档查询
 private String mMime;
 
 // 需要上传的图片资源,因为这里测试为了方便起见,直接把 bitmap 传进来,真正在项目中一般不会这般做,
 // 而是把图片的路径传过来,在这里对图片进行二进制转换
 private Bitmap mBitmap = null;
 
 public FormImage(Bitmap bitmap) {
 this.mBitmap = bitmap;
 }
 
 public String getName() {
 return "file";
 }
 
 public String getFileName() {
 return "add.png";
 }
 
 // 对图片进行二进制转换
 public byte[] getValue() {
 ByteArrayOutputStream bos = new ByteArrayOutputStream();
 mBitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
 return bos.toByteArray();
 }
 
 // 因为我知道是 png 文件,所以直接根据文档查的
 public String getMime() {
 return "image/png";
 }
}

定制PostUploadRequest

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.protocol.HTTP;
import org.json.JSONException;
import org.json.JSONObject;

import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.toolbox.HttpHeaderParser;

import android.util.Log;

/*
 * 发送文件的volley 
 * post请求 COOKIE
 * */
public class PostUploadRequest extends Request {

 private Map sendHeader = new HashMap();

 // 正确数据的时候回掉用
 private Response.Listener mListener;

 // 请求 数据通过参数的形式传入 
 private String content;
 private FormImage mImage;

 // 数据分隔线
 private String BOUNDARY = "----CloudLifeUpLoadImage"; 
 private String MULTIPART_FORM_DATA = "multipart/form-data";

 public PostUploadRequest(String url, String text, FormImage Item, Response.Listener listener,Response.ErrorListener errorListener) {

 super(Method.POST, url, errorListener);
 this.mListener = listener;
 setShouldCache(false);
 mImage = Item;
 cOntent= text;

 // 设置请求的响应事件,因为文件上传需要较长的时间,所以在这里加大了,设为5秒
 setRetryPolicy(new DefaultRetryPolicy(5000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
  DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
 }

 /*
 * 这里开始解析数据
 * @param response
 *  Response from the network
 * @return
 * */
 @Override
 protected Response parseNetworkResponse(NetworkResponse response) {
 try {
  // 防止中文乱码
  @SuppressWarnings("deprecation")
  String jsOnString= new String(response.data, HTTP.UTF_8);

  JSONObject jsOnObject= new JSONObject(jsonString);

  Log.w("upLoad", "jsonObject " + jsonObject.toString());

  return Response.success(jsonObject, HttpHeaderParser.parseCacheHeaders(response));
 } catch (UnsupportedEncodingException e) {
  return Response.error(new ParseError(e));
 } catch (JSONException je) {
  return Response.error(new ParseError(je));
 }
 }

 /*
 * 回调正确的数据
 * @param response
 *  The parsed response returned by
 * */
 @Override
 protected void deliverResponse(JSONObject response) {
 mListener.onResponse(response);
 }

 @Override
 public Map getHeaders() throws AuthFailureError {
 return sendHeader;
 }

 public void setSendCOOKIE(String COOKIE) {
 sendHeader.put("COOKIE", COOKIE);
 }

 @Override
 public byte[] getBody() throws AuthFailureError {
 ByteArrayOutputStream bos = new ByteArrayOutputStream();

 StringBuffer sb = new StringBuffer();

 if (cOntent== null) {
  /**
  * 图片
  */
  /* 第一行 */
  // `"--" + BOUNDARY + "\r\n"`
  sb.append("--" + BOUNDARY + "\r\n");

  /* 第二行 */
  // Content-Disposition: form-data; name="参数的名称"; filename="上传的文件名" +
  // "\r\n"
  sb.append("Content-Disposition: form-data;");
  sb.append(" name=\"");
  sb.append(mImage.getName());
  sb.append("\"");
  sb.append("; filename=\"");
  sb.append(mImage.getFileName());
  sb.append("\"");
  sb.append("\r\n");

  /* 第三行 */
  // Content-Type: 文件的 mime 类型 + "\r\n"
  sb.append("Content-Type: ");
  sb.append(mImage.getMime());
  sb.append("\r\n");

  /* 第四行 */
  // "\r\n" 空白的一行
  sb.append("\r\n");

  try {
  bos.write(sb.toString().getBytes("utf-8"));
  /* 第五行 */
  // 文件的二进制数据 + "\r\n"
  bos.write(mImage.getValue());
  bos.write("\r\n".getBytes("utf-8"));
  } catch (IOException e) {
  e.printStackTrace();
  }

  /* 结尾行 */
  // `"--" + BOUNDARY + "--" + "\r\n"`
  String endLine = "--" + BOUNDARY + "--" + "\r\n";
  try {
  bos.write(endLine.toString().getBytes("utf-8"));
  } catch (IOException e) {
  e.printStackTrace();
  }
  Log.v("upLoad", "=====formImage====\n" + bos.toString());
  return bos.toByteArray();
 }
 /**
  * 文字
  */
 /* 第一行 */
 // `"--" + BOUNDARY + "\r\n"`
 sb.append("--" + BOUNDARY + "\r\n");

 /* 第二行 */
 // Content-Disposition: form-data; name="text" + "\r\n"
 sb.append("Content-Disposition: form-data;");
 sb.append(" name=\"");
 sb.append("text");
 sb.append("\"");
 sb.append("\r\n");

 /* 第三行 */
 // "\r\n" 空白的一行
 sb.append("\r\n");

 /* 第四行 */
 // 文本内容
 sb.append(content);
 sb.append("\r\n");

 if (mImage == null) {
  /* 结尾行 */
  // `"--" + BOUNDARY + "--" + "\r\n"`
  String endLine = "--" + BOUNDARY + "--" + "\r\n";
  try {
  bos.write(sb.toString().getBytes("utf-8"));
  bos.write(endLine.toString().getBytes("utf-8"));
  } catch (IOException e) {
  e.printStackTrace();
  }
  Log.v("upLoad", "=====formImage====\n" + bos.toString());
  return bos.toByteArray();
 } else {
  /**
  * 图片
  */
  /* 第一行 */
  // `"--" + BOUNDARY + "\r\n"`
  sb.append("--" + BOUNDARY + "\r\n");

  /* 第二行 */
  // Content-Disposition: form-data; name="参数的名称"; filename="上传的文件名" +
  // "\r\n"
  sb.append("Content-Disposition: form-data;");
  sb.append(" name=\"");
  sb.append(mImage.getName());
  sb.append("\"");
  sb.append("; filename=\"");
  sb.append(mImage.getFileName());
  sb.append("\"");
  sb.append("\r\n");

  /* 第三行 */
  // Content-Type: 文件的 mime 类型 + "\r\n"
  sb.append("Content-Type: ");
  sb.append(mImage.getMime());
  sb.append("\r\n");

  /* 第四行 */
  // "\r\n" 空白的一行
  sb.append("\r\n");

  try {
  bos.write(sb.toString().getBytes("utf-8"));
  /* 第五行 */
  // 文件的二进制数据 + "\r\n"
  bos.write(mImage.getValue());
  bos.write("\r\n".getBytes("utf-8"));
  } catch (IOException e) {
  e.printStackTrace();
  }

 }

 /* 结尾行 */
 // `"--" + BOUNDARY + "--" + "\r\n"`
 String endLine = "--" + BOUNDARY + "--" + "\r\n";
 try {
  bos.write(endLine.toString().getBytes("utf-8"));
 } catch (IOException e) {
  e.printStackTrace();
 }
 Log.v("upLoad", "=====formImage====\n" + bos.toString());
 return bos.toByteArray();
 }

 // Content-Type: multipart/form-data; boundary=----------8888888888888
 @Override
 public String getBodyContentType() {
 return MULTIPART_FORM_DATA + "; boundary=" + BOUNDARY;
 }
}

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
RequestQueue mQueue = SingleRequestQueue.getRequestQueue();
 
FormImage image;
if (imageUri != null) {
 Bitmap bitmap = null;
 try {// 将路径转化成bitmap
 bitmap=BitmapFactory.decodeStream(
  getContentResolver().openInputStream(imageUri));
 } catch (FileNotFoundException e1) {
 e1.printStackTrace();
 }
 image = new FormImage(bitmap);
} else
 image = null;
 
PostUploadRequest post = new PostUploadRequest(C.api.userIcon, null, image,
 new Response.Listener<jsonobject>() {
 @Override
 public void onResponse(JSONObject jsonObject) {
  try {
  //TODO
  } catch (JSONException e) {
  e.printStackTrace();
  }
 }
 }, new Response.ErrorListener() {
 @Override
 public void onErrorResponse(VolleyError error) {
  Log.e("VolleyError", error.getMessage(), error);
 }
 });
 
if (!customer.getCOOKIE().equals("")) {
 // 向服务器发起post请求时加上COOKIE字段
 post.setSendCOOKIE(customer.getCOOKIE());
}
 
mQueue.add(post);</jsonobject>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 本文探讨了如何通过最小生成树(MST)来计算严格次小生成树。在处理过程中,需特别注意所有边权重相等的情况,以避免错误。我们首先构建最小生成树,然后枚举每条非树边,检查其是否能形成更优的次小生成树。 ... [详细]
  • QUIC协议:快速UDP互联网连接
    QUIC(Quick UDP Internet Connections)是谷歌开发的一种旨在提高网络性能和安全性的传输层协议。它基于UDP,并结合了TLS级别的安全性,提供了更高效、更可靠的互联网通信方式。 ... [详细]
  • 深入理解OAuth认证机制
    本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
  • 国内BI工具迎战国际巨头Tableau,稳步崛起
    尽管商业智能(BI)工具在中国的普及程度尚不及国际市场,但近年来,随着本土企业的持续创新和市场推广,国内主流BI工具正逐渐崭露头角。面对国际品牌如Tableau的强大竞争,国内BI工具通过不断优化产品和技术,赢得了越来越多用户的认可。 ... [详细]
  • 本文详细分析了JSP(JavaServer Pages)技术的主要优点和缺点,帮助开发者更好地理解其适用场景及潜在挑战。JSP作为一种服务器端技术,广泛应用于Web开发中。 ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • 在计算机技术的学习道路上,51CTO学院以其专业性和专注度给我留下了深刻印象。从2012年接触计算机到2014年开始系统学习网络技术和安全领域,51CTO学院始终是我信赖的学习平台。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 本文介绍了如何使用jQuery根据元素的类型(如复选框)和标签名(如段落)来获取DOM对象。这有助于更高效地操作网页中的特定元素。 ... [详细]
  • 本文介绍如何在 Xcode 中使用快捷键和菜单命令对多行代码进行缩进,包括右缩进和左缩进的具体操作方法。 ... [详细]
  • 在Linux系统中配置并启动ActiveMQ
    本文详细介绍了如何在Linux环境中安装和配置ActiveMQ,包括端口开放及防火墙设置。通过本文,您可以掌握完整的ActiveMQ部署流程,确保其在网络环境中正常运行。 ... [详细]
  • 本文详细分析了Hive在启动过程中遇到的权限拒绝错误,并提供了多种解决方案,包括调整文件权限、用户组设置以及环境变量配置等。 ... [详细]
author-avatar
lt7520
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有