About us
Contact us
Products
Services
Articles
 Twitter    Bookmark and Share

File Uploading Example

This example uses our FileBean component within a JSP page to upload files. The example consists of JavaBeans, an HTML form, a JSP upload handler, a JSP processor for the uploaded files and another file containing resources.


1. Data Beans

UploadBean is a Java bean that contains a String (optionalText), a String[] (textGroup), a FileBean (optionalFile) and a FileBean[] (fileList). The class com.devsphere.mapping.FileBean has three read-only properties: fileName, contentType and inputStream.

UploadBean.java:

package com.devsphere.examples.mapping.upload;

import com.devsphere.mapping.FileBean;

/**
 * Upload bean
 */
public class UploadBean implements java.io.Serializable {
    private String optionalText;
    private String textGroup[];
    private FileBean optionalFile;
    private FileBean fileList[];

    /**
     * No-arg constructor
     */
    public UploadBean() {
    }

    /**
     * Gets the optionalText property
     */
    public String getOptionalText() {
        return this.optionalText;
    }

    /**
     * Sets the optionalText property
     */
    public void setOptionalText(String value) {
        this.optionalText = value;
    }

    /**
     * Gets the textGroup property
     */
    public String[] getTextGroup() {
        return this.textGroup;
    }

    /**
     * Sets the textGroup property
     */
    public void setTextGroup(String values[]) {
        this.textGroup = values;
    }

    /**
     * Gets an element of the textGroup property
     */
    public String getTextGroup(int index) {
        return this.textGroup[index];
    }

    /**
     * Sets an element of the textGroup property
     */
    public void setTextGroup(int index, String value) {
        this.textGroup[index] = value;
    }

    /**
     * Gets the optionalFile property
     */
    public FileBean getOptionalFile() {
        return this.optionalFile;
    }

    /**
     * Sets the optionalFile property
     */
    public void setOptionalFile(FileBean value) {
        this.optionalFile = value;
    }

    /**
     * Gets the fileList property
     */
    public FileBean[] getFileList() {
        return this.fileList;
    }

    /**
     * Sets the fileList property
     */
    public void setFileList(FileBean values[]) {
        this.fileList = values;
    }

    /**
     * Gets an element of the fileList property
     */
    public FileBean getFileList(int index) {
        return this.fileList[index];
    }

    /**
     * Sets an element of the fileList property
     */
    public void setFileList(int index, FileBean value) {
        this.fileList[index] = value;
    }

}

2. HTML Form

The properties of UploadBean are mapped to the form elements of UploadForm.html:

Name Property type Element type
     
optionalText String text area
textGroup String[] text[]
optionalFile FileBean file
fileList FileBean[] file[]

The user may fill the text elements, select one or more files and then click Submit. The browser will encode the inputted text and the files' content and send them to the Web server using the "multipart/form-data" media type, which is the value of the ENCTYPE attribute of the <FORM> tag. The use of this encoding is necessary if you want to upload files.

There are interesting differences between the three text fields and the three file elements. All of the text fields must have a value. Otherwise an error is signaled for each text field whose value is missing and the values of the other fields are preserved. The file elements are treated as a list, which may contain 1-3 files. If the list is empty a single error message is shown for the entire list. Also each of the text fields may have its own default value while the file elements cannot.

The way the mapping between JavaBeans and HTML forms works was explained in a previous chapter.

UploadForm.html:

