Saturday, February 16, 2008

Uploading files with JSF

WARNING - OUTDATED CONTENT!

This article is targeted on JSF 1.2.

For JSF 2.0/2.1 with Tomahawk, please checkout my answer on this Stack Overflow question.

For JSF 2.0/2.1 on Servlet 3.0 with a custom component, please checkout this article.

For JSF 2.2, just use its native file upload component in flavor of <h:inputFile> whose value can be tied to a javax.servlet.http.Part property, see also my answer on this Stack Overflow question.

Upload and store files

Downloading files is made relatively easy using a FileServlet, but uploading files is a bit harder. Entering/selecting the raw absolute file path in h:inputText and sending it to the server so that it can be used in a File object isn't going to work, as the server doesn't have access to the client's file system. That will work only if the server as well as the client runs on the same machine and that wouldn't occur in real life.

To browse and select a file for upload you basically need a HTML input type="file" field in the form. As stated in the HTML specification you have to use the POST method and the enctype attribute of the form have to be set to "multipart/form-data". Unfortunately the Sun JSF Reference Implementation Mojarra doesn't provide a component out of the box which renders a input type="file" field. But the MyFaces Tomahawk component library, which can also be integrated in Sun JSF Reference Implementation Mojarra, provides us the t:inputFileUpload component.

Back to top

Integrating Tomahawk in Mojarra

Assuming that you already have a Mojarra environment, you just need to add at least the following JAR's to the classpath, e.g. /WEB-INF/lib. The version numbers doesn't matter that much, as long as you get the newest.

The Tomahawk JAR is the Tomahawk component library itself which under each contains the t:inputFileUpload component and the ExtensionsFilter. The commons-fileupload and commons-io JAR's are required for the file upload. They contains a multipart/form-data parser and several I/O utilities respectively. The commons-logging and commons-el JAR's are required by the core of the Tomahawk component library.

After adding the JAR's, open your web.xml and add the ExtensionsFilter to it. It should filter multipart/form-data requests and make use of the commons-fileupload to parse the request. To get uploading files work in JSF, it should at least be mapped on the servlet name of the FacesServlet, which may differ per environment. By default it is "Faces Servlet". Just check the servlet name in its <servlet> definition.

<filter>
    <filter-name>Extensions Filter</filter-name>
    <filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>Extensions Filter</filter-name>
    <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

It is not required, but you can configure the ExtensionsFilter with one or more of the following useful init-param settings which you can put in the <filter> tag:


    <init-param>
        <description>
            Set the size limit for uploaded files.
                Format: 10  - 10 bytes
                        10k - 10 KB
                        10m - 10 MB
                        1g  - 1 GB
        </description>
        <param-name>uploadMaxFileSize</param-name>
        <param-value>100m</param-value>
    </init-param>
    <init-param>
        <description>
            Set the threshold size - files below this limit are stored 
            in memory, files above this limit are stored on disk.
                Format: 10  - 10 bytes
                        10k - 10 KB
                        10m - 10 MB
                        1g  - 1 GB
        </description>
        <param-name>uploadThresholdSize</param-name>
        <param-value>100k</param-value>
    </init-param>
    <init-param>
        <description>
            Set the path where the intermediary files will be stored.
        </description>
        <param-name>uploadRepositoryPath</param-name>
        <param-value>/temp</param-value>
    </init-param>

Back to top

Basic use example

Here is a basic use example of a JSF file and the appropriate backing bean which demonstrates the working of the t:inputFileUpload.

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://myfaces.apache.org/tomahawk" prefix="t" %>

<!DOCTYPE html>

<f:view>
    <html lang="en">
        <head>
            <title>File upload test</title>
        </head>
        <body>
            <h:form id="uploadForm" enctype="multipart/form-data">
                <h:panelGrid columns="3">
                    <h:outputLabel for="file" value="Select file" />
                    <t:inputFileUpload id="file" value="#{myBean.uploadedFile}" required="true" />
                    <h:message for="file" style="color: red;" />

                    <h:panelGroup />
                    <h:commandButton value="Submit" action="#{myBean.submit}" />
                    <h:message for="uploadForm" infoStyle="color: green;" errorStyle="color: red;" />
                </h:panelGrid>
            </h:form>

            <h:outputLink value="file/#{myBean.fileName}" rendered="#{myBean.fileName != null}">
                Download back
            </h:outputLink>
        </body>
    </html>
</f:view>

Please note the enctype of the h:form. This is required to be able to POST binary data. Also note that the download link makes use of the FileServlet. Make sure that it points to the same directory as where the file is uploaded. You can configure it as an init-param.

Here is how the appropriate backing bean (request scoped) look like:

