I'm using Play Framework 2.0.2 to create an application that modifies Excel files uploaded by the user. Once the Excel file is uploaded and modified (server-side), the file is automatically downloaded by the user's browser.
However, using this code:
public static Result upload() throws IOException {
Http.MultipartFormData body = request().body().asMultipartFormData();
Http.MultipartFormData.FilePart filePart = body.getFile("uploadedFile");
modifyExcelFile(filepart.getFile()); // this method modifies the uploaded Excel file, and copies it to a file named "copy.xlsx"
return ok(new File("copy.xlsx"));
}
the file that is downloaded by the client will be named after the current Controller. For example, if my Controller is named UploadController, the downloaded file is surprisingly named uploadcontroller.xlsx.
Any idea on how I could modify my code in order to have a tighter control on the downloaded file's name? I would like the downloaded file to be named copy.xlsx, not uploadcontroller.xlsx.
Just add this in the response header:
response().setHeader("Content-Disposition", "attachment; filename=FILENAME");
Where FILENAME is the name you want your file to have.
Related
I am using springboot to upload file.
How to detect actual file mimetype after changing file extension?
Ex. if someone change abc.exe to abc.pdf then upload.
In that case I want to get actual extesion/mimetype that is .exe so I can restrict.
public void handleFileUpload(#RequestParam("file") MultipartFile file) {
System.out.println(file.getContentType());
}
Above code returning application/pdf if I change abc.exe to abc.pdf where actual file is .exe
I would like to be able to upload files in my JSF2.2 web application, so I started using the new <h:inputFile> component.
My only question is, how can I specify the location, where the files will be saved in the server? I would like to get hold of them as java.io.File instances. This has to be implemented in the backing bean, but I don't clearly understand how.
JSF won't save the file in any predefined location. It will basically just offer you the uploaded file in flavor of a javax.servlet.http.Part instance which is behind the scenes temporarily stored in server's memory and/or temporary disk storage location which you shouldn't worry about.
Important is that you need to read the Part as soon as possible when the bean action (listener) method is invoked. The temporary storage may be cleared out when the HTTP response associated with the HTTP request is completed. In other words, the uploaded file won't necessarily be available in a subsequent request.
So, given a
<h:form enctype="multipart/form-data">
<h:inputFile value="#{bean.uploadedFile}">
<f:ajax listener="#{bean.upload}" />
</h:inputFile>
</h:form>
You have basically 2 options to save it:
1. Read all raw file contents into a byte[]
You can use InputStream#readAllBytes() for this.
private Part uploadedFile; // +getter+setter
private String fileName;
private byte[] fileContents;
public void upload() {
fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
try (InputStream input = uploadedFile.getInputStream()) {
fileContents = input.readAllBytes();
}
catch (IOException e) {
// Show faces message?
}
}
Note the Path#getFileName(). This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
In case you're not on Java 9 yet and therefore can't use InputStream#readAllBytes(), then head to Convert InputStream to byte array in Java for all other ways to convert InputStream to byte[].
Keep in mind that each byte of an uploaded file costs one byte of server memory. Be careful that your server don't exhaust of memory when users do this too often or can easily abuse your system in this way. If you want to avoid this, better use (temporary) files on local disk file system instead.
2. Or, write it to local disk file system
In order to save it to the desired location, you need to get the content by Part#getInputStream() and then copy it to the Path representing the location.
private Part uploadedFile; // +getter+setter
private File savedFile;
public void upload() {
String fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
savedFile = new File(uploads, fileName);
try (InputStream input = file.getInputStream()) {
Files.copy(input, savedFile.toPath());
}
catch (IOException e) {
// Show faces message?
}
}
Note the Path#getFileName(). This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
The uploads folder and the filename is fully under your control. E.g. "/path/to/uploads" and Part#getSubmittedFileName() respectively. Keep in mind that any existing file would be overwritten, you might want to use File#createTempFile() to autogenerate a filename. You can find an elaborate example in this answer.
Do not use Part#write() as some prople may suggest. It will basically rename the file in the temporary storage location as identified by #MultipartConfig(location). Also do not use ExternalContext#getRealPath() in order to save the uploaded file in deploy folder. The file will get lost when the WAR is redeployed for the simple reason that the file is not contained in the original WAR. Always save it on an absolute path outside the deploy folder.
For a live demo of upload-and-preview feature, check the demo section of the <o:inputFile> page on OmniFaces showcase.
See also:
Write file into disk using JSF 2.2 inputFile
How to save uploaded file in JSF
Recommended way to save uploaded files in a servlet application
I have a Java Spring MVC web application. From client, through AngularJS, I am uploading a file and posting it to Controller as webservice.
In my Controller, I am gettinfg it as MultipartFile and I can copy it to local machine.
But I want to upload the file to Amazone S3 bucket. So I have to convert it to java.io.File. Right now what I am doing is, I am copying it to local machine and then uploading to S3 using jets3t.
Here is my way of converting in controller
MultipartHttpServletRequest mRequest=(MultipartHttpServletRequest)request;
Iterator<String> itr=mRequest.getFileNames();
while(itr.hasNext()){
MultipartFile mFile=mRequest.getFile(itr.next());
String fileName=mFile.getOriginalFilename();
fileLoc="/home/mydocs/my-uploads/"+date+"_"+fileName; //date is String form of current date.
Then I am using FIleCopyUtils of SpringFramework
File newFile = new File(fileLoc);
// if the directory does not exist, create it
if (!newFile.getParentFile().exists()) {
newFile.getParentFile().mkdirs();
}
FileCopyUtils.copy(mFile.getBytes(), newFile);
So it will create a new file in the local machine. That file I am uplaoding in S3
S3Object fileObject = new S3Object(newFile);
s3Service.putObject("myBucket", fileObject);
It creates file in my local system. I don't want to create.
Without creating a file in local system, how to convert a MultipartFIle to java.io.File?
MultipartFile, by default, is already saved on your server as a file when user uploaded it.
From that point - you can do anything you want with this file.
There is a method that moves that temp file to any destination you want.
http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/web/multipart/MultipartFile.html#transferTo(java.io.File)
But MultipartFile is just API, you can implement any other MultipartResolver
http://docs.spring.io/spring/docs/3.0.x/api/org/springframework/web/multipart/MultipartResolver.html
This API accepts input stream and you can do anything you want with it. Default implementation (usually commons-multipart) saves it to temp dir as a file.
But other problem stays here - if S3 API accepts a file as a parameter - you cannot do anything with this - you need a real file. If you want to avoid creating files at all - create you own S3 API.
The question is already more than one year old, so I'm not sure if the jets35 link provided by the OP had the following snippet at that time.
If your data isn't a File or String you can use any input stream as a data source, but you must manually set the Content-Length.
// Create an object containing a greeting string as input stream data.
String greeting = "Hello World!";
S3Object helloWorldObject = new S3Object("HelloWorld2.txt");
ByteArrayInputStream greetingIS = new ByteArrayInputStream(greeting.getBytes());
helloWorldObject.setDataInputStream(greetingIS);
helloWorldObject.setContentLength(
greeting.getBytes(Constants.DEFAULT_ENCODING).length);
helloWorldObject.setContentType("text/plain");
s3Service.putObject(testBucket, helloWorldObject);
It turns out you don't have to create a local file first. As #Boris suggests you can feed the S3Object with the Data Input Stream, Content Type and Content Length you'll get from MultipartFile.getInputStream(), MultipartFile.getContentType() and MultipartFile.getSize() respectively.
Instead of copying it to your local machine, you can just do this and replace the file name with this:
File newFile = new File(multipartFile.getOriginalName());
This way, you don't have to have a local destination create your file
if you are try to use in httpentity check my answer here
https://stackoverflow.com/a/68022695/7532946
I have a question about password protecting an Excel file.
The situation is that, I have a zip file, that has an Excel file in it. I need to write a Java program, to password protect the Excel file. Hence, the user should be able to unzip the file (the zip file need not be password protected). But, the Excel needs to be password-protected. When the user tries to unzip the file, he should be able to do so.
And when he tries to open the Excel file (which is inside the unzipped folder), it must ask for a password. The question is similar to Protect excel file with java, with the added complexity that, the Excel file is zipped.
I have code, that password protects only the zip file, but this is not what I want.
import java.io.File;
import java.util.ArrayList;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
/**
* Demonstrates adding files to zip file with standard Zip Encryption
*/
public class AddFilesWithStandardZipEncryption
{
public AddFilesWithStandardZipEncryption()
{
try {
// Initiate ZipFile object with the path/name of the zip file.
//ZipFile zipFile = new ZipFile("c:\\ZipTest\\AddFilesWithStandardZipEncryption.zip");
ZipFile zipFile = new ZipFile("C:\\homepage\\workspace\\PasswordProtectedFiles\\new.zip");
// Build the list of files to be added in the array list
// Objects of type File have to be added to the ArrayList
ArrayList filesToAdd = new ArrayList();
//filesToAdd.add(new File("C:\\homepage\\workspace\\passwordprotectedzipfile\\profile\\profile.txt"));
filesToAdd.add(new File("C:\\homepage\\workspace\\PasswordProtectedFiles\\new.xlsx"));
//filesToAdd.add(new File("c:\\ZipTest\\myvideo.avi"));
//filesToAdd.add(new File("c:\\ZipTest\\mysong.mp3"));
// Initiate Zip Parameters which define various properties such
// as compression method, etc.
ZipParameters parameters = new ZipParameters();
parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE); // set compression method to store compression
// Set the compression level
parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
// Set the encryption flag to true
// If this is set to false, then the rest of encryption properties are ignored
parameters.setEncryptFiles(true);
// Set the encryption method to Standard Zip Encryption
parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_STANDARD);
// Set password
parameters.setPassword("test123!");
// Now add files to the zip file
// Note: To add a single file, the method addFile can be used
// Note: If the zip file already exists and if this zip file is a split file
// then this method throws an exception as Zip Format Specification does not
// allow updating split zip files
zipFile.addFiles(filesToAdd, parameters);
}
catch (ZipException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new AddFilesWithStandardZipEncryption();
}
}
Without uncompressing, Its impossible to password protect excel which is inside a zip file.
Here is what you can do
Unzip the content using tips in What is the best way to extract a zip file using java and Compressing and Decompressing Data Using Java APIs
Password protect extracted excel file using tips in Password Protected Excel File
Zip the password protected excel file using tips in Java Compress Large File
Use java.util.zip or zip4j to decompress file to some temp direcotry or to memory, if you know it's small.
Then use HSSFWorkbook.writeProtectWorkbook from Apache POI library
Compress Excel workbook again.
I think you should check out truezip (Truezip website). It provides read/write access to ZIP, JAR, EAR, WAR etc and supports appending to existing ZIP files.
I suggest you create your zip file without the excel file in it, create your passworded excel file as directed in the link you provided and then use truezip to write this excel file to the archive. Hope this helps
I have a Java project which is used as a component in a webapp. This java code writes an xls file in a specific folder. I want to provide a download functionality for this file which should be triggered as soon as file writing is done.
The problem is - without a server environment, how can write a download functionality?
Don't write to file in a specific folder. Just write to the HTTP response body immediately. The downloading job should just be done in the webapp's code. I assume that you're using Servlets. If you set the HTTP response Content-Disposition header to attachment, then the browser will pop a Save as dialogue. If you also set the Content-Type header, then the browser will understand what to do with it (e.g. it will then be able to ask Do you want to open it in Excel or to save? and so on).
response.setHeader("Content-Type", "application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
// Now write xls to response.getOutputStream() instead of FileOutputStream.
If the API of that Java project is well designed, then you should have a method something like this:
public void writeXls(OutputStream output) throws IOException {
// Do your job to write xls to output. E.g. if you were using POI HSSF:
// WritableWorkbook workBook = Workbook.createWorkbook(output);
// ...
}
This way you can call it in the servlet as follows after setting the aforementioned headers:
yourClass.writeXls(response.getOutputStream());
Even more, it could easily be reused/tested in a plain vanilla Java application like follows:
yourClass.writeXls(new FileOutputStream("/path/to/foo.xls"));
This is how i do it. I show a download sql in my page.
response.setHeader("Content-Disposition", "attachment; " +
"filename=ContactPurge.sql");
response.setContentType("application/x-sql-data");
response.getWriter().write(procsql);
response.getWriter().write(sql);
response.flushBuffer();