File Upload Example in JSF 2

Introduction

Here you will see file upload example in JSF 2. The file upload implementation in Java based web application is very complex and you need to be dependent on Apache file upload libraries. When you work on JSF(Java Server Faces), you have JSF (Java Faces Server) pages with other inputs along with file inputs on the web page, so integration with Apache file upload libraries make more complex or else you have to be dependent on some third party file upload components like primefaces, richfaces, etc.

Servlet 3.0 is part of Java EE 6 specification, hence “Part” interface and @MultiPartConfig annotation were introduced for easy way to do the file upload without any third party libraries.

So any servlet 3.0 implementation servers like Tomcat 7.x, Jboss 6.x, GlassFish 3.x can get benefit of servlet 3.0 but the file upload feature is not available in JSF 2.1 and again you have to be dependent on servlet to do the file upload in JSF.

Recently JEE 7 specification was released and it’s now very easy to upload the file in JSF 2.2, because file upload component(<h:inputFile/>) was added in this version.

File Upload Tag in JSF 2.2

You need to do the simple three steps for uploading file in JSF 2.2. Find below steps to compile file upload example in jsf 2.

  • Add <h:inputFile/> tag in JSF page
  • Add enctype="multipart/form-data" attribute in enclosing <h:form/> tag
  • Create the field in managed bean with Part data type

Below example explains file upload function using <h:inputFile> tag in JSF 2.2.

Prerequisites

Java at least 1.8, Tomcat Server 8.5 – 9.0.39, JSF 2.2 – 2.2.20, Servlet API 3.0.1 – 4.0.1, JSTL – 1.1.2

Files Created in the Example

Input Page (Home page): index.xhtml
Managed Bean: FileUploadMBean.java, Utility Class: Utils.java
Deployment descriptor: web.xml

Project Setup

Create a maven based web project in Eclipse with below artifact and group id:

Group Id: com.roytuts, Artifact Id: jsf2-file-upload

You can use the following pom.xml file for building your project. Make sure you have the following dependencies and plugin in your pom.xml file:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.roytuts</groupId>
	<artifactId>jsf2-file-upload</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>12</maven.compiler.source>
		<maven.compiler.target>12</maven.compiler.target>
	</properties>

	<dependencies>
		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-api</artifactId>
			<version>2.2.20</version>
		</dependency>
		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-impl</artifactId>
			<version>2.2.20</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>4.0.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>javax.servlet.jsp-api</artifactId>
			<version>2.3.3</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.1.2</version>
		</dependency>
	</dependencies>

	<build>
		<finalName>jsf2-file-upload</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
			</plugin>
		</plugins>
	</build>
</project>

Deployment Descriptor – web.xml

Here in the below deployment descriptor file, I have added context parameter to specify which environment I am working on.

I have also added the JSF servlet which works as a central servlet and handles all request and response for the clients.

I declared the welcome jsf page which is displayed when the application starts up.

I am using servlet 3.1 version, so accordingly I have declared the DTD version for our web app.

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
		 http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	version="3.1">
	<display-name>jsf2-fileupload</display-name>
	<context-param>
		<param-name>javax.faces.PROJECT_STAGE</param-name>
		<param-value>Development</param-value>
	</context-param>
	<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>*.jsf</url-pattern>
	</servlet-mapping>
	<welcome-file-list>
		<welcome-file>index.jsf</welcome-file>
	</welcome-file-list>
</web-app>

View – index.xhtml

This is the jsf page and it has two inputs for uploading two files. You can upload two files at a time or you can upload one file at a time.

