Sample FileUpload Application Code


The code for the application consists of the following files:

index.jsp The main interface, as shown in Figure 2-7 and 2-8. Lists the files that have been posted.

post.jsp The file upload form, as shown in Figure 2-9.

These two JSP pages in turn make use of two Java classes.

Files.java Acts as the manager of uploaded files. Keeps track of information about the files that have been uploaded, such as the location on disk.

FileUploadHelper.java This application class wraps the Commons FileUpload class, making it easier to use in JSP pages. This provides a central location to keep track of the FileUpload configuration.

Application Presentation

The index.jsp page is shown in Listing 2-3. You'll notice a small bit of logic at the top to handle a file deletion. Otherwise, the bulk of the file deals with looping over the file list and other formatting.

Note that when your JSP page issues a sendRedirect(), as shown in the JSP scriptlet header, a return is used to avoid additional processing of logic on the page. This simple technique is used to avoid a variety of potential problems.

Listing 2-3. File Listing JSP
 <%@ page language="java" import="com.cascadetg.ch02.*" %> <% java.util.Hashtable myFilesHashtable = Files.getFiles(); java.util.Enumeration     myFilesEnumeration = myFilesHashtable.elements(); if(request.getParameter("delete") != null) {     Files.deleteFile(application, request.getParameter("file"));     response.sendRedirect("index.jsp");     return; } %> <head><title>File Upload Example</title></head> <body> <% if (myFilesHashtable.size() == 0)     { %>     No files posted. <%  } else { %> <table width="100%"  border="0" cellspacing="3" cellpadding="3">   <tr>     <td><strong>File</strong></td>     <td><strong>Size</strong></td>     <td><strong>Type</strong></td>     <td><strong>Location</strong></td>     <td>&nbsp;</td>   </tr> <%    while(myFilesEnumeration.hasMoreElements())     {         org.apache.commons.fileupload.FileItem             myFile =                 (org.apache.commons.fileupload.FileItem)                     myFilesEnumeration.nextElement(); %>   <tr>     <td><a href="<%=         Files.getDownloadPath(request) +             FileUploadHelper.getFileName(myFile.getName())             %>"><%=         FileUploadHelper.getFileName(myFile.getName())         %></a></td>     <td><%=myFile.getSize()%></td>     <td><%= myFile.getContentType()%></td>     <td><a target="_blank" href="file:///<%=         Files.getUploadPath(application) +             FileUploadHelper.getFileName(myFile.getName())                 %>">Local File</a></td>     <td><a href="<%= "index.jsp?file=" +         response.encodeURL(FileUploadHelper.getFileName(myFile.getName()))             + "&delete=true" %>">Delete</a></td>   </tr> <%     } /* End of file display iteration */ %> </table> <% } /* End of file list display */ %> <p><a href="post.jsp">Add File</a> </p> </body> </html> 

The form used to upload a file to the server is shown in Listing 2-4. You'll notice that there is only a small bit of codethe heavy lifting is handled by the FileUploadHelper class.

Listing 2-4. File Post JSP
 <%@ page language="java" import="java.sql.*" %><% com.cascadetg.ch02.FileUploadHelper     myFileHelper = new com.cascadetg.ch02.FileUploadHelper(); if(myFileHelper.doFilePost(request, application)) {     response.sendRedirect("index.jsp");     return; } %> <html> <head> <title>ch02 : File Post</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <link href="default.css" rel="stylesheet" type="text/css"> </head> <body> <form action="post.jsp" method="post"     enctype="multipart/form-data" name="form1" >     <table width="100%"  border="0" cellspacing="3" cellpadding="3">       <tr>         <td width="25%"><strong>File</strong></td>         <td><input type="file" name="file" /></td>       </tr>       <tr>         <td width="25%"><strong>Comment</strong></td>         <td><input name="Comment" type="text" size="50" maxlength="250"></td>       </tr>       <tr>         <td width="25%">&nbsp;</td>         <td><input type="submit" name="Submit" value="Upload" /></td>       </tr>     </table> </form> <p><a href="index.jsp">Return To File List </a></p> </body> </html> 

Application Logic

The FileUploadHelper (diagrammed in Figure 2-10) handles the request, storing the uploaded files in one Hashtable and the form parameters in another.

Figure 2-10. FileUploadHelper class diagram.


This application doesn't actually make use of the form parameters, but it would be easy to add access methods to get to the data if it were needed. For example, you might want to allow a user to set a comment for a file on the same page as a form upload.

Listing 2-5 shows the declaration and three main bits of information tracked when a file is uploaded. First, it's possible that more than one file may be uploaded in a single POST (hence the files hash table). Second, the parameters hash table is used to track any additional non-file form data sent by the browser. In this example, we don't actually make use of the form parameters, but it would be easy to add access methods to get to the data if it were needed. For example, you might want to allow a user to send a comment for a file on the same page as a form upload. Finally, the third instance variable, fileUpload, contains a reference to the DiskFileUpload class. This object is used to actually perform the parsing.

