9

I am using Spring MVC on a J2EE Web application.
I have created a method that bounds the request body to a model like the above

@RequestMapping(value = "/", method = RequestMethod.POST, produces = "application/json")
public AModel createEntity(@Valid @ModelAttribute MyInsertForm myInsertForm) {
    // coding..
}  

Everything are working great and when i include a property of type MultipartFile in the MyEntityForm, then i have to make the request with content type "multipart/form-data".
Also, everything are working great with this scenario too.

The problem i am facing is that i would like to have the MultipartFile property as optional.
When a client request include a file my method works great but when a client request does not include a file spring throws a

HTTP Status 500 - Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadException: Stream ended unexpectedly

Is there any way to solve this issue without creating two methods on my controller (one with a MultipartFile and another without)?

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Georgios Syngouroglou
  • 18,813
  • 9
  • 90
  • 92

3 Answers3

16

I had the same issue and just adding the required=false worked for me; because, I don't send a file all the time. Please find the sample code below,

@RequestMapping(value = "/", method = RequestMethod.POST, produces = "application/json")
public AModel createEntity(@Valid @ModelAttribute MyInsertForm myInsertForm, @RequestParam(value ="file", required=false) MultipartFile file) {
    // coding..
}  
tk_
  • 16,415
  • 8
  • 80
  • 90
3

Give a try by adding

(required=false)

to multipart property in method signature.

Juned Ahsan
  • 67,789
  • 12
  • 98
  • 136
-1

When you wish to send one or more files using HTTP, you have to use multipart request. This means that the body of the request will be like the above,

-----------------------------9051914041544843365972754266 Content-Disposition: form-data; name="text"

text default -----------------------------9051914041544843365972754266 Content-Disposition: form-data; name="file1"; filename="a.txt" Content-Type: text/plain

Content of a.txt.

-----------------------------9051914041544843365972754266 Content-Disposition: form-data; name="file2"; filename="a.html" Content-Type: text/html

When you wish to send only data (and not files) you can send them as json, key-value pairs etc.

Spring framework uses the @ModelAttribute annotation when you wish to map a multipart request to an object. When you have a normal key-value request, you use the @RequestBody annotation. Thus, you can't have the MultipartFile optional, because you have to use different annotations. Using two different methods, one per request type, solves the issue. Example,

@RequestMapping(value = "/withFile", method = RequestMethod.POST, produces = "application/json")
public ReturnModel updateFile(@ModelAttribute RequestModel rm) {
    // do something.
}

@RequestMapping(value = "/noFile", method = RequestMethod.PUT, produces = "application/json")
public ReturnModel updateJson(@RequestBody RequestModel rm) {
    // do something else.
}
Georgios Syngouroglou
  • 18,813
  • 9
  • 90
  • 92