Retrofit @body with @multipart having Issue

╄→尐↘猪︶ㄣ 提交于 2019-11-30 04:01:27
Ankit Aggarwal

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.

user4042384

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();
user4042384

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())));

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);
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...

https://www.linkedin.com/pulse/retrofit-2-how-upload-multiple-files-server-mahesh-gawale

I guess the best answer for this question can be found here. It worked perfectly for me.

This is the example of uploading 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 Arraylist of pickup Images Path. I hope this post is useful to you. kindly share your feedback as comment here.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!