POST Request to upload multipart file in Spring Boot - spring

I'm using spring boot, I need to upload a multipart file (jpg or png file). I need to send a (POST request to upload the multi part file using "postman"), can anyone provide a screen shot of "postman" of how to set it up to do that or tell me? Thanks.
method :
#RequestMapping(method = RequestMethod.POST, value = "/upload")
#ResponseBody
ResponseEntity<?> writeUserProfilePhoto(#PathVariable Long user, #RequestPart("file") MultipartFile file) throws Throwable {
byte bytesForProfilePhoto[] = FileCopyUtils.copyToByteArray(file.getInputStream()); //Return an InputStream to read the contents of the file from.
this.crmService.writeUserProfilePhoto(user, MediaType.parseMediaType(file.getContentType()),bytesForProfilePhoto);
HttpHeaders httpHeaders = new HttpHeaders();
URI uriOfPhoto = ServletUriComponentsBuilder.fromCurrentContextPath()
.pathSegment(("/users" + "/{user}" + "/photo").substring(1))
.buildAndExpand(Collections.singletonMap("user", user)).toUri();
httpHeaders.setLocation(uriOfPhoto);
return new ResponseEntity<>(httpHeaders, HttpStatus.CREATED);
}
and this is how I sent the POST request:
my configuration class:
#Configuration
#ConditionalOnClass({ Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class })
#ConditionalOnProperty(prefix = "multipart", name = "enabled", matchIfMissing = true)
#EnableConfigurationProperties(MultipartProperties.class)
public class MultipartAutoConfiguration {
#Autowired
private MultipartProperties multipartProperties = new MultipartProperties();
#Bean
#ConditionalOnMissingBean
public MultipartConfigElement multipartConfigElement() {
return this.multipartProperties.createMultipartConfig();
}
#Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
#ConditionalOnMissingBean(MultipartResolver.class)
public StandardServletMultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
}

The error in postman says
Required MultipartFile parameter 'file' is not present
The method signature looks fine defining file parameter:
ResponseEntity<?> writeUserProfilePhoto(
#PathVariable Long user, #RequestPart("file") MultipartFile file)
throws Throwable
The issue is that when using postman, you're using dog1 as the name of this parameter. Change it to file to match the expected parameter name for the multipart file.

This approach worked for me.
The error in postman says
Required MultipartFile parameter 'file' is not present
The method signature looks fine defining file parameter:
ResponseEntity<?> writeUserProfilePhoto(
#PathVariable Long user, #RequestPart("file") MultipartFile file)
throws Throwable
The issue is that when using postman, you're using dog1 as the name of this parameter. Change it to file to match the expected parameter name for the multipart file.

#Override
public Response uploadImage(String token, MultipartFile file) {
long id=tokenUtil.decodeToken(token);
Optional<User> user=userRepo.findById(id);
if(!user.isPresent()) {
throw new UserException(-5, "User does not exists");
}
UUID uuid=UUID.randomUUID();
String uniqueUserId=uuid.toString();
try {
Files.copy(file.getInputStream(), fileLocation.resolve(uniqueUserId), StandardCopyOption.REPLACE_EXISTING);
user.get().setProfilePic(uniqueUserId);
userRepo.save(user.get());
}catch (IOException e) {
e.printStackTrace();
// TODO: handle exception
}
return ResponseHelper.statusResponse(200, "Profile Pic Uploaded Successfully");
}

Related

Spring cloud feign not upload video file

I have 2 microservices. The first service(video converter) and the second service(integration Spring with Amazon S3 to store video and image on the Amazon S3).
The first service produces files by schedule and after converts File to MultipartFile uploads it to the second service and after to Amazon S3.
But I stack on the issue with Feigh uploading the video.
When I debug, I saw that the file in #RequestPart in the second service is null. But converting was done successfully.
I try adding encoding as in that post File upload spring cloud feign client, but that does not help.
Code sample first microservice:
Upload methods:
#Override
public Response<String> uploadFile(final Object object, final MultipartFile multipartFile) {
final Map<String, Object> s3Url = videoServiceFeign.uploadFile(multipartFile,
object.getId().toString(), object.getIdIds().toString(), object.getName());
object.setS3Url(s3Url.get("object").toString());
return generateSuccessResponse();
}
#Override
public Response<String> uploadFile(final Stream stream, final File file) throws IOException {
final InputStream inputStream = Files.newInputStream(file.toPath());
final MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(),
ContentType.MULTIPART_FORM_DATA.toString(), IOUtils.toByteArray(inputStream));
return this.uploadFile(stream, multipartFile);
}
Feign client:
#FeignClient(name = "video-service", url = "${video-service.ribbon.listOfServers}")
public interface VideoServiceFeign {
#PostMapping(path = "/api/v1/video/upload", consumes = {"multipart/form-data"})
Map<String, Object> uploadFile(#RequestPart("file") MultipartFile multipartFile,
#RequestParam("id") String id,
#RequestParam("ids") String ids,
#RequestParam("name") String name);
}
Upload endpoint in the second service:
#ApiOperation("Upload new video file")
#ApiResponses({
#ApiResponse(code = 200, message = "File uploaded successfully"),
#ApiResponse(code = 403, message = "Access Denied"),
#ApiResponse(code = 500, message = "Internal server error"),
#ApiResponse(code = 503, message = "Gateway timeout")
})
#ResponseStatus(HttpStatus.OK)
#PostMapping(value = "/upload", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE})
public #ResponseBody
Map<String, Object> uploadFile(#RequestPart("file") final MultipartFile file,
#RequestParam("id") final String id,
#RequestParam("ids") final String ids,
#RequestParam("name") final String name
) throws IOException {
return uploadService.uploadFile(id, ids, name, file);
}
What am I missing?
After a few days of researching, I found what I miss, the issue was with that method: public Response<String> uploadFile(final Stream stream, final File file) throws IOException
In the row:
final MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(), ContentType.MULTIPART_FORM_DATA.toString(), IOUtils.toByteArray(inputStream));
I had two issues first is the content type, I use video/mp4 not ContentType.MULTIPART_FORM_DATA.
And the second one is the first param in the constructor of MockMultipartFile I use the file.getName(), but that is incorrect because the docs say that is a field name in the multipart request. And that should be "file".

