Skip to content

Instantly share code, notes, and snippets.

@w4lle
Created November 28, 2016 13:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save w4lle/aecfecc5285c6d8e85eeff80685cadbb to your computer and use it in GitHub Desktop.
Save w4lle/aecfecc5285c6d8e85eeff80685cadbb to your computer and use it in GitHub Desktop.
Volley MultipartRequest
/*
* 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