Listing 2-5. FileUploadHelper (part 1)
 package com.cascadetg.ch02; import java.io.File; import java.util.*; import org.apache.commons.fileupload.*; import javax.servlet.http.*; /** This class is used to handle an uploaded file. */ public class FileUploadHelper {     /**   Used to store the uploaded files just uploaded. Note that      * these are tracked by the Files class.  */     Hashtable files = new Hashtable();     /**   Used to track the additional parameters sent along with the      * file. For example, you might send a textarea form element      * along with a comment describing the file.  */     Hashtable parameters = new Hashtable();     /**   The org.apache.commons.fileupload.DiskFileUpload class used      * to actually handle the upload processing.  */     DiskFileUpload fileUpload = new DiskFileUpload(); 

Listing 2-6 shows that the doFilePost() method handles the file upload as sent by the JSP. First, some basic tests are performed to ensure that a form upload has actually been posted. Next, the fileUpload object is configuredthe maximum file size, the maximum size to store in memory before spooling to disk, and the temporary location to spool the file are set. The value shown for the repository path is based on the current web application contextdepending on the operating system and application server you are using, you may wish to set this to some other value.

The remainder of the class simply parses the incoming request and then loops through the returned response for additional information. Obviously, for a large file, the fileUpload.parseRequest(request) call may block for some time while the file is uploaded. You should consider this carefully when designing your web application.

You may notice that a simple utility method (getFileName) is provided for stripping the path information from the incoming form. As of this writing, Microsoft Internet Explorer 6 returns the full path of the uploaded file sent by the user (for example, C:\myfolder\myfile.txt), whereas Mozilla-based browsers (such as Firefox) only return the actual name of the file (myfile.txt). Similarly, some operating systems return the path with \ characters for the path separator, and others use the / character. For these and a multitude of other reasons, you'll want to test your web application thoroughly to ensure that it is compatible with a wide range of browsers.

Listing 2-6. FileUploadHelper (part 2)
     /**   Returns true if it's a file post, false if not. If it's      * false, we know that we should use the standard servlet      * methods for getting the parameters.      */     public boolean doFilePost(HttpServletRequest request,         javax.servlet.ServletContext context)     {         if (request.getContentType() == null)             return false;         if (!request.getContentType().startsWith("multipart/form-data"))         {             // Not a multi-part/form-data post, which means we             // should use standard servlet methods for getting             // parameters             return false;         }         // Maximum files size in bytes before a FileUploadException         // will be thrown         fileUpload.setSizeMax(10 * Files.MB);         // maximum size that will be stored in memory before we         // start spooling to disk         fileUpload.setSizeThreshold(4 * Files.KB);         // Set the location to spool temporary files         fileUpload.setRepositoryPath(Files.getTempPath(context));         try         {             // Use the fileUpload object (DiskFileUpload) to parse             // the request.             List fileItems = fileUpload.parseRequest(request);             // Loop through the uploaded files and parameters             Iterator i = fileItems.iterator();             while (i.hasNext())             {                 FileItem file = (FileItem)i.next();                 // MS IE reports the full path as the name, but                 // we're only interested in the actual file name.                 String fileName = file.getName();                 fileName = getFileName(fileName);                 if (file.isFormField())                 {                     // If it's a form field, we'll want to make it                     // available as a parameter.                     parameters.put(                         file.getFieldName(),                         file.getString());                 } else                 {                     // If it's not a form field, we'll assume it's                     // a file and add it both to this upload, to the                     // list of posted files, and write the file to                     // disk.                     files.put(fileName, file);                     Files.getFiles().put(fileName, file);                     File upload =                         new File(                             Files.getUploadPath(context)                                 + fileName);                     file.write(upload);                 }             }         } catch (Exception e)         {             e.printStackTrace();         }         return true;     }     // A utility method to strip the path information away from the     // submitted file. We assume that the / and the \ characters     // are the only ones returned.     public static String getFileName(String in)     {         String result = in;         if (result != null)         {             if (result.indexOf("\\") > 0)                 result =                     result.substring(                         result.lastIndexOf("\\") + 1,                         result.length());             if (result.indexOf("/") > 0)                 result =                     result.substring(                         result.lastIndexOf("/") + 1,                         result.length());         }         return result;     } } 

The final code, as modeled in Figure 2-11, acts as an in-memory record of the uploaded files. You'll notice that a few attempts are made at securityfor example, the application blocks certain extensions from being uploaded to the server in an attempt to avoid spreading viruses.

Figure 2-11. Files class diagram.


The source for the application's in-memory record, shown in Listing 2-7, deals with a number of platform-specific functions in addition to tracking the files themselves. For example, depending on your operating system, you may want to deny certain file names. A list of inappropriate file extensions for Microsoft Windows is shownyou may want to add more if you are using another operating system. Similarly, instead of the relatively permissive model shown, you may want to default to denying all files and only allow certain file types to be posted (for example, your application may only allow .zip archives, both to avoid potential security issues associated with other file types and to save space on the server).

You may notice that the temporary spool location (getBasePath) is inside the WEB-INF folder. This location is only used for random, unique temporary spool filesa user cannot overwrite a file in the WEB-INF directory in this fashion, but you may want to set this to an appropriate platform-specific temporary file location for increased security.

Uploaded files are placed in an upload directory. After a file has been uploaded, anyone can download the file by merely pointing his or her web browser to the proper location. If you want to protect the files, you may want to place them instead in a WEB-INF\upload directory, in a completely different directory outside of the web application, or even in a database. From there, a user who wanted to download one of these files would have to go through the authentication scheme you've chosen, and then your application would stream the data via a servlet as needed. Keep in mind that in that case, your web application is taking on a role (streaming static file content) that is otherwise handled by a different system (for example, Apache httpd or Tomcat's dedicated static resource handler). You will want to carefully consider the implications in terms of performance before putting this into production.

Listing 2-7. File Management
 package com.cascadetg.ch02; import java.io.File; import java.util.*; import org.apache.commons.fileupload.*; import javax.servlet.http.HttpServletRequest; /** This static class is used to manage the files posted to the  * server. */ public class Files {     public static Hashtable getFiles()     {         return uploadedFiles;     }     private static Hashtable uploadedFiles = new Hashtable();     /**     * List of blocked file extensions taken from the MS security      * note posted at...      * http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q235309      */     static public final String[] blockedFileExtensions = {         ".ade", ".adp", ".bas", ".bat", ".chm", ".cmd", ".com",         ".cpl", ".crt", ".exe", ".hlp", ".hta", ".inf", ".ins",         ".isp", ".js", ".jse", ".lnk", ".mda", ".mdb", ".mde",         ".mdz", ".msc", ".msi", ".msp", ".mst", ".pcd", ".pif",         ".reg", ".scr", ".sct", ".shs", ".url", ".vb", ".vbe",         ".vbs", ".wsc", ".wsf", ".wsh",         // Also, don't allow people to upload code!         "jsp", "php", "asp", "class", "java" };     /** Useful constants */     public static int KB = 1024;     public static int MB = 1024 * 1024;     /** Needed when working with files on disks */     public static String directorySep =         System.getProperty("file.separator");     /**     * Used to determine if a file should not be uploaded based on      * file extension. */     public boolean isBlockedFile(String fileName)     {         String lowerCaseName = fileName.toLowerCase();         for (int i = 0; i < blockedFileExtensions.length; i++)         {             if (lowerCaseName.endsWith(blockedFileExtensions[i]))                 return true;         }         return false;     }     /**     * The base path corresponds to the base directory of the      * application context's WEB-INF directory. This means that      * this directory is NOT visible to the end user.      */     public static String getBasePath(         javax.servlet.ServletContext context)     { return context.getRealPath("/") + "WEB-INF" + directorySep; }     /**     * The temporary directory used to store files while they are      * being uploaded.  */     public static String getTempPath(         javax.servlet.ServletContext context)     { return getBasePath(context) + "tmp" + directorySep; }     /**     * Gets the upload directory - used to indicate the local file      * system storage area.      */     public static String getUploadPath(         javax.servlet.ServletContext context)     { return getBasePath(context) + ".." + directorySep + "ch02"             + directorySep + "upload" + directorySep;     }     /**     * The path to the upload directory - used to retrieve a file      * from the server.      */     public static String getDownloadPath(HttpServletRequest request)     {         return request.getScheme() + "://" + request.getServerName()             + ":" + request.getServerPort() + "/" + "ch02/upload/";     }     /** Deletes the uploaded file. */     public static void deleteFile(         javax.servlet.ServletContext context,         String file)     {         FileItem myFile = (FileItem)uploadedFiles.get(file);         if (myFile == null)             return;         // Marks temporary file for deletion.         myFile.delete();         // Deletes the uploaded file         File diskFile =             new File(getUploadPath(context) + myFile.getName());         if (diskFile.exists())             diskFile.delete();         // Removes from the in-memory hash.         uploadedFiles.remove(file);     } } 



    Apache Jakarta Commons(c) Reusable Java Components
    Real World Web Services
    ISBN: N/A
    EAN: 2147483647
    Year: 2006
    Pages: 137
    Authors: Will Iverson

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net