JSF 2.0 File upload
Solution 1
First of all, this (old) question and answer assumes JSF 2.0/2.1. Since JSF 2.2 there's a native <h:inputFile>
component without the need for 3rd party component libraries. See also How to upload file using JSF 2.2 <h:inputFile>? Where is the saved File?
The easiest way would be using Tomahawk for JSF 2.0. It offers a <t:inputFileUpload>
component.
Here's a step-by-step tutorial:
-
Create a blank dynamic web project for Servlet 3.0 and JSF 2.0. The
web.xml
must comply Servlet 3.0 spec and already contain the JSF servlet:<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="YourProjectName" version="3.0"> <display-name>Your Project Name</display-name> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.xhtml</url-pattern> </servlet-mapping> </web-app>
The
faces-config.xml
must comply JSF 2.0 spec:<?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0"> </faces-config>
-
Download Tomahawk 1.1.10 for JSF 2.0. Extract the zip file, go to the
/lib
folder and copy all*.jar
files into your/WEB-INF/lib
.It are 18 files, of which
batik*.jar
andxml*.jar
are unnecessary for using alone thet:inputFileUpload
component. You could leave them away.
-
Configure the Tomahawk extensions filter in
web.xml
. It's the one who's responsible for handlingmultipart/form-data
requests which is required to be able to send files over HTTP.<filter> <filter-name>MyFacesExtensionsFilter</filter-name> <filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</filter-class> </filter> <filter-mapping> <filter-name>MyFacesExtensionsFilter</filter-name> <servlet-name>Faces Servlet</servlet-name> </filter-mapping>
Note that the
<servlet-name>
must match the exact<servlet-name>
of theFacesServlet
as you've definied inweb.xml
.
-
Create a simple Facelet,
upload.xhtml
:<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:t="http://myfaces.apache.org/tomahawk" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:head> <title>Tomahawk file upload demo</title> </h:head> <h:body> <h:form enctype="multipart/form-data"> <t:inputFileUpload value="#{bean.uploadedFile}" /> <h:commandButton value="submit" action="#{bean.submit}" /> <h:messages /> </h:form> </h:body> </html>
Note the
enctype="multipart/form-data"
attribute on<h:form>
, this is very important in order to be able to send files with HTTP.
-
Create a simple managed bean,
com.example.Bean
:package com.example; import java.io.IOException; import javax.faces.application.FacesMessage; import javax.faces.bean.ManagedBean; import javax.faces.bean.RequestScoped; import javax.faces.context.FacesContext; import org.apache.commons.io.FilenameUtils; import org.apache.myfaces.custom.fileupload.UploadedFile; @ManagedBean @RequestScoped public class Bean { private UploadedFile uploadedFile; public void submit() throws IOException { String fileName = FilenameUtils.getName(uploadedFile.getName()); String contentType = uploadedFile.getContentType(); byte[] bytes = uploadedFile.getBytes(); // Now you can save bytes in DB (and also content type?) FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(String.format("File '%s' of type '%s' successfully uploaded!", fileName, contentType))); } public UploadedFile getUploadedFile() { return uploadedFile; } public void setUploadedFile(UploadedFile uploadedFile) { this.uploadedFile = uploadedFile; } }
That should be it. Open it by http://localhost:8080/projectname/upload.xhtml.
As to your concrete questions:
what should i do to pass the file from the JSF to the managed bean and then transform it to a byte[](To be able to handle it over to the EJB)?
This is answered above.
How can a servlet help me?
It is able to process and control HTTP requests/responses. In a JSF environment, the FacesServlet
already does all the work.
Do i need a servlet to do this?
In a JSF environment, the FacesServlet
is mandatory. But it's already provided by the API, you don't need to write one yourself. However, to be able to download files from a database, another servlet is definitely useful. You can find a basic example here: Servlet for serving static content.
Also i found that in some blog it mentions something about servlets 3.0, but i dont know if my working enviroment is ussing it, how can if i am ussing servlets 3.0(I am ussing JEE6)?
If you're using Servlet 3.0 container like Glassfish 3, JBoss AS 6, Tomcat 7, etc and the web.xml
is declared as Servlet 3.0, then you're definitely using Servlet 3.0. Servlet 3.0 is part of Java EE 6.
Solution 2
For completeness, I just want to provide a fully functional self contained example of how this is done with JSF 2.2, either with non-Ajax and Ajax requests. Keep in mind JSF 2.2 uses different namespaces and you need to be working with a Servlet 3.0 container (as Tomcat 7.0.x, JBoss AS 6.x and 7.x and GlassFish 3.x are).
fileUpload.xhtml
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head />
<h:body>
<h:form enctype="multipart/form-data">
<h:inputFile value="#{uploadBean.file}" />
<h:commandButton value="Post Upload" action="#{uploadBean.upload}" />
</h:form>
<h:form enctype="multipart/form-data">
<h:inputFile value="#{uploadBean.file}" />
<h:commandButton value="Ajax Upload">
<f:ajax listener="#{uploadBean.upload}" execute="@form"
render="countOutput" />
</h:commandButton>
<!-- Counts the uploaded items -->
<h:outputText id="countOutput"
value="Files uploaded #{uploadBean.filesUploaded}" />
</h:form>
</h:body>
</html>
UploadBean.java:
@ManagedBean
@ViewScoped
public class UploadBean {
private int filesUploaded = 0;
//javax.servlet.http.Part (Servlet 3.0 API)
private Part file;
private String fileContent;
/**
* Just prints out file content
*/
public void upload() {
try {
fileContent = new Scanner(file.getInputStream())
.useDelimiter("\\A").next();
System.out.println(fileContent + " uploaded");
filesUploaded++;
} catch (IOException e) {
e.printStackTrace();
}
}
public int getFilesUploaded() {
return filesUploaded;
}
public Part getFile() {
return file;
}
public void setFile(Part file) {
this.file = file;
}
}
See also:
Solution 3
I would recommend using a companent library like Tomahawk's <t:inputFileUpload>
or PrimeFaces <p:fileUpload>
.
BalusC also has a nice blog post about Uploading files with JSF 2.0 and Servlet 3.0.
Solution 4
BalusC's blog post: Uploading files with JSF 2.0 and Servlet 3.0 is what saved me, because I had problems running RichFaces 4 fileUpload tag with Spring WebFlow.
It's worth to modify BalusC's code to use Spring's MultipartResolver
- you don't need his MultipartMap
from another blog post.
I achieved it by modifying a decode
method in FileRenderer
like this:
UploadedFile ret = null;
Object req = context.getExternalContext().getRequest();
if (req instanceof MultipartHttpServletRequest) {
MultipartFile file = ((MultipartHttpServletRequest)req).getFile(clientId);
File temp = null;
try {
temp = File.createTempFile("_UPLOAD_", null);
file.transferTo(temp);
String name = new File(file.getOriginalFilename()).getName();
ret = new UploadedFile(temp, name);
} catch (IOException e) {
throw new RuntimeException("Could not create temp file.", e);
}
} else {
throw new IllegalStateException("Request is not multipart. Use spring's multipart resolver.");
}
// If no file is specified, set empty String to trigger validators.
((UIInput) component).setSubmittedValue( ret == null ? EMPTY_STRING : ret);
A UploadedFile
is a simple serializable POJO used to return results to backing bean.
Solution 5
In JSF 2.2 you can easily upload file using tag without using commons-io or filter. This tag support both normal and ajax process.
Normal:
<h:inputFile id="file" value="#{fileUploadBean.uploadedFile}"/>
<h:commandButton id="button" action="#{fileUploadBean.sumbit()}" value="Upload"/>
Ajax:
<h:inputFile id="file" value="#{fileUploadBean.uploadedFile}"/>
<h:commandButton id="button" value="submit">
<f:ajax execute="@all" render="@all" onevent="statusUpdate"/>
</h:commandButton>
Design your managed bean as follows:
@Named
@RequestScoped
public class FileUploadBean {
private Part uploadedFile;
}
javing
Enthusiastic java developer based in London, I love stackoverflow, I use it regularly for many years and is a great way of helping and ask for help. Also i love blogging about software. Please visit my Blogs: Javing (Medium) Javing (Blogger)
Updated on April 22, 2020Comments
-
javing about 4 years
I am looking around a few blogs, to try to find how to upload files using JSF 2.0 But all the solutions kind of confuse me. I would like to know what do I exactly need to be able to successfully upload a file(MP3, PDF, video... what ever type) and store it in a database as a @Lob. This is what I have done so far:
I created an entity that has an attribute of type byte[] and it is also annotated with a @Lob annotation.
I created an EJB that will introduce the entity with with a method that has a byte[] as a parameter and inserts it into the database using the EntityManager class( persist method).
I created a JSF page with an input tag of type "file" and a submit button
I prepared a managed bean to interchange information about the file with the JSF page.
Now I am stuck, and I have lots of doubts:
What should I do to pass the file from the JSF to the managed bean and then transform it to a byte[](To be able to handle it over to the EJB)?
How can a servlet help me?
Do I need a servlet to do this?
Also I found that in some blog it mentions something about servlets 3.0, but I don't know if my working environment is using it, how can if I am using servlets 3.0 (I am using JEE6)?
I never did file upload before and also I am not very familiar with servlets. I am confused, someone could give me some starting tips, please?
-
javing about 13 yearsI did all that. It seems ok i have no more errors, but it looks like i cant persist that byte[] to the data base. I opened a new questions and i explained all i did step by step: stackoverflow.com/questions/5431512/…
-
Rasmus Franke about 13 yearsTried this method, with some problems. Netbeans only finds a single tag in the
http://myfaces.apache.org/tomahawk
namespace,inputHtml
. With some investigation, I see that this is the only file inMETA-INF.resources.org.apache.myfaces.custom
package. I CAN still use the component, with what seems to be full functionality, but I get warnings:JSF1064: Unable to find or serve resource, inputFileUpload.xhtml, from library, org.apache.myfaces.custom
. Any idea of what this is about? I've seen others ask about the same thing, but always 0 answers on those posts. -
jsaven over 11 yearsGreat answer, thanks! Just one issue I ran into running in Java 6: on server startup I get this: javax.faces.FacesException: java.lang.ClassNotFoundException: [Ljava.lang.String;, I found the solution here: java.net/node/656623. In summary, add this to startup options for your server: -Dsun.lang.ClassLoader.allowArraySyntax=true
-
user1503117 over 10 yearsHi BaluC Thanks for your solution, but solution does not seem to work in TomEE 1.5.2 / CODI on windows.I have a page with primefaces form and tomahawk subform and tomahawk inputfileuploads. The getter/setter methods are not invoked for fileUpload and I am using @ConversationScoped from CODI in managed bean. Tomahawk Configuration is as per mentioned by you . Please let me know where I am going wrong. Regards, senthil
-
BalusC over 10 years@user: If you've a question, press "Ask Question" button on right top. This section is for comments on the answer.
-
jacekn about 10 yearsThe solution works but the Tomahawk download link is dead. Use myfaces.apache.org homepage to get to the downloads.
-
alexander about 9 yearsDo not get me wrong, but I'm struggeling with your example. It does not work for me at all.
file
is alywas null...? -
Aritz about 9 yearsI tried in a test project in tomcat 7 and got it working @alexander. Which server are you using? Do you have some filter configured?
-
alexander about 9 yearsThe new one from JBoss - wildfly-8.1.0.Final. And yes,
<filter> <filter-name>PrimeFaces FileUpload Filter</filter-name> <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class> </filter>
-
alexander about 9 yearsI googled a lot, and found NOTHING about a filter in plain JSF. Only tomahawk and jsf. So I removed my filters - and it simply does not work. What am I missing here? Is there any need of filter, if I am using only jsf? Even your resource is without filter?
-
Aritz about 9 yearsJSF adds no filter to your application. You only have to configure a Servlet. Just try a test project with the minimal configuration. Do further debugging. Check if the faces Servlet is being hit. If not, something is preventing the request reach the Servlet. Anyway, JSF 2 relies in the your server native file upload capabilities, Jboss AS in your case
-
nettie over 7 yearsHey @alexander - did you get it to work? I was getting the nulls, but it works when I use Primefaces FileUpload feature - in advanced or "auto" mode as described here [primefaces.org/showcase/ui/file/upload/auto.xhtml]. The difference was the "fileUploadListener". I did set up the
<h:form enctype="multipart/form-data">
tag as in the PF "basic" example. Good luck! -
nettie over 7 yearsI'm uploading a file just fine, and whitelisting for the 3 filetypes I want (doc|pdf|txt). Then I convert it to a byte[] and send it as an email attachment. My question is - what is the best way to check that the file is secure before sending it in email? Is there something I can do in the backing bean?
-
Aritz over 7 years@itgirl I guess there's no way to do it and it's totally unrelated to the view logic of your application, that's for sure. The two possibilities I can think for it right now are letting the client analyze the file content or sending it to some system which performs this task for you in the cloud before you email it. stackoverflow.com/questions/4721406/…
-
nettie over 7 yearsThanks @XtremeBiker. Now I'm looking at the VirusTotal public API for that.