Upload two files and an object are failing with error 415 - java

I am trying to consume an http rest call that takes input of two files a dto
#RequestMapping(name = "/my/endpoint", method = RequestMethod.POST, consumes = {MediaType.MULTIPART_FORM_DATA_VALUE,
MediaType.APPLICATION_JSON_VALUE})
public #ResponseBody
EndpointDto createEndpoint(#RequestBody MultipartFile requestFile, #RequestBody MultipartFile responseFile,
#RequestBody MyDto myDto){
return endpointService.createEndpoint(requestFile, responseFile, myDto);
}
I received the following error:
org.springframework.web.HttpMediaTypeNotSupportedException:
Content type 'multipart/form-data;boundary=----WebKitFormBoundarylq2UHYfBi0nAsRo7;charset=UTF-8' not supported
I consume the endpoint through swagger.
I think that the problem lies in the way I handle the input fields but I don't know what is the problem.

You can change the controller parameter as below
#RequestMapping(name = "/my/endpoint", method = RequestMethod.POST)
public ResponseEntity<EndpointDTO> createEndpoint(
#RequestPart(value = "file1") MultipartFile filea,
#RequestPart(value = "file2") MultipartFile fileb,
#RequestPart MyDto myDto){
return endpointService.createEndpoint(filea, fileb, myDto);
}
You can get the files and DTO values using #RequestPart.
You can test above API using following curl
curl -v -H "Content-Type:multipart/form-data" -F "myDto=#body;type=application/json" -F "file1=#file1.txt" -F "file2=#file2.txt" -X POST http://<path>/my/endpoint
Note: Here I'm using 'body' file to pass the payload and file1.txt & file2.txt to pass the MultipartFile. Hope you are familiar with the curl command and understand it.

Sample controller
#PostMapping(value = "/documents")
#Timed
public ResponseEntity<DocumentDTO> createDocument(#RequestPart String document, #RequestParam("file") MultipartFile file, HttpServletRequest httpServletRequest) throws URISyntaxException {
DocumentDTO documentDTO = convertStringToDTO(document);
DocumentDTO result = documentService.save(documentDTO, file);
return ResponseEntity.created(new URI("/api/documents/" + result.getId()))
.headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
.body(result);
}
// com.fasterxml.jackson.databind.ObjectMapper;
private DocumentDTO convertStringToDTO(String document) {
ObjectMapper objectMapper = new ObjectMapper();
DocumentDTO documentDTO = null;
try {
documentDTO = objectMapper.readValue(document, DocumentDTO.class);
} catch (IOException e) {
log.error("DocumentString to JSON", e);
}
return documentDTO;
}
You have to send the data in form-data format from front-end with key as a file containing bytes and document JSON object.

Related

Spring Boot MultipartFile always has value of null

So I'm making a RESTful API backend for a JavaScript frontend and want to upload a file to Google Cloud Storage. I have this function to handle the file upload:
#RequestMapping(value = "/uploadFile", method = RequestMethod.POST, consumes = { "multipart/form-data" })
public ResponseEntity<?> uploadFile(#ModelAttribute("file") FileDTO fileDTO) {
FunctionResponse uploadResponse = cloudStorage.uploadObject(fileDTO.getFile());
if (uploadResponse.successful()) {
return new ResponseEntity<>(uploadResponse.getMessage(), HttpStatus.OK);
} else {
return new ResponseEntity<>(uploadResponse.getMessage(), HttpStatus.BAD_REQUEST);
}
}
My fileDTO class looks like this:
public class FileDTO implements Serializable {
private MultipartFile file;
public MultipartFile getFile() {
return file;
}
}
However whenever I try and access the MultipartFile it always throws a java.lang.NullPointerException.
I have tried various SO answers from threads with similar problems but none have worked so far.
I have multipart.enabled=true in my application.properties.
Any help would be appreciated and let me know if you need any more information.
When a multipart/form-data request arrives, the data must be obtained by using #RequestParam, not #ModelAttribute + if the value you need of the request is a file, then, it should be deserialized into a MultipartFile object.
#RequestMapping(value = "/uploadFile", method = RequestMethod.POST, consumes = {"multipart/form-data"})
public ResponseEntity<?> uploadFile(#RequestParam(name = "file") MultipartFile file) {
// your handle ...
}

Return XML or JSON from a REST controller based on request parameters

