can you please help on below points to understand Jersey flow.
Considering below example code
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces({ MediaType.APPLICATION_JSON })
public CustomObject acceptFile(#FormDataParam("json") FormDataBodyPart json,
#FormDataParam("data") FormDataContentDisposition contentDisposition,
#FormDataParam("data") final InputStream input){
...
}
if I transfer file of 20 MB, control does not get into above method until all 20 MB data is transferred to server from client. this is my observation. am I correct?
Does Jersey creates temporary files or stores file contents in memory?
if Jersey creates temporary files where does these temporary files being created?
For completeness I tried to use HTML as client.
Related
I have to upload a binary file to my server using UI/Postman client. My backend code for Rest API is:
#POST
#Produces({JSONHeaders.MEDIA_TYPE_JSONAPI, MediaType.APPLICATION_JSON})
#Path("loadLicense")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response loadLicense2(#ApiParam("load a license") File input) {
....
}
But the file I get has header details added to it which I don't need. File content is something like:
----------------------------013134317098674079511595^M
Content-Disposition: form-data; name="file"; filename="license.lic"^M
Content-Type: application/octet-stream^M
^M
^#^#^T.^#^#m.....^#^#^#^K^#^A^#^#^#^#^C^#^#^#(^#.^E^#^#^#^K^#.^#^#^#^G.^#^#^#^K^#.^#^#^#^#^B^#^#^#^K^#.^#^#^#^#^#^#^#^#^K^#.^#^#^#^#^F^#^#^#^K^#.^#^#^
^#^#^#^U^#^N^BGR^#^#^#^#^M^#^G^Bc^#^#^#^#^K^#^O^B1.0^#^#^#^#^Q^#4^Bpermanent^#^#^#^#^G^#.
^G.^V......I..^HC_.^^.^U...Y..G.^K.R.^?^O&..^.{V.Z.......h^B.<^O....w'#bk.^B]..*...8.W93...Z.\..... ..g.a+.....,^M
----------------------------013134317098674079511595--^M
But I just need the binary content. Is there any way to do that?
Note: I tried #FormParam - it doesn't work and I get this error
The #FormParam is utilized when the content type of the request entity is not application/x-www-form-urlencoded]
Tried #FormDataParam - not able to resolve it in code.
Instead of #FormParam you might need to use #FormDataParam, depending on how you send the data via Postman. They have different purposes, i.e. are for use with different MIME types:
#FormParam is intended to be used with MIME type application/x-www-form-urlencoded (constant MediaType.APPLICATION_FORM_URLENCODED)
#FormDataParam is intended to be used with multipart/form-data (constant MediaType.MULTIPART_FORM_DATA)
The following snippet expects the file being sent via form data:
#POST
#Produces({JSONHeaders.MEDIA_TYPE_JSONAPI, MediaType.APPLICATION_JSON})
#Path("loadLicense")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response loadLicense2(
#FormDataParam("file") InputStream istream,
#FormDataParam("file") FormDataContentDisposition disp) {
}
The input stream contains the binary data, the second parameter gives you some information about the uploaded file, e.g. the file name.
You need the jersey-media-multipart artifact for this:
https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-multipart
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>3.0.2</version>
</dependency>
I want to programm a messenger, which runs on a Server and can send an zip file at any size. So you would send the zip file to the server and when any other person is online, the server sends the zip File to the other person. I have no idea what servertype I could use and when I was reserching I found nothing. Because I want to run the sever on my Raspberry Pi, it would be also helpfull, if I could slow the datastream down. It would be very helpful, if one of you could recommend servertypes, classes or methods, so that I can do more research.
Thank you in advance
You can create a maven-project on EclipseIDE and use Jersey for API-layer (tutorial: https://www.journaldev.com/498/jersey-java-tutorial).
Your class:
#Path("/zip")
public class ZIPRest{
#POST
#Path("/upload")
#Consumes("application/json")
#Produces("application/json")
public Response uploadZIP(InputStream file){
// TODO: convert InputStream in BLOB and save it on database
}
}
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.
I run a simple backend app which allows to upload files. I use Jersey and run it in Jetty. The piece of my code looks like this:
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(#Context UriInfo uriInfo, FormDataMultiPart multipart, #Context HttpServletRequest httpRequest) {
FormDataBodyPart fileId = multipart.getField("fileId");
FormDataBodyPart fileSize = multipart.getField("fileSize");
FormDataBodyPart file = multipart.getField("file");
ContentDisposition cd = file.getContentDisposition();
String fileName = cd.getFileName();
long size = Long.valueOf(fileSize.getValue());
...
Upload works just fine, but I found that the method is called just when the whole stream is uploaded to the backend. So, for instance, if I send huge file (3Gigs to be uploaded) my POST request immediately appears on the backend, but the method above is invoked only when the whole 3 Gigs are uploaded through the network.
I would like to make some checks in the method and don't upload the file for some cases, so it doesn't need to pass the whole content to the backend and then send the error message back.
How can I avoid uploading the whole file content to the backend but make the method is invoked before I start to read from the data stream?
Eventually I worked it around with 2 sequential POSTs the client should make to upload such big files:
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response newUpload(#Context UriInfo uriInfo, FormDataMultiPart multipart,
#Context HttpServletRequest httpRequest) {
FormDataBodyPart fileSize = multipart.getField("fileSize");
long size = Long.valueOf(fileSize.getValue());
if (!checkSizeLimits(size)) {
return Response.status(Status.BAD_REQUEST).build();
}
// here comes some code which generates an unique id and its URI for the data
...
return Response.status(Status.CREATED).entity(new FileUploadInfo(uri.toString())).build();
}
#POST
#Path("/{fileId}")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(#Context UriInfo uriInfo, FormDataMultiPart multipart,
#Context HttpServletRequest httpRequest, #PathParam("fileId") String fileId) {
FormDataBodyPart fileSize = multipart.getField("fileSize");
FormDataBodyPart file = multipart.getField("file");
//...
return Response.status(Status.CREATED).entity(new FileUploadInfo(uri.toString())).build();
}
It looks ugly, but better than to do the file size check after the data stream is completely loaded. So, client should make POST call to the newUpload() method first providing the file size. If the size is ok, the response contains URI for the second POST to stream the file data. The second method can do the file size check again (not provided), to be sure that the initial POST had the same file size field.
I am looking to create a RESTful API for use with an Android and iOS app. So far I have been experimenting with using Jersey on the server and then the appropriate http libraries on the client side. At the moment I have been using multipart/related as the mimetype for the request with JSON forming the first part of the body then a jpeg image as the second.
So far I have had problems with making the request to the server, getting a 406 Not Acceptable from Jersey. I note that multipart/related is primarily used in sending emails. Is there actually a way that I can support mixed type content as an upload or have I entirely mis-understood the usage of multipart/related in this context?
You may want to look at this blog, for more information, but here is the important part to help you along:
http://www.mkyong.com/webservices/jax-rs/file-upload-example-in-jersey/
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(
#FormDataParam("file") InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition fileDetail) {
String uploadedFileLocation = "d://uploaded/" + fileDetail.getFileName();
// save it
writeToFile(uploadedInputStream, uploadedFileLocation);
String output = "File uploaded to : " + uploadedFileLocation;
return Response.status(200).entity(output).build();
}
I expect you want multipart/form-data instead, as this is part of the description of multipart/related:
The Multipart/Related media type is intended for compound objects
consisting of several inter-related body parts. For a
Multipart/Related object, proper display cannot be achieved by
individually displaying the constituent body parts. The content-type
of the Multipart/Related object is specified by the type parameter.
The "start" parameter, if given, points, via a content-ID, to the
body part that contains the object root. The default root is the
first body part within the Multipart/Related body.
For more on this mime type you can look at
https://www.rfc-editor.org/rfc/rfc2387
If you are wanting to submit image along with the json body, you can base64 encode the image and include the base64 string in the json. Then on the server side, you base64 decode the string and upload the image file to the blobstore. See the file upload example (at the bottom of the page) here https://developers.google.com/appengine/docs/java/blobstore/overview
Alternatively, you could do a separate upload to the blobstore and get the blobkey for the uploaded image. You can then include the blobkey in the json body that you post to the server.Using this approach you would need to get the uploadurl every time you need to do a new image upload.