Multipart file upload with OkHttp + Spring - android

I recently switched to OkHttp. After the switch, the code below does the upload.
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"qqfile\""),
RequestBody.create(
MediaType.parse(filename),
new File(filename)))
.build();
If you compare images, the second image has multipartFiles size = 0. It should be of size = 1. How to populate multipartHttpRequest correctly using OkHttp to make server accept successful upload?
Controller code
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.util.WebUtils;
#RequestMapping (
method = RequestMethod.POST,
value = "/upload",
produces = MediaType.APPLICATION_JSON_VALUE + ";charset=UTF-8"
)
public String upload(
HttpServletRequest request,
HttpServletResponse response
) throws IOException {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
MultipartHttpServletRequest multipartHttpRequest =
WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);
final List<MultipartFile> files = multipartHttpRequest.getFiles("qqfile");
if (files.isEmpty()) {
LOG.error("qqfile name missing in request or no file uploaded");
return some error code here
}
MultipartFile multipartFile = files.iterator().next();
//process file code below
}
return failure;
}

You can get a MultipartFile more easier:
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(#RequestParam("qqfile") MultipartFile file) throws IOException {
if (!file.isEmpty()) {
// ...
}
return "failure";
}
And then, with OkHttp:
RequestBody body = new MultipartBuilder()
.addFormDataPart("qqfile", filename, RequestBody.create(MediaType.parse("media/type"), new File(filename)))
.type(MultipartBuilder.FORM)
.build();
Request request = new Request.Builder()
.url("/path/to/your/upload")
.post(body)
.build();
OkHttpClient client = new OkHttpClient();
Response response = client.newCall(request).execute();
That worked fine to me.
Be careful with MediaType.parse(filename), you must pass a valid type like text/plain, application/json, application/xml...

Builder requestBodyBuilder = new MultipartBody.Builder()
.setType(MultipartBody.FORM);
File file= new File(FILE_PATH + FILE_NAME);
requestBodyBuilder.addFormDataPart("file", FILE_NAME, RequestBody.create(MultipartBody.FORM, file));
fileVO.getOriginalFlnm()
you can omission this field.
And also you have to set 'MultipartHttpServletRequest' parameter AND consumes, produces in header
#PostMapping(path = "/save", consumes = "multipart/*", produces = "application/json;charset=utf-8")
public boolean CONTROLLER(MultipartHttpServletRequest request, #RequestParam Map<String, Object> param) {
boolean result = SERVICE.save(request, param);
return result;
}

Related

Multiple image uploading using multipart retrofit or volley