This is my controller:
#PostMapping(value = "/endpoint", produces = { APPLICATION_JSON_VALUE, APPLICATION_XML_VALUE})
#ResponseBody
public Result generateResult(#Valid #RequestBody Request request) throws JsonProcessingException {
Result result = new Result();
// some code here
return result;
}
and this is my Request class:
#Data
#NoArgsConstructor
public class Request {
#NotNull
private String name;
private String type = "application/json";
}
the controller produces the correct output based on the Accept header in the request sent by the client. However, I want to send no Accept header and only send the following request:
{
"name": "my name",
"type": "application/xml"
}
Then based on the type the correct format should be output. I tried to add HttpServletResponse response to the parameter list of the controller method and then set the content type like this:
response.setHeader(CONTENT_TYPE, request.geType());
but it always returns json. any idea what else I should do?
I think a standard Spring's ResponseEntity builder give you all needed variety:
return ResponseEntity
.ok(//any object for json structure)
.headers(//any header)
.build();
Instead .ok() you can you any other method (that's http status code)
or
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyHeader", "MyValue");
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.OK);
based on the comments I post this answer which worked for me. I changed my controller method like this:
#PostMapping(value = "/endpoint", produces = { APPLICATION_JSON_VALUE,
APPLICATION_XML_VALUE})
#ResponseBody
public ResponseEntity<Result> generateResult(#Valid #RequestBody Request request)
throws JsonProcessingException {
Result result = new Result();
// some code here
return ResponseEntity.accepted()
.headers(headers)
.body(result);
}

Parsing MultipartFile data to string in spring

I am trying to parse the MultipartFile data to string and return the string as response in java springboot. Can anyone suggest the right approach for this?
controller.java
#POST
#Path("/modelInfo")
#Produces({ "application/json" })
public Response getPretrainedModel(MultipartFile data) throws IOException {
String content = new String(data.getBytes(), StandardCharsets.UTF_8);
return Response.status(Response.Status.OK).entity(content).build();
}
file.json
{
"documents": [
{
"id": "1",
"text": "abc"
}
]
}
I am sending file.json in request body as multipart/form-data and I want to read the content of the file and store it as string.
If you are using Spring and Spring Boot, then you are not using the proper annotation. Spring does not support Jax-RS specification. Therefor, change your annotations for this one:
// #POST
// #Path("/modelInfo")
// #Produces({ "application/json" })
#PostMapping(value = "/modelInfo", produces = MediaType.APPLICATION_JSON_VALUE)
Then, to return an object, you can just return the object in the method:
#PostMapping(value = "/modelInfo", produces = MediaType.APPLICATION_JSON_VALUE)
public String getPretrainedModel(#RequestParam("file") MultipartFile data) throws IOException {
String content = new String(data.getBytes(), StandardCharsets.UTF_8);
return content;
}
Note:
Don't forget to add the annotation #RequestParam in your method parameter to get the uploaded file. The name file must be the name of the attribute uploaded by your POST request
By default, the HTTP Response is 200 when you don't tell Spring to send something else.
If you want to override that, annotate your method with #ResponseStatus

Java, Rest API, multipart

I want to save an entity in DB. The entity has several fields and photo (photo I will save in byte[]). I wrote a RestController, but it hasn't worked.
Format JSON, I use postman, in form-data I add a file, in raw I put body and use JSON.
#RequestMapping(value = "/upload", method = RequestMethod.POST, consumes = {"multipart/form-data"})
#ResponseBody
public void storeAd(#RequestPart("client") #Valid Client client, #RequestPart("file") #Valid MultipartFile file) throws IOException {
Client myClient = client;
byte[] s = file.getBytes();
int a = s.length;
}
I see error:
Resolved exception caused by handler execution:
org.springframework.web.HttpMediaTypeNotSupportedException:
Content type 'application/json' not supported
Request from postman1
You need to add "Content-Type : application/x-www-form-urlencoded" in header section.

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

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?
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
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.
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.
Couldn't you change your
#RequestMapping(value="/create", method=RequestMethod.POST)
to
#RequestMapping(value="/create",
method=RequestMethod.POST, consumes ={"multipart/form-data"})
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...
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")
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
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);
}
}
Exception is thrown because you don't have appropriate HttpMessageConverter, to process multipart/form-data request.
Workaround

Categories