Spring #RequestPart multipart/mixed Object errors - spring

I am attempting to upload a file with additional parameters using RequestParts. I have the file uploading correctly; however, when I try and add in the additional parameters I get an error in response.
My Controller:
#RequestMapping(value = "/v1/cases/{caseId}/file", method = RequestMethod.POST, produces = "application/json; charset=utf-8")
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public Success uploadFile(
#RequestPart(value="file") MultipartFile file,
#RequestPart(value="fileParameters") FileParameters fileParameters) throws FileNotFoundException, IOException {
I have tried to POST to this 2 different ways with different errors:
1)
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="file"; filename="myFile"
Content-Type:
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="fileParameters"
{"filePassword":"testPassword", "configuration":{}, "target":null}
----WebKitFormBoundaryE19zNvXGzXaLvS5C
this errors with:
The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method. See 'supportedMediaTypes' in 'additionalInfo' for a list of supported types
2)
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="file"; filename="myFile"
Content-Type:
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="fileParamters[filePassword]"
testPassword
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="fileParamters[configuration]"
{}
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="fileParamters[target]"
null
----WebKitFormBoundaryE19zNvXGzXaLvS5C
which returns the following error:
"rootExceptionClass": "org.springframework.web.multipart.support.MissingServletRequestPartException",
"rootExceptionMessage": "Required request part 'keyParameters' is not present."
I'm assuming the first approach is the correct one; however, the application does support JSON, so I'm not sure what I am missing configuration wise. Is there something I have to add to the request for this to work correctly, or am I missing something in a message converter.
Note: Not sure this matters but I am using Postman to test the endpoint.

add
Content-Type: application/json;
under the line of
Content-Disposition: form-data; name="fileParameters"
to explicit how to resolve your parameters
see spring docs here

I have met the same issue with you! I changed the #RequestPart to #Multipart, the issue was fixed. hope it can help for you!

Related

Parsing multipart/mixed responses

I want to parse a multipart/mixed web response I'm getting in to proper content,
--Boundary_33046_835445861_1627668603035
Content-Type: application/json
Content-Disposition: form-data; name="contentAnalyzerResponse"
{"cpf:inputs":{"documentIn":{"cpf:location":"InputFile0","dc:format":"application/pdf"},"params":{"cpf:inline":{"elementsToExtract":["text","tables"],"renditionsToExtract":["tables","figures"]}}},"cpf:engine":{"repo:assetId":"urn:aaid:cpf:58af6e2c-1f0c-400d-9188-078000185695"},"cpf:status":{"completed":true,"type":"","status":200},"cpf:outputs":{"elementsRenditions":[{"cpf:location":"fileoutpart0","dc:format":"image/png"},{"cpf:location":"fileoutpart1","dc:format":"image/png"},{"cpf:location":"fileoutpart2","dc:format":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},{"cpf:location":"fileoutpart3","dc:format":"image/png"},{"cpf:location":"fileoutpart4","dc:format":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},{"cpf:location":"fileoutpart5","dc:format":"image/png"},{"cpf:location":"fileoutpart6","dc:format":"image/png"},{"cpf:location":"fileoutpart7","dc:format":"image/png"},{"cpf:location":"fileoutpart8","dc:format":"image/png"},{"cpf:location":"fileoutpart9","dc:format":"image/png"},{"cpf:location":"fileoutpart10","dc:format":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},{"cpf:location":"fileoutpart11","dc:format":"image/png"},{"cpf:location":"fileoutpart12","dc:format":"application/vnd.
--Boundary_33046_835445861_1627668603035
Content-Type: application/octet-stream
Content-Disposition: form-data; name="fileoutpart92"
�PNG
�޾�L���޺S�|��wp���F��k�^����{��{�d\'�����|v������Q<H=||�϶�7����yHBz��q���o݉մ�\:���/�[Ó���:�� ����Tկ�����K�/|g��HY��F�����/��ݳ/�7�6�w$�����񉟏�F�򁱑�sZ�0T�I��p���0�힍��:�J�����_��>���k��9~���C�P��Pl3���K\�:�ʵ����?z��G�w�V��_yg/�������~Z_3��W����x�[���N�9U}�E�~|�g��:�u��m�B��ZQ����z�O��=W�=gܪ�|x�2����o|pU��/���~�����ޒ������}����}�W���v���k��pM�yI��I<�t�w��
���}~�����M<����7~�c�l���gF��?���o�!` ��0�G�ioG.ީ������^��S�96Ź��a8K�{�N�paa8�<�1���p�]؝�>�x�#Y�z���y�����w>s�K���c�5��pQ�b����i���3�8���������&�h>?wo���{���WjɅO݉�T�w���8��:�ut�̩�Eu����&^���>sʸmk<������1
��oB"�0� �������ƾ��ܴ�a8c�u�~��<%0
The response I'm getting is similar to the responses above and I want to get the individual content from the response.

How to support multipart/form-data and application/json by a same method spring boot Rest

I have a POST method that needs to support both multipart/form-data and application/json.
i.e. consumes = { MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE }
When I'm supporting Multipart request, I need a multipart file and a multipart json which can be obtained by declaring as below:
Line 1-> #RequestPart("file") MultipartFile file, #RequestPart("jsonString") InputJsonVO inputJsonVO
Similarly when supporting an application/json, I need to accept the whole body as a Json content:
Line 2 -> #RequestBody InputJsonVO inputJsonVO
It works fine when we have either line 1 or line 2, but not both in the same method as parameters.
`#PostMapping(path = "/multipart", consumes = { MediaType.MULTIPART_FORM_DATA_VALUE,
MediaType.APPLICATION_JSON_VALUE })
public String getMessage(#RequestPart(required=false, name="file") MultipartFile file, #RequestPart(required=false, name="jsonString") InputJsonVO inputJsonVO,
#RequestBody(required=false) InputJsonVO inputJsonVO2
)`
With this method declaration if I send a POST request:
POST /multipart HTTP/1.1
Host: localhost:8080
content-type: application/json
Content-Length: 335
<A Valid Json>
This works fine.
But when I sent a POST request as below from postman, it doesn't work:
POST /multipart HTTP/1.1
Host: localhost:8080
Content-Length: 650
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="/C:/Users/sdamarla/Downloads/J867FE94.jpeg"
Content-Type: image/jpeg
(data)
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="jsonString"
Content-Type: application/json
<A valid Json>
----WebKitFormBoundary7MA4YWxkTrZu0gW
Gives below error:
Content type 'multipart/form-data;boundary=--------------------------335202067624768397899751' not supported]
Note: multipart request is working fine when removing the #RequestBody and the corresponding parameter.
Please let me know if this is a valid use case and if so where am I failing.
Just define two different methods, one for each representation:
#PostMapping(path = "/multipart", consumes = MediaType.APPLICATION_JSON_VALUE)
public String getMessage(#RequestBody InputJsonVO inputJsonVO) {
getMessage(null, inputJsonVO);
}
#PostMapping(path = "/multipart", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public String getMessage(#RequestPart MultipartFile file, #RequestPart InputJsonVO inputJsonVO) {
// your code here
}

Intellij IDEA REST Client file uploading

I am trying to upload file through Intellij IDEA REST Client. I choose "File to upload (multipart/form-data)" and choose file to send. What is parameter name of this file? In my Sprint Controller i use this code
#RequestMapping(method = RequestMethod.POST, value = "/{id}/photo")
public void setCover(#PathVariable int id,
#RequestParam MultipartFile file) {
System.out.println(file.getName());
}
I also tried different names, such as "file", "fileToSend", "File to send" for #RequestParam, but Spring always cant find MultipartFile paramater.
I use the following code which works for me:
POST http://localhost:9003/goods/add HTTP/1.1
Content-Type: multipart/form-data; boundary=boundary
--boundary
Content-Disposition: form-data; name="file"; filename="file.csv"
// The 'input.txt' file will be uploaded
< /Users/xing/Desktop/file.csv
--boundary
Content-Disposition: form-data; name="advertType"
1
--boundary
// The method in the Spring controller
public Xxxx add(#RequestParam("file") MultipartFile file, Long advertType) {
For more information, please refer to https://www.jetbrains.com/help/ruby/exploring-http-syntax.html#use-multipart-form-data
File upload is not allowed due to security concern, not for application running on local machine. This solution worked for me. Its based on the comment by vincent.
See below:
POST http://localhost:8080/api/test HTTP/1.1
Content-Type: multipart/form-data; boundary=WebAppBoundary
--WebAppBoundary
Content-Disposition: form-data; name="param1"; filename="myfile.csv"
Content-Type: application/csv
// below will the path to the file (i.e. myfile.csv)
< C:/users/user/data/sample/myfile.csv
--WebAppBoundary
Content-Disposition: form-data; name="param2"
// value of param2
test
--WebAppBoundary
###
If you wish to do multipart file uploads inside IntelliJ IDEA's REST Client, please upvote this bug report => https://youtrack.jetbrains.com/issue/WEB-20197

Using CommonsMultipartResolver to parse an HTTP request with embedded multipart content

I am using Spring Integration to receive an HTTP request which has multipart content nested inside a multipart request as shown below. When using CommonsMultipartResolver as the resolver the LinkedMultiValueMap passed to the receiving service activator contains a map of all the parts but the imbedded multipart is an UploadedMultipartFile which contains the entire content. In the sample boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL is the boundary of the embedded multipart.
How can I get the embedded multipart parsed into a LinkedMultiValueMap so that I can get the version and payload? Is it possible for the CommonsMultipartResolver to do this or is there another way to parse it?
Http Request:
POST http://xxxxx:8087/edi846Inbound HTTP/1.1
Content-Type: multipart/form-data;boundary=DM1-Sb0636VXPQNO3412Ygegb9suqr
.......
Content-Length: 2787
--DM1-Sb0636VXPQNO3412Ygegb9suqr
Content-Disposition: form-data; name="from"
Content-Type: text/plain;charset=ISO-8859-1 Content-Length: 7
gisb-acknowledgement-receipt
--DM1-Sb0636VXPQNO3412Ygegb9suqr
Content-Disposition: form-data; name="input-format" Content-Type:
text/plain;charset=ISO-8859-1 Content-Length: 3
X12
--DM1-Sb0636VXPQNO3412Ygegb9suqr
Content-Disposition: form-data; name="input-data"; filename="TEST-DTEBS_846_3563_10142015102600.x12"
Content-Type:
multipart/encrypted;boundary=boundary2--extKDvsqGExTQI2WVuplHFCUQJ3XVL protocol:
application/pgp-encrypted
boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL
Content-Disposition: form-data; name="version" Content-Type:
application/pgp-encrypted Content-Length: 10
Version: 1
boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL
Content-Disposition: form-data; name="payload" Content-Type: application/octet-stream Content-Length:
1118
-----BEGIN PGP MESSAGE----- Version: BCPG v1.47
hQIOA8aa0/bci2e/EAf/fkgOBK+cOoeY+44htcvjE9Sxk9RK73aOEaxDOBNqFOsV
Nzw1va7cc7wzYOTlHhZV/MkpXq+IrZV316moJu1EAhscN9YmyReVDOzrkzZ1hBmq
V2MlAr5/CRqS7nQEmCqy/Mz0STtAPZNg3FOh8F79dJnRws5/SdW+zvn2MoSvGTs3
0YvjmtPq2YyVkMlAvJ62f903UYNIiAcEe1k8gWDVW9LJ4tGud+8H0bsG8EFWPsSI
b5rON+MKGykbWGnbSrOy9cqslJaghj91r7ZbsXXXiRn9v4rpOardfiBEnoamI5Tz
jfDKESnr7CqoZgb62je+NJrB5puoAwy8LTynXx4cmQgAnf8lb6f+mIxa1U1Mu6iR
KNTjrH83Cx2BjTra8E8hu0O7GvuczGfA9NiONmxbglgKK58/QVYdlsZUiGTaWkkY
4nMHiaFe9TiPQ6W2vMGutLFR3V6YSshchCskl6cP1OdaIXCYgzZKIjUWHePzd/ds
zCZeNqul1N7iIQ0L5lfSGgfB2eDeeK3JKFjetrrbJQXz0+XeTZLPMSMr6W5Ggq3l
PnoJVTrxUd3b2WKgR4FZB+imYRWEz5KLnB5ZVedC+fU24bECcNptrTQaZZUWnR3Z
ABJqz8avBrNV0Jf9BaFRxcWkrWyr4KtxDArxXOuMHNvGVtj+hhPZcPGj3N9Xam3E
6snAGebIiAEivZPYLVVVk0lZW2H0ISwkKkjD8qs7h8wa7Qbchp2K5IyENEzi20oe
FNRoCwHyjsCY0nECHCG3WON0EXG2DZDTvA17OoyfuKnRT09FVt3OOEPTV048vUid
kUoGa7uT7ud9En7uNSfmDpw+xHxB38N986BKBtoeJlGgDYISJkIgr40TIKMLE/Yc
whDnmKxT68dfSGcv/DIUzYs+d/OBzSpHIWK87me5QnhmLTQ1xwfwtFoTyk6B3Vzx
ljlZFD6e7PJfjo/RIhb0zMvtBvRTONRrMXKRdRY=
=serM
-----END PGP MESSAGE-----
boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL--
--DM1-Sb0636VXPQNO3412Ygegb9suqr--
Embedded content from Map:
boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL
Content-Disposition: form-data; name="version" Content-Type: application/pgp-encrypted Content-Length:
10
Version: 1
boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL
Content-Disposition: form-data; name="payload" Content-Type: application/octet-stream Content-Length:
1118
-----BEGIN PGP MESSAGE----- Version: BCPG v1.47
hQIOA8aa0/bci2e/EAf/fkgOBK+cOoeY+44htcvjE9Sxk9RK73aOEaxDOBNqFOsV
Nzw1va7cc7wzYOTlHhZV/MkpXq+IrZV316moJu1EAhscN9YmyReVDOzrkzZ1hBmq
V2MlAr5/CRqS7nQEmCqy/Mz0STtAPZNg3FOh8F79dJnRws5/SdW+zvn2MoSvGTs3
0YvjmtPq2YyVkMlAvJ62f903UYNIiAcEe1k8gWDVW9LJ4tGud+8H0bsG8EFWPsSI
b5rON+MKGykbWGnbSrOy9cqslJaghj91r7ZbsXXXiRn9v4rpOardfiBEnoamI5Tz
jfDKESnr7CqoZgb62je+NJrB5puoAwy8LTynXx4cmQgAnf8lb6f+mIxa1U1Mu6iR
KNTjrH83Cx2BjTra8E8hu0O7GvuczGfA9NiONmxbglgKK58/QVYdlsZUiGTaWkkY
4nMHiaFe9TiPQ6W2vMGutLFR3V6YSshchCskl6cP1OdaIXCYgzZKIjUWHePzd/ds
zCZeNqul1N7iIQ0L5lfSGgfB2eDeeK3JKFjetrrbJQXz0+XeTZLPMSMr6W5Ggq3l
PnoJVTrxUd3b2WKgR4FZB+imYRWEz5KLnB5ZVedC+fU24bECcNptrTQaZZUWnR3Z
ABJqz8avBrNV0Jf9BaFRxcWkrWyr4KtxDArxXOuMHNvGVtj+hhPZcPGj3N9Xam3E
6snAGebIiAEivZPYLVVVk0lZW2H0ISwkKkjD8qs7h8wa7Qbchp2K5IyENEzi20oe
FNRoCwHyjsCY0nECHCG3WON0EXG2DZDTvA17OoyfuKnRT09FVt3OOEPTV048vUid
kUoGa7uT7ud9En7uNSfmDpw+xHxB38N986BKBtoeJlGgDYISJkIgr40TIKMLE/Yc
whDnmKxT68dfSGcv/DIUzYs+d/OBzSpHIWK87me5QnhmLTQ1xwfwtFoTyk6B3Vzx
ljlZFD6e7PJfjo/RIhb0zMvtBvRTONRrMXKRdRY=
=serM
-----END PGP MESSAGE-----
boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL--
Not sure what you mean, but I'd suggest to DEBUG the code in the MultipartAwareFormHttpMessageConverter.readMultipart(). That is a place where an UploadedMultipartFile appears.
A quick look at the CommonsMultipartResolver seems to indicate it doesn't support nested multiparts.
It might not be too hard to subclass it and override parseRequest(), but you might have to dig into commons-fileupload as well.
EDIT
Regarding multipart response:
I just patched the http sample and found that, as long as the request has a proper accept header, simply returning a MultiValueMap "just works".
If you need more control over the part headers, you would need to subclass the AllEncompassingFormHttpMessageConverter and override getHttpEntity() to insert extra headers and configure the gateway to use the custom adapter. Basic headers work ok, though - this...
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("foo", "Hello");
map.add("bar", "baz");
map.add("fiz", "qux".getBytes());
return map;
...results in this...
--6_zk8PXoaiUO_By2XJuUpjs5CEEnYM-wj0qE
Content-Disposition: form-data; name="foo"
Content-Type: text/plain;charset=ISO-8859-1
Content-Length: 5
Hello
--6_zk8PXoaiUO_By2XJuUpjs5CEEnYM-wj0qE
Content-Disposition: form-data; name="bar"
Content-Type: text/plain;charset=ISO-8859-1
Content-Length: 3
baz
--6_zk8PXoaiUO_By2XJuUpjs5CEEnYM-wj0qE
Content-Disposition: form-data; name="fiz"
Content-Type: application/octet-stream
Content-Length: 3
qux
--6_zk8PXoaiUO_By2XJuUpjs5CEEnYM-wj0qE--

How do I make a Multipart request without creating files on the hard disk?

I need to request an http api, the problem is that instead of a common post request where all the parameters are separated by an &, they expect a Multipart request for each one of the parameters like this:
POST /core/eligibility HTTP/1.1
Host: server_host:server_port
Content-Length: 2408
Content-Type: multipart/form-data; boundary=XbCY
--XbCY
Content-Disposition: form-data; name=“PayloadType“
X12_270_Request_005010X279A1
--XbCY
Content-Disposition: form-data; name=“ProcessingMode"
RealTime
--XbCY
Content-Disposition: form-data; name=“PayloadID"
e51d4fae-7dec-11d0-a765-00a0c91e6da6
--XbCY
Content-Disposition: form-data; name=“TimeStamp"
2007-08-30T10:20:34Z
--XbCY
Content-Disposition: form-data; name=“UserName"
hospa
--XbCY
Content-Disposition: form-data; name=“Password"
8y6dt3dd2
--XbCY
Content-Disposition: form-data; name=“SenderID"
HospitalA
--XbCY
Content-Disposition: form-data; name=“ReceiverID"
PayerB
--XbCY
Content-Disposition: form-data; name=“CORERuleVersion"
2.2.0
--XbCY
Content-Disposition: form-data; name=“Payload"
<contents of file go here -- 1674 bytes long as specified above>
--XbCY—
There is a nice question and answer about sending a Multipart request with ruby, the problem is that you have to create a file for each of the parameters, creating like 10 different files for a simple api request is nonsense.
Is there a way to do the same without the need to create a file on disk?
Yes, there is :)
By looking at the gem rest-client, I found that there is a nice parameter called multipart, when its true, all the parameters are sent like a Multipart request.
I.e.:
require 'rest-client'
request_params = {
CORERuleVersion: "value1",
PayloadType: "value2",
ProcessingMode: "value3",
UserName: "value4",
Password: "value5",
SenderID: "value6",
ReceiverID: "value7",
PayloadID: "value8",
TimeStamp: Time.now.utc.iso8601,
Payload: "long_payload",
multipart: true
}
RestClient.post("http://www.example.com", request_params)
It's not possible to tell what your concern is, creating the files because of disk I/O or clutter, or what.
If it's any sort of I/O, you should be able to use Ruby's StringIO class, instead of a regular IO object. Everything is written and read in memory, using strings as buffers.

Resources