Here notice I have used prependid="false", because I don’t want to append the form id with the input id or name. Suppose you have a form with id form1 and the form has input text field and input text field has id name then your input text field’s real id will be form1:name but it would be difficult to maintain such real id with JavaScript or java while I am trying to access directly. Using prependid="false" gives us the real id as name of input text field.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:f="http://xmlns.jcp.org/jsf/core"
	xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
	<h:head>
		<title>JSF 2.x File Upload Example</title>
	</h:head>
	<h:body>
		<h2>Select and upload a file</h2>
		<p>
			<!-- Shows the error or success message -->
			<h:outputText value="#{fileUploadMBean.message}"
				rendered="#{!empty fileUploadMBean.message}"></h:outputText>
			<!-- notice the enctype for file upload -->
			<h:form prependid="false" enctype="multipart/form-data">
				<h:panelGrid>
					<!-- input for files -->
					<h:inputFile value="#{fileUploadMBean.file1}"></h:inputFile>
					<h:inputFile value="#{fileUploadMBean.file2}"></h:inputFile>
					<!-- action which is responsible for uploading file(s) -->
					<h:commandButton action="#{fileUploadMBean.uploadFile()}"
						value="Upload"></h:commandButton>
				</h:panelGrid>
			</h:form>
		</p>
	</h:body>
</html>

JSF Managed Bean

In the below managed bean I have defined an action called uploadFile(), which gets triggered from the jsf page and uploads the file to the destination and you are in the right place for file upload example in jsf 2.

In this managed bean class I also bind the form’s input field to upload the files.

I also show the end users either success or error messages depending on the success or failure of file upload.

Notice I have kept the managed bean in view scope which is greater than request scope and less than session scope and scope is available in the view only.

package com.roytuts.jsf.mbean;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.file.Files;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.servlet.http.Part;

import com.roytuts.jsf.util.Utils;

@ManagedBean
@ViewScoped
public class FileUploadMBean implements Serializable {
	private static final long serialVersionUID = 1L;

	private Part file1;
	private Part file2;
	private String message;

	public Part getFile1() {
		return file1;
	}

	public void setFile1(Part file1) {
		this.file1 = file1;
	}

	public Part getFile2() {
		return file2;
	}

	public void setFile2(Part file2) {
		this.file2 = file2;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public String uploadFile() throws IOException {
		boolean file1Success = false;

		if (file1 != null && file1.getSize() > 0) {
			String fileName = Utils.getFileNameFromPart(file1);

			/**
			 * destination where the file will be uploaded
			 */
			File savedFile = new File("/jsf2-file-upload", fileName);

			// System.out.println("savedFile.toPath(): " + savedFile.toPath());

			try (InputStream input = file1.getInputStream()) {
				Files.copy(input, savedFile.toPath());
			} catch (IOException e) {
				e.printStackTrace();
			}

			file1Success = true;
		}

		boolean file2Success = false;

		if (file2 != null && file2.getSize() > 0) {
			String fileName = Utils.getFileNameFromPart(file2);
			File savedFile = new File("/jsf2-file-upload", fileName);

			System.out.println(savedFile.getAbsolutePath());

			try (InputStream input = file2.getInputStream()) {
				Files.copy(input, savedFile.toPath());
			} catch (IOException e) {
				e.printStackTrace();
			}

			file2Success = true;
		}

		if (file1Success || file2Success) {
			// System.out.println("File uploaded to : " + path);
			/**
			 * set the success message when the file upload is successful
			 */
			setMessage("File successfully uploaded");
		} else {
			/**
			 * set the error message when error occurs during the file upload
			 */
			setMessage("Error, select atleast one file!");
		}

		/**
		 * return to the same view
		 */
		return null;
	}
}

Utility Class – Utils.java

This file contains all the utility methods used in application. For example, here I have only one method which extracts the file name from the Part.

package com.roytuts.jsf.util;

import javax.servlet.http.Part;

public final class Utils {

	private Utils() {
	}

	public static String getFileNameFromPart(Part part) {
		final String partHeader = part.getHeader("content-disposition");
		for (String content : partHeader.split(";")) {
			if (content.trim().startsWith("filename")) {
				String fileName = content.substring(content.indexOf('=') + 1).trim().replace("\"", "");
				return fileName;
			}
		}
		return null;
	}

}

Testing the Application

The home page http://localhost:8080/jsf2-file-upload/ will look similar to the below image:

jsf2 file upload

If you do not select at least one file then you will see the following error:

jsf 2 file upload

Select and click on Upload button to upload the selected files:

jsf2 file upload

Finally files got successfully uploaded:

jsf2 file upload

That’s all. Hope you have got idea how  on file upload example in JSF 2.

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *