Created
November 28, 2016 13:32
-
-
Save w4lle/aecfecc5285c6d8e85eeff80685cadbb to your computer and use it in GitHub Desktop.
Volley MultipartRequest
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Created by w4lle 2016 . | |
* Copyright (c) 2016 Boohee, Inc. All rights reserved. | |
*/ | |
package com.boohee.one.http.client; | |
import com.android.volley.AuthFailureError; | |
import com.boohee.one.http.JsonCallback; | |
import com.boohee.one.http.JsonParams; | |
import com.google.gson.Gson; | |
import com.google.gson.reflect.TypeToken; | |
import java.io.ByteArrayInputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.DataOutputStream; | |
import java.io.IOException; | |
import java.io.UnsupportedEncodingException; | |
import java.util.HashMap; | |
import java.util.Map; | |
/** | |
* multipart 上传文件 | |
*/ | |
public class MultipartRequest extends BaseJsonRequest { | |
private final String twoHyphens = "--"; | |
private final String lineEnd = "\r\n"; | |
private final String boundary = "apiclient-" + System.currentTimeMillis(); | |
/** | |
* Default constructor with predefined header and post method. | |
* | |
* @param url request destination | |
* @param params predefined custom header | |
* @param callback | |
*/ | |
public MultipartRequest(String url, JsonParams params, JsonCallback callback){ | |
super(Method.POST, url, params, callback, callback); | |
} | |
@Override | |
public String getBodyContentType() { | |
return "multipart/form-data;charset=utf-8;boundary=" + boundary ; | |
} | |
@Override | |
public byte[] getBody() { | |
ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
DataOutputStream dos = new DataOutputStream(bos); | |
try { | |
// populate text payload | |
Map<String, String> params = getParams(); | |
if (params != null && params.size() > 0) { | |
textParse(dos, params, getParamsEncoding()); | |
} | |
// populate data byte payload | |
Map<String, DataPart> data = getByteData(); | |
if (data != null && data.size() > 0) { | |
dataParse(dos, data); | |
} | |
// close multipart form data after text and file data | |
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); | |
return bos.toByteArray(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} catch (AuthFailureError authFailureError) { | |
authFailureError.printStackTrace(); | |
} | |
return null; | |
} | |
@Override | |
protected Map<String, String> getParams() throws AuthFailureError { | |
JsonParams params = getJsonParams(); | |
Map<String, String> retMap = new Gson().fromJson(params.toString(), new TypeToken<HashMap<String, String>>() {}.getType()); | |
return retMap; | |
} | |
/** | |
* Custom method handle data payload. | |
* | |
* @return Map data part label with data byte | |
* @throws AuthFailureError | |
*/ | |
protected Map<String, DataPart> getByteData() throws AuthFailureError { | |
return null; | |
} | |
/** | |
* Parse string map into data output stream by key and value. | |
* | |
* @param dataOutputStream data output stream handle string parsing | |
* @param params string inputs collection | |
* @param encoding encode the inputs, default UTF-8 | |
* @throws IOException | |
*/ | |
private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException { | |
try { | |
for (Map.Entry<String, String> entry : params.entrySet()) { | |
buildTextPart(dataOutputStream, entry.getKey(), entry.getValue()); | |
} | |
} catch (UnsupportedEncodingException uee) { | |
throw new RuntimeException("Encoding not supported: " + encoding, uee); | |
} | |
} | |
/** | |
* Parse data into data output stream. | |
* | |
* @param dataOutputStream data output stream handle file attachment | |
* @param data loop through data | |
* @throws IOException | |
*/ | |
private void dataParse(DataOutputStream dataOutputStream, Map<String, DataPart> data) throws IOException { | |
for (Map.Entry<String, DataPart> entry : data.entrySet()) { | |
buildDataPart(dataOutputStream, entry.getValue(), entry.getKey()); | |
} | |
} | |
/** | |
* Write string data into header and data output stream. | |
* | |
* @param dataOutputStream data output stream handle string parsing | |
* @param parameterName name of input | |
* @param parameterValue value of input | |
* @throws IOException | |
*/ | |
private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException { | |
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd); | |
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd); | |
// dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd); | |
dataOutputStream.writeBytes(lineEnd); | |
dataOutputStream.write(parameterValue.getBytes("utf-8")); | |
dataOutputStream.writeBytes(lineEnd); | |
} | |
/** | |
* Write data file into header and data output stream. | |
* | |
* @param dataOutputStream data output stream handle data parsing | |
* @param dataFile data byte as DataPart from collection | |
* @param inputName name of data input | |
* @throws IOException | |
*/ | |
private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException { | |
dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd); | |
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + | |
inputName + "\"; filename=\"" + dataFile.getFileName() + "\"" + lineEnd); | |
if (dataFile.getType() != null && !dataFile.getType().trim().isEmpty()) { | |
dataOutputStream.writeBytes("Content-Type: " + dataFile.getType() + lineEnd); | |
} | |
dataOutputStream.writeBytes(lineEnd); | |
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent()); | |
int bytesAvailable = fileInputStream.available(); | |
int maxBufferSize = 1024 * 1024; | |
int bufferSize = Math.min(bytesAvailable, maxBufferSize); | |
byte[] buffer = new byte[bufferSize]; | |
int bytesRead = fileInputStream.read(buffer, 0, bufferSize); | |
while (bytesRead > 0) { | |
dataOutputStream.write(buffer, 0, bufferSize); | |
bytesAvailable = fileInputStream.available(); | |
bufferSize = Math.min(bytesAvailable, maxBufferSize); | |
bytesRead = fileInputStream.read(buffer, 0, bufferSize); | |
} | |
dataOutputStream.writeBytes(lineEnd); | |
} | |
/** | |
* Simple data container use for passing byte file | |
*/ | |
public class DataPart { | |
public String fileName; | |
public byte[] content; | |
public String type; | |
/** | |
* Default data part | |
*/ | |
public DataPart() { | |
} | |
/** | |
* Constructor with data. | |
* | |
* @param name label of data | |
* @param data byte data | |
*/ | |
public DataPart(String name, byte[] data) { | |
fileName = name; | |
content = data; | |
} | |
/** | |
* Constructor with mime data type. | |
* | |
* @param name label of data | |
* @param data byte data | |
* @param mimeType mime data like "image/jpeg" | |
*/ | |
public DataPart(String name, byte[] data, String mimeType) { | |
fileName = name; | |
content = data; | |
type = mimeType; | |
} | |
/** | |
* Getter file name. | |
* | |
* @return file name | |
*/ | |
public String getFileName() { | |
return fileName; | |
} | |
/** | |
* Setter file name. | |
* | |
* @param fileName string file name | |
*/ | |
public void setFileName(String fileName) { | |
this.fileName = fileName; | |
} | |
/** | |
* Getter content. | |
* | |
* @return byte file data | |
*/ | |
public byte[] getContent() { | |
return content; | |
} | |
/** | |
* Setter content. | |
* | |
* @param content byte file data | |
*/ | |
public void setContent(byte[] content) { | |
this.content = content; | |
} | |
/** | |
* Getter mime type. | |
* | |
* @return mime type | |
*/ | |
public String getType() { | |
return type; | |
} | |
/** | |
* Setter mime type. | |
* | |
* @param type mime type | |
*/ | |
public void setType(String type) { | |
this.type = type; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment