Create a REST API to upload Multipart file data in spring boot - java

I have created a rest API to accept MULTIPART_FORM_DATA as below. But once I hit the service using Postman, I am getting HTTP Status 415 – Unsupported Media Type exception
#POST
#Path("/fileupload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
public String uploadfile(#RequestParam(value = "file") MultipartFile file) {
System.out.println(file.getName());
return "Success String";
}
What is wrong here? To consume MediaType.MULTIPART_FORM_DATA, do I need to make any modifications?
In Postman I have attached a text file in the BODY and hit the endpoint. The content type is set as "multipart/form-data"

Seems like you are confused with Spring rest API with Rest easy implementation.
In Resteasy,
Normal way to handle uploaded file is via
MultipartFormDataInput or Map uploaded file to a
POJO class via #MultipartForm
https://www.mkyong.com/webservices/jax-rs/file-upload-example-in-resteasy/
How to POST a multipart/form data with files programatically in a REST API
If you want to use spring rest approach, refer here
Multipart File upload Spring Boot

Have a look on below tutorial on uploading file in spring boot
https://devkonline.com/tutorials/content/ANGULAR-8-SPRING-BOOT-FILE-UPLOAD

You have probably imported different annotations.
Try it this way
import org.springframework.web.bind.annotation.*;
import static org.springframework.http.MediaType.*;
#PostMapping(value = "/fileupload", consumes = MULTIPART_FORM_DATA_VALUE, produces = APPLICATION_JSON_VALUE)
public String uploadfile(#RequestParam(value = "file") MultipartFile file) {
System.out.println(file.getName());
return "Success String";
}

Related

Trouble sending multipart request

I'm creating a new endpoint to upload and process excel and csv files.
I'm trying to create an endpoint using springs Multipart upload, but I cannot reach the endpoint from Postman or using curl in command line.
I have a RestController
#RestController
#RequestMapping("/v1/finance/ratecard")
public class RateCardController
and I am able to access other endpoints in this controller without a problem.
I added new endpoint to this controller.
#PostMapping(value = "/uploadFile")
#ResponseStatus(HttpStatus.OK)
public void uploadExcelFile(#RequestPart("file") MultipartFile file, #RequestPart("meta-data") UploadRateCardRequest uploadRateCardRequest) {
//Unrelated logic here
}
And I'm trying to send POST request using postman, I haven't touched Content-Type header, it's generated by Postman, but I have had no success reaching it. I always get 404 error. Postman Config
I have tried adding consumes = "multipart/mixed" and "multipart/form-data" to #PostMapping annotation, but those changes had no effect.
What am I doing wrong? Am I missing some obvious request parameter in Postman, or is my controller set up wrong?
I had problems in uploadExcelFile method, one of dependencies I was using could not detect valid beans for an autowired interface. That was causing this issue.
Nothing was wrong with Controller set up or postman config pictured in the post.

How to get and image that my Spring boot API returns as FileSystemResource

