Rich Faces consists of some really useful components that can be used to make as they say some very "rich web applications".
In this tutorial i will be explaining about how to use richfaces file upload component to store a file into the database and then retrieve the file using a Jersey restful web service.
The file upload component of rich faces supports two modes of uploading.
- To store the uploaded file in a temporary directory or
- To keep an in memory representation of it.
If you want to create temp files then specify the following filter initialization parameter in the web.xml file.
<init-param> <param-name>createTempFiles</param-name> <param-value>true</param-value> </init-param>
But we are going to set it to false.
Following is the filter configuration for richfaces
<context-param> <param-name>org.richfaces.SKIN</param-name> <param-value>ruby</param-value> </context-param> <context-param> <param-name>org.richfaces.CONTROL_SKINNING</param-name> <param-value>enable</param-value> </context-param> <filter> <display-name>RichFaces Filter</display-name> <filter-name>richfaces</filter-name> <filter-class>org.ajax4jsf.Filter</filter-class> <init-param> <param-name>createTempFiles</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>maxRequestSize</param-name> <param-value>10000000</param-value> </init-param> </filter> <filter-mapping> <filter-name>richfaces</filter-name> <servlet-name>Faces Servlet</servlet-name> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> </filter-mapping>
The relevant code for jsp file is listed below.
<h:form enctype="multipart/form-data"> .... <h:panelGrid columns="2" columnClasses="top,top"> <rich:fileUpload fileUploadListener="#{fileUpload.listener}" maxFilesQuantity="#{fileUpload.uploadsAvailable}" id="upload" immediateUpload="#{fileUpload.autoUpload}" allowFlash="#{fileUpload.useFlash}"> <a4j:support event="onuploadcomplete" reRender="info" /> </rich:fileUpload> <h:panelGroup id="info"> <rich:panel bodyClass="info"> <f:facet name="header"> <h:outputText value="Uploaded Files Info" /> </f:facet> <h:outputText value="No files currently uploaded" rendered="#{fileUpload.size==0}" /> <rich:dataGrid columns="1" value="#{fileUpload.files}" var="file" rowKeyVar="row"> <rich:panel bodyClass="rich-laguna-panel-no-header"> <h:panelGrid columns="2"> <a4j:mediaOutput element="img" mimeType="#{file.mime}" createContent="#{fileUpload.paint}" value="#{row}" style="width:100px; height:100px;" cacheable="false"> <f:param value="#{fileUpload.timeStamp}" name="time"/> </a4j:mediaOutput> <h:panelGrid columns="2"> <h:outputText value="File Name:" /> <h:outputText value="#{file.name}" /> <h:outputText value="File Length(bytes):" /> <h:outputText value="#{file.length}" /> </h:panelGrid> </h:panelGrid> </rich:panel> </rich:dataGrid> </rich:panel> <rich:spacer height="3"/> <br /> <a4j:commandButton action="#{fileUpload.clearUploadData}" reRender="info, upload" value="Clear Uploaded Data" rendered="#{fileUpload.size>0}" /> </h:panelGroup> </h:panelGrid> </h:form>
The code for the fileUpload backing bean is mentioned below.
In the code below all the parameters are passed to the DAO class directly i recommend that you use a DTO and pass it instead.
public class FileUploadBacking { private ArrayList<filevo> files = new ArrayList<filevo>(); private int uploadsAvailable = 10; private boolean autoUpload = false; private boolean useFlash = false; public int getSize() { if (getFiles().size() > 0) { return getFiles().size(); } else { return 0; } } //used to write in the display pane public void paint(OutputStream stream, Object object) throws IOException { stream.write(getFiles().get((Integer) object).getData()); } public void listener(UploadEvent event) throws Exception { UploadItem item = event.getUploadItem(); FileStoreDAO fdao=FileStoreDAO.getInstance(); FacesContext fctx=FacesContext.getCurrentInstance(); HttpServletRequest request=(HttpServletRequest)fctx.getExternalContext().getRequest(); HttpSession session=request.getSession(); // Call the storeFile method of fileStoreDAO passing it the params. //Create a DTO for such calls String result=fdao.storeFile(item.getData(),item.getFileName(),item.getContentType(),session.getAttribute("userID").toString()); if(result.equalsIgnoreCase("success")) { FileVO fileVO = new FileVO(); fileVO.setName("your application domain"+" context root"+"rest resource mapping"+item.getFileName()); fileVO.setLength(item.getData().length); fileVO.setData(item.getData()); else{ FacesMessage fmsg=new FacesMessage(FacesMessage.SEVERITY_ERROR,"Db error","Some Db error has occured could not upload your files"); fctx.addMessage(null, fmsg); } files.add(fileVO); uploadsAvailable--; } //clear the data public String clearUploadData() { for(int i=0;i<files.size();i++){ FileStoreDAO fdao=FileStoreDAO.getInstance(); fdao.removeData(files.get(i).getFileName()); } files.clear(); return "success"; } //rest of the code
The DAO class for storing,reading or updating files is listed below:-
public class FileStoreDAO { private FileStoreDAO(){ } public static FileStoreDAO getInstance(){ return new FileStoreDAO(); } public void removeData(String fileName){ DBConnection conn = null; PreparedStatement pstmt = null; Statement stmt=null; try{ conn = new DBConnection(); stmt = conn.getStatement(); stmt.executeUpdate("delete from file_store where file_name like '"+fileName+"'"); } catch (Exception e) { e.printStackTrace(); } finally { try { if (stmt != null) { stmt.close(); } conn.closeConnection(); } catch (Exception e1) { e1.printStackTrace(); } } } public String storeFile(byte data[],String fileName,String fileType,String userID){ DBConnection conn = null; PreparedStatement pstmt = null; Statement stmt=null; ResultSet rs = null; String outcome; boolean flag=false; try{ conn = new DBConnection(); stmt = conn.getStatement(); ByteArrayInputStream bis=new ByteArrayInputStream(data); rs=stmt.executeQuery("Select count(*) from file_store where file_name like '"+fileName+"'"); if(rs.next()){ if(rs.getInt(1)>0){ flag=true; } } rs=null; if(flag){ pstmt=conn.getPreparedStatement("update file_store set file_data=? , file_type=? , user_id=? , file_size=? , mod_date=sysdate() where file_name like ?" ); pstmt.setAsciiStream(1,(InputStream)bis,data.length); pstmt.setString(2,fileType); pstmt.setString(3,userID); pstmt.setLong(4,data.length); pstmt.setString(5,"'"+fileName+"'"); pstmt.executeUpdate(); } else{ pstmt = conn.getPrepareStatement("Insert into file_store (file_name,file_data,file_type,user_id,file_size,mod_date) values (?,?,?,?,?,sysdate())"); pstmt.setString(1,fileName); pstmt.setAsciiStream(2,(InputStream)bis,data.length); pstmt.setString(3,fileType); pstmt.setString(4,userID); pstmt.setLong(5,data.length); pstmt.executeUpdate(); System.out.println("After insert"); } } catch (Exception e) { e.printStackTrace(); outcome="failure"; } finally { try { if (rs != null) { rs.close(); } if (pstmt != null) { pstmt.close(); } if (stmt != null) { stmt.close(); } conn.closeConnection(); } catch (Exception e1) { e1.printStackTrace(); } } outcome="success"; return outcome; } public FileDTO readFile(String fileName){ DBConnection conn = null; Statement stmt = null; ResultSet rs = null; FileDTO fileDTO=new FileDTO(); try { conn = new DBConnection(); String query="Select file_name,file_type,file_size,file_data from file_store where file_name=?"; pstmt = conn.getPrepardedStatement(query); pstmt.setString(1,"'"+fileName +"'"); rs=stmt.executeQuery(); if(rs.next()){ fileDTO.setFileData(rs.getAsciiStream("file_data")); fileDTO.setMime(rs.getString("file_type")); fileDTO.setLength(rs.getLong("file_size")); fileDTO.setFileName(rs.getString("file_name")); } } catch (Exception e) { fileDTO=null; e.printStackTrace(); } finally { try { if (rs != null) { rs.close(); } if (stmt != null) { stmt.close(); } conn.closeConnection(); } catch (Exception e1) { e1.printStackTrace(); } } return fileDTO; } }
Now all we have to do is write the code of the jersey based restful web service and configure the jersey servlet.
The jersey servlet configuration is shown below:-
<servlet> <servlet-name>JerseyWebService</servlet-name> <servlet-class> com.sun.jersey.spi.container.servlet.ServletContainer </servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value> com.blogspot.ramannanda.editor.rest </param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>JerseyWebService</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping>The jersey servlet intercepts any call to the resource under /rest.
The code for the resource class is shown below.
@Path("/") public class FileResource { /** * @param filename passed in the get request * @returns builds and returns the response * **/ @GET @Path("/files/{filename}") @Produces(MediaType.WILDCARD) public Response returnFileAsStream(@PathParam("filename") String fileName){ FileStoreDAO ftDAO=FileStoreDAO.getInstance(); FileDTO fdto=ftDAO.readFile(fileName); if(fdto!=null){ String contentType=fdto.getMime(); InputStream is=fdto.getFileData(); return Response.ok(is,contentType).build(); } else { return Response.noContent().build(); } } }The FileResouce class has a mapping of /files/{filename} specified where filename is the path parameter. For example if a call to http://your-domain/yourcontextroot/rest/files/abc.jpg comes the method annotated with the get annotation simply call's the DAO class's readFile method passing it the file name as abc.jpg and get the data as a stream(if the file exists), The method then builds a response and returns it to the client.
Hope this tutorial was helpful