Tuesday, 4 June 2013

File Upload is Easy in JSF2.2

To bring the File Upload feature in Java based web application is one of the difficult and complex job, we need to dependent on 3rd party libraries like Apache Commons FileUpload Libraries. These libraries codes are complex and most of them boilerplate code.

If we are using Java Server Faces (JSF), we have the page with some fields and file upload menu the its add more complexity, fields are binded to backing bean but these file uploads components are need to tie up with some 3rd party file upload libraries.

In Primefaces provide easy way to do the file upload in JSF web application, even though primefaces internally used the same Apache Commons FileUpload Libraries, but provide simple JSF tags. We need configure  some listeners.

In Servlet 3.0 they introduced the Part Interfaces and @MultiPartConfig annotations for easy way to do the file upload without any 3rd party libs, Servlet 3.0 is part of Java EE 6 specification. so any servlet 3.0 implementation servers  like Tomcat 7, Jboss 6, GlassFish 3 they can get benefit of servlet 3.0. but this feature is not available in JSF 2.1. so again still it's complex to use file upload in JSF, because we need to mix servlet and JSF backing bean.

Recently JSF 2.2 is released as part of Java EE 7 specification. Now this specs are final and its going to release Q2 of 2013.

Check my post about An introduction to JSF 2.2

in this post i going to show the File Upload feature with a demo

At last JSF 2.2 is added the File Upload component, so we just use <h:inputFile> tag to make the file upload web application so easily, and this component use the Part interface, which its introduced its part of Servlet 3.0. so this JSF2.2 libraries is working perfectly with Tomcat 7 (because tomcat 7 is implemented the Servlet 3.0 spec).

To bring the File Upload feature we need to follow 3 step process

  1. Add <h:inputFile> tag in JSF page
  2. Add enctype="multipart/form-data" attribute in enclosing <h:form> tag
  3. Create the field in Backing bean with Part data type.

Setup the Environment

JSF 2.2 lib are part of Java EE 7, but we can include as a libraries into existing Java EE 6 platform without upgrading the server.
we can get the JSF 2.2 libraries (Mojarra implementation) from here

Step 1:  Add <h:inputFile> tag in JSF page

In JSF page add the <h:inputFile> tag where we need file upload component

  <h:inputFile value="#{demoBean.file1}" />

here i bind the value property to file1 field, which data type is Part, check the third step


Step 2:  Add enctype="multipart/form-data" attribute in enclosing <h:form> tag

When u want file upload feature then we need to inform the browser that form may contain multiple normal text input field  and some file upload component, so prepare the POST request in special form, like parts by part with special delimiter boundary.
 <h:form enctype="multipart/form-data">
</h:form>

so index.xhtml file looks like

    
        Facelet Title
    
    
        Hello from Facelets
        
        
            

            
             

            
        
    




Step 2:  Create Backing Bean

now create the backing bean for this page. we need to create the fields for input File component with Part type. Part interface is introduced in servlet 3.0 for represent the file chunks sent by browser, JSF 2.2 use this Part interface, Using the Part interface we can get the header information of each file chunk sent by browser, these header contain the file name and other meta information about the file.

Part interface also contain write() method to write the file contents into specified server location, or u can get the InputStream then we can process it.

DemoBean.java

import java.io.IOException;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.servlet.http.Part;


/**
 *
 * @author ramki
 */
@ManagedBean
@SessionScoped
public class DemoBean {

    private Part file1;
    private Part file2;

    // getters and setters for file1 and file2

    public String upload() throws IOException {
         InputStream inputStream = file1.getInputStream();        
        FileOutputStream outputStream = new FileOutputStream(getFilename(file1));
        
        byte[] buffer = new byte[4096];        
        int bytesRead = 0;
        while(true) {                        
            bytesRead = inputStream.read(buffer);
            if(bytesRead > 0) {
                outputStream.write(buffer, 0, bytesRead);
            }else {
                break;
            }                       
        }
        outputStream.close();
        inputStream.close();
       
        return "success";
    }

    private static String getFilename(Part part) {
        for (String cd : part.getHeader("content-disposition").split(";")) {
            if (cd.trim().startsWith("filename")) {
                String filename = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
                return filename.substring(filename.lastIndexOf('/') + 1).substring(filename.lastIndexOf('\\') + 1); // MSIE fix.
            }
        }
        return null;
    }
}


here we need get the file name from the Header of the chunk, so there is boilerplate code can do, here i don't like this method :-(

there is no direct method to retrieve the file name. so use this code we can get the name of the file is uploaded by client, then using write method we can store into server.


Get my sample project from my Github or download from here

For more information (step by step) see the screencast

Screencast

Related Posts Plugin for WordPress, Blogger...