MockMvc Test does not get to the endpoint for a Multipart file in a RestController

I am calling a service in an orders controller which receives a multipart file and processes it and saving it into a database. I am trying to create a Spring Rest Doc for it but it is not even hitting the endpoint. I am creating a list of orders which is what the service expects. It receives the order as a stream as shown and converts into a stream of orders before saving it into a database. I have shown the main part of the controller and my code for generating the rest docs. When I run the code I get the following exception, it never even hits the endpoint when I set a breakpoint. I also used fileupload() but that did not work either.
Exception is:
Content type = application/json
Body = {"path":"/orders/order_reception","exceptionName":
"MissingServletRequestPartException","message":"Required request part 'uploadFile' is not
present",
"rootExceptionName":"MissingServletRequestPartException",
"rootMessage":"MissingServletRequestPartException: Required request part 'uploadFile' is not present"}
#RestController
#RequestMapping(value = "/orders")
#Validated
class OrderController{
#PostMapping(path = "/order_reception")
public ResponseEntity receiveData(#RequestPart MultipartFile uploadFile,
HttpServletRequest request,
HttpServletResponse response) {
if (!uploadFile.isEmpty()) {
try {
Reader reader = new InputStreamReader(request.getInputStream()));
... save file
return new ResponseEntity<>(HttpStatus.HttpStatus.CREATED);
} catch (Exception e) {
return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
return new ResponseEntity(HttpStatus.BAD_REQUEST);
}
#Test
public void sendData() throws Exception {
ObjectMapper mapper = new ObjectMapper();
Order order = repository.getOrder("1233333");
List<Order> orderList = new ArrayList<>():
resourceList.add(order);
MockMultipartFile orderFile = new MockMultipartFile("order-data", "order.json", "application/json",
mapper.writeValueAsString(orderList).getBytes(Charset.defaultCharset()));
mockMvc.perform(multipart("/orders/order_reception")
.file(orderFile))
.andExpect(status().isCreated())
.andDo(document("send-order",
preprocessRequest(prettyPrint()),
preprocessResponse(prettyPrint())));
}
Thank you Marten Deinum, your suggestion that the file name was wrong fixed it.
I simply changed name in the MockMultipartFile( "uploadsFile", ...)

Testing a Post multipart/form-data request on REST Controller

I've written a typical spring boot application, now I want to add integration tests to that application.
I've got the following controller and test:
Controller:
#RestController
public class PictureController {
#RequestMapping(value = "/uploadpicture", method = RequestMethod.POST)
public ResponseEntity<VehicleRegistrationData> uploadPicturePost(#RequestPart("userId") String userId, #RequestPart("file") MultipartFile file) {
try {
return ResponseEntity.ok(sPicture.saveAndParsePicture(userId, file));
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
}
Test:
#Test
public void authorizedGetRequest() throws Exception {
File data = ResourceUtils.getFile(testImageResource);
byte[] bytes = FileUtils.readFileToByteArray(data);
ObjectMapper objectMapper = new ObjectMapper();
MockMultipartFile file = new MockMultipartFile("file", "test.jpg", MediaType.IMAGE_JPEG_VALUE, bytes);
MockMultipartFile userId =
new MockMultipartFile("userId",
"userId",
MediaType.MULTIPART_FORM_DATA_VALUE,
objectMapper.writeValueAsString("123456").getBytes()
);
this.mockMvc.perform(multipart("/uploadPicture")
.file(userId)
.file(file)
.header(API_KEY_HEADER, API_KEY)).andExpect(status().isOk());
}
Testing the controller with the OkHttp3 client on android works seamlessly, but I can't figure out how to make that request work on the MockMvc
I expect 200 as a status code, but get 404 since, I guess, the format is not the correct one for that controller
What am I doing wrong?
It must be a typo.
In your controller, you claim the request URL to be /uploadpicture, but you visit /uploadPicture for unit test.

Springboot Required request part 'file' is not present

I am working on a file upload controller and I am currently getting the following error when testing in Postman.
{
"timestamp": "2019-04-18T14:53:07.988+0000",
"status": 400,
"error": "Bad Request",
"message": "Required request part 'file' is not present",
"path": "/upload"
}
At the moment my controller is very simple but first I need to overcome this problem.
I have looked at the answers given
[here](upload file springboot Required request part 'file' is not present"upload file springboot Required request part file is not present")!
But unfortunately, anything suggested here did not resolve my problem
Any help with this error would be appreciated
This is my controller:
#Controller
public class UploadController {
#ResponseBody
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public boolean upload(#RequestParam("file") MultipartFile file) throws IOException {
try {
if (!file.isEmpty()) {
return true;
} else {
return false;
}
}
catch(Exception e){
e.printStackTrace();
return false;
}
}
}
It's difficult without knowing how you are sending the data but here's how i solved sending multipart/form-data through a #RestController:
#PostMapping(value = "/foo", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
ResponseEntity fileUpload(#Requestparam("bar") LinkedList<MultipartFile> payload) {
MultipartFile file = payload.get(0)
...
Spring just wouldn't accept anything another than a linked list in my case, but that was form-data sent as an Angular2+ FormData object with field name bar.
As you hasve not mentioned your request model, let it be EarningRequest, so know your model data is:
class EarningRequest{
private FilePart file;
//and other data which you want to add.
//add the getter setters also, so that jackson can map the json to this pojo
}
#RestController
public class UploadController {
#PostMapping(value = "/upload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public boolean upload (#ModelAttribute EarningRequest earningRequest){
//earningRequest contains the file
//you can get the filePart as earningRequest.getFile()
return true;
}
}
In postman under "key" I wasn't setting anything. I needed to set this as 'file'. I previously made the assumption all I had to do was click the drop-down and select file.
I will include below all the updated code & a link to the image which explains this better(I couldn't display image here as reputation < 10)
link to postman Image
#RestController
public class UploadController {
#PostMapping("/upload")
#ResponseBody
public boolean upload(#RequestParam("file") MultipartFile file) {
try{
if(file.isEmpty() ==false){
System.out.println("Successfully Uploaded: "+ file.getOriginalFilename());
return true;
}
else{
System.out.println("ERROR");
return false;
}
}
catch(Exception e){
System.out.println(e);
return false;
}
}
}

Integration test case and file upload

I wrote some code for related to upload a file using spring, It works fine, Now I am writing integration test cases for that but I am facing some issue
My controller method,
#RequestMapping(value = "/{attributeName}/upload", method = RequestMethod.POST)
#ResponseBody
public Result uploadCompany(HttpServletRequest request,
#RequestParam MultipartFile file, #PathVariable String attributeName,
#RequestParam long dateKey)
throws IOException, PromotionException {
some code
}
Test cases
#Test
public void shouldReturnTrueStatusWhenUploadCompany() throws Exception {
MockMultipartFile file = new MockMultipartFile("company_upload", "company_upload.csv",
MediaType.MULTIPART_FORM_DATA_VALUE, EMPLOYEE_NUMBER_FILE_CONTENT.getBytes(UTF_8));
mockMvc.perform(
MockMvcRequestBuilders.fileUpload(
PROMOTION + StringUtils.replace(ATTRIBUTE_NAME, "{attributeName}", "COMPANY") + "/upload")
.file(file).param("dateKey", "852017") .contentType(MediaType.MULTIPART_FORM_DATA)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
But I am getting
2017-05-09 13:42:42,506 ERROR [Test worker] INTERNAL_SERVER_ERROR:
org.springframework.web.bind.MissingServletRequestParameterException: Required MultipartFile parameter 'file' is not present
Where am I wrong?
change your line
MockMultipartFile file = new MockMultipartFile("company_upload", "company_upload.csv",
MediaType.MULTIPART_FORM_DATA_VALUE, EMPLOYEE_NUMBER_FILE_CONTENT.getBytes(UTF_8));
to
MockMultipartFile file = new MockMultipartFile("file", "company_upload.csv",
MediaType.MULTIPART_FORM_DATA_VALUE, EMPLOYEE_NUMBER_FILE_CONTENT.getBytes(UTF_8));
or change your controller method declaration to something like this
public Result uploadCompany(HttpServletRequest request,
#RequestParam(value = "company_upload") MultipartFile file, #PathVariable String attributeName,
#RequestParam long dateKey)

Resources