Here's my controller below:
#RequestMapping(value="/upload", method=RequestMethod.PUT)
public ResponseEntity<String> handleFileUpload(
#RequestParam("file") MultipartFile file,
#RequestParam("data") String campaignJson,
Principal principal) throws JsonParseException, JsonMappingException, IOException {
I want to be able to receive a MultipartFile as well as a JSON string containing data associated to the file (title, description, etc).
I can get MultipartFile uploading to work on it's own, and I can receive a JSON string and parse it on its own, but when I have them together in 1 controller, it fails. Whenever I print out the String campaignJson it says [object Object] instead of the data that I'm sending (when I print out the data being sent in angular, it's in correct JSON format.)
I've tried #RequestBody, #RequestParam, #RequestPart, but to no avail.
My question is: How do I receive both a MultipartFile and data in the form of JSON in one Spring controller?
This worked for me :
#RequestMapping(value = "/{id}/upload", method = RequestMethod.PUT)
public DocumentResource uploadPut(#PathVariable("id") Long id,
MultipartHttpServletRequest request,
HttpServletResponse response) {
String next = request.getFileNames().next();
MultipartFile file = request.getFile(next);
.....
}
Edit :
Using the MultipartHttpServletRequest should not limit you in any way to use other #PathVariables or #RequestParams, so passing title and description should be possible.
I used it to upload multiple images with AngularJS and FileUploader
( angular-file-upload v1.1.5 )
like this
var uploader = new FileUploader({
url: config.apiUrl('/machine/' + $scope.id + '/images/'),
method: "post",
queueLimit: maxFiles
});
Related
I am working on a Spring Boot Project where I want to send JSON data and Multipart File (Image) in a single API call. For this, I referred- https://blogs.perficient.com/2020/07/27/requestbody-and-multipart-on-spring-boot/#:~:text=Usually%20we%20add%20%40RequestBody%20and,So%2C%20annotation%20should%20be%20altered.
My Controller is-
#PostMapping(value = "/create",consumes = {MediaType.APPLICATION_JSON_VALUE,MediaType.MULTIPART_FORM_DATA_VALUE})
public ResponseEntity<SuccessResponse<PostDto>> createPost(
#RequestPart("post") String post,
#RequestPart("image") MultipartFile file,
#RequestParam(name = "userid") Integer uid,
#RequestParam(name = "categoryid") Integer categoryId) {
log.info("Filename :" + file.getOriginalFilename());
log.info("Size:" + file.getSize());
log.info("Contenttype:" + file.getContentType());
//convert the post string to POJO
PostDto postDto=postService.getJson(post);
//Now create the post
PostDto newPost = this.postService.createPost(postDto, uid, categoryId, file);
SuccessResponse<PostDto> successResponse = new SuccessResponse<>(AppConstants.SUCCESS_CODE,
AppConstants.SUCCESS_MESSAGE, newPost);
return new ResponseEntity<>(successResponse, HttpStatus.OK);
}
I am using Postman for testing-
When I make the request, I get the following error (Note- I have set the error response in Spring Security as seen in the image.)
[nio-8085-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required part 'image' is not present.]
I tried another approach but it gives another error-
#PostMapping("/uploadimage/{postid}/{isUpdatingPost}")
public ResponseEntity<SuccessResponse<String>> uploadImage(#RequestParam(name="file") MultipartFile file, #PathVariable("postid") int postid, #PathVariable("isUpdatingPost")boolean isUpdatingPost){
String result=this.postService.uploadImage(file, postid, isUpdatingPost);
SuccessResponse<String> response=new SuccessResponse<>(AppConstants.SUCCESS_CODE,AppConstants.SUCCESS_MESSAGE,result);
return new ResponseEntity<>(response,HttpStatus.OK);
}
[Request processing failed: org.springframework.web.multipart.MultipartException: Current request is not a multipart request] with root cause
org.springframework.web.multipart.MultipartException: Current request is not a multipart request
I am not able to understand the problem in these approaches. I also set the content type to multipart/form-data in Postman and the consume parameter in #PostMapping, but still getting these errors.
Please help in finding the problem!
This worked for me.
For attaching single file with #RequestParam:
#PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<?> uploadImage(#RequestParam MultipartFile file) throws IOException {
// ...
}
For attaching file in DTO with #ModelAttribute:
public record FileDTO(
Integer id,
MultipartFile file) {
}
#PostMapping(value = "/2", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.IMAGE_JPEG_VALUE)
public ResponseEntity<?> uploadImage2(#ModelAttribute FileDTO dto) throws IOException {
// ...
}
BTW, you probably want use OpenAPI(Swagger UI) for manually testing your app, it's easier than using postman.
Reference article: https://www.baeldung.com/spring-file-upload
I want to test my Spring Controller that has input json and multipart file, however even if the function works, I can't get the test works
I tried using MockMvcRequestBuilders.fileUpload but the test always get 405
The controller:
#PutMapping(value = "/upload", consumes = {"multipart/form-data"})
public BaseResponse<SomeModel> updateSomeModelContent(
#ApiIgnore #Valid #ModelAttribute MandatoryRequest mandatoryRequest,
#PathVariable("id") String id,
#RequestParam("file") MultipartFile file,
#RequestParam("json") String json) throws IOException {
final CommonSomeModelRequest request = JSONHelper.convertJsonInStringToObject(json, CommonSomeModelRequest.class);
return makeResponse(someModelSer.updateContent(id, request, mandatoryRequest, file));
}
The test:
#Test
public void updateCountryContentSuccessTest() throws Exception {
MockMultipartFile file1 = new MockMultipartFile("file", "filename-1.jpeg", "image/jpeg", "some-image".getBytes());
MockMultipartFile file2 = new MockMultipartFile("json", "", "application/json","{\"exampleAttr\": \"someValue\"}".getBytes());
when(this.someModelService
.updateContent(id, request, MANDATORY_REQUEST, file1))
.thenReturn(someModelUpdatedContent);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders
.fileUpload("/upload/{id}", id)
.file(file1)
.file(file2)
.requestAttr("mandatory", MANDATORY_REQUEST);
this.mockMvc.perform(builder)
.andExpect(status().isOk());
verify(this.someModelService)
.updateContent(id, request, MANDATORY_REQUEST, file1);
}
The result status is always 405, I don't know how to make it 200
MockMvcRequestBuilders.multipart(...) create MockMultipartHttpServletRequestBuilder which support only POST.
But in your controller you use POST. You should change PUT to POST mapping in the rest controller.
Also according to RFCs we should use POST instead of PUT on multipart upload.
Have a look at Spring MVC Framework: MultipartResolver with PUT method
I am trying so much to send a request like CommonsMultipartFile and one java object.I constructed controller like follows.
public #ResponseBody Response upload(#RequestParam CommonsMultipartFile userPhoto, #RequestBody UserDetails userDetailsId,
#RequestParam String authCode)
//method impl
}
when I am trying to send request from postman:
In form-data uploaded image(1st screenshot) ,In Body-raw(2nd screenshot) i am sending user object.This is what I done.Can you please tell me how to fix this issue.Or can you please suggest me right way if I am wrong.
Thanks in advance.
#RequestMapping(method = RequestMethod.POST, headers = ("content-type=multipart/*"), produces = "application/json", consumes = "image/*")
public RestResponse save(#RequestParam("bankAddress") String bankAddress, #RequestParam("bankNameAr") String bankNameAr, #RequestParam("bankNameEn") String bankNameEn, #RequestParam("bankPhone") String bankPhone, #RequestParam("bankStatus") BigDecimal bankStatus, #RequestParam("countryId") long countryId,
#RequestParam("bankImage") MultipartFile file) {
.
.
.
}
and use byte[] data = file.getBytes(); to get file into byte[] and use for further process.
I have implemented Jaxb2RootElementHttpMessageConverter for converting XML request to my java object and it works. My controller looks like
#RequestMapping(value = "/post", method = RequestMethod.POST)
public MyResponse post(#RequestBody MyRequest request, BindingResult result)
I want to recieve simultaneously raw xml request for storing logs and converted java object for validation and another processes like
#RequestMapping(value = "/post", method = RequestMethod.POST)
public MyResponse post(#RequestBody String originalRequest, #RequestBody #Valid MyRequest request, BindingResult result)
I have tried to get response body as HttpServletRequest's InputStream, but I got IOException: Stream closed
How to do it if I want so Spring make transformation and validation instead of my code?
I want to create a API which can have parameter as multipart file and JSON object (#RequestBody). Please find following snippet while calling this API. I am getting HTTP 415 Unsupported Media Type error. If I remove #RequestBody LabPatientInfo reportData then it works fine.
#RequestMapping(value={"/lab/saveReport"}, method={RequestMethod.POST},
consumes={"multipart/form-data"}, headers={"Accept=application/json"})
#ResponseBody
public ResponseEntity<String>
saveReport(#RequestParam(value="reportFile") MultipartFile reportFile,
#RequestBody LabPatientInfo reportData) throws IOException {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
logger.info("in Lab Save Report");
logger.info("Report Data {} ", reportData);
//logger.info("Request BODY {} ", request.getAttribute("data"));
return new ResponseEntity<String>(HttpStatus.OK);
}
following is LabPatientInfo class.
#RooJson(deepSerialize = true)
#RooToString
public class LabPatientInfo {
private String firstName;
private String phoneNumber;
private String DateOfBirth;
private Integer age;
private String gender;
private String refferedBy;
private String reportfile;
private String reportType;
private String reportDate;
private String purpose;
private String followUpDate;
private List<ReportDataInfo> analytes;
while hitting API I am passing following JSON object with uploaded file..
{
"firstName":"abc",
"phoneNumber":"898989",
"DateOfBirth":"asas",
"age":"asas",
"gender":"asas",
"refferedBy":"asas",
"reportfile":"asas",
"reportType":"asas",
"reportDate":"asas",
"purpose":"asas",
"followUpDate":"asas",
"analytes":null
}
You can use #RequestPart like below. This will support both json object and multipart file.
#ResponseBody
public ResponseEntity<String>
saveReport(#RequestPart (value="reportFile") MultipartFile reportFile,
#RequestPart LabPatientInfo reportData) throws IOException {
In order to test it using curl you can create one file for your json part (reportData). Say for example you create "mydata.json" file and paste your json payload in it. And say your reportFile is "report.txt". Now you can send request using curl like below.
curl -v -H "Content-Type:multipart/form-data" -F "reportData=#mydata.json;type=application/json" -F "reportFile=#report.txt;type=text/plain" http://localhost:8080/MyApp/lab/saveReport
An example of a post method which receives a json object and a generic file:
public ResponseEntity<Resource> postGenerateReport(#RequestPart GenerateReportDTO, generateReportDTO, #RequestPart MultipartFile jxhtmlReport)
For the PostMan setup (or curl or anyother REST test utility) you just have to add form-data request with 2 elements:
Key:generateReportDTO, Value: File with .json extension (and compatible content with the object)
Key:jxhtmlReport, Value: just any file.
Gl
When a parameter is annotated with #RequestPart the content of the part is passed through an HttpMessageConverter to resolve the method argument with the 'Content-Type' of the request part in mind. This is analogous to what #RequestBody does to resolve an argument based on the content of a regular request.
so, we can parse #Requestbody as #RequestPart as "abaghel" and reportData need to be a json file.
Spring Roo 2.0.0.M3 includes support for automatic scaffolding of a REST API.
For complete information, see the REST API in the reference manual.
Note the M3 version generate artifacts that could change in newer versions, so your project might not upgrade automatically if you open it with RC1 or above.
May the Force be with you.