Implementing file uploads using JSF and myfaces

Source: Internet
Author: User
Tags filter file size file system file upload ftp hash string version
JS Web browsers provide a simple way for us to send files using Web applications, but the current version of the Java Web Standards (Servlets, JSP, and JSF) is not helping us. Fortunately, there are third-party framework components (such as Apache Commons File Upload, Apache myfaces, and Oracle ADF Faces) that implement this feature, exposing both simple APIs and custom tags (tag).

The previous section of this article describes how the file upload operation was implemented, explaining the myfaces and common file uploads (the former used internally). It is important that we understand how these open source framework components work internally, because only then can we use them efficiently and modify them to suit our needs. The second part of this article describes a simple application that lets users upload files using a Web browser.

   Web-based file uploads

We've used the term "upload" a bit too much. When a Web administrator publishes a file on his or her own site, it says that it has "uploaded" a file. When Web developers create HTML forms and scripts that allow ordinary users to send a file through a Web browser, they also say they have implemented the file upload feature.

These two meanings overlap in some ways, because Web administrators may use a web-based interface to publish files (pages, images, scripts, and so on). Companies that provide free personal web sites, such as Yahoo, implement the web-based file upload feature to allow people to upload their own pages. It allows any individual with a Web browser and Internet access to publish a small web site. However, there are some better ways to publish Web content, such as FTP or secure FTP. In this case, you can use a dedicated application (such as an FTP client) to upload your content to a Web server instead of a Web browser.

This article discusses the issue of file uploads from the perspective of web developers. For example, a web-based mail application, such as Yahoo Mail, enables file uploads, because only then will users be able to send messages with attachments. Another good example is a job-seeking web site that allows users to send their resumes to recruiters. The sample application in this article calculates the hash value of the uploaded file. You can do any processing of uploaded files in your own application, such as storing their contents in a database or sending them as attachments to a message. Now, let's see how to implement file uploads in a Web application.

An HTML form can contain one or more <input type= "file" elements, which the browser displays (renders) as input fields in which users are allowed to enter file paths. After each file entry field, the Web browser adds a button that opens a file dialog box that allows the user to select a file (instead of the input path):


Figure 1: Web Form with file input fields
When the user clicks the Submit button on the form, the Web browser encodes the form's data, including the selected file, file name (or path), and some other parameters of the form. The browser then sends the encoded data to the Web server, which passes the data to the script specified by the <form> tag's action attribute. If you develop a Java Web application, the action script may be a servlet (small service program) or JSP page.

Because the default encoding of form data and the default get method are not appropriate for file uploads, forms that contain file input fields must specify Multipart/form-data encoding and Post methods in the <form> tag:

...
...


But things are not that simple, because application servers that implement servlet and JSP specifications are not necessarily able to handle multipart/form-data encoding. Therefore, you must analyze the requested input stream, for example, the Apache generic file upload is a small Java package that allows you to retrieve the contents of the uploaded file from the encoded data. The API for this package is flexible, allowing you to store small files in memory and store large files in a temporary directory on disk. You can specify a threshold for a file size, a file that is greater than this is written to disk, not kept in memory, and you can set the maximum size of the file that is allowed to be uploaded.

The Org.apache.commons.fileupload package mentioned earlier contains a class called Diskfileupload, and its parserequest () method obtains the HttpServletRequest parameters. and returns a list of Org.apache.commons.fileupload.FileItem instances. The encoded form data is read from the data flow stream returned by the getInputStream () method of the servlet request. The name Fileitem is misleading because an instance of this interface also shows the uploaded file and the normal request parameters.

The API provided by the generic file upload package gives you the right to access the decomposed form data, but the GetParameter () and Getparametervalues () methods requested by the servlet do not work. This is a challenge because JSF components that run in the background of an input field, check box, radio box, and list box need to call both methods. We can solve this problem using the two features (filters and request wrappers) provided by the Servlets API. The next section describes how Apache Myfaces implements filters, adding a lot of the necessary support for file uploads without disrupting existing JSF components. In addition, Myfaces provides APIs for JavaBeans, as well as a custom JSF component that behaves as a

  Configuring JSF and Myfaces Extensions