Hi Can any one Please help me out in uploading multiple images selected from gallery,
parameter is 'images' as array list
I have tried with this but no response can any one help me out..
This is my request body :
MediaType mediaType = MediaType.parse("multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW");
MultipartBody.Builder mRequestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM);
if (Imagepaths.size() > 0) {
for(String path:Imagepaths) {
File file = new File(path);
mediaType = path.endsWith("png") ?
MediaType.parse("image/png") : MediaType.parse("image/jpeg");
RequestBody imageBody = RequestBody.create(mediaType, file);
mRequestBody.addFormDataPart("images", file.getName(), imageBody);
}
}
RequestBody rb = mRequestBody.build();
This is the retrofit call :
#Multipart
#POST("upload_images/")
Call<ResponseBody> retrofitImageUpload(#Header("Authorization") String auth,
#Header("Content-Type") String contentType,
#Part("images") RequestBody req);

Multipart file upload using okhttp generated by postman

Generated the code below by postman:
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("multipart/form-data; boundary=---011000010111000001101001");
RequestBody body = RequestBody.create(mediaType, "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"image\"; filename=\"[object Object]\"\r\nContent-Type: false\r\n\r\n\r\n-----011000010111000001101001--");
Request request = new Request.Builder()
.url("http://foobar.com/newsfeed/photo")
.post(body)
.addHeader("content-type", "multipart/form-data; boundary=---011000010111000001101001")
.addHeader("x-access-token", "MczCvMEbllNhGaMwEDnGXuQjrwBAYuYleFlgsUZDWRYbVaohpEGgofonYcvHsgPaTnbzHxCvJWalYFTY")
.addHeader("accept-language", "ru")
.build();
Response response = client.newCall(request).execute();
This request make a file on Server with 0 Kb size. and I couldn't put a file. So, I have to put a file like this:
RequestBody body = RequestBody.create(mediaType, new File(filename));
But I got TimeOutExaption.
How to put a file by this kind of Rest API?
I found a way to multipart file upload by Ion.
Ion.with(context).load(url).setHeader("x-access-token", token)
.setMultipartParameter("x-access-token", token)
.setMultipartContentType("multipart/form-data")
.setMultipartFile("image", "image/jpeg", file)
.asString().withResponse().setCallback(new FutureCallback<Response<String>>() {
#Override
public void onCompleted(Exception e, Response<String> result) {
if (result != null)
onSuccess(result.getResult(), result.getHeaders().code());
}
});
Rest API:

Can't access POST parameter in okhttp3 Android

I am using okhttp3 for upload image on server and i success in Upload image but i can not POST parameter with MultipartBody
my code is here..
File sourceFile = new File(sourceImageFile);
Log.logInfo("File...::::" + sourceFile + " : " + sourceFile.exists());
final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
OkHttpClient client = App.getInstance().getOkHttpClient();
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(KEY_ACCESS_TOKEN, accessToken)
.addFormDataPart(KEY_FILE, "profile.png", RequestBody.create(MEDIA_TYPE_PNG, sourceFile))
.build();
Request request = new Request.Builder()
.url(URL_IMAGE_UPLOAD)
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
I want to add "key" and "value" by POST Method in above code So how can i do.
As I learned before, see this link https://stackoverflow.com/a/34127008/6554840
In that passed member_id with its value.
So you are passing values with KEY_ACCESS_TOKEN is must be work.
.addFormDataPart(KEY_ACCESS_TOKEN, accessToken)
will work as post parameter.
I hope it will work.
Note: Must be your Web side is working.
Use this you have to create HashMap<String, String> this way and add it to Builder.
These are the Imports.
import okhttp3.OkHttpClient;
import okhttp3.FormBody;
import okhttp3.Request;
import okhttp3.RequestBody;
Code:
// HashMap with Params
HashMap<String, String> params = new HashMap<>();
params.put( "Param1", "A" );
params.put( "Param2", "B" );
// Initialize Builder (not RequestBody)
FormBody.Builder builder = new FormBody.Builder();
// Add Params to Builder
for ( Map.Entry<String, String> entry : params.entrySet() ) {
builder.add( entry.getKey(), entry.getValue() );
}
// Create RequestBody
RequestBody formBody = builder.build();
// Create Request (same)
Request request = new Request.Builder()
.url( "url" )
.post( formBody )
.build();

Retrofit #body with #multipart having Issue

Image Multipart in class type object.
case 1. (Which I had done)
Service params:
{"id":"1","name":"vishal","image/file":""}
At that time my API of Retrofit
#Multipart
#POST("webservice")
Call<SignUpResp> loadSignupMultipart(#Part("description") RequestBody description, #Part MultipartBody.Part file, #QueryMap HashMap<String, String> params);
case 2. (Where I have Problem) with #Body class<UploadwithImage>
{
"methodName":"submitLevel1Part2Icon",
"userid":"150",
"headerData":{
"fiction":{
"icon_type":"1",
"icon_id":"3"},
"nonfiction":{
"icon_type":"2",
"icon_id":"4"},
"relation":{
"icon_type":"3",
"icon_id":"0",
"name":"Ronak",
"relative_image":"<File>",
"relation_id":"3"},
"self":{
"icon_type":"4",
"icon_id":"0"}
}
}
I am trying this API
#Multipart
#POST("webservice")
Call<SubmitLevel1Part2IconResp> loadLevel1halfIconswithImage(#Part("description") RequestBody description, #Part MultipartBody.Part file, #Body UploadwithImage uploadImage);
Java side
/**
* code for multipart
*/
// create RequestBody instance from file
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), fileUpload);
// MultipartBody.Part is used to send also the actual filename
MultipartBody.Part body = MultipartBody.Part.createFormData("methodName[headerData][relation][relative_image]", fileUpload.getName(), requestFile);
// add another part within the multipart request
String descriptionString = "hello, this is description speaking";
RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString);
call = service.loadLevel1halfIconswithImage(description, body, levelOneHalfIcons);
I don't know why but it returns error like:
"#Body parameters cannot be used with form or multi-part encoding"
Any Help would Be Appreciated.
Change your method to
#Multipart
#POST("users/{id}/user_photos")
Call<models.UploadResponse> uploadPhoto(#Path("id") int userId, #PartMap Map<String, RequestBody> params);
Now to create your request parameters,
//All the String parameters, you have to put like
Map<String, RequestBody> map = new HashMap<>();
map.put("methodName", toRequestBody(methodName));
map.put("userid", toRequestBody(userId));
map.put("relation", toRequestBody(relation));
map.put("icon_type", toRequestBody(iconType));
map.put("icon_id", toRequestBody(iconId));
map.put("name", toRequestBody(name));
map.put("relation_id", toRequestBody(relationId));
//To put your image file you have to do
File file = new File("file_name");
RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), file);
map.put("relative_image\"; filename=\"some_file_name.png\"", fileBody);
// This method converts String to RequestBody
public static RequestBody toRequestBody (String value) {
RequestBody body = RequestBody.create(MediaType.parse("text/plain"), value);
return body ;
}
//To send your request
call = service.loadLevel1halfIconswithImage(description, params);
In case you do not want to use PartMap, you can simply pass them as parameters. Check my answer https://stackoverflow.com/a/37052548/1320616 to get some clue on sending image file with request.
As simple way, I have done like this:
I have tested by changing
Call<Result> resultCall = service.uploadImage(body);
to
Call<Result> resultCall = service.uploadImage(body, result); where result is
Result.java class (Response) of my API:
public class Result {
#SerializedName("result")
#Expose
private String result;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#SerializedName("value")
#Expose
private String value;
/**
* #return The result
*/
public String getResult() {
return result;
}
/**
* #param result The result
*/
public void setResult(String result) {
this.result = result;
}
}
and created object like:
Result result = new Result();
result.setResult("success");
result.setValue("my value");
You can change your class as per your need then pass object when you send request. So your ApiService class will be like:
ApiService.java
/**
* #author Pratik Butani on 23/4/16.
*/
public interface ApiService {
/*
Retrofit get annotation with our URL
And our method that will return us the List of Contacts
*/
#Multipart
#POST("upload.php")
Call<Result> uploadImage(#Part MultipartBody.Part file, #Part("result") Result result);
}
and My PHP code is:
<?php
$file_path = "";
$var = $_POST['result']; //here I m getting JSON
$file_path = $file_path . basename( $_FILES['uploaded_file']['name']);
if(move_uploaded_file($_FILES['uploaded_file']['tmp_name'], $file_path)) {
$result = array("result" => "success", "value" => $var);
} else{
$result = array("result" => "error");
}
echo json_encode($result);
?>
Hope it will helps you. Thank you.
You can also use a Map with RequestBody as value and string as keys to add parameters and you can send this using Multipart and PartMap.
Check the following code, hope it will help :
#Multipart
#POST("/add")
Call<ResponseBody> addDocument(#PartMap Map<String,RequestBody> params);
Map<String, RequestBody> map = new HashMap<>();
map.put("user_id", RequestBody.create(MediaType.parse("multipart/form-data"), SessionManager.getInstance().getCurrentUserId()));
map.put("doc_name", RequestBody.create(MediaType.parse("multipart/form-data"), CommonUtils.removeExtension(textFile.getName())));
map.put("doc_category", RequestBody.create(MediaType.parse("multipart/form-data"), category));
map.put("doc_image_file", RequestBody.create(MediaType.parse("multipart/form-data"), imageFile));
map.put("doc_text_content", RequestBody.create(MediaType.parse("multipart/form-data"), body));
map.put("doc_update_time", RequestBody.create(MediaType.parse("multipart/form-data"), "" + new Date(textFile.lastModified())));
We can add all request parameter in multipart body builder with specified type like in below one image file. I have set media type parse multipart/form-data and some other parameter I have set media type parse text/plain. This builder will build to make Multipart Body and can send by using body annotation in multipart body.
#Multipart
#POST("user/update")
Call<ResponseBody> addDocument(##Part MultipartBody file);
final MultipartBody.Builder requestBodyBuilder = new MultipartBody.Builder()
.setType(MultipartBody.FORM);
requestBodyBuilder.addFormDataPart("doc_image_file", imageFile.getName(),
RequestBody.create(MediaType.parse("multipart/form-data"), imageFile));
requestBodyBuilder.addFormDataPart("user_id", null, RequestBody.create(MediaType.parse("text/plain"),"12"));
requestBodyBuilder.addFormDataPart("doc_name", null, RequestBody.create(MediaType.parse("text/plain"),"myfile"));
requestBodyBuilder.addFormDataPart("doc_category", null, RequestBody.create(MediaType.parse("text/plain"),category));
requestBodyBuilder.addFormDataPart("doc_image_file", imageFile.getName(),RequestBody.create(MediaType.parse("multipart/form-data"),imageFile));
requestBodyBuilder.addFormDataPart("doc_text_content", null, RequestBody.create(MediaType.parse("text/plain"),body));
RequestBody multipartBody = requestBodyBuilder.build();
Here is my json request format is :
{
"task":{
"category_id":"1",
"price":"10",
"description":"1",
"task_videos_attributes":[
{
"link":"video file goes here",
"size":"100x100"
}
]
}
}
// my request becomes
HashMap<String, RequestBody> task = new HashMap();
task.put("task[category_id]", createPartFromString(categoryId));
task.put("task[price]", createPartFromString("" + etPrice.getText().toString()));
task.put("task[description]", createPartFromString("" + etDescription.getText().toString()));
// for videos file list
final List<MultipartBody.Part> body = new ArrayList<>();
for (int i = 0; i < videos.size(); i++) {
task.put("task[task_videos_attributes][" + i+ "][size]", createPartFromString("100x100"));
File videoFile = new File(videos.get(i));
RequestBody requestBody = RequestBody.create(MediaType.parse("video/mp4"), videoFile);
MultipartBody.Part fileToUpload = MultipartBody.Part.createFormData("task[task_videos_attributes][" + i + "][link]", videoFile.getName(), requestBody);
body.add(fileToUpload);
}
// here is a final call
new RestClient(this).getInstance().get().postTask(body, task).enqueue(callback);
// This function converts my string to request body
#NonNull
private RequestBody createPartFromString(String descriptionString) {
if (descriptionString == null)
return RequestBody.create(MultipartBody.FORM, "");
return RequestBody.create(
MultipartBody.FORM, descriptionString);
}
Hope this helps you...
Just follow how the web browser is doing multipart. They put nested keys in "[]" and give key to the images too.
Call<SubmitLevel1Part2IconResp> loadLevel1halfIconswithImage(#Part("headerdata[relation][icon_type]") RequestBody icon_type, #Part("headerdata[relation][name]") RequestBody name, #Part MultipartBody.Part file);
And then in java
// MultipartBody.Part is used to send also the actual filename
MultipartBody.Part body = MultipartBody.Part.createFormData("headerdata[relation][relative_image]", fileUpload.getName(), requestFile);
call = service.loadLevel1halfIconswithImage(icon_type, name, body);
https://www.linkedin.com/pulse/retrofit-2-how-upload-multiple-files-server-mahesh-gawale
I guess the best answer to this question can be found here. It worked perfectly for me.
This is the example of uploading an array of files using retrofit in Android.
This is how the service will look like
public interface ApiService {
#POST("/event/store")
Call<ResModel> event_store(#Body RequestBody file);
}
This is how the Client class look like
public class ApiClient {
public static final String API_BASE_URL = "api base url";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder = new Retrofit.Builder().baseUrl(API_BASE_URL).addConverterFactory(GsonConverterFactory.create());
public static ApiService createService(Class<ApiService> serviceClass)
{
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
}
Upload like this in activity or fragment or where you want
ApiService service = ApiClient.createService(ApiService.class);
MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
builder.addFormDataPart("event_name", "xyz");
builder.addFormDataPart("desc", "Lorem ipsum");
// Single Image
builder.addFormDataPart("files",file1.getName(),RequestBody.create(MediaType.parse("image/*"), file1));
// Multiple Images
for (int i = 0; i <filePaths.size() ; i++) {
File file = new File(filePaths.get(i));
RequestBody requestImage = RequestBody.create(MediaType.parse("multipart/form-data"), file);
builder.addFormDataPart("event_images[]", file.getName(), RequestBody.create(MediaType.parse("multipart/form-data"), file));
}
MultipartBody requestBody = builder.build();
Call<ResModel> call = service.event_store(requestBody);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Toast.makeText(getBaseContext(),"All fine",Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(getBaseContext(),t.getMessage(),Toast.LENGTH_SHORT).show();
}
});
Note: filePaths.size() is a Arraylist of pickup Images Paths.
I hope this post is useful to you. kindly share your feedback as a comment here.
this works for me.
What I did was add every additional params using:
MultipartBody.Part Partname = MultipartBody.Part.createFormData("ParamName", "Value");
Mabe you don't need to create another body, but just add others params apart from the file or whatever you are sending. finally at the interface I put as a params every bodypart that I need.
#Multipart
#POST("api/service/uploadVideo")
Call<ResponseBody> uploadVideoToServer(
#Part MultipartBody.Part video,
#Part MultipartBody.Part param2,
#Part MultipartBody.Part param3 ....
);

Creating a proper MultipartBuilder Http Request with OKHttp

ild like to recode my project and use okHttp instead of the default HttpClient implemented in Android.
I've downloaded the latest source of the okhttp-main release.
Now ive found some examples how to create and build a POST Request.
Now my Problem. I want to create a RequestBody which keep several Data (Strings, Files, whatever) but i can't assign them directly.
Means that the RequestBuilder must go through different Loops where it get it's data added.
OkHTTPs RequestBody seems to need the data immediatly as listed in the example
https://github.com/square/okhttp/wiki/Recipes
When i want to try something like
RequestBody requestBody = new MultipartBuilder().type(MultipartBuilder.FORM);
for (Object aMData : dataClass.getData().entrySet()) {
Map.Entry mapEntry = (Map.Entry) aMData;
String keyValue = (String) mapEntry.getKey();
String value = (String) mapEntry.getValue();
requestBody.addPart(keyValue, value);
}
for (DataPackage dataPackage : dataClass.getDataPackages()) {
requestBody.addPart("upfile[]", dataPackage.getFile());
}
requestBody.build();
it fails because build() itself create the RequestBody. Before it's just a MultipartBuilder(). If i try to force the type to RequestBody it wont compile/run.
So, what is the proper way adding thos data after creating a MultiPartBuilder and add DATA and Strings?
Uploading file in multipart using OkHttp
private static final String IMGUR_CLIENT_ID = "...";
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
// Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"title\""),
RequestBody.create(null, "Square Logo"))
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"image\""),
RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
.build();
Request request = new Request.Builder()
.header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
This worked for me using okHttp3:
OkHttpClient client = new OkHttpClient();
File file = new File(payload);
RequestBody formBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", "image.jpg",
RequestBody.create(MediaType.parse("image/jpg"), file))
.build();
Request request = new Request.Builder().url(url).post(formBody).build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
I modified Dr. Enemy's answer:
MultipartBody.Builder builder =new MultipartBody.Builder().setType(MultipartBody.FORM);
for (Object aMData : dataClass.getData().entrySet()) {
Map.Entry mapEntry = (Map.Entry) aMData;
String keyValue = (String) mapEntry.getKey();
String value = (String) mapEntry.getValue();
builder.addPart(keyValue, value);
}
for (DataPackage dataPackage : dataClass.getDataPackages()) {
builder.addPart("upfile[]", dataPackage.getFile());
}
Start adding the formDataPart to builder and at end create RequestBody
RequestBody requestBody = builder.build();
you can perform above actions with
compile 'com.squareup.okhttp3:okhttp:3.4.1'

Categories

Resources