What is the best way to right REST web service to send multiple images using JAVA jax-rs?
Although using base64 strings is an option, there are much better ways to go about sending files in a JAX-RS web service. I personally recommend creating a method that listens for the user to POST an HTTP form. This form could really contain all of the information that you would need to send, as well as identifiers.
This is similar to a method definition that I would use for a web service of this type. It is compatible with Jersey, and it allows the user to send files via a basic HTML form or any POST request. I strongly recommend taking a look at this article on building Java web services. It doesn't cover the "file uploading" aspect, but it is extremely useful and it helped me learn much more about the functionality of Java web services in general.
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces("text/html")
public Response uploadFile(
#FormDataParam("username") String username,
#FormDataParam("password") String password,
#FormDataParam("title") String title,
#FormDataParam("file") InputStream fileInputString,
#FormDataParam("file") FormDataContentDisposition fileInputDetails) {
String status = null;
String fileLocation = "/home/user/uploadtest/test.png;
NumberFormat myFormat = NumberFormat.getInstance();
myFormat.setGroupingUsed(true);
// Save the file
try {
OutputStream out = new FileOutputStream(new File(fileLocation));
byte[] buffer = new byte[1024];
int bytes = 0;
long file_size = 0;
while ((bytes = fileInputString.read(buffer)) != -1) {
out.write(buffer, 0, bytes);
file_size += bytes;
}
out.flush();
out.close();
status = "File has been uploaded to:" + fileLocation;
} catch (IOException ex) {
System.err.println("Unable to save file: " + fileLocation);
ex.printStackTrace();
}
return Response.status(200).entity(status).build();
}
Related
I'm writing a program that builds stuff in a GUI (blah blah blah... irrelevant details), and the user is allowed to export that data as a .tex file which can be compiled to a PDF. Since I don't really want to assume they have a TeX environment installed, I'm using an API (latexonline.cc). That way, I can construct an HTTP GET request, send it to the API, then (hopefully!) return the PDF in a byte-stream. The issue, though, is that when I submit the request, I'm only getting the page data back from the request instead of the data from the PDF. I'm not sure if it's because of how I'm doing my request or not...
Here's the code:
... // preceding code
DataOutputStream dos = new DataOutputStream(new FileOutputStream("test.pdf"));
StringBuilder httpTex = new StringBuilder();
httpTex.append(this.getTexCode(...)); // This appends the TeX code (nothing wrong here)
// Build the URL and HTTP request.
String texURL = "https://latexonline.cc/compile?text=";
String paramURL = URLEncoder.encode(httpTex.toString(), "UTF-8");
URL url = new URL(texURL + paramURL);
byte[] buffer = new byte[1024];
try {
InputStream is = url.openStream();
int bufferLen = -1;
while ((bufferLen = is.read(buffer)) > -1) {
this.getOutputStream().write(buffer, 0, bufferLen);
}
dos.close();
is.close();
} catch (IOException ex) {
ex.printStackTrace();
}
Edit: Here's the data I'm getting from the GET request:
https://pastebin.com/qYtGXUsd
Solved! I used a different API and it works perfectly.
https://github.com/YtoTech/latex-on-http
I have a HTTP POST method that works fine if I upload text files. But if I try to upload a word document, pdf, zip, gzip, etc... the files that are uploaded get corrupted in the process. I'm using Postman to send the request. I do a "POST" method, enter the url, add headers (tried all sorts of headers and it really does not change anything so now I don't have any entered), and then on the body I select "formdata" and select the file. I really just need to fix this to be able to support files that end in .csv.gz and .csv. Currently, csv is fine but the .csv.gz is the type that is corrupting. I tried other non-text files as well just to see what happens and they corrupt too. I cannot figure out if there is some encoding, filter, etc... that is causing this to happen that I can remove or some setting I need to apply. Or if there is some other way to handle this with jersey so the non-text files stay the same as the original file.
My application is running Spring v1.5.3 and Jersey 2.25.
#Override
public Response uploadTopicFile(String topic, FormDataMultiPart formDataMultipart) throws Exception {
List<BodyPart> bodyParts = formDataMultipart.getBodyParts();
// Getting the body of the request (should be a file)
for (BodyPart bodyPart : bodyParts) {
String fileName = bodyPart.getContentDisposition().getFileName();
InputStream fileInputStream = bodyPart.getEntityAs(InputStream.class);
String uploadedFileLocation = env.getProperty("temp.upload.path") + File.separator + fileName;
this.saveFile(fileInputStream, uploadedFileLocation);
String output = "File uploaded to : " + uploadedFileLocation;
log.debug(output);
}
return Response.status(201).build();
}
private void saveFile(InputStream uploadedInputStream, String serverLocation) {
try {
// Create the output directory
Files.createDirectories(Paths.get(serverLocation).getParent());
// Get the output stream
OutputStream outputStream = new FileOutputStream(new File(serverLocation));
int read = 0;
byte[] bytes = new byte[1024];
// Loop through the stream
while ((read = uploadedInputStream.read(bytes)) != -1) {
// Output to file
outputStream.write(bytes, 0, read);
}
// Flush and close
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return;
}
There was a filter causing the corruption. Filter was updated and issue resolved.
I have made a rest api in this it is working fine but i want to read size of file and i have used below code to read size of file
#POST
#Path("/test")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response upload( FormDataMultiPart form ){
System.out.println(" size of file="+ filePart.getContentDisposition().getSize());
}
but i got the size of file -1 .
Can any one suggest me how can i read actual size of file .
But using
System.out.println(" data name ="+ filePart.getContentDisposition().getFileName());
i got correct name of file .
First of all, I think the best way to restrict data size is setting on the server configuration. Please see the related ref.
Secondly, since it comes with the Stream, it goes til to meet EOF or similar one. That means you cannot find the size at the first place.
Third, however, one of the alternative way for judging size in jersey is using the contents size of the HTTP header. The server gets 'Content-Length' header at the first place to know the size of the body. #Context HttpServletRequest request has request.getContentLength() method. But since it has multiparts, you need to be careful that the body size has sum of the data with protocol overheads (seperator/contents infos)
Good Luck
Hope this is what you wanted. I have verified it in my system. This prints the size of the file in bytes.
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(#FormDataParam("file") InputStream uploadedInputStream, #FormDataParam("file") FormDataContentDisposition fileDetail) {
String uploadedFileLocation = "/home/Desktop/" + fileDetail.getFileName();
// save it
writeToFile(uploadedInputStream, uploadedFileLocation);
File file = new File(uploadedFileLocation);
System.out.println(file.length() + " in bytes");
String output = "File uploaded to : " + uploadedFileLocation;
return Response.status(200).entity(output).build();
}
// save uploaded file to new location
private void writeToFile(InputStream uploadedInputStream, String uploadedFileLocation) {
try {
OutputStream out = new FileOutputStream(new File(uploadedFileLocation));
int read = 0;
byte[] bytes = new byte[1024];
out = new FileOutputStream(new File(uploadedFileLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
make sure you have the following dependency in your pom.xml
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>2.13</version>
</dependency>
also add this to your application class which extends resource config. This registers your class with jersey as having multipart content.
super(YourClass.class, MultiPartFeature.class);
Try using HttpServletRequest . Kindly see the docs for more details.
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response putFile(#Context HttpServletRequest request){
Part part = request.getPart("filename");
long fileSize = part.getSize();
}
I'm using a Java REST service for a file upload.
The file should land on my server, which it does, then move to Amazon S3 bucket.
The upload to the server is fine, but the 2nd call to another method does not work.
I assume because there is a timeout issue?
The code to move the file to amazon works in another app, but I am not able to get it working within my REST project.
Here is the method:
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(#FormDataParam("file") InputStream inputStream,
#FormDataParam("file") FormDataContentDisposition file, #FormDataParam("filename") String filename){
Logger log = Logger.getLogger("Mike");
String response = "";
File f = null;
try {
final String FILE_DESTINATION = "C://uploads//" + file.getFileName();
f = new File(FILE_DESTINATION);
OutputStream outputStream = new FileOutputStream(f);
int size = 0;
byte[] bytes = new byte[1024];
while ((size = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, size);
}
outputStream.flush();
outputStream.close();
log.info("upload complete for initial file!");
//move file to Amazon S3 Bucket.
AmazonS3 s3 = new AmazonS3Client(
new ClasspathPropertiesFileCredentialsProvider());
log.info("trying put request");
PutObjectRequest request = new PutObjectRequest("site.address.org","/pdf/PDF_Web_Service/work/"+f.getName(),f);
log.info(f.getName());
log.info(f.getAbsolutePath());
s3.putObject(request);
log.info("put request complete");
response = "File uploaded " + FILE_DESTINATION;
} catch (Exception e) {
e.printStackTrace();
}
return Response.status(200).entity(response).build();
}
Specifically, here is the part not working. I am not getting any log info either:
//move file to Amazon S3 Bucket.
AmazonS3 s3 = new AmazonS3Client(
new ClasspathPropertiesFileCredentialsProvider());
log.info("trying put request");
PutObjectRequest request = new PutObjectRequest("site.address.org","/pdf/PDF_Web_Service/work/"+f.getName(),f);
log.info(f.getName()); log.info(f.getAbsolutePath());
s3.putObject(request); log.info("put request complete");
Michael,
If it's a time-out issue, it's common practice to use guava's Listenable Future to chain your tasks together. What your web sequence will look like then is:
a) Client sends file
b) Server responds with 200 once file completes uploading.
c) Once the server is done loading the file, chain the future to then upload to S3.
Chaining listenable futures is common practice to separate functionality and ensure a time out doesn't occur by breaking up your code and essentially pipe-lining it.
Please let me know if you have any questions!
I moved the Amazon code into the try block and now it works.
I am sending images from my android client to java jersey restful service and I succeded in doing that.But my issue is when I try to send large images say > 1MB its consumes more time so I like to send image in CHUNKS can anyone help me in doing this.How to send(POST) image stream in CHUNKS to server
references used :
server code & client call
server function name
/*** SERVER SIDE CODE****/
#POST
#Path("/upload/{attachmentName}")
#Consumes(MediaType.APPLICATION_OCTET_STREAM)
public void uploadAttachment(
#PathParam("attachmentName") String attachmentName,
#FormParam("input") InputStream attachmentInputStream) {
InputStream content = request.getInputStream();
// do something better than this
OutputStream out = new FileOutputStream("content.txt");
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
// whatever processing you want here
out.write(buffer, 0, len);
}
out.close();
return Response.status(201).build();
}
/**********************************************/
/**
CLIENT SIDE CODE
**/
// .....
client.setChunkedEncodingSize(1024);
WebResource rootResource = client.resource("your-server-base-url");
File file = new File("your-file-path");
InputStream fileInStream = new FileInputStream(file);
String contentDisposition = "attachment; filename=\"" + file.getName() + "\"";
ClientResponse response = rootResource.path("attachment").path("upload").path("your-file-name")
.type(MediaType.APPLICATION_OCTET_STREAM).header("Content-Disposition", contentDisposition)
.post(ClientResponse.class, fileInStream);
You should split the file in the client and restore part of the file in the server.
and after that you should merge the files together. Take a look at split /merge file on coderanch
Enjoy ! :)
Another path is available, if you don't want to code too much consider using :
file upload apache that is great ! :)