ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Uploading Files with Beans

by Budi Kurniawan
04/05/2001

How many times have you asked yourself or been curious about how the developers at Hotmail or Yahoo Mail process the attachments to your email? Rest assured that you are not the only one. Too often Java Internet developers only concentrate on processing strings from an HTML form, and when asked by the boss if they can do file upload, they have to do some research before they can come back with an answer. File upload is too rarely discussed by even respectable Java literature.

And, with the growth of the Internet, file upload has now also played significant roles beyond email applications. Other Internet/intranet applications such as Web-based document management systems and the likes of "Secure File Transfer via HTTP" require uploading files to the server extensively. This article discusses all you need to know about file upload. But first things first. Before you jump too excitedly into coding, you need to understand the underlying theory: the HTTP request. Knowledge of the HTTP request is critical because when you process an uploaded file, you work with raw data not obtainable from an HttpServletRequest object's methods such as getParameter, getParameterNames, or getParameterValues.

The HTTP Request

Each HTTP request from the Web browser or other Web client applications consists of three parts:

These three parts are explained in the following sections.

The Request Method, URI and Protocol

The first subpart of the first part, the HTTP request method, indicates the method used in the HTTP request. In HTTP 1.0, it could be one of the following three: get, head, or post. In HTTP 1.1, in addition to the three methods, there are four more methods: delete, put, trace, and options. Among the seven, the two methods that are most frequently used are get and post. get is the default method. You use it, for example, when you type a URL such as http://www.onjava.com in the Location or Address box of your browser to request a page. The post method is common too. You normally use this as the value of the <form> tag's method attribute. When uploading a file, you must use the post method.

The second part of the first part, the URI, specifies an Internet resource. A URI is normally interpreted as being relative to the Web server's root directory. Thus, it starts with a forward slash (/) that is of the following format.

/virtualRoot/pageName

For example, in a typical JavaServer Pages application the URI could be the following.

/eshop/login.jsp

More information about URI can be found here.

The third component of the first part is the protocol and the protocol version understood by the requester (the browser). The protocol must be HTTP and the version could be 1.0 or 1.1. Most Web servers understand both versions 1.0 and 1.1 of HTTP. Therefore, this kind of Web server can serve HTTP requests in both versions as well. If you are still using an old HTTP 1.0 Web server, you could be in trouble if your users use modern browsers that send requests using HTTP 1.1 protocol.

Combining the three sub-parts of the first component of an HTTP request, the first component would look like the following.

POST /virtualRoot/pageName HTTP/version

For instance:

POST /eshop/login.jsp HTTP/1.1

The HTTP Request Headers

The second component of an HTTP request consists of a number of HTTP headers. There are four types of HTTP headers: general, entity, request, and response. These headers are summarized in Tables 1, 2 and 3. The response headers are HTTP Response specific, thus not relevant to be discussed here.

Table 1: HTTP General Headers
Header Description
Pragma

The Pragma general header is used to include implementation specific directives that may apply to any recipient along the request/response chain. This is to say that pragmas notify the servers that are used to send this request to behave in a certain way. The Pragma header may contain multiple values. For example, the following line of code inform all proxy servers that relay this request not to use a cached version of the object but to download the object from the specified location:

Pragma: no-cache
Date

The Date general header represents the date and time at which the message was originated.


Table 2: HTTP Entity Headers.
Header Description
Allow

This header lists the set of method supported by the resource identified by the requested URL. The purpose of this field is strictly to inform the recipient of valid methods associated with the resource. The Allow header is not permitted in a request using the post method, and thus should be ignored if it is received as part of a post entity. For instance,

Allow: get, head
Content-Encoding

This header is used to describe the type of encoding used on the entity. When present, its value indicates the decoding mechanism that must be applied to obtain the media type referenced by the Content-Type header. For example,

Content-Encoding:
x-gzip
Content-Length

