基于Volley的文件上传

来源:互联网 发布:2017软件水平报考 编辑:程序博客网 时间:2024/04/29 15:20

http://blog.csdn.net/com314159/article/details/39853865

尊重原版本原创。


源代码的地址在:

git@github.com:com314159/VolleyMultiPartRequest.git

上面的是ssh

下面的是http地址

https://github.com/com314159/VolleyMultiPartRequest


是根据

https://github.com/smanikandan14/Volley-demo

这位大神修改而来的, 但是那位大神的代码有bug, 上传文件不成功.


注: 我的demo里面还集成了okhttp, 不需要的同学不用理这个类即可


实现方法:

1.添加三个jar包,

httpcore-4.3.2.jar

httpclient-4.3.5.jar

httpmime-4.3.5.jar


2.实现MultiPartStack

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.example.volleytest;  
  2.   
  3.   
  4. import java.io.File;  
  5. import java.io.IOException;  
  6. import java.util.Map;  
  7.   
  8. import org.apache.http.HttpEntity;  
  9. import org.apache.http.HttpResponse;  
  10. import org.apache.http.client.HttpClient;  
  11. import org.apache.http.client.methods.HttpDelete;  
  12. import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;  
  13. import org.apache.http.client.methods.HttpGet;  
  14. import org.apache.http.client.methods.HttpPatch;  
  15. import org.apache.http.client.methods.HttpPost;  
  16. import org.apache.http.client.methods.HttpPut;  
  17. import org.apache.http.client.methods.HttpUriRequest;  
  18. import org.apache.http.entity.ByteArrayEntity;  
  19. import org.apache.http.entity.ContentType;  
  20. import org.apache.http.entity.mime.HttpMultipartMode;  
  21. import org.apache.http.entity.mime.MultipartEntityBuilder;  
  22. import org.apache.http.entity.mime.content.FileBody;  
  23. import org.apache.http.entity.mime.content.StringBody;  
  24. import org.apache.http.impl.client.DefaultHttpClient;  
  25. import org.apache.http.params.HttpConnectionParams;  
  26. import org.apache.http.params.HttpParams;  
  27. import org.apache.http.protocol.HTTP;  
  28.   
  29. import com.android.volley.AuthFailureError;  
  30. import com.android.volley.Request;  
  31. import com.android.volley.Request.Method;  
  32. import com.android.volley.toolbox.HurlStack;  
  33.   
  34. /**  
  35.  * @author ZhiCheng Guo  
  36.  * @version 2014年10月7日 上午11:00:52 这个Stack用于上传文件, 如果没有这个Stack, 则上传文件不成功  
  37.  */  
  38. public class MultiPartStack extends HurlStack {  
  39.     @SuppressWarnings("unused")  
  40.     private static final String TAG = MultiPartStack.class.getSimpleName();  
  41.     private final static String HEADER_CONTENT_TYPE = "Content-Type";  
  42.       
  43.       
  44.       
  45.       
  46.     @Override  
  47.     public HttpResponse performRequest(Request<?> request,  
  48.             Map<String, String> additionalHeaders) throws IOException, AuthFailureError {  
  49.           
  50.         if(!(request instanceof MultiPartRequest)) {  
  51.             return super.performRequest(request, additionalHeaders);  
  52.         }  
  53.         else {  
  54.             return performMultiPartRequest(request, additionalHeaders);  
  55.         }  
  56.     }  
  57.       
  58.     private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {  
  59.         for (String key : headers.keySet()) {  
  60.             httpRequest.setHeader(key, headers.get(key));  
  61.         }  
  62.     }  
  63.       
  64.     public HttpResponse performMultiPartRequest(Request<?> request,  
  65.             Map<String, String> additionalHeaders)  throws IOException, AuthFailureError {  
  66.         HttpUriRequest httpRequest = createMultiPartRequest(request, additionalHeaders);  
  67.         addHeaders(httpRequest, additionalHeaders);  
  68.         addHeaders(httpRequest, request.getHeaders());  
  69.         HttpParams httpParams = httpRequest.getParams();  
  70.         int timeoutMs = request.getTimeoutMs();  
  71.         // TODO: Reevaluate this connection timeout based on more wide-scale  
  72.         // data collection and possibly different for wifi vs. 3G.  
  73.         HttpConnectionParams.setConnectionTimeout(httpParams, 5000);  
  74.         HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);  
  75.           
  76.           
  77.         /* Make a thread safe connection manager for the client */  
  78.         HttpClient httpClient = new DefaultHttpClient(httpParams);  
  79.   
  80.         return httpClient.execute(httpRequest);  
  81.     }  
  82.       
  83.       
  84.   
  85.     static HttpUriRequest createMultiPartRequest(Request<?> request,  
  86.             Map<String, String> additionalHeaders) throws AuthFailureError {  
  87.         switch (request.getMethod()) {  
  88.             case Method.DEPRECATED_GET_OR_POST: {  
  89.                 // This is the deprecated way that needs to be handled for backwards compatibility.  
  90.                 // If the request's post body is null, then the assumption is that the request is  
  91.                 // GET.  Otherwise, it is assumed that the request is a POST.  
  92.                 byte[] postBody = request.getBody();  
  93.                 if (postBody != null) {  
  94.                     HttpPost postRequest = new HttpPost(request.getUrl());  
  95.                     if(request.getBodyContentType() != null)  
  96.                         postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());  
  97.                     HttpEntity entity;  
  98.                     entity = new ByteArrayEntity(postBody);  
  99.                     postRequest.setEntity(entity);  
  100.                     return postRequest;  
  101.                 } else {  
  102.                     return new HttpGet(request.getUrl());  
  103.                 }  
  104.             }  
  105.             case Method.GET:  
  106.                 return new HttpGet(request.getUrl());  
  107.             case Method.DELETE:  
  108.                 return new HttpDelete(request.getUrl());  
  109.             case Method.POST: {  
  110.                 HttpPost postRequest = new HttpPost(request.getUrl());  
  111.                 postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());  
  112.                 setMultiPartBody(postRequest,request);  
  113.                 return postRequest;  
  114.             }  
  115.             case Method.PUT: {  
  116.                 HttpPut putRequest = new HttpPut(request.getUrl());  
  117.                 if(request.getBodyContentType() != null)  
  118.                     putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());  
  119.                 setMultiPartBody(putRequest,request);  
  120.                 return putRequest;  
  121.             }  
  122.             // Added in source code of Volley libray.  
  123.             case Method.PATCH: {  
  124.                 HttpPatch patchRequest = new HttpPatch(request.getUrl());  
  125.                 if(request.getBodyContentType() != null)  
  126.                     patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());  
  127.                 return patchRequest;  
  128.             }  
  129.             default:  
  130.                 throw new IllegalStateException("Unknown request method.");  
  131.         }  
  132.     }  
  133.       
  134.     /**  
  135.      * If Request is MultiPartRequest type, then set MultipartEntity in the  
  136.      * httpRequest object.  
  137.      *   
  138.      * @param httpRequest  
  139.      * @param request  
  140.      * @throws AuthFailureError  
  141.      */  
  142.     private static void setMultiPartBody(HttpEntityEnclosingRequestBase httpRequest,  
  143.             Request<?> request) throws AuthFailureError {  
  144.   
  145.         // Return if Request is not MultiPartRequest  
  146.         if (!(request instanceof MultiPartRequest)) {  
  147.             return;  
  148.         }  
  149.   
  150.         // MultipartEntity multipartEntity = new  
  151.         // MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);  
  152.   
  153.         MultipartEntityBuilder builder = MultipartEntityBuilder.create();  
  154.   
  155.         /* example for setting a HttpMultipartMode */  
  156.         builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);  
  157.   
  158.         // Iterate the fileUploads  
  159.         Map<String, File> fileUpload = ((MultiPartRequest) request).getFileUploads();  
  160.         for (Map.Entry<String, File> entry : fileUpload.entrySet()) {  
  161.   
  162.             builder.addPart(((String) entry.getKey()), new FileBody((File) entry.getValue()));  
  163.         }  
  164.   
  165.         ContentType contentType = ContentType.create(HTTP.PLAIN_TEXT_TYPE, HTTP.UTF_8);  
  166.         // Iterate the stringUploads  
  167.         Map<String, String> stringUpload = ((MultiPartRequest) request).getStringUploads();  
  168.         for (Map.Entry<String, String> entry : stringUpload.entrySet()) {  
  169.             try {  
  170.                 builder.addPart(((String) entry.getKey()),  
  171.                         new StringBody((String) entry.getValue(), contentType));  
  172.             } catch (Exception e) {  
  173.                 e.printStackTrace();  
  174.             }  
  175.         }  
  176.   
  177.         httpRequest.setEntity(builder.build());  
  178.     }  
  179.   
  180. }  


