How to save uploaded file in JSF

V.Rohan picture V.Rohan · Jan 8, 2013 · Viewed 65.7k times · Source

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?

Answer

BalusC picture BalusC · Jan 8, 2013

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.