I have a spring boot application deployed on a tomcat that's make me able to upload images from and android application. Now I'm trying to get that images. The problem is that my endpoint of my controller returns a FileSystemResource and I don't know how to handle it.
Endpoint:
#GetMapping(value = "/getFotoPerfil", produces = MediaType.IMAGE_JPEG_VALUE)
public FileSystemResource getFotoPerfil(#RequestParam("path") String path) {
return utilitiesService.findInFileSystem(path);
}
The response I receive:
If I make the call with Postman, it works:
Any help will be appreciated
Your problem is that your client code seems to be assuming that it will be getting JSON. The controller is returning an image (although it's a PNG, even though you're inaccurately telling the client it's image/jpeg), which is binary data. In Java, this response should normally be handled as a byte[] instead of a String.

Spring RestController submit file

As a part of a client request - image file must be submitted to my Spring RestController endpoint.
Is it possible to use #RequestParam("file") MultipartFile file with RestController ?
If so, could you please show an example.
Yes, it is possible and quite simple:
#RequestMapping("upload")
public void upload(#RequestParam("file") MultipartFile file){
//Do what you like with the file
}

Spring file upload content type validation, always octet-stream?

I'm trying to implement pdf file uploading in my Restful Spring Boot application.
I have the following method;
#RequestMapping(value = FILE_URL, method = RequestMethod.POST)
public ResponseDTO submitPDF(
#ModelAttribute("file") FileDTO file) {
MediaType mediaType = MediaType.parseMediaType(file.getFile().getContentType());
System.out.println(file.getFile().getContentType());
System.out.println(mediaType);
System.out.println(mediaType.getType());
if(!"application/pdf".equals(mediaType.getType())) {
throw new IllegalArgumentException("Incorrect file type, PDF required.");
}
... more code here ...
}
FileDTO is just a wrapper around MultipartFile.
I'm then using Postman to POST the request with form-data body 'file'=<filename.pdf>
The content type in the printlns above is ALWAYS octet-stream. No matter what type of file I send in (png, pdf, etc) its always octet stream. If I specifically set application/pdf as Content-Type header in Postman the MultipartFile within FileDTO ends up as null.
Question is, is there something wrong with my Spring Controller method, or is the request just not being built correctly by Postman?
If Postman can't get the Content-Type right, can I expect actual client apps to properly set content type to pdf?
Have you tried Apache Tika library for detecting mime types of uploaded file?
Code Example in Kotlin
private fun getMimeType(file: File) = Tika().detect(file)
The FileDTO will wrap the whole content of the multipart/form-data so if your uploaded file input is named file, your DTO/Form/POJO should be alike to:
class FileDTO{
#NotNull
private String anotherAttribute;
#NotNull
private MultipartFile file;
//Getters and Setters
}
Therefore you should also change your controller function to
#RequestMapping(value = FILE_URL, method = RequestMethod.POST)
public ResponseDTO submitPDF(#ModelAttribute FileDTO fileWrapper) {
MediaType mediaType = MediaType.parseMediaType(fileWrapper.getFile().getContentType());
System.out.println(fileWrapper.getFile().getContentType());
System.out.println(mediaType);
System.out.println(mediaType.getType());
if(!"application/pdf".equals(mediaType.getType())) {
throw new IllegalArgumentException("Incorrect file type, PDF required.");
}
... more code here ...
}
To use this sort of functions you should use the StandardServletMultipartResolver in your MVC configurer file. Something like:
#EnableWebMvc
#Configuration
#ComponentScan("mypackage.web.etc")
public class WebMvcConfig extends WebMvcConfigurerAdapter{
#Bean
public StandardServletMultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
}
I hope it suites you.
Normally file uploads are wrapped in a MIME multipart message format, so the content type in the HTTP header can only be multipart/form-data and you specify the MIME type of each field (include files) separately in each part.
It seems in Postman there's no way to specify the MIME type for a multi-part field so I can only assume it's a missing feature.
I've had this issue before, using the following fixed the issue:
Files.probeContentType(path)
The above returns a string with the format type. Seems to be the most reliable solution I've tried.

How to create APIs that accept file in the request object using jersey?

I'm creating apis that needs to accept a file and other informations which will be sent in a createAppRequest. What should I need to do to my apis to be able to let the user upload a file through the apis.
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response createApp(CreateAppRequest){
// save app to db
}
Request class:
public class CreateAppRequest{
// Other fields like name, createDate
#JsonProperty("file")
#Property("file")
private byte [] file;
public byte[] getFile() {
return file;
}
public void setFile(byte[] file) {
this.file = file;
}
}
I'll assume you're using the latest jersey release (2.7).
First you need to enable the MultiPart support in Jersey by adding the following to your pom.xml (if you are using maven, if not add the dependency to your project the same way you have added jersey):
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.7</version>
</dependency>
MultiPart is a Jersey Feature (such as the Jackson feature for example) and this means you will have to register it with both your client (if you have one) and your server apps.
Client side example (optional):
final Client client = ClientBuilder.newBuilder()
.register(MultiPartFeature.class)
.build();
Server side example:
final Application application = new ResourceConfig()
.packages("your.root.package.here")
.register(MultiPartFeature.class)
Once you've done all of the above you can define your post method like:
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA_TYPE)
public Response createApp(
#DefaultValue("true") #FormDataParam("enabled") boolean enabled,
#FormDataParam("data") FileData bean,
#FormDataParam("file") InputStream file,
#FormDataParam("file") FormDataContentDisposition fileDisposition) {
// your code here
}
For more information and examples take a look at the official jersey docs - https://jersey.java.net/documentation/latest/user-guide.html#multipart
However if you find this whole procedure too complicated you can always put your file in the request body as application/octet-stream and then read it in your post method with a MessageBodyReader<T>. If you are not sure what all these mean, or how to use them, again, check the jersey docs :)

Categories