Currently, the main implementation of the JSF specification is the JSF reference implementation (RI), while Apache provides another implementation, namely myfaces. There may be other JSF implementations, of course, but JSF Ri and Myfaces are among the two most popular. Many developers prefer the former, because Sun calls it an "official" implementation, but Myfaces has some interesting extensions (such as support for uploading file operations). If you want, you can use the myfaces extension with Sun's JSF ri. All you have to do is put Myfaces-extensions.jar files, JSF ri jar files and Commons-fileupload-1.0.jar files into the Web-inf/lib directory of your Web application. The following are the required jar files:

JSF 1.1 RI Jsf-api.jarjsf-impl.jar
JSTL 1.1 RI Jstl.jarstandard.jar
Myfaces extension Myfaces-extensions.jar
Apache Commons (for JSF and myfaces extensions) Commons-collections.jarcommons-digester.jarcommons-beanutils.jarcommons-logging.jarcommons-fileupload-1.0.jar


The Multipartrequestwrapper class in the Org.apache.myfaces.component.html.util package acts as a bridge between myfaces and common file uploads. This class extends the httpservletrequestwrapper, overloading the Getparametermap (), Getparameternames (), GetParameter (), and Getparametervalues () methods So that they can adapt to the Multipart/form-data encoding method. In addition, Multipartrequestwrapper offers two new methods, namely Getfileitem () and Getfileitems (), It allows you to access uploaded files through the Org.apache.commons.fileupload.FileItem interface.

When the myfaces detects the encoding, the Extensionsfilter in the Org.apache.myfaces.component.html.util package establishes the Multipartrequestwrapper instance. Therefore, you do not need to care about the decomposition of form data, but if you want to change how the uploaded file is handled, it is useful to know how it is implemented. In a typical application, you must configure Extensionsfilter in the web.xml description of your Web application so that it can intercept the HTTP request before JSF's Facesservlet:

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

! DOCTYPE Web-app Public
"-//sun Microsystems, INC.//DTD Web application 2.3//en"
"Http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>

<context-param>
<param-name> Javax.faces.STATE_SAVING_METHOD </param-name>
<param-value> Client </param-value>
</context-param>