package mypackage;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.myfaces.custom.fileupload.UploadedFile;

public class MyBean {

    // Init ---------------------------------------------------------------------------------------

    private UploadedFile uploadedFile;
    private String fileName;

    // Actions ------------------------------------------------------------------------------------

    public void submit() {

        // Just to demonstrate what information you can get from the uploaded file.
        System.out.println("File type: " + uploadedFile.getContentType());
        System.out.println("File name: " + uploadedFile.getName());
        System.out.println("File size: " + uploadedFile.getSize() + " bytes");

        // Prepare filename prefix and suffix for an unique filename in upload folder.
        String prefix = FilenameUtils.getBaseName(uploadedFile.getName());
        String suffix = FilenameUtils.getExtension(uploadedFile.getName());
        
        // Prepare file and outputstream.
        File file = null;
        OutputStream output = null;
        
        try {
            // Create file with unique name in upload folder and write to it.
            file = File.createTempFile(prefix + "_", "." + suffix, new File("c:/upload"));
            output = new FileOutputStream(file);
            IOUtils.copy(uploadedFile.getInputStream(), output);
            fileName = file.getName();

            // Show succes message.
            FacesContext.getCurrentInstance().addMessage("uploadForm", new FacesMessage(
                FacesMessage.SEVERITY_INFO, "File upload succeed!", null));
        } catch (IOException e) {
            // Cleanup.
            if (file != null) file.delete();

            // Show error message.
            FacesContext.getCurrentInstance().addMessage("uploadForm", new FacesMessage(
                FacesMessage.SEVERITY_ERROR, "File upload failed with I/O error.", null));

            // Always log stacktraces (with a real logger).
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(output);
        }
    }

    // Getters ------------------------------------------------------------------------------------

    public UploadedFile getUploadedFile() {
        return uploadedFile;
    }

    public String getFileName() {
        return fileName;
    }

    // Setters ------------------------------------------------------------------------------------

    public void setUploadedFile(UploadedFile uploadedFile) {
        this.uploadedFile = uploadedFile;
    }

}

Note: make "c:/upload" at least configureable. Maybe as a property in a propertiesfile which could also be shared by the FileServlet.

Back to top

Copyright - There is no copyright on the code. You can copy, change and distribute it freely. Just mentioning this site should be fair.

(C) February 2008, BalusC

224 comments:

«Oldest   ‹Older   201 – 224 of 224
Sami said...

Hi BalusC! This is working like a charm. What is the best solution if you have file upload as a part of another form or in the same form where is plenty other data to submit as well? I have a form where is 10 fields and one of them is file uploading. I think that only one form is possible. Any nice solution to that? I think that I just have to make one submit and do everything at the same time, upload file, take the name of the file and path and insert it to another formBean and call controller ja insert the data to db? Basically the problem is that I have about 10 forms where is uploading as a part, is there any nice way to include uploading to every page so that I don't need to repeat the same code in many places?

siraj said...

After submit the request or page refresh, how to keep the file name in the box.

siraj said...

after submit the request or page refresh, how to keep the file name in the box.

siraj said...

Hi Balu,

How can i retain the file name in the box after save the file.

Tosha Shah said...

Hi I am able to do upload but i need something like when i upload file one of the entity feild must be updated with text.

Here is my code

Do let me know wt possibly i am doing wrong?

CiomemberEdit.xhtml






Member photo



My File upload bean

publicvoid listener(UploadEvent event) throws Exception{
memberHome memberinstance = new memberHome();
memberinstance.setphoto(item.getFileName());
}
My Home entity
public void setphoto(String image)
{
log.info("In method set photo");
imagename = image;
image = "file";
getInstance().setMemberPhoto(image);
update();
}

fkclai said...

When successfully upload a file using your suggested coding, an intermediary file will be created at path defined at uploadRepositoryPath


How to clean up this file without interrupt the online service?

Unknown said...

Hai BAlusC...
I tried the same code but when i add the jar files commons-io-1.3.2.jar and tomahawk-1.1.10.jar to the libraries,im getting a error message in netbeans7.2
.
.
Error occurred during deployment: Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: java.lang.RuntimeException: com.sun.faces.config.ConfigurationException:
Source Document: jar:file:/C:/Users/Sandeep/Documents/NetBeansProjects/Upload/build/web/WEB-INF/lib/tomahawk-1.1.10.jar!/META-INF/faces-config.xml
Cause: Class 'org.apache.myfaces.webapp.filter.ServeResourcePhaseListener' is missing a runtime dependency: java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory. Please see server.log for more details.
C:\Users\Sandeep\Documents\NetBeansProjects\Upload\nbproject\build-impl.xml:1027: The module has not been deployed.
See the server log for details.
.
.
.
Can u pls heip in in resolving it

