How to upload file using JSF 2.2 <h:inputFile>? Where is the saved File?

t3s0 picture t3s0 · Dec 28, 2014 · Viewed 52.3k times · Source

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.

Answer

BalusC picture BalusC · Dec 28, 2014

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.

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. You can do this in an (ajax) action (listener) method the usual way. Here's an example which does it with an ajax listener during the HTML DOM change event:

<h:form enctype="multipart/form-data">
    <h:inputFile value="#{bean.file}">
        <f:ajax listener="#{bean.save}" />
    </h:inputFile>
</h:form>
private Part file; // +getter+setter

public void save() {
    String fileName = Paths.get(filePart.getSubmittedFileName()).getFileName().toString(); // MSIE fix.

    try (InputStream input = file.getInputStream()) {
        Files.copy(input, new File(uploads, fileName).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.

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, check the last item of <o:graphicImage> demo on OmniFaces showcase.

See also: