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/
Related
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.
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)
I'm developing an Android app that sends requests to a server (rails) through Retrofit.
My current issue is file upload. On server side I have paperclip to handle file upload.
I can't seem to include a TypedFile inside an object which I'd like to send as a parameter
Here is the api method I'm calling, whit its parameters
#Multipart
#POST("/containers/{id}/items")
void addItem(#Path("id") int id,
#Part("item")NewItemData newItemData,
Callback<String> callback);
Basically I want to post this object (containing a TypedFile)
public class NewItemData{
String original_filename;
String content_type;
TypedFile file;
String description;
String location;
int container_id;
...
}
edit:
I forgot to show you how i create the object
public NewItemData(Context context, String file_path){
String mime_type = FileUtilities.getMimeType(file_path);
String[] file_name_parts = file_path.split("/");
String file_name = file_name_parts[file_name_parts.length-1];
this.original_filename = file_name;
this.full_file_path = file_path;
this.content_type = mime_type;
File file_tmp = new File(file_path);
this.file = new TypedFile("application/octet-stream", file_tmp);
this.description = "";
this.location = "";
}
end edit
This is the error that I'm getting:
retrofit.RetrofitError: retrofit.converter.ConversionException: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_ARRAY at line 1 column 2
And this is the object NewItemData converted to json
{"original_filename":"IMG_20150121_221732.jpg","content_type":"image/jpeg","description":"","file":{},"location":"","container_id":0}
As you can see the "file" field is empty, so I assume that the error above is referring to the fact that "file" => {} instead of the binary file
What I've tried so far hasn't worked, so my questions are:
is possible to post a "wrapper" object in multipart mode?
if so, what annotation should I write and where?
should i implement a custom serializer?
If you need additional info, just ask
Thank you
When you create the restAdapter Instance, just add this line to add a converter .addConverterFactory( GsonConverterFactory.create()) like below
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(RestConnection.BASE_URL_MULTIMEDIA)
.addConverterFactory( GsonConverterFactory.create())
.client(client)
.build();
I have the following controller set up:
#PreAuthorize("hasAuthority('ROLE_USER')")
#RequestMapping(value = "/me/avatar", method = RequestMethod.POST)
public #ResponseBody boolean setAvatar(Principal principal, MultipartHttpServletRequest request) {
String username = ((User) ((OAuth2Authentication) principal).getPrincipal()).getUsername();
MultipartFile file = request.getFile("avatar");
return Boolean.TRUE;
}
And when I use Square Retrofit to POST to this controller:
#Multipart
#POST("/user/me/avatar?access_token={access_token}")
void uploadAvatar(#Name("access_token") String accessToken, #Name("avatar") TypedFile image, retrofit.http.Callback<Boolean> callback);
I get a MultipartHttpServletRequest which has the "avatar" parameter, with the proper file name and everything, but no multipart files.
What am I doing wrong that would cause me to get MultipartParams but no MultipartFiles? I've tried various other TypedOutput formats, but I get the same result. If I hit the same controller from Postman (a Chrome plugin) everything works as expected, leading me to think it's a bug in Retrofit?
This was due to a bug in Retrofit, which has been fixed as of today. The above code now works to upload a file from Retrofit to a Spring based api server.