This header indicates the size of the entity-body, in decimal number of octets, sent to the recipient or, in the case of the head method, the size of the entity-body that would have been sent had the request been a get. Applications should use this field to indicate the size of the entity-body to be transferred, regardless of the media type of the entity. A valid Content-Length field value is required on all HTTP/1.0 request messages containing an entity-body. Any Content-Length header greater than or equal to zero is a valid value. For example,

Content-Length:
32345
Content-Type

The Content-Type header indicates the media type of the entity-body sent to the recipient or, in the case of the head method, the media type that would have been sent had the request been a get. For example,

Content-Type:
text/html
Expires

The Expires header gives the date and time after which the entity should be considered invalid. This allows information providers to suggest the volatility of the resource or a date after which the information may no longer be accurate. Applications must not cache this entity beyond the date given. The presence of an Expires header does not imply that the original resource will change or cease to exist at, before, or after that time. However, information providers should include an Expires header with that date. For example,

Expires: Thu, 29
Mar 2001 13:34:00 GMT
Last-Modified

The Last-Modified header indicates the date and time at which the sender believes the resource was last modified. The exact semantics of this field are defined in terms of how the recipient should interpret it. If the recipient has a copy of this resource that is older than the date given by the Last-Modified field, that copy should be considered stale For example,

Last-Modified: Thu, 10 Aug 2000
12:12:12 GMT

Table 3: HTTP Request Headers
Header Description
From

The From header specifies who is taking responsibility for the request. This field contains the email address of the user submitting the request. For example,

From: dragonlancer@labsale.com
Accept

This header contains a semicolon-separated list of MIME representation schemes that are accepted by the client. The server uses this information to determine which data types are safe to send to the client in the HTTP response. Although the Accept field can contain multiple values, the Accept line itself can also be used more than once to specify additional accept types (this has the same effect as specifying multiple accept types on a singe line). If the Accept filed is not used in the request header, the default accepts types of text/plain and text/html are assumed. For example,

Accept:
text/plain; text/html Accept; image/gif; image/jpeg
Accept-Encoding

This header is very similar to the accept header in syntax. However, it specifies the content-encoding schemes that are acceptable in the response. For instance,

Accept-Encoding: x-compress; x-zip
Accept-Language

This header is also similar to the Accept header. It specifies the preferred response language. The following example specifies English as the accepted language:

Accept-Language: en
User-Agent

The User-Agent, if present, specifies the name of the client browser. The first word should be the name of the software followed by a slash and an optional version number. Any other product names that are part of the complete software package may also be included. Each name/version pair should be separated by white space. This field is used mostly for statistical purposes. It allows servers to track software usage and protocol violation. For example,

User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)

Referer

This header specifies the URI that contained the URI in the request header. In HTML, it would be the address of the page that contained the link to the requested object. Like the User-Agent header, this header is not required but is mostly for the server's statistical and tracking purpose. For example,

Referer:
http://localhost/Atoms/Details.htm
Authorization

The Authorization header contains authorization information. The first word contained in this header specifies the type of authorization system to use. Then, separated by white space, it should be followed by the authorization information such as a user name, password, and so forth. For example,

Authorization: user ken:dragonlancer
If-Modified-Since

This header is used with the GET method to make it conditional. Basically, if the object hasn't changed since the date and time specified by this header, the object is not sent. A local cached copy of the object is used instead. For example,

If-Modified-Since: Thu, 10 Aug 2000 12:12:29 GMT

The Entity Body

The entity body is the content of the HTTP request itself. It is best to illustrate this with an example. An example of an HTTP header is given below.

