Spring: data and JSON file in the same request

I know how to create endpoints that process files using MediaType.MULTIPART_FORM_DATA and @FormDataParam("file") FormDataBodyPart bodyPart , but I was wondering if I can also have JSON data for this request? Something like:

  @POST @Path("somepath") @Consumes(MediaType.MULTIPART_FORM_DATA) public Response uploadFileAndJSON(@RequestBody SomeModel someModel, @FormDataParam("file") FormDataBodyPart bodyPart) { return null; } 

For now, if I add some JSON data to the "raw" tab in the next Postman request, I get an HTTP 415 Unsupported Media Type , probably because I indicated that I am using MULTIPART_FORM_DATA , but I also use @RequestBody , which is looking for JSON content that is APPLICATION_JSON . So, how can I get the JSON data and the file being processed in the same request? I know that it is possible to do this in two queries, I just want to do this in one, if possible?

enter image description here

+8
java json spring rest multipartform-data
source share
2 answers

Why are you using Spring and Jersey annotations? You should stick to using annotations designed for the framework. Since you use a jersey, you should stick to its annotations.

So here is what you need to consider regarding your current code and environment.

  • There cannot be two separate bodies. With your code, what seems to be expected to happen.
  • You can place JSON as part of a body with several parts. To do this, you must also annotate SomeModel with Jersey @FormDataParam

     @POST @Path("somepath") @Consumes(MediaType.MULTIPART_FORM_DATA) public Response uploadFileAndJSON( @FormDataParam("model") SomeModel someModel, @FormDataParam("file") FormDataBodyPart bodyPart) { } 
  • In the Jersey configuration, you need to register a MultiPartFeature . If you do not, the body cannot be deserialized, and you will receive exceptions and error responses.

  • Now the problem is the postman. You can see a similar problem here . The problem was that Content-Type not set for the JSON body part. For example, a body might look something like

     --AaB03x Content-Disposition: form-data; name="model" {"some":"model", "data":"blah"} --AaB03x Content-Disposition: form-data; name="file"; filename="file1.txt" Content-Type: text/plain ... contents of file1.txt ... --AaB03x-- 

    In fact, you can see the body if you click the Preview button in Postman. The problem is that there is no Content-Type for the "model" part, as you can see in the "file" . This is because you cannot install individual parts of Content-Type in Postman. The one you see will be detected from the file extension. For example, a .txt file will force Postman to set the Content-Type to text/plain and the .png file to image/png .

    If you look in the link above, I suggested, maybe you could use a .json file instead of entering data. Of course, it was just a theory. I have not actually tested it.

    In any case, the Content-Type must be set so that Jersey can know in order to deserialize it as JSON. If the theory of the .json extension .json not exhausted, then you can use another client, for example cURL, which I showed in the link, or you can use the Jersey client to check, as shown.

  • Do not set the Content-Type header to multipart/form-data in Postman. It installs it for you when you use form-data . I just saw a message where someone said that there is an error when you set the header. I can’t find the message now, not what I confirmed, but I just leave it.


UPDATE

Thus, the OP was able to find a way to set Content-Type: application/json to the "model" part. But sometimes it happens that with the Javascript client you cannot install it. Thus, there will be no Content-Type . If so, Jersey will not be able to deserialize JSON since it does not know that JSON is actually being sent. If you absolutely cannot or don’t know how to set the Content-Type for individual parts, you can resort to the following steps.

 @POST @Path("somepath") @Consumes(MediaType.MULTIPART_FORM_DATA) public Response uploadFileAndJSON(@FormDataParam("model") FormDataBodyPart jsonPart, @FormDataParam("file") FormDataBodyPart bodyPart) { jsonPart.setMediaType(MediaType.APPLICATION_JSON_TYPE); SomeModel model = jsonPart.getValueAs(SomeModel.class); } 
+5
source share

Yes, you can get this as data with several forms.

you will get this in angularjs:

 $scope.uploadFile = function () { var file = $scope.selectedFile[0]; $scope.upload = $upload.upload({ url: 'api/upload', method: 'POST', data: angular.toJson($scope.model), file: file }).progress(function (evt) { $scope.uploadProgress = parseInt(100.0 * evt.loaded / evt.total, 10); }).success(function (data) { //do something }); }; $scope.onFileSelect = function ($files) { $scope.uploadProgress = 0; $scope.selectedFile = $files; }; public Response uploadFileAndJSON(@RequestParam("data") String data, @MultiPartFile("file")File file) { you can data as form data and convert it like you want to your object using Gson jar. return null; } 

Look at this for angularjs code: Angularjs, how do I load multi-page form data and a file?

https://puspendu.wordpress.com/2012/08/23/restful-webservice-file-upload-with-jersey/

+1
source share

All Articles