I am uploading a file in JSF. I am using Tomahawk's <t:inputFileUpload>
for this, but the same question is applicable on e.g. PrimeFaces <p:fileUpload>
and JSF 2.2 <h:inputFile>
.
I have the below backing bean code:
private UploadedFile uploadedFile; // +getter+setter
public String save() throws IOException {
String name = uploadedFile.getName();
System.out.println("File name: " + name);
String type = uploadedFile.getContentType();
System.out.println("File type: " + type);
long size = uploadedFile.getSize();
System.out.println("File size: " + size);
InputStream stream = uploadedFile.getInputStream();
byte[] buffer = new byte[(int) size];
stream.read(buffer, 0, (int) size);
stream.close();
}
I am able to get the file name, type and size, but I am unable to save this file at a specific path. I can't figure out the proper way to save the uploaded file. How can I achieve this?
The getInputStream()
method of the uploaded file represents the file content.
InputStream input = uploadedFile.getInputStream();
You need to copy it to a file. You should first prepare a folder on the local disk file system where the uploaded files should be stored. For example, /path/to/uploads
(on Windows, that would be on the same disk as where the server runs). Note that you should absolutely not store the files in expanded WAR folder or even the IDE project's folder by using a hardcoded path or a web-relative path or getRealPath()
for the reasons mentioned here Uploaded image only available after refreshing the page.
Then, you need to autogenerate the filename. Otherwise, when someone else uploads a file with coincidentally the same name later, it would be overwritten. You could use Files#createTempFile()
facility to get an autogenerated filename.
Path folder = Paths.get("/path/to/uploads");
String filename = FilenameUtils.getBaseName(uploadedFile.getName());
String extension = FilenameUtils.getExtension(uploadedFile.getName());
Path file = Files.createTempFile(folder, filename + "-", "." + extension);
The path to uploads could if necessary be parameterized based on one of several ways shown in this Q&A: Recommended way to save uploaded files in a servlet application. The FilenameUtils
is part of Apache Commons IO which you should already have in your classpath as it's a dependency of the Tomahawk file upload component.
Finally, just stream the uploaded file to that file (assuming Java 7):
try (InputStream input = uploadedFile.getInputStream()) {
Files.copy(input, file, StandardCopyOption.REPLACE_EXISTING);
}
System.out.println("Uploaded file successfully saved in " + file);
Then, to download it back, easiest would be to register /path/to/uploads
as a new webapp context or a virtual host so that all those files are available by an URL. See also Load images from outside of webapps / webcontext / deploy folder using <h:graphicImage> or <img> tag.
PrimeFaces uses two file upload decoder for uploading content of p:fileupload
NativeFileUploadDecoder is the default upload decoder and it requires servlet container 3.0. So if your servlet container is less than 3 then it will not work with you. Also some application servers make a restriction on using multi-part content
So if you have a problem with the native upload decoder for any reason you have to use the other decoder which is "CommonsFileUploadDecoder"
CommonsFileUploadDecoder depends on Apache common lib so you have to put the commons-fileupload and commons-io jars in your class-path the version depends on your primefaces version but 1.3 and 2.2 respectively works for me.
to use CommonsFileUploadDecoder you have to use filter
<filter>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
wait the filter only will not work because inside the filter it checks about the uploader if its not provided and it detect at least JSF 2.2 so it will bypass the request to the default decoder "Native" and then it will not work for your also
to force the filter to use the common decoder you have to put the following context param in your web.xml
<context-param>
<param-name>primefaces.UPLOADER</param-name>
<param-value>commons</param-value>
</context-param>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With