I have a servlet application that need to receive some files from some clients (in general not html\javascript based!) and I have to limit the filesize for each file. Thisi is a classical problem.
The streaming API of the apache fileUpload allow to stream a multi-part request to the server avoiding the need of saving the request content in temporary files before they are processed. Is this Correct?
Anyway with this approach I obviously can't know the actual filesize.
What I though was:
The client knows the file size. So it will send a form-field containing the file size.
The content-length http header contains the request size, so I can take it as an upperbound of the filesize
I can count the bytes I'm saving
Now assuming that I want to make all the necessary validations server-side. This because I'm paranoic and I don't trust the clients, then:
a. options (1) and (2) are useful in case "good" clients make bad requests. So a first validation can be based on that.
b. option (3) is the only completely server-side option I found. So it is needed.
So I though that I could count the bytes I read and if the file exceedes the size-limit I print errors, delete the file I was writing and then make the "return" in servlet doPost.
Am I doing right or there are some other better way to go?
Try like this into your Servlet, also get all information about file from item
//TODO Create and check tmpDir & destinationDir then do as below
PrintWriter out = response.getWriter();
response.setContentType("text/xml;charset=UTF-8");
File file = null;
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
fileItemFactory.setSizeThreshold(10 * 1024 * 1024);
fileItemFactory.setRepository(tmpDir); /* Set the temporary directory for uploaded files of size above threshold. */
ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
try {
List items = uploadHandler.parseRequest(request);
Iterator itr = items.iterator();
while (itr.hasNext()) {
FileItem item = (FileItem) itr.next();
if (item.getSize() <######||item.getSize() > 0){ // Where you can control file size
if (item.isFormField()) {
System.out.println("Field = " + item.getFieldName() + ", Value = " + item.getString());
} else {
System.out.println("Field Name = " + item.getFieldName() + ", File Name = " + item.getName() + ", Content type = " + item.getContentType() + ", File Size = " + item.getSize());
file = new File(destinationDir, item.getName()); ///Destination for permanent save*/
item.write(file);
}
out.println("Upload success");
}else{
out.println("File Size is not be zero OR more than ####");
}
}
} catch (FileUploadException ex) {
out.println("Upload Failed" + ex.getMessage());
log("Error while parsing the request", ex);
} catch (Exception ex) {
out.println("Upload Failed" + ex.getMessage());
log("Error while uploading file", ex);
}
out.close();
Related
I am fetching S3 objects and then sending the object in email as an attachment. I am saving the contents in a temporary file. For images the code is working fine but in case of documents (pdf, docx, csv) files the attachments are sent without extension so they are not accessible.
try {
fullObject = s3Client.getObject(new GetObjectRequest(bucketName, key));
System.out.println("fullObject: " + fullObject);
ObjectMetadata metadata = fullObject.getObjectMetadata();
System.out.println(" meta data type: " + metadata.getContentType());
InputStream inputStream = fullObject.getObjectContent();
String extension = fullObject.getKey();
int index = extension.lastIndexOf('.');
if(index > 0) {
extension = extension.substring(index + 1);
System.out.println("File extension is " + extension);
}
File file = File.createTempFile(key, "."+ extension );
System.out.println("file: "+ file);
try (OutputStream outputStream = new FileOutputStream(file)) {
IOUtils.copy(inputStream, outputStream);
} catch (Exception e) {
System.out.println("error in copying data from one file to another");
}
dataSource = new FileDataSource(file);
System.out.println("added datasource in the list");
attachmentsList.add(dataSource);
}
Upon going through this code, I got to know that the issue was not in this code but when I was setting the name of the File. I was setting filename without any extension, for example I set Filename as "temporary" this caused the documents to be saved with tmp extension. All I had to do was add the extension of the object with its name ("temporary.docx"), this solved the issue and attachments were sent properly and were accessible.
I was going over a nodejs tutorial which mentioned that Node.JS does not keep the file in memory when writes files to a disk and it flushes chunks of file to disk as and when it receives it. Is Java capable of handling file in a similar fashion or does it keep the entire file in memory before flushing to disk? In the past , I have faced out of memory exception when I tried to upload files using servlets.
The answer is Yes, In java you can use streaming APIs that can help you do it.
try the following guide to understand it better :
http://commons.apache.org/proper/commons-fileupload/streaming.html
Example :
Fileupload using Servlet:
// Check that we have a file upload request
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
ow we are ready to parse the request into its constituent items. Here's how we do it:
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload();
// Parse the request
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (item.isFormField()) {
System.out.println("Form field " + name + " with value " + Streams.asString(stream) + " detected.");
} else {
System.out.println("File field " + name + " with file name " + item.getName() + " detected.");
// Process the input stream
...
}
}
And at last you can write the input stream in a file using the follwing approach :
FileOutputStream fout= new FileOutputStream ( yourPathtowriteto );
BufferedOutputStream bout= new BufferedOutputStream (fout);
BufferedInputStream bin= new BufferedInputStream(stream);
int byte;
while ((byte=bin.read()) != -1)
{
bout.write(byte_);
}
bout.close();
bin.close();
This question already has answers here:
Upload multiple files at once to a Struts2 #Action
(2 answers)
Closed 7 years ago.
How to upload multiple file in any location. My Problem is that i am selecting multiple files but when i click on the upload button only last one file is uploaded with rename name and the rename name is all file name append with comma like this (file1,file2,flie3)
Here is the code
File saveFile = null;
String tempPath = System.getProperty("java.io.tmpdir");
saveFile = new File(tempPath + File.separator + fileUploadFileName);
FileUtils.copyFile(fileUpload, saveFile);
By using Apache commons fileupload FileItem, the sample code will be like this
try {
// parses the request's content to extract file data
List formItems = upload.parseRequest(request);
Iterator iter = formItems.iterator();
// iterates over form's fields
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
// processes only fields that are not form fields
if (!item.isFormField()) {
String fileName = new File(item.getName()).getName();
String filePath = uploadPath + File.separator + fileName;
File storeFile = new File(filePath);
// saves the file on disk
item.write(storeFile);
}
}
request.setAttribute("message", "Upload has been done successfully!");
} catch (Exception ex) {
request.setAttribute("message", "There was an error: " + ex.getMessage());
ex.printStackTrace();
}
Download MultipleFilesUpload.zip from Multi File Upload. Refer to this Upload for more details :
I have a java program that call my Perl script to upload a file. It has a file parameter to the Perl script that contain the location of file to upload.
public static void legacyPerlInspectionUpload(String creator, String artifactId, java.io.File uploadedFile, String description ) {
PostMethod mPost = new PostMethod(getProperty(Constants.PERL_FILE_URL) + "inspectionUpload.pl");
try {
String upsSessionId = getUpsSessionCookie();
//When passing multiple cookies as a String, seperate each cookie with a semi-colon and space
String cookies = "UPS_SESSION=" + upsSessionId;
log.debug(getCurrentUser() + " Inspection File Upload Cookies " + cookies);
Part[] parts = {
new StringPart("creator", creator),
new StringPart("artifactId", artifactId),
new StringPart("fileName", uploadedFile.getName()),
new StringPart("description", description),
new FilePart("fileContent", uploadedFile) };
mPost.setRequestEntity(new MultipartRequestEntity(parts, mPost.getParams()));
mPost.setRequestHeader("Cookie",cookies);
HttpClient httpClient = new HttpClient();
int status = httpClient.executeMethod(mPost);
if (status == HttpStatus.SC_OK) {
String tmpRetVal = mPost.getResponseBodyAsString();
log.info(getCurrentUser() + ":Inspection Upload complete, response=" + tmpRetVal);
} else {
log.info(getCurrentUser() + ":Inspection Upload failed, response=" + HttpStatus.getStatusText(status));
}
} catch (Exception ex) {
log.error(getCurrentUser() + ": Error in Inspection upload reason:" + ex.getMessage());
ex.printStackTrace();
} finally {
mPost.releaseConnection();
}
}
In this part of my Perl script, it get the information about the file, read from it and write the content to a blink file in my server.
#
# Time to upload the file onto the server in an appropropriate path.
#
$fileHandle=$obj->param('fileContent');
writeLog("fileHandle:$fileHandle");
open(OUTFILE,">$AttachFile");
while ($bytesread=read($fileHandle,$buffer,1024)) {
print OUTFILE $buffer;
}
close(OUTFILE);
writeLog("Download file, checking stats.");
#
# Find out if the file was correctly uploaded. If it was not the file size will be 0.
#
($size) = (stat($AttachFile))[7];
Right now the problem is this only work for file with no space in its name, otherwise $size is 0. I was reading online and it seems both Java file and Perl filehandle work with space, so what am I doing wrong?
Your poor variable naming has tripped you up:
open(OUTFILE,">$AttachFile");
^^^^^^^---this is your filehandle
while ($bytesread=read($fileHandle,$buffer,1024)) {
^^^^^^^^^^^--- this is just a string
You're trying to read from something that's NOT a filehandle, it's just a variable whose name happens to be "filehandle". You never opened up the specified file for reading. e.g. you're missing
open(INFILE, "<$fileHandle");
read(INFILE, $buffer, 1024);
I am trying to let the user save data from my servlet as a CSV file. Originally I was just locating their desktop to drop the file, but permission would be denied with this route so I want to ask the user where they want to save it.
From what I am seeing, I cannot use the Swing API in a servlet because Tomcat does not know how to draw the GUI. I tried this code:
String fileName = "ClassMonitor" + formatter.format(currentDate) + ".csv";
File csvFile = new File(fileName);
//Attempt to write as a CSV file
try{
JFileChooser fileChooser = new JFileChooser();
fileChooser.setSelectedFile(csvFile);
int returnValue = fileChooser.showSaveDialog(null);
if(returnValue == JFileChooser.APPROVE_OPTION)
{
BufferedWriter out = new BufferedWriter(new FileWriter(csvFile));
//Iterates and writes to file
for(ClassInfo classes : csvWrite)
{
//Check if the class has a comma. Currently, only section titles have a comma in them, so that's all we check for.
classes.setSectionTitle(replaceComma(classes.getSectionTitle()));
out.write(classes.toString());
}
//Close the connection
out.close();
}
//Log the process as successful.
logger.info("File was successfully written as a CSV file to the desktop at " + new Date() + "\nFilename" +
"stored as " + fileName + ".");
}
catch(FileNotFoundException ex)
{
//Note the exception
logger.error("ERROR: I/O exception has occurred when an attempt was made to write results as a CSV file at " + new Date());
}
catch(IOException ex)
{
//Note the exception
logger.error("ERROR: Permission was denied to desktop. FileNotFoundException thrown.");
}
catch(Exception ex)
{
//Note the exception
logger.error("ERROR: Save file was not successfull. Ex: " + ex.getMessage());
}
}
But this will throw a headlessException.
Any guidance on how to implement something like a save file dialog in a servlet would be appreciated.
Just write it to the response body instead of to the local(!!) disk file system.
response.setContentType("text/csv"); // Tell browser what content type the response body represents, so that it can associate it with e.g. MS Excel, if necessary.
response.setHeader("Content-Disposition", "attachment; filename=name.csv"); // Force "Save As" dialogue.
response.getWriter().write(csvAsString); // Write CSV file to response. This will be saved in the location specified by the user.
The Content-Disposition: attachment header takes care of the Save As magic.
See also:
JSP generating Excel spreadsheet (XLS) to download
You can't call the JFileChooser from the servlet because the servlet runs on the server, not on the client; all of your Java code is executed on the server. If you want to save the file on the server, you need to already know the path you want to write to.
If you want to prompt the user's browser to save the file, use the content-disposition header: Uses of content-disposition in an HTTP response header