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

发现问题

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

数据格式

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

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步,在最后的一个文件的末尾加上统一的结束行。

上传的图像实体类

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<JSONObject> {

 private Map<String, String> sendHeader = new HashMap<String, String>();

 // 正确数据的时候回掉用
 private Response.Listener<JSONObject> 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<JSONObject> 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<JSONObject> 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<String, String> 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;
 }
}

实例

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);

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

(0)

相关推荐

  • Android Volley扩展实现支持进度条的文件上传功能

    volley是一个轻量级的开源网络通信框架,开源的好处就是可以自由定制自己需要的jar包.volley里网络通信时android2.3以上用的HttpUrlConnection,2.3以下用的HttpClient,我做的改动只考虑了2.3以上,不支持2.3版本以下.HttpUrlConnection默认传输数据是将数据全部写到内存中再发送到服务端,Volley就是采用默认的方式,这样在上传大文件时很容易就out of memory,有一种解决办法是设置每次传输流的大小: 已知文件大小:conne

  • Android使用Volley实现上传文件功能

    一个项目中用到的使用Volley上传头像文件的例子,供大家参考,具体内容如下 /** * Created by wangshihui on 2015/11/30. * 上传文件 * url:..... method:post 参数:file 接口给的参数:file 就是表单的key,传给mFilePartName; 这是个测试类,测试上传头像没有问题,适合只上传单个文件的场景 */ public class MultipartRequest extends Request<JSONObject>

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

    发现问题 项目中有发表动态的功能,该功能可以将文本和图片上传至服务器. Volley通过定制PostUploadRequest实现文件上传的功能,本文以一张图片上传为例. 数据格式 以下为项目中图片上传实例的数据格式 多张图片上传可通过添加--WebKitFormBoundary 内容实现 POST /CloudLife/user/social HTTP/1.1 Host: localhost Connection: keep-alive Cache-Control: max-age=0 Acc

  • Android ProgressDialog用法之实现app上传文件进度条转圈效果

    ProgressDialog 继承自AlertDialog,AlertDialog继承自Dialog public class ProgressDialog extends AlertDialog ProgressDialog的创建方式有两种,一种是new ProgressDialog,一种是调用ProgressDialog的静态方法show()创建并显示,这种进度条只能是圆形条. ProgressDialog dialog = ProgressDialog.show(this, "提示&quo

  • Android 解决WebView无法上传文件的问题

    Android 解决WebView无法上传文件的问题 Android原生的WebView并不支持上传文件,需要我们自己实现相应的方法.于是我把工作中的相关代码记录下来.下次直接拿来用就行了.一点一滴都是经验. 1.需要定义三个变量 private ValueCallback<Uri[]> uploadMessageAboveL; private final static int FILE_CHOOSER_RESULT_CODE = 10000; private ValueCallback<

  • Java负载均衡服务器实现上传文件同步

    负载服务器Z,应用服务器A 和B ,从A上传的附件,如何在B上下载下来? 这个问题我的解决思路如下(后来被一个装逼的面试官给批评了这种做法,不过我瞧不起他) 服务器A.B 上传附件的时候,将这个附件备份到服务器Z ,当A.B下载文件的时候,首先会在自己服务器的目录下寻找,如果找不到,就会从服务器Z 上下载一份到当前服务器. 服务器之间的文件备份通过sftp,参考:https://www.jb51.net/article/196008.htm(下文中的SftpCustom 类就是这个链接里的 "S

  • Android中Volley框架进行请求网络数据的使用

    问题的阐述:Android SDK中的HttpClient和HttpUrlConnection两种请求方式用来处理网络的复杂的操作,但当应用比较复杂的时候需要我们编写大量的代码处理很多东西:图像缓存,请求的调度等等: 解决:Volley就是为解决这些而生,它与2013年Google I/O大会上被提出:使得Android应用网络操作更方便更快捷:抽象了底层Http Client等实现的细节,让开发者更专注与产生RESTful Request.另外,Volley在不同的线程上异步执行所有请求而避免

  • Android上传文件到服务端并显示进度条

    最近在做上传文件的服务,简单看了网上的教程.结合实践共享出代码. 由于网上的大多数没有服务端的代码,这可不行呀,没服务端怎么调试呢. Ok,先上代码. Android 上传比较简单,主要用到的是 HttpURLConnection 类,然后加一个进度条组件. private ProgressBar mPgBar; class UploadTask extends AsyncTask<Object,Integer,Void>{ private DataOutputStream outputStr

  • 基于ASP.NET+EasyUI框架实现图片上传提交表单功能(js提交图片)

    我的风格,先给大家展示下效果图,具体效果图如下所示,如果大家感觉还不错很满意请参考实现代码. HTML的代码: <form id="ff" runat="server" method="post"> <div id="content" style="margin-left:50px;"> <table style="width:300px;" id=&quo

  • 定制FileField中的上传文件名称实例

    FileField中的upload_to属性可以设定上传文件的存储目录和名称,它可以是个字符串,也可以是个callable,比如一个方法. 当upload_to的值设为一个方法时,就可以对上传文件的名称进行修改了.方法需要两个参数,instance与filename,instance为此FileField所属的Model实例,filename为上传文件的名称. 举例: def user_directory_path(instance, filename): # file will be uplo

  • Android选择图片或拍照图片上传到服务器

    最近要搞一个项目,需要上传相册和拍照的图片,不负所望,终于完成了!  不过需要说明一下,其实网上很多教程拍照的图片,都是缩略图不是很清晰,所以需要在调用照相机的时候,事先生成一个地址,用于标识拍照的图片URI 具体上传代码: 1.选择图片和上传界面,包括上传完成和异常的回调监听 package com.spring.sky.image.upload; import java.util.HashMap; import java.util.Map; import android.app.Activi

随机推荐