3. 实现MultiPartRequest, 这个接口是为了方便扩展

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.example.volleytest;  
  2.   
  3. import java.io.File;  
  4. import java.util.Map;  
  5.   
  6. /** 
  7.  * @author ZhiCheng Guo 
  8.  * @version 2014年10月7日 上午11:04:36 
  9.  */  
  10. public interface MultiPartRequest {  
  11.   
  12.     public void addFileUpload(String param,File file);   
  13.       
  14.     public void addStringUpload(String param,String content);   
  15.       
  16.     public Map<String,File> getFileUploads();  
  17.       
  18.     public Map<String,String> getStringUploads();   
  19. }  


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Copyright 2013 Mani Selvaraj 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. package com.example.volleytest;  
  18.   
  19. import java.io.File;  
  20. import java.io.UnsupportedEncodingException;  
  21. import java.util.HashMap;  
  22. import java.util.Map;  
  23.   
  24. import com.android.volley.NetworkResponse;  
  25. import com.android.volley.Request;  
  26. import com.android.volley.Response;  
  27. import com.android.volley.Response.ErrorListener;  
  28. import com.android.volley.Response.Listener;  
  29. import com.android.volley.toolbox.HttpHeaderParser;  
  30.   
  31. /** 
  32.  * MultipartRequest - To handle the large file uploads. 
  33.  * Extended from JSONRequest. You might want to change to StringRequest based on your response type. 
  34.  * @author Mani Selvaraj 
  35.  * 
  36.  */  
  37. public class MultiPartStringRequest extends Request<String> implements MultiPartRequest{  
  38.   
  39.     private final Listener<String> mListener;  
  40.     /* To hold the parameter name and the File to upload */  
  41.     private Map<String,File> fileUploads = new HashMap<String,File>();  
  42.       
  43.     /* To hold the parameter name and the string content to upload */  
  44.     private Map<String,String> stringUploads = new HashMap<String,String>();  
  45.       
  46.     /** 
  47.      * Creates a new request with the given method. 
  48.      * 
  49.      * @param method the request {@link Method} to use 
  50.      * @param url URL to fetch the string at 
  51.      * @param listener Listener to receive the String response 
  52.      * @param errorListener Error listener, or null to ignore errors 
  53.      */  
  54.     public MultiPartStringRequest(int method, String url, Listener<String> listener,  
  55.             ErrorListener errorListener) {  
  56.         super(method, url, errorListener);  
  57.         mListener = listener;  
  58.     }  
  59.   
  60.   
  61.   
  62.     public void addFileUpload(String param,File file) {  
  63.         fileUploads.put(param,file);  
  64.     }  
  65.       
  66.     public void addStringUpload(String param,String content) {  
  67.         stringUploads.put(param,content);  
  68.     }  
  69.       
  70.     /** 
  71.      * 要上传的文件 
  72.      */  
  73.     public Map<String,File> getFileUploads() {  
  74.         return fileUploads;  
  75.     }  
  76.       
  77.     /** 
  78.      * 要上传的参数 
  79.      */  
  80.     public Map<String,String> getStringUploads() {  
  81.         return stringUploads;  
  82.     }  
  83.       
  84.   
  85.     @Override  
  86.     protected Response<String> parseNetworkResponse(NetworkResponse response) {  
  87.         String parsed;  
  88.         try {  
  89.             parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));  
  90.         } catch (UnsupportedEncodingException e) {  
  91.             parsed = new String(response.data);  
  92.         }  
  93.         return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));  
  94.     }  
  95.   
  96.     @Override  
  97.     protected void deliverResponse(String response) {  
  98.         if(mListener != null) {  
  99.             mListener.onResponse(response);  
  100.         }  
  101.     }  
  102.       
  103.     /** 
  104.      * 空表示不上传 
  105.      */  
  106.     public String getBodyContentType() {  
  107.         return null;  
  108.     }  
  109. }  

3.使用方法和volley原生的request的使用方法是一样的, 只是要使用新的Stack, 如下面的是put的方法的使用方法. 如果是post, 就修改成post方法就可以了

        RequestQueue mSingleQueue = Volley.newRequestQueue(this, new MultiPartStack());    MultiPartStringRequest multiPartRequest = new MultiPartStringRequest(            Request.Method.PUT, url, responseListener, errorListener) {        @Override        public Map<String, File> getFileUploads() {            return files;        }        @Override        public Map<String, String> getStringUploads() {            return params;        }    };    mSingeQueue.add(multiPartRequest)


0 0