<HTML>
<HEAD><TITLE>Upload Form</TITLE></HEAD>
<BODY>
<H3>File Uploading Example</H3>
<FORM METHOD="POST" ENCTYPE="multipart/form-data">
<P> Optional Text <BR>
<TEXTAREA NAME="optionalText" ROWS="5" COLS="30">
</TEXTAREA>
<P> Text group <BR>
<INPUT TYPE="TEXT" NAME="textGroup" SIZE="20"> <BR>
<INPUT TYPE="TEXT" NAME="textGroup" SIZE="20"> <BR>
<INPUT TYPE="TEXT" NAME="textGroup" SIZE="20"> <BR>
<P> Optional file <BR>
<INPUT TYPE="FILE" NAME="optionalFile">
<P> File list <BR>
<INPUT TYPE="FILE" NAME="fileList"> <BR>
<INPUT TYPE="FILE" NAME="fileList"> <BR>
<INPUT TYPE="FILE" NAME="fileList"> <BR>
<P>
<INPUT TYPE="SUBMIT" VALUE="Submit">
<INPUT TYPE="RESET" VALUE="Reset">
</FORM>
</BODY>
</HTML>

3. Bean Resources

The UploadBeanResources.properties file contains some default values, the list of optional properties and the names of the two JSP files described in the next sections.

UploadBeanResources.properties:

[DEFAULT_VALUE.optionalText]=123
[DEFAULT_VALUE.textGroup.length]=3
[DEFAULT_VALUE.textGroup.1]=abc
[OPTIONAL_PROPERTIES]=optionalText optionalFile
[FORM_NAME]=UploadForm.html
[PROC_NAME]=UploadProc.jsp

4. JSP Handler

The UploadHndl.jsp handler is based on a template that was described in a previous chapter and is very similar to the handler of the first example (SimpleHndl.jsp).

The Servlet API does not support the "multipart/form-data" encoding type, which is necessary for file uploading. The com.devsphere.mapping.ServletFormData class can parse the input stream of the wrapped javax.servlet.http.HttpServletRequest to get a parameter set that includes strings, string arrays, FileBean objects and FileBean arrays.

To enable the "multipart/form-data" parsing, you must use the constructor of ServletFormData that accepts two parameters, pass a HttpServletRequest object whose content-type starts with "multipart/form-data" and the second parameter (allowMultipart) must be true. If these conditions aren't met the multipart parser isn't enabled, the getParameter() method is delegated to the HttpServletRequest object and the getFileParameter() method returns null (or an empty enumeration in the case of getFileParameterNames()).

To ensure that the server's performance doesn't drop under a certain point you should ignore any HTTP request whose content-length exceeds an experimentally determined limit. Extensive testing that simulate the production environment should be performed in order to determine a safe value for that limit. Also you could limit the number of file uploadings that could be performed at the same time.

The JSP handler of this example arbitrarily limits the content-length of the processed requests to 400,000.

UploadHndl.jsp:

<%@ page language="java" %>
<%@ page import="com.devsphere.mapping.*, com.devsphere.logging.*" %>
<jsp:useBean id="uploadBean" scope="request"
    class="com.devsphere.examples.mapping.upload.UploadBean"/>
<%
// Determine the HTTP method
boolean isPostMethod = request.getMethod().equals("POST");

// Verify the content length
int contentLength = request.getContentLength();
if (isPostMethod && (contentLength < 0 || contentLength > 400000))
    application.log("Request ignored. Content-Length: " + contentLength);
else {
    // Get the bean resources
    java.util.ResourceBundle beanRes
        = HandlerUtils.getBeanResources(uploadBean.getClass());

    // Construct the base path
    String basePath = request.getServletPath();
    int slashIndex = basePath.lastIndexOf('/');
    basePath = slashIndex != -1 ? basePath.substring(0, slashIndex+1) : "";

    // Create a logger that wraps the servlet context
    ServletLogger logger = new ServletLogger(application);

    // Wrap the form data
    FormData formData = new ServletFormData(request, true);

    // Form-to-bean mapping: request parameters are mapped to bean properties
    java.util.Hashtable errorTable
        = FormUtils.formToBean(formData, uploadBean, logger);

    if (isPostMethod && errorTable == null) {
        // Construct the processor's path
        String procPath = basePath + beanRes.getString("[PROC_NAME]").trim();

        // Process the valid data bean instance
        application.getRequestDispatcher(procPath).forward(request, response);
    } else {
        if (!isPostMethod)
            // Ignore the user errors if the form is requested with GET.
            errorTable = HandlerUtils.removeUserErrors(errorTable);

        // Construct the form's path
        String formPath = basePath + beanRes.getString("[FORM_NAME]").trim();
        formPath = application.getRealPath(formPath);

        // Get the form template
        FormTemplate template = FormUtils.getTemplate(new java.io.File(formPath));

        // Get a new document
        FormDocument document = template.getDocument();

        // Bean-to-form mapping: bean properties are mapped to form elements
        FormUtils.beanToForm(uploadBean, errorTable, document, logger);

        // Send the form document
        document.send(out);
    }
}
%>

5. JSP Processor

The UploadProc.jsp processor gets only valid bean objects and outputs the values of their properties. In addition, the uploaded files are saved in a directory.

UploadProc.jsp:

<%@ page language="java" %>
<%@ page import="java.io.*, com.devsphere.mapping.*" %>
<jsp:useBean id="uploadBean" scope="request"
    class="com.devsphere.examples.mapping.upload.UploadBean"/>
<%
    byte buf[] = new byte[1024 * 4];
    String dir = request.getServletPath();
    int slashIndex = dir.lastIndexOf('/');
    dir = slashIndex != -1 ? dir.substring(0, slashIndex+1) : "";
    dir = application.getRealPath(dir + "uploaded");
%>
<HTML>
<HEAD><TITLE>Upload Form</TITLE></HEAD>
<BODY>
<H3>File Uploading Example</H3>
<P><B></B>
<P><B> UploadBean properties: </B>
    <P> optionalText = <%= uploadBean.getOptionalText() %>
    <P> textList[0] = <%= getItem(uploadBean.getTextGroup(), 0) %>
    <P> textList[1] = <%= getItem(uploadBean.getTextGroup(), 1) %>
    <P> textList[2] = <%= getItem(uploadBean.getTextGroup(), 2) %>
    <P> optionalFile = <%= saveFile(uploadBean.getOptionalFile(), dir, buf) %>
    <P> fileList[0] = <%= saveFile(uploadBean.getFileList(), 0, dir, buf) %>
    <P> fileList[1] = <%= saveFile(uploadBean.getFileList(), 1, dir, buf) %>
    <P> fileList[2] = <%= saveFile(uploadBean.getFileList(), 2, dir, buf) %>
</BODY>
</HTML>

<%!
    // Gets the item of list
    String getItem(String list[], int index) {
        if (list == null || index >= list.length)
            return "";
        return list[index];
    }

    // Saves a file and returns its name
    String saveFile(FileBean fileBeanArray[], int index, String dir, byte buf[])
        throws IOException {
        if (fileBeanArray == null || index >= fileBeanArray.length)
            return "";
        return saveFile(fileBeanArray[index], dir, buf);
    }

    // Saves a file and returns its name
    String saveFile(FileBean fileBean, String dir, byte buf[])
        throws IOException {
        if (fileBean == null)
            return "";
        new File(dir).mkdirs();
        File file = new File(dir, fileBean.getFileName());
        FileOutputStream output = new FileOutputStream(file);
        try {
            InputStream input = fileBean.getInputStream();
            try {
                while (true) {
                    int count = input.read(buf);
                    if (count == -1)
                        break;
                    output.write(buf, 0, count);
                }
            } finally {
                input.close();
            }
        } finally {
            output.close();
        }
        return fileBean.getFileName();
    }
%>

6. Hints and Tips

When you use file uploading, make sure that

  • the value of the ENCTYPE attribute of the <FORM> tag is "multipart/form-data"
  • you use the ServletFormData(HttpServletRequest request, boolean allowMultipart) constructor
  • the value of the allowMultipart flag is true

Click here to purchase our JSP File Upload component
with full Source Code for only $17.


Copyright © 2000-2009 Devsphere

About us
Contact us
Products
Services
Articles