PRATIK's diarry said...

HI Balus ,

One quick question . Is there any way other than using tomahawk for file upload.?

afaki said...

Hi BalusC,
im using primefaces fileupload, when i try to upload a file from local to a shared folder on a server, i get this error: "Logon failure: unknown user name or bad password".
What would you recommend to solve that problem,
thanks so much

Rishi@Blog said...

Hi BalusC

i have an issue , i have tried your code with Websphere portal server7
and RAD 8.5 ,i got following error
and i am not able to execute can you please help.

"[9/14/13 14:50:08:144 IST] 00000034 webcontainer E com.ibm.ws.webcontainer.WebContainer handleRequest SRVE0255E: A WebGroup/Virtual Host to handle /fileupload2/fileupload.jsp has not been defined."

Shasha said...

Hi BalusC
Could you please post the normal upload using plain Java code
Sha

Shasha said...

Hi BalusC
Could you please post the normal upload using plain Java code
Sha

Unknown said...

Hi, my problem is the t:inputFileUpload is not displaying in the page. Have you any idea what can be the problem?? Thank you

Unknown said...
This comment has been removed by the author.
Unknown said...

I study this topic, build and deploy my project. But when I browse the file for uploading,there's no action in backing bean, uploading file is not work. Please help.

Unknown said...

i am using netbean 7.3.1 and glassfish 3 so please help how to uplaod the default image in jsf latter these image is replace newly upload image

Unknown said...

this is mt java code
public class FileUploadController {
private String destination="D:\\tmp\\";


/**
* Creates a new instance of FileUploadController
*/
public FileUploadController() {
}

public void upload(FileUploadEvent event)
{
FacesMessage msg = new FacesMessage("Success! ", event.getFile().getFileName() + " is uploaded.");
FacesContext.getCurrentInstance().addMessage(null, msg);
try {
copyFile(event.getFile().getFileName(), event.getFile().getInputstream());
}
catch (IOException e)
{
e.printStackTrace();
}
}

public void copyFile(String fileName, InputStream in) {
try {
// write the inputStream to a FileOutputStream
OutputStream out = new FileOutputStream(new File(destination + fileName));
int read = 0;
byte[] bytes = new byte[1024];

while ((read = in.read(bytes)) != -1) {
out.write(bytes, 0, read);
}

in.close();
out.flush();
out.close();
System.out.println("New file created!");
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
this is my xhtml file code
     




this is web.xml file i am maaping of filter in this file
filter-name>PrimeFaces FileUpload Filter
org.primefaces.webapp.filter.FileUploadFilter


PrimeFaces FileUpload Filter
Faces Servlet

filter-name>PrimeFaces FileUpload Filter
org.primefaces.webapp.filter.FileUploadFilter


PrimeFaces FileUpload Filter
Faces Servlet


filter-name>PrimeFaces FileUpload Filter
org.primefaces.webapp.filter.FileUploadFilter


PrimeFaces FileUpload Filter
Faces Servlet


in above code the image not show on destination place and not show on our page ?

Martini said...

Hi Balus,

Fists of all my excuses i am braziliam and i don't espeak and write english well.

I spend tree weks trying do do a fileupload, i tested aboout 30 examples, jsf 2.2 inputfile, primefaces fipeupload ... None of them runs as suposed. Then a finally found your example tomahawk, e all Works ok. Thank you.

Unknown said...

Hi Balus,
I have uploaded the file.It is working fine but when i through a validation error from backing bean.My file becomes null but all the other fields are populated.Is that the default behavior of file upload.Can I keep the file intact even after the validation error.

Thanks
Anu

Hridayesh Kalauni said...

Hello Baluc,

Thanks for the post,it was really helpful.

I have just one issue-

On page refresh,same file is being uploaded again. I even setUploadedFile(null) at the end of submit method but still doesn't work.

Any help would be really appreciated.

Unknown said...

i initialize the t:inputfileupload in my html pages its working perfectly. In same page i initialize the another t:inputfileupload its block the fileupload method. its working for only one file upload in page.i want to initialize t:inputfileupload one more component please help me
both files for different category based upon menu

Leo said...

Thanks...
But I have a problem. The setter method is never called, then a NPE raised.
What I forgot?

Liam Flint said...

Use "Long Path This very useful if you are having problems
in deleting, unlocking, copying and even renaming files, also very easy.

Daily Digital Blogger said...

same code worked in jboss 4.2.3 GA. and recently we migrate jboss to wildfly 26 deployed on it we use jsf 1.2, myfaces,java 8 servlet 2.5. inputfileuplod bean mapped setter and getter get null value.

«Oldest ‹Older   201 – 224 of 224   Newer› Newest»