2

Im about to start crying, because Ive tried many solutions and topics, but it doesn`t work.

The issue: I have to upload an String (it was a bitmap, but I have base64 coded) to our lovely server, so I have created a background Thread in Android to do it, and calling the backend. I get a HTTP 400 error message, with the following message:

org.springframework.web.bind.MissingServletRequestParameterException","message":"Required MultipartFile parameter 'file' is not present","path":"/backend/newimage"}.

My headers:

Content-Disposition: form-data; name="file"
Content-Type: text/plain; charset=UTF-8
Content-Length: 24069
Content-Transfer-Encoding: binary
/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAA0JCgsK.......etc.....binary

I don`t see in headers the following part:

enctype: "multipart/form-data”). and I don`t understand why, my retforit interce looks like this:

@POST("/newimage")
@Multipart
String uploadImageToIdea(@Query("id") String id, @Part("file") String file );

I don`t understand the error message, because I HAVE the file param here.

I had tried the following (didn`t work obviously:

my code to call the backend (not the final version, but first let things make work :) ):

   new Thread() {
                @Override
                public void run() {
                    MultipartTypedOutput file = new MultipartTypedOutput();
                    for (int i = 0; i < imagesToUpload.size(); ++i) {
                        Bitmap imageBitmap = imagesToUpload.get(i);
                        ByteArrayOutputStream stream = new ByteArrayOutputStream();

                        imageBitmap.compress(Bitmap.CompressFormat.JPEG, 60, stream);
                        byte[] byteArray = stream.toByteArray();
                        String bitmapString = Base64.encodeToString(byteArray, Base64.DEFAULT);
                        backend.uploadImageToIdea(submitIdeaResponse.getIdeaDetails().getId(), bitmapString);
                    }
                }
            }.start();

Note from my backend developer:

You need to send a multipart request (enctype="multipart/form-data”).

So, can someone please help me out, why I have HTTP 400 with the error message above? What can I change in my code to make this call work ? Thank you

Community
  • 1
  • 1
narancs
  • 5,234
  • 4
  • 41
  • 60

3 Answers3

1

You should use TypedFile for sending file in Multipart.

@Multipart
@POST("/newimage")
String uploadImageToIdea(@Part("id") TypedString id, @Part("file") TypedFile file);

for more information link.

Kishan Vaghela
  • 7,678
  • 5
  • 42
  • 67
1

I had this exact issue for some time. Understanding the working code below should help you resolve this.

Retrofit

@Multipart @POST("/gifts")
void save( @Part("gift") Gift gift,
           @Part("file") TypedFile file,
           Callback<Resource<Gift>> callback);

Spring

@RequestMapping(value="/gifts", method=RequestMethod.POST)
public @ResponseBody HttpEntity<Gift> addGift(
        @RequestPart Gift gift,
        @RequestPart MultipartFile file) {...}

Note Spring will use reflection to match part names with controller method parameters. So the parameter file should match part "file". You can always override this in Spring by adding the part name manually: @RequestPart("file")

Example Call:

service.save(gift, typedFile, new Callback<Resource<Gift>>() {

        @Override
        public void success(Resource<Gift> resources, Response response)
        {/*...*/}

        @Override
        public void failure(RetrofitError error)
        {/* ... */}
});

Tip; don't mix multipart request with query strings unless you want a headache. Matching parts with parts seems to work well from one platform to another.

Nestor Ledon
  • 1,925
  • 2
  • 23
  • 36
  • 1
    Hey Xerosigma, so if Note Spring will use reflection to match part names with controller method parameters, I`m not good with TypedString ? Because there is no file param. I created my own TypedString with file param, but it didn`t worked. – narancs Jun 30 '15 at 08:42
  • Right. I think your real issue here is the overall use of TypedString. Just send a String part and you should be good. – Nestor Ledon Jun 30 '15 at 15:55
0

Okay, I have figured out the solution:

                     for (int i = 0; i < imagesToUpload.size(); ++i) {
                        Bitmap imageBitmap = imagesToUpload.get(i);
                        try {
                            String fileNameWithPath = getCacheDir().getAbsolutePath() + "file_" + String.valueOf(i);
                            FileOutputStream out = new FileOutputStream(fileNameWithPath);
                            imageBitmap.compress(Bitmap.CompressFormat.PNG, 60, out);
                            out.close();
                            backend.uploadImageToIdea(submitIdeaResponse.getIdeaDetails().getId(), new TypedFile("multipart/form-data",new File(fileNameWithPath)));
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

and the retrofit interface is the following:

    @POST("/newimage")
    @Multipart
    String uploadImageToIdea(@Part ("id") String id, @Part("file") TypedFile file );

So I don`t base64Code the image and uploading from the memory, BUT saving into the cache dir and upload the file itself. Using TypeFile of Retrofit for it.

narancs
  • 5,234
  • 4
  • 41
  • 60