I have a list like
[{
Imgstr:"obj as string",
Ingfile:file
},{
Imgstr:"obj as string",
Ingfile:file
}
]
How can I upload them as multipart x if it is a single obj I am sending as multipart body and file
try going to this link and I'll include some of it here:
If this is your first uploading files with Retrofit tutorial, you should visit our uploading files with Retrofit and uploading multiple files tutorials.
In the previous tutorials, we've used various upload options in the FileUploadService class:
public interface FileUploadService {
// previous code for single file uploads
#Multipart
#POST("upload")
Call<ResponseBody> uploadFile(
#Part("description") RequestBody description,
#Part MultipartBody.Part file);
// previous code for multiple files
#Multipart
#POST("upload")
Call<ResponseBody> uploadMultipleFiles(
#Part("description") RequestBody description,
#Part MultipartBody.Part file1,
#Part MultipartBody.Part file2);
}
The second option let's you upload multiple files, but you always have to specify in advance how many. This is difficult when your app doesn't have a fixed number of files and it can vary depending on the use case or user input.
Upload a Dynamic Amount of Files
The solution for this problem is to pass a List or Array of MultipartBody.Part objects. Retrofit and OkHttp will then build an appropriate multipart request with all files. Java arrays or lists allow you to freely add files as required.
Endpoint Declaration
You know the theory, so it's time to look at an example. As always, we'll start with describing the endpoint interface. Of course, this depends on your backend. Make sure your API can handle a random amount of files!
public interface FileUploadService {
#Multipart
#POST("upload")
Call<ResponseBody> uploadMultipleFilesDynamic(
#Part("description") RequestBody description,
#Part List<MultipartBody.Part> files);
}
In the previous examples we carried a description with every request. We'll keep it to show you how it would work, but of course it's only a single description for a lot of files. If you need to also send a dynamic amount of other information, you should check out our tutorial on #PartMap.
The second part of the implementation is using the new endpoint declaration and passing some files. We'll reuse the helper methods from our previous tutorials to simplify creating the necessary multiparts:
#NonNull
private RequestBody createPartFromString(String descriptionString) {
return RequestBody.create(
okhttp3.MultipartBody.FORM, descriptionString);
}
#NonNull
private MultipartBody.Part prepareFilePart(String partName, Uri fileUri) {
// https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
// use the FileUtils to get the actual file by uri
File file = FileUtils.getFile(this, fileUri);
// create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(
MediaType.parse(getContentResolver().getType(fileUri)),
file
);
// MultipartBody.Part is used to send also the actual file name
return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
}
Finally, we'll put everything together to build the upload request:
Uri photoUri = ... // get it from a file chooser or a camera intent
Uri videoUri = ... // get it from a file chooser or a camera intent
// ... possibly many more file uris
// create list of file parts (photo, video, ...)
List<MultipartBody.Part> parts = new ArrayList<>();
// add dynamic amount
if (photoUri != null) {
parts.add(prepareFilePart("photo", photoUri));
}
if (videoUri != null) {
parts.add(prepareFilePart("video", videoUri));
}
// ... possibly add more parts here
// add the description part within the multipart request
RequestBody description = createPartFromString("hello, this is description speaking");
// create upload service client
FileUploadService service = ServiceGenerator.createService(FileUploadService.class);
// finally, execute the request
Call<ResponseBody> call = service.uploadMultipleFilesDynamic(description, parts);
call.enqueue(...);
All of the steps above should be fairly familiar to you. We simply create a part for each file and the description. After everything is put together, we can create a new Call object from our FileUploadService and execute the request as usual.
Related
I try to upload an image from an Android App to a Django server using Retrofit 2 and OkHttp3.
For that, I used to create a RequestBody instance using the following lines:
RequestBody requestImageFile =
// NOW this call is DEPRECATED
RequestBody.create(
MediaType.parse("image/*"),
// a File instance created via the path string to the image
imageFile
);
I used the previous instance in the next method call as argument:
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part image = MultipartBody.Part.createFormData("image", imageFile.getName(), requestImageFile);
Finally, I fired up the Retrofit interface to do the rest:
// finally, execute the request
Call<ResponseBody> call = service.upload(image);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.v("Upload", "success");
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e("Upload error:", t.getMessage());
}
});
Some months ago, Android Studio did not told me that create() was deprecated. When I open the project now, it tells me that create() is deprecated. Does somebody know how to fix it ?
Just swap the parameters from
RequestBody.create(MediaType.parse("image/*"), imageFile);
to
RequestBody.create(imageFile, MediaType.parse("image/*"));
You can use the Kotlin extensions as well.
val requestImageFile = imageFile.asRequestBody("image/*".toMediaTypeOrNull())
Here is how to do it easily with kotlin extension functions from okhttp like:
toRequestBody():
change from :
val requestImageFile = RequestBody.create(
MediaType.parse("image/*"),
imageFile
);
to this:
val requestImageFile = imageFile.toRequestBody(MediaType.parse("image/*"))
'
more info here: https://square.github.io/okhttp/upgrading_to_okhttp_4/
You can change from:
RequestBody.create(MediaType.parse("image/*"), imageFile);
to:
RequestBody.Companion.create(imageFile, MediaType.parse("image/*"))
I'm trying to upload an image from Android Studio to Laravel server using Retrofit2 Multipart encoding, but i keep getting "500 Internal Server Error", which means something is going wrong server-side probably, but i can't pin what it is.
this is my interface call (Android Studio):
#Multipart
#POST("public/imagem")
Call<ResponseBody> uploadImagem(#Part MultipartBody.Part part,
#Part("name") RequestBody name,
#Part("animal_id") long animal_id,
#Part("ativo") int ativo);
this is the request (Android Studio):
//Create a file object using file path
File file = new File(filePath);
// Create a request body with file and image media type
RequestBody fileReqBody = RequestBody.create(MediaType.parse("image/*"), file);
// Create MultipartBody.Part using file request-body,file name and part name
MultipartBody.Part part = MultipartBody.Part.createFormData("upload", file.getName(), fileReqBody);
//Create request body with text description and text media type
RequestBody name = RequestBody.create(MediaType.parse("text/plain"), "image-type");
WebService.getInstance().getService().uploadImagem(part, name, animal_id, 1).enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
//THIS IS WHERE I WANT TO GET
} else {
//THIS IS WHERE IM GETTING AT EVERYTIME
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
this is my route (Laravel):
Route::post('imagem','ImagemController#createImagem');
this is the "createImagem" function inside "ImagemController" (Laravel):
public function createImagem(Request $request){
$destinationPath = url('/midia'); //i have a "midia" folder inside "public" folder
$image = $request->file('part');
$name = $request->input('name');
$image->move($destinationPath, $name);
$dbPath = $destinationPath. '/'.$name;
$imagem = new Imagem();
$imagem->animal_id = $request->input('animal_id');
$imagem->img_url = $dbPath;
$imagem->ativo = $request->input('ativo');
$imagem->save();
return response()->json($imagem);
}
and these are the attributes inside "Imagem" table and their types:
but i'm getting 500 Internal Server Error, so probably something server-side isn't according to what would be right logically, can you help me find what is wrong in my code?
ps. I do have other requests to this server that are fully functional, but all of them are just fields, while this has a file, which needs Multipart encoding, unlike the others.
EDIT:
This is the server error log:
[2019-06-11 21:21:03] local.ERROR: Call to a member function move() on null {"exception":"[object] (Symfony\\Component\\Debug\\Exception\\FatalThrowableError(code: 0): Call to a member function move() on null at /.../Controllers/ImagemController.php:28)
So it seems i am unable to get file with
$image = $request->file('part');
I think the error could be because path must to be a path and not an url:
$destinationPath = url('/midia');
If you want to move the file to public folder, you have to use public_path() for the path:
$image = $request->file('part');
$destinationPath = 'midia';
$name = $request->input('name') .'.'. $image->getClientOriginalExtension();
$image->move(public_path($destinationPath), $name);
If you want to avoid the error and not waste server resources when there is no image in the request, add a validation at the start of your function:
public function createImagem(Request $request){
$this->validate($request, [
'part' => 'required|image|max:2048',
// other fields validations
]);
// the createImagem logic here
}
if the validation fails, you will not try to move the file and will not query DB either, then the proper error response will automatically be sent back to the client where you can handle it.
try this code hope its helpfull for you.
#Multipart
#POST("public/imagem")
Call<ResponseBody> uploadImagem(#Part MultipartBody.Part part);
if you are using key part
$image = $request->file('part');
also use that key "part" in java code
Uri uri1 = Uri.parse(event_image);
File file = new File(uri1.getPath());
RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part image = MultipartBody.Part.createFormData("part", file.getName(), reqFile);
mService.addEvent(image).enqueue(new Callback<LoginResponse>() {
#Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
}
#Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
}
});
I sent image file and content (text) using retrofit from android client and tried to get them in the server side but can not do that and the error is always : it is null.
Please how can I send image and receive it using #Retrofit and Slim framework?
If anyone can help, I will appreciate.
..............................................
Tried to send the image from android client like a multipart file and receive it with slim using method (getUploadedFiles) and it didn't work.
#Multipart
#POST("createPostWithImage")
Call<DefaultResponse> uploadTestPost(
#Part("desc") RequestBody desc,
#Part MultipartBody.Part image
);
$app-> post('/createPostWithImage', function(Request $request, Response $response) {
$directory = __DIR__.'../photos/1';
$uploadedFiles = $request->getUploadedFiles();
$uploadedFile = $uploadedFiles['photo'];
$uploadedFile->moveTo($directory);
});
get the file which was sent from android client and save it into specific folder.
$app->post('/file', function($request,$response) {
try{
$directory = $this->get('upload_directory');
$uploadedFiles = $request->getUploadedFiles();
$uploadedFile = $uploadedFiles['example1'];
$extension = pathinfo($uploadedFile->getClientFilename(), PATHINFO_EXTENSION);
$basename = mt_rand(10000000, 99999999);
$uploadedFile->moveTo($directory . DIRECTORY_SEPARATOR . $basename.'.'.$extension);
return $response->withJson(array('message' =>$uploadedFile),200);
}
catch(\Exception $ex){
return $response->withJson(array('error' => $ex->getMessage()),422);
}
});
//minimal code to get started ...
I'm sending multipart requests with retrofit and it works fine. but when my file name is contain Persian character ,my app crashes and i get this error:
java.lang.IllegalArgumentException: Unexpected char 0x62f at 35 in
Content-Disposition value: form-data; name="photo";
filename="دوچرخه.jpg"
this is how i send my multipart request:
File imageFile = new File(imagePath);
ProgressRequestBody fileBody = new ProgressRequestBody(imageFile, this);
MultipartBody.Part filePart = MultipartBody.Part.createFormData("photo", imageFile.getName(), fileBody);
RetroInterface retroInterface = RetrofitClientInstance.getRetrofitInstance().create(RetroInterface.class);
Call<SendFileResponse> call = retroInterface.sendPhoto(token, myHashmap, filePart);
how can I fix this issue?!
My not perfect solution, becouse it can change some characters, is to put URLEncoder.encode(file.name, "utf-8") instead of plain name.
Just a suggestion though but as a workaround you try renaming the file to an id (timestamp / anything else) for the filename and add a name field that will contain the actual name if the file...
public class Object {
private String filename;
private File actualFile;
}
That way when retrieving later you can still always have reference to the file you want.
We can use addUnsafeNonAscii() method from Header.Builder class by which we can add a header with the specified name and value. Does validation of header names, allowing non-ASCII values. So we can pass any language characters as an value including persian character too.
val fileName = "your file name with extention"
val reqFile = RequestBody.create(MediaType.parse("image/*"), File(imageDir))
val header = Headers.Builder()
header.addUnsafeNonAscii("Content-Disposition", "form-data; name=\"image\"; filename=\"$fileName")
val body = MultipartBody.Part.create(header.build(), reqFile)
myApi.uploadItem(body)
If, I'm using Postmam file upload without problems. But, when anroid tries upload file in server, method throws NPE, becouse MultipartFile file = null.
Android
RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file);
Call<MediaResponseModel> call = service.uploadImage(requestBody);
call.enqueue(new RetrofitCallback<>(callback));
#POST("/uploadImage")
Call<MediaResponseModel> uploadImage(#Part("file") RequestBody file);
Server
#RequestMapping(value = "/uploadImage", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<?> imageUpload(#RequestHeader(value = "id") String sessionId,
#RequestParam (value = "file") MultipartFile file)
ApplicationContext
<bean id="jsonConverter"
class="org.springframework.http.converter.json.GsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
<mvc:annotation-driven >
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.GsonHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
It's difficult to do it on android using HTTP, there are some third party libraries you can use that.
ion
retrofit
Both are good libraries, I have used both in my projects.
You can use Retrofit network library , it is the fastest one available
It supports multipart files and its implementation is very simple
http://square.github.io/retrofit/