<servlet>
<servlet-name> Facesservlet </servlet-name>
<servlet-class>
Javax.faces.webapp.FacesServlet
</servlet-class>
<load-on-startup> 1 </load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name> Facesservlet </servlet-name>
<url-pattern>/faces/* </url-pattern>
</servlet-mapping>

<servlet-mapping>
<servlet-name> Facesservlet </servlet-name>
<url-pattern> *.faces </url-pattern>
</servlet-mapping>

<filter>
<filter-name> Extensionsfilter </filter-name>
<filter-class>
Org.apache.myfaces.component.html.util.ExtensionsFilter
</filter-class>
<init-param>
<param-name> uploadmaxfilesize </param-name>
<param-value> 10m </param-value>
</init-param>
<init-param>
<param-name> uploadthresholdsize </param-name>
<param-value> 100k </param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name> Extensionsfilter </filter-name>
<servlet-name> Facesservlet </servlet-name>
</filter-mapping>

<welcome-file-list>
<welcome-file> index.jsp </welcome-file>
</welcome-file-list>

</web-app>


The two filter parameters in the preceding example tell myfaces to put files smaller than 100K into memory and ignore (i.e. not handle) files that occupy more than 10MB of disk space. Files that are between uploadthresholdsize and uploadmaxfilesize are stored on disk as temporary files. If you try to load a file that is too large, the current version of Myfaces ignores all form data, just as a user submits an empty form. If you want to give some hint to a user who has failed to upload a file, you need to change the Myfaces Multipartrequestwrapper class and find the location to catch the sizelimitexceededexception exception. and use Facescontext.getcurrentinstance (). AddMessage () to warn the user.

As mentioned earlier, the Myfaces extension contains the file upload component, which we can use on JSF pages. The next section describes how to implement such an operation. Use the Myfaces file upload component.

In order to use JSF and myfaces in Web pages, you must declare their tag libraries in the <% @taglib%> directive:

<%@ 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/extensions" prefix= "x"%>


JSF's


...
Value= "#{mybean.myfile}"
storage= "File"
Required= "true"/>
...


The Myfaces <x:inputFileUpload> tag enables you to define the properties of the UI component, and its rendering part (renderer) generates <input type= "file" elements. The Org.apache.myfaces.custom.fileupload package contains UI component classes (Htmlinputfileupload), Render parts (Htmlfileuploadrenderer), Custom tag handlers (Htmlinputfileuploadtag), uploadedfile interfaces, and other auxiliary classes. The Htmlinputfileupload class extends the JSF standard HtmlInputText component and overloads some of its methods. Htmlfileuploadrenderer is responsible for generating HTML tags and obtaining fileitem from Multipartrequestwrapper.

Myfaces does not give you direct access to the Fileitem instance created by the generic file upload, which provides its own UploadedFile interface to obtain the content, content type, file name, and file size of the uploaded file. The background bean for a JSF form must have an attribute of type UploadedFile. The previous example uses the JSF expression (#{mybean.myfile}) to bind the value of the UI component to such a bean. The JSF framework component gets the value of the Htmlinputfileupload component, which is a uploadedfile instance, and sets the MyFile property of the background bean:

Import Org.apache.myfaces.custom.fileupload.UploadedFile;
...
public class Mybean {
Private UploadedFile MyFile;

Public UploadedFile Getmyfile () {
return myFile;
}

public void Setmyfile (UploadedFile myFile) {
This.myfile = MyFile;
}
...
}


Myfaces has two implementations of the UploadedFile interface: Uploadedfiledefaultmemoryimpl and Uploadedfiledefaultfileimpl. The former is used when the <x:inputFileUpload> tag has no storage attribute, or if the value of this property is memory. Use the latter when the value of the storage property is file.

The Uploadedfiledefaultmemoryimpl class obtains the content, file name, file size, and content type of the uploaded file from the Fileitem instance, and stores all this information in a private field. Thus, even if a generic file upload keeps the file on disk, this implementation of UploadedFile will save the contents of the uploaded file in memory, wasting resources.

The Uploadedfiledefaultfileimpl class uses a transition field to hold a pointer to a Fileitem instance and uses it to get the contents of the uploaded file only when the getInputStream () method is invoked. This implementation saves memory space, but if it is serialized (serialize), then after the serialization (deserialization) is restored, you cannot get the file content. Therefore, the background bean for the file upload form cannot be saved in the session scope (scope), because the application server serializes the dialog bean when the application restarts or the server shuts down.

If you want a working, efficient solution, keep the background bean in the request scope and specify storage= "file" in <x:inputFileUpload> to conserve memory resources. You can also resolve serialization problems for Uploadedfiledefaultfileimpl classes by adding the WriteObject () method that serializes the contents of the uploaded file. To ensure the efficiency of this implementation of UploadedFile, the corresponding ReadObject () method should re-establish a temporary file instead of reading the contents from memory.

One problem to note when using myfaces is that the UploadedFile interface does not define a method for removing the temporary files that the generic file is built on disk. When the Fileitem instance is cleaned as garbage, the files should be deleted. The Defaultfileitem class for common file uploads has a finalize () method that deletes temporary files that they manage when objects that manage temporary files are removed from memory. If your application is uploading large files, you may want to delete them as soon as they are processed without having to wait for the garbage removal process. To achieve this, you must add a Getfileitem () method (in Uploadedfiledefaultfileimpl) that should return the Fileitem instance, which has the delete () method.

  Sample Application

The previous section describes how myfaces supports file uploads with the help of a generic file upload. Now let's look at an application that actually exploits this feature. JSF forms (myform.jsp) lets the user select a file and a report digest to algorithm, the background bean (Mybean.java) uses this algorithm to compute a hash value that is displayed in another Web page (myresult.jsp). These pages and background beans are combined with a JSF configuration file (Faces-config.xml).

myform.jsp page

This JSF form uses the Myfaces tag, along with other standard JSF tags to render tags, messages, drop-down lists that contain the algorithm for reporting abstracts, and use JSF expressions (#{ Mybean.processmyfile}) Specifies the command button that handles the action method of the uploaded file:

<%@ 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/extensions" prefix= "x"%>

<f:view>
<x:inputfileupload id= "Myfileid" value= "#{mybean.myfile}" storage= "File" required= "true"/>
<f:selectitem itemlabel= "" Itemvalue= ""
<f:selectitem itemlabel= "MD5" itemvalue= "MD5"
<f:selectitem itemlabel= "SHA-1" itemvalue= "SHA-1"
<f:selectitem itemlabel= "SHA-256" itemvalue= "SHA-256"
<f:selectitem itemlabel= "SHA-384" itemvalue= "SHA-384"
<f:selectitem itemlabel= "SHA-512" itemvalue= "SHA-512"

action= "#{mybean.processmyfile}"/>

</f:view>


Mybean class

The background bean has three properties: MyFile, Myparam, and Myresult. The role of the MyFile property has been explained earlier. It lets you get the content and file name, file size, and content type of the uploaded file. The value of the Myparam attribute is the method of reporting digest. The Myresult property will hold the hash value after the execution of the Processmyfile () method. The Mybean class provides a get and set method for all of its properties:

Package com.devsphere.articles.jsfupload;

Import Org.apache.myfaces.custom.fileupload.UploadedFile;
...
public class Mybean {
Private UploadedFile MyFile;
Private String Myparam;
Private String Myresult;

Public UploadedFile Getmyfile () {
return myFile;
}

public void Setmyfile (UploadedFile myFile) {
This.myfile = MyFile;
}

Public String Getmyparam () {
return myparam;
}

public void Setmyparam (String myparam) {
This.myparam = Myparam;
}

Public String Getmyresult () {
return myresult;
}

public void Setmyresult (String myresult) {
This.myresult = Myresult;
}
...
}


Processmyfile () Gets the contents of the uploaded file through an input stream, which is obtained through Myfile.getinputstream (). The hash value is computed with the help of Java.security.MessageDigest and then converted to a string so that it can be accessed by the Myresult property:

Package com.devsphere.articles.jsfupload;
...
Import Javax.faces.application.FacesMessage;
Import Javax.faces.context.FacesContext;

Import Java.security.MessageDigest;
Import java.security.NoSuchAlgorithmException;

Import java.io.*;

public class Mybean {
...
Public String Processmyfile () {
try {
MessageDigest md= messagedigest.getinstance (myparam);
InputStream in = new Bufferedinputstream (
Myfile.getinputstream ());
try {
byte[] buffer = new byte[64 * 1024];
int count;
while ((count = in.read (buffer)) > 0)
Md.update (buffer, 0, count);
finally {
In.close ();
}
byte hash[] = Md.digest ();
StringBuffer buf = new StringBuffer ();
for (int i = 0; I hash.length i++) {
int b = hash[i] & 0xFF;
int C = (b > 4) & 0xF;
c = C 10? ' 0 ' + C: ' A ' + c-10;
Buf.append ((char) c);
c = B & 0xF;
c = C 10? ' 0 ' + C: ' A ' + c-10;
Buf.append ((char) c);
}
Myresult = Buf.tostring ();
return "OK";
catch (Exception x) {
Facesmessage message = new Facesmessage (
Facesmessage.severity_fatal,
X.getclass (). GetName (), X.getmessage ());
Facescontext.getcurrentinstance (). AddMessage (null, message);
return null;
}
}

}


Faces-config.xml file

The JSF configuration file defines the background bean in the request scope and specifies a navigation rule:


! DOCTYPE Faces-config Public
"-//sun Microsystems, Inc.//dtd JavaServer Faces Config 1.1//en"
"Http://java.sun.com/dtd/web-facesconfig_1_1.dtd" >




Mybean

Com.devsphere.articles.jsfupload.MyBean

Request



/myform.jsp

OK
/myresult.jsp




myresult.jsp page

This web page shows some information about the uploaded file:

<%@ taglib uri= "Http://java.sun.com/jsf/core" prefix= "F"%>
<%@ taglib uri= "http://java.sun.com/jsf/html" prefix= "H"%>




















The file name displayed may have the full path of the client file system, as follows:


Figure 2: Output information generated by the resulting page
   Summary

In many cases, users need to upload files through the browser, but there is no ideal way to process these files on the server side. Keeping the contents of a file in memory is acceptable for small files, but storing the uploaded files in a temporary file complicates the situation. Myfaces allows you to choose a solution that fits your application needs, but there are some minor problems with this framework component. When you no longer need temporary files, it cannot let you delete them; The file name is sometimes with a file path, and there is no warning when the user uploads a file that is too large. These flaws can be patched because we can use the source code, and this article introduces some of the areas where myfaces code can be improved. In any case, for most applications, myfaces is in demand without modification. Examples of this article are uploading 1.0 environmental tests using JSF 1.1.01, Myfaces 1.0.9, and generic files.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.