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

早过忘川 提交于 2020-01-09 09:03:50

问题


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?


回答1:


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



回答2:


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.



回答3:


You have not given the param names to your @RequestParts ?

public @ResponseBody ActivityTemplate createActivityTemplate(
    @RequestPart("activityTemplate") ActivityTemplate activityTemplate, @RequestPart("file") MultipartFile jarFile)
{
   //process the file and JSON
}

Note: do not forget to include the jackson mapper .jar (maps your Json to ActivityTemplate) file in your classpath.




回答4:


Couldn't you change your

@RequestMapping(value="/create", method=RequestMethod.POST)

to

@RequestMapping(value="/create",
                method=RequestMethod.POST, consumes ={"multipart/form-data"})



回答5:


The default content type is 'application/octet-stream'. Since you are uploading jar file and JSON the content type should be set in the @RequestMapping annotation as follows:

@RequestMapping(value="/create", method=RequestMethod.POST, headers="content-type=application/json,application/java-archive")



回答6:


The error message indicates that there is no HttpMessageConverter registered for a multi-part/MIME part of content type: application/octet-stream. Still, your jarFile parameter is most likely correctly identified as application/octet-stream, so I'm assuming there's a mismatch in the parameter mapping.

So, first try setting the same name for the parameter and the form's input element.

Another problem is that the JSON is uploaded as a (regular) value of a text input in the form, not as a separate part in the multi-part/MIME. So there's no content-type header associated with it to find out that Spring should use the JSON deserializer. You can use @RequestParam instead and register a specific converter like in this answer: JSON parameter in spring MVC controller




回答7:


this may help you, while receiving MultipartFile you should set request header content-type to "multipart/form-data" , then in your controller use consumes="multipart/form-data" , consumes also used to map our request to our method in controller.

If you want to receive JSON data , better to send request in the form of JSONString , just receive that jsonstring, later convert into json Object format then, use that object for yours operations.

check below code :

@RequestMapping(value="/savingImg", method=RequestMethod.POST, 
        consumes="multipart/form-data", produces="application/json")
public ResponseEntity<?> savingAppIMgDtlss(
        @RequestParam(value="f1", required = false) MultipartFile f1 , 
        @RequestParam(value="f2", required = false) MultipartFile f2 ,
        @RequestParam(value="f3", required = false) MultipartFile f3 ,
        @RequestParam(value="f4", required = false) MultipartFile f4 ,
        @RequestParam(value="f5", required = false) MultipartFile f5 ,
        @RequestParam(value="f6", required = false) MultipartFile f6 ,
        @RequestParam(value="f7", required = false) MultipartFile f7 ,
        @RequestParam(value="f8", required = false) MultipartFile f8 ,@RequestParam("data") String jsonString) 
                throws Exception , ParseException {
    try{
        JSONObject gstcTranObj = new JSONObject();
                //converting JSONString to JSON
        net.sf.json.JSONObject jsonDtls = net.sf.json.JSONObject.fromObject(jsonString);
        System.out.println("f1::"+f1.getOriginalFilename());
        System.out.println("f2::"+f2.getOriginalFilename());
        System.out.println("f3::"+f3.getOriginalFilename());
        System.out.println("f4::"+f4.getOriginalFilename());
        System.out.println("f5::"+f5.getOriginalFilename());
        System.out.println("f6::"+f6.getOriginalFilename());
        System.out.println("f7::"+f7.getOriginalFilename());
        System.out.println("f8::"+f8.getOriginalFilename());
} catch (Exception e) {
        e.printStackTrace();

        return new ResponseEntity<>("Failed",HttpStatus.NOT_FOUND);
    }finally{

    }
return new ResponseEntity<>("Success", HttpStatus.OK);

  }
}



回答8:


Exception is thrown because you don't have appropriate HttpMessageConverter, to process multipart/form-data request. Workaround




回答9:


You can use @RequestPart from org.springframework.web.bind.annotation.RequestPart; It is used as Combining @RequestBody and file upload.

Using @RequestParam like this @RequestParam("file") MultipartFile file you can upload only file and multiple single data (key value ) like

        @RequestMapping(value = "/uploadFile", method = RequestMethod.POST,  consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
    public void saveFile(
                         @RequestParam("userid") String userid,
                         @RequestParam("file") MultipartFile file) {

    }

you can post JSON Object data and and File both using @RequestPart like

    @RequestMapping(value = "/patientp", method = RequestMethod.POST,  consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<?> insertPatientInfo(
                                            @RequestPart PatientInfoDTO patientInfoDTO,
                                            @RequestPart("file") MultipartFile file) {
}

You are not limited to using multipart file uploads directly as controller method parameters. Your form objects can contain Part or MultipartFile fields, and Spring knows automatically that it must obtain the values from file parts and converts the values appropriately.

Above method can respond to the previously demonstrated multipart request containing a single file. This works because Spring has a built-in HTTP message converter that recognizes file parts. In addition to the javax.servlet.http.Part type, you can also convert file uploads to org.springframework.web.multipart.MultipartFile. If the file field permits multiple file uploads, as demonstrated in the second multipart request, simply use an array or Collection of Parts or MultipartFiles.

        @RequestMapping(value = "/patientp", method = RequestMethod.POST,  consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<?> insertPatientInfo(
                                                @RequestPart PatientInfoDTO patientInfoDTO,
                                                @RequestPart("files") List<MultipartFile> files) {
    }

Happy To Help...



来源:https://stackoverflow.com/questions/27294838/how-to-process-a-multipart-request-consisting-of-a-file-and-a-json-object-in-spr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!