Spring Boot Multipart File Upload - Tips to Improve Performance - java

I am exposing RESTful API to the reactjs front end application which is used to upload a file to Database.
Server Side Controller Code:
#RequestMapping(value = "/api/upload", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public UploadResponse uploadDocument(#RequestParam("doc") MultipartFile doc,
#RequestParam("metaData") String metaData, HttpServletResponse response) {
// logic to save in DB
return new UploadResponse();
}
Client Side JS Code:
uploadDocument(formData, callback) {
instance.post('/api/upload', formData)
.then((response) => {
callback(response);
})
.catch((error) => {
const errorObj = {
status: error.response.status,
data: {
message: error.response.data.message,
},
};
callback(errorObj);
});
}
application.properties
spring.http.multipart.max-file-size=20MB
spring.http.multipart.max-request-size=20MB
I am trying to upload a 20MB file (CSV or any other) , it is taking too much time to reach the controller side. (~ 1-2 minutes )
Please suggest some good techiniques or tips to improve the performance using same multipart request.
(ex: Chunking or Compressing or Streaming)

I think the easiest way would be to just zip content at javascript side and upload it to you spring boot application.
react js parts: please read upload zip file from reactjs to nodejs
spring boot multipart octet stream handling - necessary classes, test mocks etc. are described at How to go from spring mvc multipartfile into zipinputstream
Using this you should be able to zip content at react side and use it at your spring application.
Or you just zip at react side and upload the file in a normal way without any special octet stream handling in spring boot but just using java zip package classes to unzip files.

Related

Spring Boot serving an m3u8 playlist

I'm trying to serve an m3u8 playlist through Spring Boot. I have a running ffmpeg process that is transcoding a multicast in real-time and sending the files to /src/resources/public/output.m3u8. I see the playlist updating and the new .ts files being generated correctly however when trying to watch the stream in a video player, it only plays a certain amount of video. Is there a way to properly serve up a running playlist in Java instead of serving it statically?
EDIT: When starting a basic http server with python python3 -m http.server, I'm able to view the stream perfectly fine. Is there a Spring Boot way to accomplish the same task?
With Spring 4.1 your approach will work there is no issue in it. Here below is another approach in case if you want to look
#RequestMapping(value = "/VMS-49001/playlist/{listName:.+}")
public ResponseEntity<byte[]> testphoto() throws IOException {
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/vnd.apple.mpegurl"));
headers.setContentDispositionFormData(fileName, fileName);
return new ResponseEntity<byte[]>(IOUtils.toByteArray(in), headers, HttpStatus.CREATED);
}

Stream content from external http resource

I am trying to use my spring boot application as a proxy for certain image or video content hosted externally.
#GetMapping("/video.mp4")
public ResponseEntity<Resource> getVideo(#PathVariable String filename) {
HttpHeaders headers = getHttpHeaders(filename);
ResponseEntity<Resource> exchange = restTemplate.exchange("https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_30mb.mp4", HttpMethod.GET, entity, Resource.class);
return ResponseEntity.ok().headers(headers).body(exchange.getBody());
}
I want to stream the content from the external resource to the client without downloading it first. My sample code above seems to first download the full content in to memory and then serves it.
How can I proxy the content directly without downloading it first?

Java Spark REST api upload file

I'm working with java using java-spark to create the Rest Api and I'm having trouble figuring out how to receive a file so then I can process it. Haven't found anything as like in Spring that handles MultipartFile. Also this proyect is ran on a Tomcat server.
As per the official documentation, the following code you get you started:
post("/yourUploadPath", (request, response) -> {
request.attribute("org.eclipse.jetty.multipartConfig", new MultipartConfigElement("/temp"));
try (InputStream is = request.raw().getPart("uploaded_file").getInputStream()) {
// Use the input stream to create a file
}
return "File uploaded";
});

CXF file upload service: Couldn't determine the boundary from the message

I am prototyping a very simple POST service to upload a file:
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Path("fileUpload")
public Response uploadFile(MultipartBody body) {
//never gets to here
System.out.println("In uploadFile");
//TODO: implementation
return Response.ok().build();
}
I get
org.apache.cxf.interceptor.Fault: Couldn't determine the boundary from the message!
I also tried to replace the method declaration with:
public Response uploadFile(List<Attachment> attachments,
#Context HttpServletRequest request) {
as per some Google findings, to no help.
I am using two different clients to invoke this service: chrome://poster, which has a field to include a file attachment, and a simple Python script as is explained here. Both clients produce the same result.
How should I change my service implementation or the call or both in order to be able to pass the CXF validation and enter into the actual body of the service?
REFERENCES:
JAX-RS : Support for Multiparts
Apache CXF: JAX-RS Restful web service for uploading/downloading Text file + Java client
The server side code looks fine. Problem is the way you are sending data from client. You are sending data as a stream in payload not as an attachment which has boundary. To verify quickly you can enable logging request and response by enabling CXF Feature LoggingFeature or Interceptors LoggingInInterceptor and LoggingoutInterceptor. In the log if you see data coming Payload then you are sending data as stream in this case you need to change the way you send the data else you can change consumes to application/octetstream and receive data using inputstream directly.
I'm not aware of the tool you are using, however I use Chrome Extension to postman to test the REST services. If you install the extension and launch the application.
You can upload the file using below approach.
Change Method type to POST from the drop down.
Enter the URL
Select Tab Body
Select Form-Data Radio Button
On the right most row select file from drop down. as shown in diagram.
Choose file to upload.
Optional enter multipart key.
Finally click send.
We can reproduce your error by selecting binary radio button and uploading file as shown below.

How to send a blob from Endpoint Function to a Servlet

I managed to upload the blob from Javascript to Java Endpointfunction
Javascript
var request = gapi.client.helloworldendpoints.uploadImage({
'imageData': __upload.imageData,
'fileName': __upload.fileName,
'mimeType': __upload.mimeType,
'size': __upload.size
});
Java Endpoint
public ImageUploadRequest uploadImage(
Request imageData,
#Named("fileName") String fileName,
#Named("mimeType") String mimeType,
#Named("size") float size
) { ... }
Request is just this
public class Request {
public Blob image;
}
Now i want to send a MultipartRequest from my Java Endpoint at GAE to my UploadServlet to create a blobkey and save the data into blobstorage, since Blobstorage only accepts data send to servlet. How can I create a MultipartRequest?
There are numerous ways to construct an HTTP request in Java. This question, while dealing with some very specific systems, is too broad for Stack Overflow, since the real question is "how can I build and execute a multi-part/form-data request in Java?" You should look into the UrlFetch service on App Engine, since this is how all HTTP requests are sent. You can find examples of HTTP requests in Java all over the internet.

Categories