发现问题
项目中有发表动态的功能,该功能可以将文本和图片上传至服务器。
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);
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍Android Volley框架使用方法详解,包括了Android Volley框架使用方法详解的使用技巧和注意事项,需要的朋友参考一下 本文主要从两个方面对Android Volley框架的使用方法进行讲解,具体内容如下 一、网络请求 1.get方式请求数据 2.post方式请求数据 3.请求Json数据 二、图片加载 1.ImageRequest加载图片 2.Imag
本文向大家介绍Android Volley框架使用源码分享,包括了Android Volley框架使用源码分享的使用技巧和注意事项,需要的朋友参考一下 过去在Android上网络通信都是使用的Xutils 因为用它可以顺道处理了图片和网络这两个方面,后来发觉Xutils里面使用的是HttpClient 而Google在6.0的版本上已经把HttpClient废除了,所以开始寻找新的网络框架,ok
本文向大家介绍Android使用Volley实现上传文件功能,包括了Android使用Volley实现上传文件功能的使用技巧和注意事项,需要的朋友参考一下 一个项目中用到的使用Volley上传头像文件的例子,供大家参考,具体内容如下 调用方法如下: private File mSelectedPictureFile; mSelectedPictureFile是一个File文件,参数名是file 通
我已经有了一个子类
使用Django REST框架的通用,我创建了一个我认为应该能够通过POST请求上传照片的终端。 到目前为止,我尝试使用Android和curl将文件发布到此endpoint,并观察到相同的行为:创建了一条新记录,但没有附加该文件。因为该文件是必填字段,服务器然后返回500错误。 这个问题看起来很相似,但是他没有使用REST框架的通用视图,我不知道为什么...我想在适当的时候利用它们。 这是我的D
本文向大家介绍Android Volley框架全面解析,包括了Android Volley框架全面解析的使用技巧和注意事项,需要的朋友参考一下 Volley简介 我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据。Android系统中主要提供了两种方式来进行HTTP通信,HttpURLConnection和HttpCl