I\'m developing a RESTful service based on Spring 3.2. I\'m facing a problem with a controller handling mixed multipart HTTP request, with a Second part with XMLor JSON form
I have managed to solve the problem
Endpoint example:
@PostMapping("/")
public Document create(@RequestPart Document document,
@RequestPart(required = false) MultipartFile file) {
log.debug("#create: document({}), file({})", delegation, file);
//custom logic
return document;
}
Exception:
"error_message": "Content type 'application/octet-stream' not supported"
Exception is thrown from the next method:
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(HttpInputMessage,MethodParameter,Type)
Solution:
We have to create custom converter @Component, which implements HttpMessageConverter or HttpMessageConverter and knows about MediaType.APPLICATION_OCTET_STREAM. For simple workaround it's enough to extend AbstractJackson2HttpMessageConverter
@Component
public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
/**
* Converter for support http request with header Content-Type: multipart/form-data
*/
public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return false;
}
@Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
return false;
}
@Override
protected boolean canWrite(MediaType mediaType) {
return false;
}
}
Not sure if you had fixed your problem, but I also had a similar problem where my JSON object was not getting picked up by my controller when mixing @RequestPart and MultipartFile together.
The method signature for your call looks correct:
public ResponseEntity<List<Map<String, String>>> createUser(
@RequestPart("file") MultipartFile file, @RequestPart(required=false) User user) {
// ... CODE ...
}
However make sure your request looks something like this:
POST /createUser
Content-Type: multipart/mixed; boundary=B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E
--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E
Content-Disposition: form-data; name="user";
Content-Type: application/xml; charset=UTF-8
<user><!-- your user xml --></user>
--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E
Content-Disposition: form-data; name="file"; filename="A551A700-46D4-470A-86E7-52AD2B445847.dat"
Content-Type: application/octet-stream
/// FILE DATA
--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E--
I have managed to solve problem:
@SuppressWarnings("rawtypes")
@RequestMapping(value = "/DataTransfer", method = RequestMethod.POST, produces = {
MediaType.APPLICATION_JSON_UTF8_VALUE }, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE} )
@ApiOperation(value = "Sbm Data Transfer Service", response = Iterable.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "Successfully find."),
@ApiResponse(code = 400, message = "There has been an error."),
@ApiResponse(code = 401, message = "You are not authorized to save the resource"),
@ApiResponse(code = 403, message = "Accessing the resource you were trying to reach is forbidden"),
@ApiResponse(code = 404, message = "The resource you were trying to reach is not found") })
ResponseEntity processDataTransfer(@RequestPart(name="file") MultipartFile file, @RequestPart(name="param") DataTransferInputDto param);
have you tried
ResponseEntity<List<Map<String, String>>> createUser(
@RequestPart("file") MultipartFile file, @RequestBody(required=false) User user) {
or
ResponseEntity<List<Map<String, String>>> createUser(
@RequestPart("file") MultipartFile file, @RequestParam(required=false) User user) {
If this does not work can you show us mapping.xml
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...