我正在使用MultiPartRequester类将多部分图像上传到服务器,但是我发现其中的某些部分已被弃用。例如HttpConnectionParams,getConnectionManager()等,因此有人拥有不使用新API级别进行文件上传的新解决方案吗?
我正在使用此代码。
public class MultiPartRequester { private Map<String, String> map; private AsyncTaskCompleteListener mAsynclistener; private int serviceCode; private HttpClient httpclient; private Activity activity; private AsyncHttpRequest request; private static final String TAG = "MultiPartRequester"; public MultiPartRequester(Activity activity, Map<String, String> map, int serviceCode, AsyncTaskCompleteListener asyncTaskCompleteListener) { this.map = map; this.serviceCode = serviceCode; this.activity = activity; } class AsyncHttpRequest extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... urls) { map.remove("url"); try { HttpPost httppost = new HttpPost(urls[0]); httpclient = new DefaultHttpClient(); HttpConnectionParams.setConnectionTimeout( httpclient.getParams(), 600000); MultipartEntityBuilder builder = MultipartEntityBuilder .create(); for (String key : map.keySet()) { if (key.equalsIgnoreCase(AndyConstants.Params.PICTURE)) { File f = new File(map.get(key)); builder.addBinaryBody(key, f, ContentType.MULTIPART_FORM_DATA, f.getName()); } else { builder.addTextBody(key, map.get(key), ContentType .create("text/plain", MIME.UTF8_CHARSET)); } AppLog.Log(TAG, key + "---->" + map.get(key)); } httppost.setEntity(builder.build()); ActivityManager manager = (ActivityManager) activity .getSystemService(Context.ACTIVITY_SERVICE); if (manager.getMemoryClass() < 25) { System.gc(); } HttpResponse response = httpclient.execute(httppost); String responseBody = EntityUtils.toString( response.getEntity(), "UTF-8"); reurn responseBody; } catch (Exception e) { e.printStackTrace(); } catch (OutOfMemoryError oume) { System.gc(); } finally { if (httpclient != null) httpclient.getConnectionManager().shutdown(); } return null; } @Override protected void onPostExecute(String response) { if (mAsynclistener != null) { mAsynclistener.onTaskCompleted(response, serviceCode); } } } public void cancelTask() { request.cancel(true); AppLog.Log(TAG, "task is canelled"); } }
这是FileUploadMultipartRequest类:
/** * Multipart request for sending files over http * also can return generic type of response data * @param <T> the type of data for http responses */ public class FileUploadMultipartRequest<T> extends BaseRequest<T> { private static final MediaType JSON = MediaType.parse("application/json"); private File[] files; private String jsonString; private RequestBody requestBody; public FileUploadMultipartRequest(String url, Map<String, String> headers, String jsonString, OnEmptyResponseListener listener, ErrorTypeListener errorListener, File... files) { super(Method.POST, url, headers, listener, new ErrorListenerImpl(errorListener)); this.jsonString = jsonString; this.files = files; } public FileUploadMultipartRequest(String url, Map<String, String> headers, String jsonString, Type responseType, Response.Listener listener, ErrorTypeListener errorListener, File... files) { super(Method.POST, url, headers, responseType, listener, new ErrorListenerImpl(errorListener)); this.jsonString = jsonString; this.files = files; } @Override public String getBodyContentType() { return buildMultipartEntity().contentType().toString(); } @Override public byte[] getBody() throws AuthFailureError { Buffer buffer = new Buffer(); try { buildMultipartEntity().writeTo(buffer); } catch (IOException e) { VolleyLog.e("IOException writing to ByteArrayOutputStream"); } return buffer.readByteArray(); } private RequestBody buildMultipartEntity() { if (requestBody == null) { MultipartBuilder multipartBuilder = new MultipartBuilder().type(MultipartBuilder.FORM); multipartBuilder.addPart( Headers.of("Content-Disposition", "form-data; name=json-part"), RequestBody.create(JSON, jsonString)); for (File file : files) { String contentType = URLConnection.guessContentTypeFromName(file.getName()); multipartBuilder.addFormDataPart("files-part", file.getName(), RequestBody.create(MediaType.parse(contentType), file)); } requestBody = multipartBuilder.build(); } return requestBody; } }
这是BaseRequest类:
/** * this a abstract request class for handling http http responses * note : all volley request should extend this class for http request * * @param <T> the type of data for http responses */ public abstract class BaseRequest<T> extends Request<T> { private final Map<String, String> headers; /** * the type response that {@link com.android.volley.Response.Listener} should return */ private Type responseType; /** * generic listener for successful http request */ private Response.Listener<T> listener; /** * constructor for request that returns data type {@link T} * * @param method http verb e.g. POST, GET & etc * @param url request URL * @param headers http headers * @param responseType type of data that response should return * @param listener event for successful request * @param errorListener event for failed request */ public BaseRequest(int method, String url, Map<String, String> headers, Type responseType, Response.Listener listener, ErrorListenerImpl errorListener) { super(method, url, errorListener); this.headers = headers; this.responseType = responseType; //noinspection unchecked this.listener = listener; } /** * constructor for requests with no returning data * @param method http verb e.g. POST, GET & etc * @param url request URL * @param headers http headers * @param onEmptyResponseListener event for successful request (but no data return) * @param errorListener event for failed request */ public BaseRequest(int method, String url, Map<String, String> headers, OnEmptyResponseListener onEmptyResponseListener, ErrorListenerImpl errorListener) { super(method, url, errorListener); this.headers = headers; //noinspection unchecked listener = new OnEmptyResponseImpl(onEmptyResponseListener); } protected Response<T> parseNetworkResponse(NetworkResponse response) { // if response type is null so just pass null to success event if (this.responseType == null && new String(response.data).isEmpty()) { return Response.success(null, HttpHeaderParser.parseCacheHeaders(response)); } // if response type is specified try { Gson gson = new Gson(); String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); // we use GSON to reflect response data to the generic type and pass to success event T parseObject = gson.fromJson(json, responseType); return Response.success(parseObject, HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JsonSyntaxException e) { return Response.error(new ParseError(e)); } } @Override protected void deliverResponse(T response) { if (listener != null) { // call successful response event when listener not empty listener.onResponse(response); } } @Override protected void onFinish() { super.onFinish(); listener = null; } /** * this class forward response event to {@link com.khosravi.mehrdadz.garagesale.Network.RequestType.BaseRequest.OnEmptyResponseListener} * when volley {@link com.android.volley.Response.Listener} is called */ private static class OnEmptyResponseImpl implements Response.Listener { OnEmptyResponseListener onEmptyResponseListener; /** * @param onEmptyResponseListener interface for response with not data return */ public OnEmptyResponseImpl(OnEmptyResponseListener onEmptyResponseListener) { this.onEmptyResponseListener = onEmptyResponseListener; } /** * we call {@link com.khosravi.mehrdadz.garagesale.Network.RequestType.BaseRequest.OnEmptyResponseImpl#onEmptyResponseListener} * when volley listener is class so no null object passed to the event * * @param response */ @Override public void onResponse(Object response) { onEmptyResponseListener.OnEmptyResponse(); } } /** * interface for http response with no returning data */ public interface OnEmptyResponseListener { void OnEmptyResponse(); } public Map<String, String> getHeaders() throws AuthFailureError { return this.headers != null ? this.headers : super.getHeaders(); } }
这是GsonRequest类:
@SuppressWarnings("JavaDoc") /** * Gson request that return generic type of response data * @param <T> the type of data for http responses */ public class GsonRequest<T> extends BaseRequest<T> { protected static final String PROTOCOL_CHARSET = "utf-8"; /** * Content type for request. */ private static final String PROTOCOL_CONTENT_TYPE = String.format("application/json; charset=%s", PROTOCOL_CHARSET); /** * message body of http request */ private final String requestBody; /** * Request return response object of Type {@link T} * @param url * @param headers * @param type * @param listener * @param errorListener */ public GsonRequest(String url, Map<String, String> headers, Type type, Listener<T> listener, ErrorTypeListener errorListener) { super(Method.GET, url, headers, type, listener, new ErrorListenerImpl(errorListener)); requestBody = null; } /** * Request return response object of Type {@link T} * @param url * @param headers * @param jsonObject json object to send with request * @param type * @param listener * @param errorListener */ public GsonRequest(String url, Map<String, String> headers, JSONObject jsonObject, Type type, Listener<T> listener, ErrorTypeListener errorListener) { super(Method.POST, url, headers, type, listener, new ErrorListenerImpl(errorListener)); this.requestBody = jsonObject == null ? null : jsonObject.toString(); } /** * Request return empty response * @param url * @param headers * @param jsonObject json object to send with request * @param listener * @param errorListener */ public GsonRequest(String url, Map<String, String> headers, JSONObject jsonObject, OnEmptyResponseListener listener, ErrorTypeListener errorListener) { super(Method.POST, url, headers, listener, new ErrorListenerImpl(errorListener)); this.requestBody = jsonObject == null ? null : jsonObject.toString(); } /** * Request return empty response * @param url * @param headers * @param listener * @param errorListener */ public GsonRequest(String url, Map<String, String> headers, BaseRequest.OnEmptyResponseListener listener, ErrorTypeListener errorListener) { super(Method.GET, url, headers, listener, new ErrorListenerImpl(errorListener)); requestBody = null; } @Override public String getBodyContentType() { return PROTOCOL_CONTENT_TYPE; } @Override public byte[] getBody() { try { return requestBody == null ? null : requestBody.getBytes(PROTOCOL_CHARSET); } catch (UnsupportedEncodingException uee) { VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", requestBody, PROTOCOL_CHARSET); return null; } } }
鳕鱼样本:
public class MyRequest { public MyRequest(Context context) { volleySingleton = VolleySingleton.getInstance(context); } private static final String INSERT_NEW_PIC = "INSERT_NEW_PIC"; public void UploadNewPic(File[] Images, BaseRequest.OnEmptyResponseListener listener, ErrorTypeListener errorListener) { FileUploadMultipartRequest fileUploadMultipartRequest = new FileUploadMultipartRequest("url", null, null, listener, errorListener,Images); volleySingleton.addToRequestQueue(fileUploadMultipartRequest, INSERT_NEW_PIC); } }
您可以在我的请求中添加更多请求,然后随时随地致电。像这样:
MyRequest myRequest; private HashMap<FrameLayout,File> Images; myRequest = new MyRequest(context); Images = new HashMap<>(); myRequest.UploadNewPic(Images.values().toArray(new File[Images.values().size()]), new BaseRequest.OnEmptyResponseListener() { @Override public void OnEmptyResponse() { Toast.makeText(getApplicationContext(), "added pics successfully", Toast.LENGTH_LONG).show(); finish(); } }, new ErrorTypeListener() { @Override public void onError(ErrorType errorType) { } });
服务器端编码(.net):
public class CustomMultipartFormDataStreamProvider : MultipartFormDataStreamProvider { public CustomMultipartFormDataStreamProvider(string path) : base(path) { } //below only allows images and pdf files to be uploaded. public override Stream GetStream(HttpContent parent, System.Net.Http.Headers.HttpContentHeaders headers) { // following line handles other form fields other than files. if (String.IsNullOrEmpty(headers.ContentDisposition.FileName)) return base.GetStream(parent, headers); // restrict what filetypes can be uploaded List<string> extensions = new List<string> { "png", "gif", "jpg", "jpeg", "tiff", "pdf", "tif", "bmp","doc","docx","ods","xls","odt","csv","txt","rtf" }; var filename = headers.ContentDisposition.FileName.Replace("\"", string.Empty); // correct for chrome. //make sure it has an extension if (filename.IndexOf('.') < 0) { return Stream.Null; } //get the extension var extension = filename.Split('.').Last(); //Return stream if match otherwise return null stream. return extensions.Contains(extension) ? base.GetStream(parent, headers) : Stream.Null; } public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers) { var name = !string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName) ? headers.ContentDisposition.FileName : "NoName"; name = name.Replace("\"", string.Empty); //name = (Guid.NewGuid()).ToString() +System.IO.Path.GetExtension(name); //this is here because Chrome submits files in quotation marks which get treated as part of the filename and get escaped name = Path.GetRandomFileName().Replace(".", string.Empty) + Path.GetExtension(name); //this is here because Chrome submits files in quotation marks which get treated as part of the filename and get escaped return name; } }
公共类ImageRouteHandler:
IRouteHandler { public IHttpHandler GetHttpHandler(RequestContext requestContext) { var filename = requestContext.RouteData.Values["filename"] as string; var section = requestContext.RouteData.Values["section"] as string; if (string.IsNullOrEmpty(filename) && string.IsNullOrEmpty(section)) { // return a 404 HttpHandler here requestContext.HttpContext.Response.StatusCode = 404; requestContext.HttpContext.Response.End(); return null; } requestContext.HttpContext.Response.Clear(); requestContext.HttpContext.Response.Cache.SetMaxAge(TimeSpan.FromSeconds(500000)); requestContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.Public); requestContext.HttpContext.Response.ContentType = GetContentType(filename); // find physical path to image here. var path = GetPath(section); if (string.IsNullOrEmpty(path)) { // return a 404 HttpHandler here requestContext.HttpContext.Response.StatusCode = 404; requestContext.HttpContext.Response.End(); return null; } var filepath = requestContext.HttpContext.Server.MapPath(path + filename); requestContext.HttpContext.Response.WriteFile(filepath); requestContext.HttpContext.Response.End(); return null; } private static string GetPath(string section) { switch (section) { case "user": return "~/Resources/Users/";//where you want save pics in project } return ""; } private static string GetContentType(string path) { switch (Path.GetExtension(path)) { case ".bmp": return "Image/bmp"; case ".gif": return "Image/gif"; case ".jpg": return "Image/jpeg"; case ".png": return "Image/png"; } return ""; } }
并像这样更改您的RouteConfige:
public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); // proccess all for protected resources with ImageRouteHandler routes.Add("ImagesRoute", new Route("res/{section}/{filename}", new ImageRouteHandler())); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } }
服务器端的示例代码:
public interface IUserManagement { void UploadNewPics( IEnumerable<string> imageUrls); } public class UserManagement : IUserManagement { public void UploadNewPics(IEnumerable<string> imageUrls) { using (var ctx = new Context()) { foreach (var imageUrl in imageUrls) { //save to data base . . . } try { ctx.SaveChanges(); } catch (Exception e) { throw; } } } } public class UserApiController : ApiController { [HttpPost] public async Task<IHttpActionResult> UploadNewPics() { if (!Request.Content.IsMimeMultipartContent()) { throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); } var root = HttpContext.Current.Server.MapPath("~/Resources/Users/"); var provider = new CustomMultipartFormDataStreamProvider(root); try { // Read the form data. await Request.Content.ReadAsMultipartAsync(provider); IUserManagement userManagement = new UserManagement(); var imageUrls = provider.FileData.Select(x=> Path.GetFileName(x.LocalFileName)); //userManagement.UploadUserImage(uploadImageJson, Path.GetFileName(imageFile.LocalFileName), (long)imageFile.Headers.ContentLength); userManagement.UploadNewPics(imageUrls); } catch (Exception e) { return InternalServerError(); } return Ok(); } }