Accept: application/vnd.ms-excel, application/msword, */*
Accept-Language: en-au
Connection: Keep-Alive
Host: localhost
Referer: http://localhost/examples/jsp/num/demo.jsp
User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)
Content-Length: 32
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate

LastName=truman&FirstName=daniel

A lot is revealed in the HTTP header above. The first line tells us that the browser that sends this request can accept a number of file formats, including Microsoft Excel and Microsoft Word. It is followed by the language used (in this case, Australian English), the type of connection (keep-alive), and the name of the host (localhost). It also tells the server that the request is sent from the demo.jsp which is located in http://localhost/examples/jsp/num/ directory. Then in the User-Agent entry, the Request tells that the user is using a Microsoft Internet Explorer version 4.01, which is compatible with Netscape 4.0. The user operation system is also recorded to be Windows 98. The meaning of the information to follow can be retrieved from the previous tables.

Following the header is two pairs of carriage-return line-feed characters. The length of this separator is 4 bytes since each carriage-return line-feed character pair consists of the ASCII characters number 13 and 10. From the HTTP header above we can see that the body consists of the following code:

LastName=truman&FirstName=daniel

This is clearly from a form with two input boxes: one called LastName with the value truman and the other named FirstName with the value daniel.

Note that the length of LastName=truman&FirstName=daniel is 32.

Now that you have finished dissecting an HTTP request, you are ready to take this information to the coding stage. To program a complete file upload application, you need to know both the server side and the client side. First we will learn how to program the HTML on the client side, and then we will study the Java code for the server side.

The Client Side HTML

Prior to the RFC 1867 standard, there were eight possible values for the type attribute of an input element: checkbox, hidden, image, password, radio, reset, submit, and text. While these form elements have proven useful in a wide variety of applications in which input from the user needs to be transferred to the server, none of these is useful for sending a file, either text or binary. Next, it was proposed that the Type attribute of an Input element has another possible value: file. In addition, it defines a new MIME media type, multipart/form-data, and specifies the behavior of HTML user agents when interpreting a form with enctype="multipart/form-data" or <input type="file" /> tags.

The author of an HTML form who wants to request one or more files from a user might write:

<form action="Jsp1.jsp" enctype="multipart/form-data" method="post">
File to Upload: <input name="filename" type="file" />
<br />
<input type="submit" value="Upload" />
</form>

When an input tag of type file is encountered, the browser might show a display of previously selected file names and a "Browse" button or selection method. Selecting the "Browse" button would cause the browser to enter into a file selection mode appropriate for the platform. Window-based browsers might pop up a file selection window, for example. In such a file selection dialog, the user would have the option of replacing a current selection, adding a new file selection, etc.

The HttpServletRequest Interface

Internet programming in Java always involves the use of Servlets or JSP pages, depending on the architecture you choose to implement. This means that you will use one of the classes or interfaces in the javax.servlet package or the javax.servlet.http package. The most important interface is the Servlet interface in the javax.servlet package that must be implemented by all servlets. However, I will not present an introduction to Servlets in this article and can only refer you to Sun's Web site if you need more details about this API. What is of importance here is the HTTP request and how to process it. When working with the HTTP request, you will work with either the javax.servlet.ServletRequest interface or javax.servlet.http.HttpServletRequest. The ServletRequest interface is a generic interface that is extended by HttpServletRequest to provide request information for HTTP Servlets.

The HttpServletRequest interface has the following signature.

public interface HttpServletRequest extends ServletRequest

The Servlet container creates an HttpServletRequest object and passes it as an argument to the Servlet's service methods (doGet, doPost, etc). For a File Upload Bean, you can then pass this HttpServletRequest object to the Bean for further processing, like the one in this article.

HttpServletRequest's Important Methods

Some important methods of HttpServletRequest are given in the following list.

public long getDateHeader(java.lang.String name)

Returns the value of the specified request header as a long value that represents a Date object. Use this method with headers that contain dates, such as If-Modified-Since.

The date is returned as the number of milliseconds since January 1, 1970 GMT. The header name is case insensitive.

If the request did not have a header of the specified name, this method returns -1. If the header can't be converted to a date, the method throws an IllegalArgumentException.

public java.lang.String getHeader(java.lang.String name)

Returns the value of the specified request header as a String. If the request did not include a header of the specified name, this method returns null. The header name is case insensitive. You can use this method with any request header.

public java.util.Enumeration getHeaderNames()

Returns an enumeration of all the header names this request contains. If the request has no headers, this method returns an empty enumeration.

Some Servlet containers do not allow do not allow Servlets to access headers using this method, in which case this method returns null

public java.util.Enumeration getHeaders(java.lang.String name)

Returns all the values of the specified request header as an Enumeration of String objects.

Some headers such as Accept-Language can be sent by clients as several headers each with a different value rather than sending the header as a comma separated list.

If the request did not include any headers of the specified name, this method returns an empty Enumeration. The header name is case insensitive. You can use this method with any request header.

public java.lang.String getMethod()

Returns the name of the HTTP method with which this request was made, for example, get, post, or put. This is the same as the value of the CGI variable REQUEST_METHOD.

public java.lang.String getPathInfo()

Returns any extra path information associated with the URL the client sent when it made this request. The extra path information follows the Servlet path but precedes the query string. This method returns null if there was no extra path information.

This is the same as the value of the CGI variable PATH_INFO.

public java.lang.String getPathTranslated()

Returns any extra path information after the Servlet name but before the query string and translates it to a real path. This is the same as the value of the CGI variable PATH_TRANSLATED.

If the URL does not have any extra path information, this method returns null.

public java.lang.String getQueryString()

Returns the query string that is contained in the request URL after the path. This method returns null if the URL does not have a query string. This is the same as the value of the CGI variable QUERY_STRING.

public java.lang.String getRemoteUser()

Returns the login of the user making this request, if the user has been authenticated, or null if the user has not been authenticated. Whether the user name is sent with each subsequent request depends on the browser and type of authentication. This is the same as the value of the CGI variable REMOTE_USER.

public java.lang.String getRequestedSessionId()

Returns the session ID specified by the client. This may not be the same as the ID of the actual session in use. For example, if the request specified an old (expired) session ID and the server has started a new session, this method gets a new session with a new ID. If the request did not specify a session ID, this method returns null.

public java.lang.String getRequestURI()

Returns the part of this request's URL from the protocol name up to the query string in the first line of the HTTP request.

public java.lang.String getServletPath()

Returns the part of this request's URL that calls the Servlet. This includes either the Servlet name or a path to the Servlet, but does not include any extra path information or a query string. This is the same as the value of the CGI variable SCRIPT_NAME.

public HttpSession getSession(boolean create)

Returns the current HttpSession associated with this request or, if there is no current session and create is true, returns a new session.

If create is false and the request has no valid HttpSession, this method returns null.

To make sure the session is properly maintained, you must call this method before the response is committed.

public HttpSession getSession()

Returns the current session associated with this request or, if the request does not have a session, creates one.

HTTP request of an uploaded file

To illustrate how you can process a file upload, you should familiarize yourself with the HTTP request of an uploaded file. The following small application demonstrates how to upload a file and writes the HTTP request into a file. Viewing the file with a text editor will reveal the format of the request, which in turn enables you to extract the filename, the file content, and other useful information that are mixed together. This small application is meant as a preparation before we discuss the real File Upload Bean and consists of an HTML file called main.html, a JSP file called Jsp1.jsp, and a JavaBean called SimpleBean.

The main.html file is the one that the client can use to select a file to upload to the server and is given as follows.

<html>
<head>
<title>File Upload</title>
</head>
<body>
<form action="jsp1.jsp" enctype="MULTIPART/FORM-DATA" method=post>
Author: <input type="text" name="author" />
<br />
Company: <input type="text" name="company" />
<br />
Select file to upload <input type="file" name="filename" />
<br />
<input type="submit" value="Upload" />
</form>
</body>
</html>

You can see that the enctype attribute is used in the <form> tag and its value is "MULTIPART/FORM-DATA". There are four input elements including the submit button. The first two are normal text elements called Author and Company. The third one is an element of type file, the input element that is used to select a file.

The action attribute of the form has the value of Jsp1.jsp, meaning that the request (and also the file uploaded) is sent to the Jsp1.jsp file.

The Jsp1.jsp simply calls a Bean called SimpleBean.

<jsp:useBean id="TheBean" scope="page" class="SimpleBean " />
<%
TheBean.doUpload(request);
%>

And here is the code for the SimpleBean Bean.

import java.io.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletInputStream;

public class FileUploadBean {

public void doUpload(HttpServletRequest request) throws
IOException {
PrintWriter pw = new PrintWriter(
new BufferedWriter(new FileWriter("Demo.out")));
ServletInputStream in = request.getInputStream();

int i = in.read();
while (i != -1) {
pw.print((char) i);
i = in.read();
}
pw.close();
}
}

It will write everything on the HttpServletRequest object to a file named Demo.out.

The user interface is given by the main.html file and is shown in Figure 1. For this example, we enter some input values for the Author and Company input elements and select a file called abisco.html with the following content. I select an HTML file to upload because I would like to show the content of the file in the format. Since an HTML file is more or less a text file, the content will be easy to display.

The content of the abisco.html file is as follows.

<html>
<head>
<title>Abisco</title>
</head>
</html>

Screen shot.
Figure 1. The user interface for the example.

When you click the Upload button (see Figure 1 again), the form will be sent. This includes the file called abisco.html. This form is submitted to the Jsp1.jsp file. This JSP file itself does not return any response to the browser. However, it creates a file called Demo.out.

Open the Demo.out file, and you will see the following.

-----------------------------7d15340138
Content-Disposition: form-data; name="Author"

A. Christie
-----------------------------7d15340138
Content-Disposition: form-data; name="Company"

Abisco
-----------------------------7d15340138
Content-Disposition: form-data; name="Filename"; filename="C:\123data\abisco.html"
Content-Type: text/html

<html>
<head>
<title>Abisco</title>
</head>
</html>
-----------------------------7d15340138--

In brief, the entity body of the HTTP request contains all the form input, including the uploaded file. Those input values are separated from each other by a delimiter. Sometimes called a boundary, this delimiter consists of a few dozen dash characters followed by a random number. In the example above, the delimiter is the following line.

-----------------------------7d15340138

The last delimiter ends the entity body with two more dashes.

For an input value that comes from a non-file element, the delimiter is follows by the following line.

Content-Disposition: form-data; name=inputName

where inputName is the name of the form element.

For example:

Content-Disposition: form-data; name="Author"

Two sequences of carriage return linefeed characters and the element value follow the line.

For the file, two lines follow the delimiter. The first contains the name of the FILE input element and the complete path of the file in the user's computer. From the HTTP request above, this line is as follows.

Content-Disposition: form-data; name="Filename"; filename="C:\123data\abisco.html"

It states that the FILE input element is called Filename and the file path is C:\123data\abisco.html. Note that Windows browsers include the file path, but Unix/Linux and Mac browsers only send the filename.

The second line contains the content type of the file. Therefore, its value depends on the file being uploaded. For this example, the value is text/html.

Content-Type: text/html

Like the non-File input element, the content starts after two sequences of carriage return linefeed characters.

That's all you need to know to write a File Upload Bean.

Brainy FileUpload Bean

Some file upload code is written as part of a bigger application. Often the piece of code that does the extraction of the uploaded file is integrated with the other pieces as a whole, making it unusable for other applications. The solution here gives you the file upload function in a Bean, which we all know is a component in the Java platform. As such, this Bean is portable and can be used in any application that requires file upload.

I call this Bean Brainy FileUploadBean. The complete code is given in Listing 1. This section gives you the detailed descriptions of what the code does, so that you can extend the functionality if you so desire.

The first line of code is the package information. When I wrote the Bean, it was part of the package called com.brainysoftware.web. You probably don't want to use the same name for the package; therefore you should change the first line of the code.

package com.brainysoftware.web;

Alternatively, you can remove this line entirely if you don't want the class to be a member of any package.

Next are the import statements that tell you what classes or interfaces are used in the Bean. Of special interest are the HttpServletRequest interface from the javax.servlet.http package and the abstract class ServletInputStream from the javax.servlet package. This class is a subclass of java.io.InputStream.

Also imported are Dictionary and Hashtable from the java.util package and PrintWriter, BufferedWriter, FileWriter, and IOException from the java.io package.

Then comes the class, FileUploadBean. The class has 5 private fields, 6 public methods and 2 private methods.

The FileUploadBean Class's Fields

The five fields of the FileUploadBean class are all private. They are as follows.

The FileUploadBean Class's Methods

The first four public methods are used to return the FileUploadBean object's private fields. They are getFilepath, getFilename, getContentType and getFieldValue.

You pass the HttpServletRequest object created by the Servlet/JSP container to the doUpload method. This object represents the HTTP request that you need to process to extract the HTML form's element names-values and the uploaded file. The method starts by obtaining the ServletInputStream object using the getInputStream method of the HttpServletRequest object.

As explained before, each form element is separated by the boundary and a sequence of carriage return line feed characters. Therefore, you can read the content of the HttpServletRequest object line by line. The following line of code defines a byte array called line.

byte[] line = new byte[128];

You then use the readLine method of ServletInputStream to read the first line of the HttpServletRequest object's content.

int i = in.readLine(line, 0, 128);

The first line should be the boundary, and its length, if no error has occurred, should be much longer than 3. Therefore, a length of less than three can be assumed erroneous and the doUpload method should exit.

if (i < 3)
  return;

The boundary and the length of the boundary are important values, as you will see later. The boundary is terminated by a sequence of carriage return linefeed characters. Therefore the actual length is two less than the number of bytes returned by the readLine method.

int boundaryLength = i - 2;

The boundary is retrieved from the byte array line by discarding the last two carriage return linefeed characters.

String boundary = new String(line, 0, boundaryLength);

The field fields is then instantiated with a Hashtable object. This Hashtable object is used to store the HTML form element name/value pairs.

fields = new Hashtable();

Having the boundary you can then start extracting the form element value by reading the HttpServletRequest object's content line by line using the while loop, until it reaches the end of it when the readLine method returns -1. All HTML form elements start with a boundary followed by the content-disposition line that starts with the following characters.

Content-Disposition: form-data; name=

There are two types of form elements: file and non-file (normal form elements such as TEXT or HIDDEN elements). The difference between the two is based on the file element, which contains the following string.

filename="filename"

Therefore, you can use this information to distinguish the file from the non-file input elements using the following two if statements.

if (newLine.startsWith("Content-Disposition: form-data; name=\"")) {
if (newLine.indexOf("filename=\"") != -1) {
// a file form element, code to extract the file here

. . .

}
else {
//this is a field, code to extract fields here

. . .

}
}

Now, let's a look at the code to extract the file content first. Afterwards, we have a look at the code to extract non-file form elements.

The filepath is contained in the content-disposition. To retrieve the file path and the filename, the doUpload method calls the setFilename private method. This method will be discussed in the next section but it is sufficient to say that setFilename extracts the file path and the filename information and assign them to the filepath and filename fields.

After the setFilename method call, filename should not be null. Otherwise, an error has occurred and the doUpload method returns entirely.

if (filename==null)
  return;

The next line after the content-disposition line is the content type line. So call the readLine method again and call the setContentType private method. This method is similar to setFilename. It retrieves the content type of the uploaded file from the raw bytes and assign it contentType.

The next line after the line that contains the file content type is a blank line. Therefore, call the readLine method again.

i = in.readLine(line, 0, 128);

Then, begins the actual file content. We should be ready to write the file to the disk, using a PrinterWriter object.

PrintWriter pw = new PrintWriter(new BufferedWriter(
new FileWriter(
( savePath==null? "" : savePath ) + filename
)));

Where the file should be saved to depends on whether the savePath field has been set. If the savePath was not set, its value is null, and the file should be saved in the default directory. If the savePath field has been set, its value will not be null so the uploaded file must be uploaded to this directory.

We can then extract the file content by using a while loop that reads one line at a time and writes it to disk using the write method of the PrintWriter. However, we know that the last line of the file includes two carriage return line feed characters. Therefore, the bytes saved to the disk must not include these two characters. So if the line read is not the last line of the file, write all the bytes read to the disk. If it is, write all the bytes read minus the last two characters.

However, we do not know the size of the file. What we know is that the next line after the file content is another boundary. Or, if the file is the last HTML form element, the next line is the boundary plus two dash characters. Therefore, by checking whether or not the next line is a boundary we will know how to exit from the while loop. This is the reason why I said the boundary value was important. We need the boundary value for this.

We could read the next line and use the startsWith method to check if the next line is a boundary. However, string manipulation is expensive. To avoid string manipulation, we compare the length of the byte array read by readLine. The latter should be equal to boundaryLength + 2. Or, if it is the last line in the HttpServletRequest object, it should be equal to boundaryLength + 4 because of the last two dash characters. Because a line could also be as long as a boundary without being a boundary, we compare it with the boundary when the length matches. Now you know why the boundaryLength value is also important.

The whole thing is illustrated by the following lines of code.

while (i != -1 && !newLine.startsWith(boundary)) {
i = in.readLine(line, 0, 128);
if ((i==boundaryLength+2 || i==boundaryLength+4) // + 4 is eof
&& (new String(line, 0, i).startsWith(boundary)))
pw.print(newLine.substring(0, newLine.length()-2));
else
pw.print(newLine);
newLine = new String(line, 0, i);

}

After the file content is saved to the disk, close the PrintWriter.

pw.close();

The non-file form elements can be retrieved similarly. Instead of writing the values to the disk, however, the name-value pairs are put into the Dictionary object.

fields.put(fieldName, fieldValue.toString());

Using the Bean

Once you compile the Bean, you can use it from your Servlet or JSP page. Chances are you are using the Bean with a Servlet/JSP container such as Tomcat. The easiest way to deploy the Bean is to compress the class file into a jar file and chuck it to the lib directory of Tomcat. You need to restart Tomcat for the jar file to be loaded.

The following are an HTML file and a JSP file that illustrate the use of the Bean. The HTML file contains a form with a few elements.

<html>
<head>
<title>File Upload</title>
</head>
<body>
<form action=jsp1.jsp enctype="MULTIPART/FORM-DATA" method=post>
Author: <input type=text name=author>
<br>
Company: <input type=text name=company>
<br>
Comment: <textarea name=comment></textarea>
<br>
Select file to upload <input type=file name=filename>
<br>
Description: <input type=text name=description>
<br>
<input type=submit value="Upload">
</form>
</body>
</html>

When the user submits the form, the HTTP request will be handed to Jsp1.jsp, which uses the FileUpload Bean to process the request. The code of the Jsp1.jsp is given below.

<jsp:useBean id="TheBean" scope="page"
class="com.brainysoftware.web.FileUploadBean" />
<%
TheBean.doUpload(request);
out.println("Filename:" + TheBean.getFilename());
out.println("<BR>Content Type:" + TheBean.getContentType());
out.println("<BR>Author:" + TheBean.getFieldValue("Author"));
out.println("<BR>Company:" + TheBean.getFieldValue("Company"));
out.println("<BR>Comment:" + TheBean.getFieldValue("Comment"));
%>

Summary

File upload is not an easy topic and code to process it is not readily available. This article has presented the theory as well as the code for a File Upload Bean. The compiled version of the Bean is available for download from my Web site.

Budi Kurniawan is a senior J2EE architect and author.


Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.