Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to process a multipart request consisting of a file and a JSON object in Spring restful service?

Tags:

I have the following resource (implemented using Spring 4.05.RELEASE) which accepts a file and a JSON object:

(P.S. activityTemplate is a serializable entity class)

... @RequestMapping(value="/create", method=RequestMethod.POST) public @ResponseBody ActivityTemplate createActivityTemplate(         @RequestPart ActivityTemplate activityTemplate, @RequestPart MultipartFile jarFile) {    //process the file and JSON } ... 

and this is the form I am testing from:

<form method="POST" enctype="multipart/form-data"     action="http://localhost:8080/activityTemplates/create">     JSON: <input type="text" name="activityTemplate" value='/* the JSON object*/'><br />      File to upload: <input type="file" name="file">     <input type="submit" value="Upload"> </form> 

and this is the error that I get:

 There was an unexpected error (type=Unsupported Media Type, status=415).  Content type 'application/octet-stream' not supported 

So how should I make the resource accept the JSON object as part of the multipart request, or should I be sending the form in a different way?

like image 615
Sami Avatar asked Dec 04 '14 13:12

Sami


People also ask

How do I pass a multipart file in JSON?

To pass the Json and Multipart in the POST method we need to mention our content type in the consume part. And we need to pass the given parameter as User and Multipart file. Here, make sure we can pass only String + file not POJO + file. Then convert the String to Json using ObjectMapper in Service layer.

Does spring handle multipart request?

By default, Spring does no multipart handling, because some developers want to handle multiparts themselves. You enable Spring multipart handling by adding a multipart resolver to the web application's context. Each request is inspected to see if it contains a multipart.


2 Answers

This took me two days to work for me!

client (angular):

$scope.saveForm = function () {       var formData = new FormData();       var file = $scope.myFile;       var json = $scope.myJson;       formData.append("file", file);       formData.append("ad",JSON.stringify(json));//important: convert to string JSON!       var req = {         url: '/upload',         method: 'POST',         headers: {'Content-Type': undefined},         data: formData,         transformRequest: function (data, headersGetterFunction) {           return data;         }       }; 

Spring (Boot):

@RequestMapping(value = "/upload", method = RequestMethod.POST)     public @ResponseBody     Advertisement storeAd(@RequestPart("ad") String adString, @RequestPart("file") MultipartFile file) throws IOException {          Advertisement jsonAd = new ObjectMapper().readValue(adString, Advertisement.class); //do whatever you want with your file and jsonAd 
like image 189
mohi Avatar answered Sep 19 '22 13:09

mohi


Hope this should help you. You need to set the boundary in your request to inform the HTTP Request. is simple; A brief introduction to the multipart format can be found in the below link

HTML 4.01 Specification for multipart

The following example illustrates "multipart/form-data" encoding. If the Json Object is "MyJsonObj" , and file that need to be send is "myfile.txt", the user agent might send back the following data:

Content-Type: multipart/form-data; boundary=MyBoundary  --MyBoundary Content-Disposition: form-data; name="myJsonString" Content-Type: application/json  MyJsonObj //Your Json Object goes here --MyBoundary Content-Disposition: form-data; name="files"; filename="myfile.txt" Content-Type: text/plain  ... contents of myfile.txt ... --MyBoundary-- 

or if your files is of type image with name "image.gif" then,

--MyBoundary Content-Disposition: file; filename="image.gif" Content-Type: image/gif Content-Transfer-Encoding: binary  ...contents of image.gif... --MyBoundary-- 

You specify boundary in the Content-Type header so that the server knows how to split the data sent.

So, you basically need to select a boundary value to:

  • Use a value that won't appear in the HTTP data sent to the server like 'AaB03x'.
  • Be consistent and use the same value all over the request.
like image 44
Sridhar DD Avatar answered Sep 18 '22 13:09

Sridhar DD