guozhang

Java Beginner

JspSmartUpload component

   JspSmartUpload component, which could be derived from http://www.jspsmart.com (the Official Website), is an utility for files’ upload and download from the Java Server Pages or servlets.

 

²        Classes

JspSmartUpload component contains merely five classes: File, Files, Request, SmartUpload and SmartUploadException as well. All classes reside in the same package called com.jspsmart.upload.

1.       com.jspsmart.upload.File

This class directly inherits from java.lang.Object, the ancestor of all classes in Java. It’s an abstract representation of an upload file sent by clients. Although this class is not marked abstract, you cannot explicitly instantiate it.

      APIs of com.jspsmart.upload.File comes next:

Method Summary(copy from http://aboutjsp.com)

void fileToField(java.sql.ResultSet rs, java.lang.String columnName)

          Save the file in a field of a database.

byte getBinaryData(int index)

          Returns the byte corresponding to the table index containing the transmitted data.

String getContentDisp()

          Returns the content disposition.

String getContentString()

          Returns the full content.

String getContentType()

          Returns the content type, which can be retrieved by using getTypeMIME() and getSubTypeMIME() introduced later.

String getFieldName()

          Returns the field's name of the HTML form.

String getFileExt()

          Returns the file's extension.

String getFileName()

          Returns the file's name.

String getFilePathName()

          Returns the full path of the file.

int getSize()

          Returns the file's size.

String getSubTypeMIME()

          Returns the sub type mime.

String getTypeMIME()

          Returns the MIME Type.

boolean isMissing()

          Test if a file is present.

void saveAs(String destFilePathName)

          Save the file to the specified destination.

void saveAs(String destFilePathName, int optionSaveAs)

          Save the file to the specified destination.

 

From the APIs listed above, it’s rather straightforward to see that JspSmartUpload component provides not only the ability to store those uploaded files as files on disk of the web server but also that as a filed of a table in databases.

In addition, File class supplies 3 constants, which serve as options of SaveAs function. These constants are technically exploited by the saveAs method, the last one in the table above.

 

Field Summary(copy from http://aboutjsp.com)

static int SAVEAS_PHYSICAL

         Using this option, those uploaded files will be saved right beneath the root directory of the OS, say C:/ .

static int SAVEAS_VIRTUAL

         Using this option, those uploaded files will be saved in the context directory of the web application, say

 <WEB_SERVER_DIR>/webapps/MyWebApp/ .

static int SAVEAS_AUTO

        This option leaves directory selection to the component itself. The selection rule is like this: If the directory specified by the destFilePath(the 1st argument) exists, SAVEAS_VIRTUAL will be applied. Otherwise, SAVEAS_PHYSICAL will be put into use.

 

2.     com.jspsmart.upload.Files

Files class is nothing but a collection of Files. You cannot directly instantiate it, neither:

Method Summary(copy from http://aboutjsp.com)

java.util.Collection getCollection()

          Returns a Collection to browse the files.

int getCount()

Returns the number of files in the collection.

java.util.Enumeration getEnumeration()

          Returns an Enumeration to browse the files.

com.jspsmart.upload.File getFile(int index)

          Returns the file object corresponding to the index.

long getSize()

          Returns the size of all files of the collection.

 

3.     com.jspsmart.upload.Request

Request is the equivalent of ServletRequest class. It, however, exposes only 3 methods of ServletRequest:

Method Summary(copy from http://aboutjsp.com)

java.lang.String getParameter(java.lang.String name)

Returns the value of a request parameter as a String, or null if the parameter does not exist.

java.util.Enumeration getParameterNames()

 Returns an Enumeration of String objects containing the names of the parameters contained in this request.

java.lang.String[] getParameterValues(java.lang.String name)

Returns an array of String objects containing all of the values the given request parameter has, or null if the parameter does not exist.

 

You’re incorrect if you think of this class as a subclass of ServletRquest. As a matter of fact, this class directly inherits from java.lang.Object class.

4.     com.jspsmart.upload.SmartUpload

SmartUpload class, performing files upload and download, is definitely in the core of JspSmartUpload component.

SmartUpload class provides one no-arguments constructor:

Constructor Summary(copy from http://aboutjsp.com)

SmartUpload()

        Creates an new SmartUpload instance.

 

Its methods are:

Method Summary(copy from http://aboutjsp.com)

void downloadField(java.sql.ResultSet rs, java.lang.String columnName, java.lang.String contentType, java.lang.String destFileName)

          Downloads a field from a database's table.

void downloadFile(java.lang.String sourceFilePathName)

          Downloads a file.

void downloadFile(String sourceFilePathName, java.lang.String contentType)

          Downloads a file.

void downloadFile(String sourceFilePathName, java.lang.String contentType, java.lang.String destFileName)

          Downloads a file

void downloadFile(String sourceFilePathName, java.lang.String contentType, java.lang.String destFileName, int blockSize)

          Downloads a file.

void fieldToFile(java.sql.ResultSet rs, String columnName,

                                                   String destFilePathName)

    Save a field from a database's table to a file.

byte getBinaryData(int index)

         Returns the byte corresponding to the table index containing the transmitted data.

Files getFiles()

          Returns the collection of the uploaded files.

Request getRequest()

          Returns the request object.

int getSize()

          Returns the total size of data uploaded.

void init(javax.servlet.ServletConfig config)

          Deprecated. Since Version 2.1 of jspSmartUpload, use initialize(javax.servlet.ServletConfig, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) instead.

void initialize(javax.servlet.jsp.PageContext pageContext)

          Initialize the object with implicits objects.

void initialize(javax.servlet.ServletConfig config,

               javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)

          Initialize the object with implicits objects.

void initialize(javax.servlet.ServletContext application,

 javax.servlet.http.HttpSession session, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, javax.servlet.jsp.JspWriter out)

Deprecated. Use initialize(javax.servlet.ServletConfig,

javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) instead.

int save(java.lang.String destPathName)

          Saves all the uploaded files in the specified destination. The return value is the count of files that are successfully saved.

int save(java.lang.String destPathName, int option)

          Saves all the uploaded files in the specified destination. The return value indicates the count of files that are successfully saved.

void service(javax.servlet.http.HttpServletRequest request,

 javax.servlet.http.HttpServletResponse response) Deprecated. Since Version 2.1 of jspSmartUpload, use

initialize(javax.servlet.ServletConfig, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) instead.

void setAllowedFilesList(java.lang.String allowedFilesList)

          Set the list of allowed files.

void setContentDisposition(java.lang.String contentDisposition)

          Sets the Content Disposition.

void setDeniedFilesList(java.lang.String deniedFilesList)

          Set the list of denied files.

void setDenyPhysicalPath(boolean deny)

          Sets if the component deny physical path.

void setForcePhysicalPath(boolean force)

          Sets if the component force physical path.

void setMaxFileSize(long maxFileSize)

          Sets the maximum file size. The file size is measured in bit.

void setTotalMaxFileSize(long totalMaxFileSize)

          Sets the total maximum file size. The file size is measured in bit.

void upload()

         Uploads data from the form.

void uploadInFile(java.lang.String destFilePathName)

          The uploadInFile method creates a new file with all data of the POST form.

 

SmartUpload class exposes 3 options as parameters of save(), which are used for designating the physical location where the uploaded file will be stored:

Field Summary(copy from http://aboutjsp.com)

static int SAVE_AUTO

static int SAVE_PHYSICAL

static int SAVE_VIRTUAL

They have the same meaning as SAVEAS_AUTO, SAVEAS_PHYSICAL, SAVEAS_VIRTUAL respectively.

 

5.     com.jspsmart.upload.SmartUploadException

As most of exceptions, SmartUploadException extends from java.lang.Exception class. Once exception occurs during the upload/download, this exception will be generated and thrown.

 

²        Examples

The following applications demonstrate the usage of JspSmartUpload component, including:

¨         Dump information of uploaded files

¨         Upload a file and save it on the disk of the web server

¨         Download a file from the disk of the web server

¨         Upload a file and save it into back-up database

¨         Download a file from database

 

1.     Dump information of uploaded files

This application shows how to retrieve information of a uploaded file. The 1st page is for file selection:

1.bmp 

        Once the users choose a file(or not), they’re supposed to click the Upload button. The info of the chosen file is listed:

2.bmp
3.bmp

 

Implementation:

1). Create the file selection page with your tools(I did it with Dreamweaver)

files.jsp

<%@ page contentType="text/html; charset=gb2312" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<link rel="stylesheet" href="../css/css.css">

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>Select a local file and hit Upload</title>

<style type="text/css">

<!--

.style1 {

      font-size: 18px;

      font-weight: bold;

}

-->

</style>

</head>

<body>

<center class="style1">

  Select a local file and hit Upload button.

</center>

<form action="fileInfoDumper.jsp"  name="fileForm"

 enctype="multipart/form-data" method="post" >

  <center>

    <input type="file" name="MyUploadFile" />

    <br>

    <br>

    <input type="submit" name="Submit" value="Upload" />

  </center>

</form>  

</body>

</html>

 

These jsp codes aren’t obscure at all. Two points, however, deserve to be emphasized: the enctype attribute of the form should be set as multipart/form-data and the method attribute should be set to be POST; otherwise, you will get:

4.bmp
   2). Information retrieval page

fileInfoDumper.jsp

<%@ page contentType="text/html; charset=gb2312" errorPage="" %>

<%@ page import="com.jspsmart.upload.*" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<link rel="stylesheet" href="../css/css.css">

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>Dump information of uploaded files</title>

<style type="text/css">

<!--

.style1 {

      font-size: 18px;

      font-weight: bold;

}

-->

</style>

</head>

<body>

<%!

   //2 helper functions

   private static String trimString(String original, int len){

      if(original == null)

            return null;

      return (original.length() > len)?(original.substring(0, len - 3) + "..."):original;

   }

  

   private static String replaceEmptyString(String original,

String replacement){

       if(original == null || original.length() == 0)

             return replacement;

         return original;

   }

%>

<table width="1021" border="1">

  <caption>

  <span class="style1">  Files' information  </span>

  </caption>

  <tr align="center" bgcolor="#CC9900">

    <td width="44">name</td>

    <td width="53">extension</td>

    <td width="78">path</td>

    <td width="41">size</td>

      <td width="109">content type</td>

      <td width="88">content string</td>

      <td width="171">content disposition</td>

      <td width="73">field name</td>

      <td width="120">isMissing</td>

  </tr>

  <tr align="center">

    <%

        SmartUpload su = new SmartUpload();

        su.initialize(pageContext);

        su.upload();

        java.util.Iterator itor =  su.getFiles().getCollection().iterator();

        if(itor.hasNext())

           while(itor.hasNext()){

            File uploadFile = (File)itor.next();

      %>

    <td><%= replaceEmptyString(uploadFile.getFileName(),"---") %></td>

        <td><%= replaceEmptyString(uploadFile.getFileExt(),"---") %></td>

        <td><%= replaceEmptyString(uploadFile.getFilePathName(), "---") %></td>

        <td><%= uploadFile.getSize() %> b</td>

        <td><%= uploadFile.getContentType() %></td>

        <td><%= trimString(uploadFile.getContentString(), 10) %></td>

        <td><%= replaceEmptyString(uploadFile.getContentDisp(), "---") %></td>

        <td><%= uploadFile.getFieldName() %></td>

        <td><%= uploadFile.isMissing() %></td>

      <%

         }

       else{  //no file found

      %>

         <td width="180" colspan="9" align="center">No file detected</td>

      <%

       }

      %>

  </tr>

</table>

</body>

</html>

 

Two functions defined beforehand serves as helpers. trimString() makes the length of the given string be at most len length and replaceEmptyString() will replace null o zero-length string with the specified string(the second parameter).

The key point is the usage of SmartUpload class. At first, an instance of SmartUpload class is created. Then, it is initialized with its initialize() and upload() is called. This is a common way to get upload files. The codes next are quite simple to be understood, just invoking File’s member functions and display them.

Tip: How to judge whether the clients have chosen a valid local file

     Not every client is obedient. Clients may commit mistakes or some one does deliberately. The chief problem is that how can we(developers) distinguish bad inputs from valid ones. For the file upload operation, the problem becomes how can developers see whether clients have chosen valid files or not. Experiments can speak louder than assumptions.

     As a matter of fact, there are only 2 kinds of bad inputs here. One is that clients input nothing, the other is that clients input a never-existing file path. Under the first situation, File class’ isMissing() will return true because nothing is supplied and getSize() will return zero. In the other one, the getSize() of File class will result in zero while isMissing() will return true. Yes! The getSize() method is the watershed. If getSize() returns zero, you can declare that the inputted file path is absolutely invalid. Otherwise, the input is OK.

 

2.     Upload a file and save it on the disk of the web server

This application will show how to save a file on the disk at a specified directory. If the upload operation succeeds, the page will be like this:

5.bmp
 

Implementation:

I.       File selection page

       I intend to reuse the files.jsp used in the first application with a little alternation: change the action attribute of the form to be ‘singleFileUpload.jsp’.

II.     File upload page

The JSP code is listed here:

singleFileUpload.jsp

<%@ page contentType="text/html; charset=gb2312"

                                         import="com.jspsmart.upload.*" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<link rel="stylesheet" href="../css/css.css">

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>Single file upload</title>

<style type="text/css">

<!--

.style1 {

      font-size: 18px;

      font-weight: bold;

}

.style2 {

      color: #3300FF;

      font-weight: bold;

}

.style3 {

      color: #FF0000;

      font-weight: bold;

}

.style4 {

      color: #00FF00;

      font-weight: bold;

}

.style6 {

      font-size: 18;

      font-weight: bold;

      color: #FF0000;

}

-->

</style>

</head>

<body>

   <%

        SmartUpload su = new SmartUpload();

        su.initialize(pageContext);

        su.upload();

%>

   <span class="style1">The total size of the upload files is:</span> <span class="style2"><%= su.getSize() %></span> <span class="style1">bits.</span><br>

   <span class="style6">

   <%--

  save those files into tmp directory, the subdirectory of web application’s

  root directory

--%>

   <%= su.save("/temp") %> file(s) saved successfully.

   <%   

        java.util.Iterator itor =  su.getFiles().getCollection().iterator();

        if(itor.hasNext()){

      %>

   </span>

   <ul>

      <%

         //demonstrating File’s saveAs method

           while(itor.hasNext()){

                File uploadFile = (File)itor.next();

                  try{

                     if(uploadFile.getSize() != 0){

                    uploadFile.saveAs("/temp/" + uploadFile.getFileName(), File.SAVEAS_VIRTUAL);

      %>

                 <li class="style4">File <%= uploadFile.getFileName() %> is saved successfully</li>

      <%          }else{

      %>

                <li class="style3"><%= uploadFile.isMissing()? "No file is supplied." :uploadFile.getFileName()+"is zero size." %></li>  

      <%

      }

                }catch(Exception e){

      %>

                 <li class="style3">Failed to save file <%= uploadFile.getFileName() %></li>  

      <%     

                  }

            }

       %>

</ul>

       <%}

  %>

</body>

</html>

 

There are quite few changes between fileInfoDumper.jsp and singleFileUpload.jsp. In fact, uploading a file and saving it as a disk file is easy. Once you have a valid instance of File object, invoking save() will do:

su.save(“/tmp”, SmartUpload.SAVE_VIRTUAL);

This statement will save all the uploaded files into tmp directory, relative to the root directory of the web application.

There is one more thing to address: you are supposed to create the directory yourself, by hand or programmatically. That’s, if the tmp directory does not exist, you should create it and then the code will work fine. Otherwise, the save operation won’t work although the page will display it as successfully done.

The later scriplet demonstrates another way to store uploaded files, using File’s saveAs(). You should check whether the inputted file is valid or not before you save it. Or a zero-length file with the same file name will be stored. As mentioned before, the above JSP page use getSize() of File object to judge its validity. Only those files whose length is not zero can be uploaded and saved in the subdirectory(named temp) right beneath the web application’s root directory.

Still, you are supposed to create the directory where the uploaded files will be saved as if it does not exist, otherwise saveAs() method will throws an exception:

java.lang.IllegalArgumentException: This path does not exist (1135).

com.jspsmart.upload.SmartUpload.getPhysicalPath(SmartUpload.java:1089)

com.jspsmart.upload.File.saveAs(File.java:91)

 

Don’t be confused by the getSize() method of SmartUpload, which does not indicate the real size of the uploaded files. Even no file is uploade, getSize() won’t return zero:

6.bmp
Variation

I have to admit that this application is too simple and impractical. In reality, some other non-file fields may be posted as well or several files, say email attachments need uploading or others. I’ll take some variation for example.

I. posting non-file fields

First of all, a form with non-file fields should be prepared:

multipleFields.jsp

<%@ page contentType="text/html; charset=gb2312" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<link rel="stylesheet" href="../css/css.css">

<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />

<title>Multiple Fileds</title>

</head>

<body>

<form action="multipleFieldsHandler.jsp" name="uploadForm" method="post" enctype="multipart/form-data" >

   <table  border="0" align="center" cellpadding="2" cellspacing="2" bordercolor="#0000FF">

     <!--DWLayoutTable-->

        <tr>

          <td width="61" height="26" >User name</td>

          <td colspan="2" ><input  name="UserName" type="text" size="40" /></td>

        </tr>

     

        <tr>

          <td height="26" >Password</td>

          <td colspan="2" ><input name="Password" type="password" size="44" /></td>

        </tr>

 

        <tr>

          <td height="28" >File</td>

          <td colspan="2" ><input name="UploadFile" type="file" size="30" /></td>

        </tr>

 

        <tr>

          <td height="28">&nbsp;</td>

          <td width="54">&nbsp;</td>

          <td width="161" valign="top"><input type="submit" value="Submit" /></td>

        </tr>

  </table>

</form>

</body>

</html>

Its effect lies below:
7.bmp

Now comes the handler page:

multipleFieldsHandler.jsp

<%@ page contentType="text/html; charset=gb2312" import="com.jspsmart.upload.*" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<link rel="stylesheet" href="../css/css.css">

<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />

<title>Multiple Field Handler</title>

<style type="text/css">

<!--

.style1 {

      font-size: 18px;

      color: #0000FF;

      font-weight: bold;

}

.style2 {color: #FF6633}

.style3 {

      font-size: 18px;

      color: #006633;

}

-->

</style>

</head>

<body>

  <%

     SmartUpload su = new SmartUpload();

       su.initialize(pageContext);

       su.upload();

  %>

  <span class="style1">      Retrieve non-file fields' value</span><br>

      <ul class="style2">

  <%

     Request suRequest = su.getRequest();

       for(java.util.Enumeration names = suRequest.getParameterNames(); names.hasMoreElements();){

             String name = (String)names.nextElement();

             String[] values = suRequest.getParameterValues(name);

              for(String value : values){

  %>

      <li><%= name %> : <%= value %></li>

  <%       } 

       }

  %>

      </ul>

  <span class="style1">Retrieve file information</span><br>

  <ul class="style3">

  <%

      java.util.Iterator itor =  su.getFiles().getCollection().iterator();

        if(itor.hasNext())

           while(itor.hasNext()){

               File uploadFile = (File)itor.next();

  %>

      <li><%= uploadFile.getFileName() %> is received </li>

  <%

            uploadFile.saveAs("/tmp/" + uploadFile.getFileName(), File.SAVEAS_VIRTUAL);

  %>

  and saved.

  <%        

            }

  %>     

  </ul>

</body>

</html>

 

As you can see, values of non-file fields could be retrieved by com.jspsmart.upload.Request object, which generated with getRequest() of SmartUpload class. You can treat com.jspsmart.upload.Request instances as javax.servlet.Request instances. Nevertheless, you should have a clear knowledge of that they are not the same and no inheritance exists between them.

The following figure shows what are retrieved:

8.bmp
II. uploading multiple files

    Uploading multiple files is as easy and simple as doing single one. The JSP file singleFileUpload.jsp is enough for handling uploading multiple files because it has taken multiple files into consideration.

3.     Download a file from the disk of the web server

Invoking SmartUpload component’s downloadFile() is enough. For example,

su.downloadFile(“/tmp/background.jpg”);

will download background.jpg in the tmp directory under the root directory of the web application.

If the downloaded file can be opened by the browser, say the background.jpg, the browser will open it automatically. Passing null into setContentDisposition() and invoking it before you call downloadFile() can avoid it. setContentDispostion(null) will make the browser add ‘attachment’ attribute automatically:

 

<%

  SmartUpload su = new SmartUpload();

  su.initialize(pageContext);

  su.setContentDisposition(null);

  su.downloadFile("/tmp/bgall.jpg");

%>

 

If you comment the code in bold, when the code is executed, the picture will be opened by the browser:

9.bmp 

By applying setContentDisposition(null), a file download dialog will pop up:

10.bmp
4.    
Upload a file and save it into back-up database

Uploading a file and saving it into back-up database sounds quite cool and a little fussy. Fortunately, SmartUpload component gives us this capability. The fileToField() of com.jspsmart.upload.File class is specialized for this purpose. Let’s do it step by step.

1). Create a table in database (take MS SQL Server 2000 for example)

    I’m going to create a table with following columns:

    a). fileId        the id of the file

    b). fileName    the name of the file

    c). fileSize      the size of the file

d). fileContent   the content of the file

 

    The SQL script is listed here:

Table creation script

CREATE TABLE [files] (

      [fileId] [int] IDENTITY (1, 1) NOT NULL ,

      [fileName] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,

      [fileSize] [int] NOT NULL CONSTRAINT [DF_FileTable_fileSize] DEFAULT (0),

      [fileContent] [image] NULL ,

      CONSTRAINT [PK_FileTable] PRIMARY KEY  CLUSTERED

      (

           [fileId]

      )  ON [PRIMARY]

) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

 

In MS SQL Enterprise Manager, the table looks like this:

11.bmp
2). Create the upload page

 

 

<%@ page contentType="text/html; charset=gb2312" import="java.sql.*, javax.naming.*, com.jspsmart.upload.*" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<link rel="stylesheet" href="../css/css.css">

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>Save file into database</title>

<style type="text/css">

<!--

.style1 {

      color: #0000FF;

      font-weight: bold;

}

.style2 {

      color: #FF0000;

      font-weight: bold;

}

-->

</style>

</head>

<body>

   <span class="style1">

   <%

      Connection conn = null;

        try{

            SmartUpload su = new SmartUpload();

            su.initialize(pageContext);

             su.upload();

            

             java.util.Iterator itor =  su.getFiles().getCollection().iterator();

            if(itor.hasNext()){

                  //establish DB connection

InitialContext ctx = new InitialContext();

                   javax.sql.DataSource connectionPool = (javax.sql.DataSource) ctx.lookup("java:comp/env/mssqlDataSource");

                   conn = connectionPool.getConnection();

               //create an updatable statement

Statement stmt = conn.createStatement(

ResultSet.TYPE_FORWARD_ONLY,

ResultSet.CONCUR_UPDATABLE); 

                   while(itor.hasNext()){

                       File file = (File)itor.next();

                        if(file.getSize() == 0)  //invalid file given

                            continue;  //process next file

                        //retrieve the newest fileId

ResultSet rs = stmt.executeQuery("insert into files(fileName, fileSize, fileContent) values (null, 0, null) select @@IDENTITY as 'fileId'");

                        int fileId = -1;

                        if(rs.next())

                             fileId = rs.getInt("fileId");

                        rs.close();

                       

            rs = stmt.executeQuery("select * from files where fileId=" + fileId);

                        if(rs.next()){

                             rs.updateString("fileName", file.getFileName());

                             rs.updateInt("fileSize", file.getSize());

                             file.fileToField(rs, "fileContent");

                             

rs.updateRow();  //remember to call updateRow

                        }

                        rs.close();

                        %>

                        File <%= file.getFileName() %> has been saved into database.</span><br>

                        <span class="style2">

                        <%

                   }

stmt.close();

             }else{

             %>

             No file is provided.

             <%

             }

        }catch(Exception ex){

            ex.printStackTrace();

        }finally{

            if(conn != null)

               conn.close();  //close the connection

        }

   %>

</span>

</body>

</html>

 

The core codes are marked as bold. Retrieving the fileId is a little smart. But that is a basis that almost every developer knows. Once the fileId is extracted, the code derives a ResultSet object related to that fileId. Then, updating the ResultSet object is performed. That’s all you need do so as to uploading a file into database. You can check whether the files have already saved into database or not. If everything goes fine, the files will be saved:12.bmp

Not everything will fit you.

   I have to admit that I have lied to you. The contents in the database are not always correct. If you’re trying to read information out from the database, you’ll find that some files cannot be recovered.

   Why? You have no fault at all. It’s the File class that has some bugsL If you have the source code, you’ll understand more clearly. The source code of the fileToField() is as follows:

public void fileToField(ResultSet rs, String columnName)

        throws SQLException, SmartUploadException, IOException, ServletException{

    long numBlocks = 0L;

    int blockSize = 0x10000;

    int leftOver = 0;

    int pos = 0;

    if(rs == null)

       throw new IllegalArgumentException("The RecordSet cannot be null (1145).");

    if(columnName == null)

       throw new IllegalArgumentException("The columnName cannot be null (1150).");

    if(columnName.length() == 0)

      throw new IllegalArgumentException("The columnName cannot be empty (1155).");

      numBlocks = BigInteger.valueOf(m_size).divide(BigInteger.valueOf(blockSize))

.longValue();

      leftOver = BigInteger.valueOf(m_size).mod(BigInteger.valueOf(blockSize))

.intValue();

      try {

            for(int i = 1; (long)i < numBlocks; i++){

          rs.updateBinaryStream(columnName,

new ByteArrayInputStream(m_parent.m_binArray, pos, blockSize), blockSize);

               pos = i * blockSize;    

          }

 

         if(leftOver > 0)

           rs.updateBinaryStream(columnName,

new ByteArrayInputStream(m_parent.m_binArray, pos, leftOver), leftOver);

       

        }

        catch(SQLException e){

            byte binByte2[] = new byte[m_size];

            System.arraycopy(m_parent.m_binArray, m_startData, binByte2, 0, m_size);

            rs.updateBytes(columnName, binByte2);

        }

        catch(Exception e){

            throw new SmartUploadException("Unable to save file in the DataBase (1130).");

        }

    }

 

Look at the snippet with yellow background color. ResultSet’s updateXXX method does not support ‘append mode’. That is, the content of the corresponding column will contain values the last call of updateXXX method designates. For example,

rs.updateString(1, “abc”);

rs.updateString(1, “def”);

   The first column won’t have value ‘abcdef’. In fact, its content is ‘def’. ‘abc’ is overwritten and gone.

Therefore, the value of the content is determined by the last invocation. If your file’s length is less than 0x10000 (blockSize), your file will be fully saved into database. Otherwise, your file’s content is not integrated and hence you cannot recover it from the database.  

Fix it

Having an idea of what’s going on, there is always a way to deal with it. Yes, you have to modify the source code. I changed mine as follows:

public void fileToField(ResultSet rs, String columnName)

        throws SQLException, SmartUploadException, IOException, ServletException{

    if(rs == null)

        throw new IllegalArgumentException("The RecordSet cannot be null (1145).");

    if(columnName == null)

        throw new IllegalArgumentException("The columnName cannot be null (1150).");

    if(columnName.length() == 0)

      throw new IllegalArgumentException("The columnName cannot be empty (1155).");

    try {

          rs.updateBinaryStream(columnName,

new ByteArrayInputStream(m_parent.m_binArray, m_startData, m_size),

 m_size);

    } catch(SQLException e){

        rs.updateBytes(columnName, getContent());

    } catch(Exception e){

        throw new SmartUploadException("Unable to save file in the DataBase (1130).");

    }

}

 

//One of my friends advises that this class should provide a method to see its whole

// content conveniently. I agreeJ

public byte[] getContent(){

byte[] content = new byte[m_size];

System.arraycopy(m_parent.m_binArray, m_startData, content, 0, m_size);

return content;

}

 

With this method, you now can upload your files correctly. Have fun!

 

5.     Download a file from database

Let’s continue with file downloading.

    1). Create the page listing all the files in the database

This isn’t that hard, is it?

File listing page

<%@ page contentType="text/html; charset=gb2312" import="java.sql.*, javax.naming.*" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<link rel="stylesheet" href="../css/css.css">

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>File list</title>

 

<style type="text/css">

<!--

.style1 {

      font-size: 18px;

      font-weight: bold;

      color: #0000FF;

}

-->

</style>

</head>

 

<body>

  <table width="368" border="1" align="center">

    <caption>

    <span class="style1">    Files in the database    </span>

    </caption>

    <tr align="center">

      <td width="95">Name</td>

      <td width="133">Size</td>

      <td width="118">Operation</td>

    </tr>

      <%

         InitialContext ctx = new InitialContext();

       javax.sql.DataSource connectionPool = (javax.sql.DataSource) ctx.lookup("java:comp/env/mssqlDataSource");

       Connection conn = connectionPool.getConnection();

       Statement stmt = conn.createStatement();

       ResultSet rs = stmt.executeQuery("select fileName, fileSize, fileId from files");

       while(rs.next()){

    %>

      <tr align="center">

      <td height="24"><%= rs.getString(1) %></td>

      <td><%= rs.getInt(2) %> b</td>

      <td><a href="fileDownloadFromDB.jsp?fileId=<%= rs.getInt(3)%>">DownLoad</a></td>

    </tr>

      <%      

       }

  

     rs.close();

     stmt.close();

     conn.close();               

      %>

  </table>

 

</body>

</html>

 

The outcome looks like the following:

13.bmp
2) Download the specified file

  

Downloading page

<%@ page contentType="text/html; charset=gb2312" import="java.sql.*, javax.naming.*, com.jspsmart.upload.*" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=gb2312">

<title>File download from database</title>

</head>

<body>

<%

   InitialContext ctx = new InitialContext();

   javax.sql.DataSource connectionPool = (javax.sql.DataSource) ctx.lookup("java:comp/env/mssqlDataSource");

   Connection conn = connectionPool.getConnection();

   Statement stmt = conn.createStatement();

   ResultSet rs = stmt.executeQuery("select * from files where fileId=" + request.getParameter("fileId"));

   if(rs.next()){

      SmartUpload su = new SmartUpload();

        su.initialize(pageContext);

        su.downloadField(rs, "fileContent", null, rs.getString("fileName"));

   }

  

   rs.close();

   stmt.close();

   conn.close();                  

%>

</body>

</html>

 

    It’s not necessary to explain more on the code above for it’s not obscure at all. SmartUpload’s downloadField() handles everything for us.

   

14.bmp 

 

 

 

 

    Everything seems all right. But you will see unrecognizable text if you are working with non-English language.  Luckily, someone has solved this problemJ

Coding conversion

public static String toUtf8String(String s) {

    StringBuffer sb = new StringBuffer();

    for (int i=0;i<s.length();i++) {

        char c = s.charAt(i);

        if (c >= 0 && c <= 255)

              sb.append(c);

       else {

              byte[] b = new byte[0];

              try {

                    b = Character.toString(c).getBytes("utf-8");

              } catch (Exception ex) {}

              

for (int j = 0; j < b.length; j++) {

                    int k = b[j];

                    if (k < 0)

                         k += 256;

                    sb.append("%" + Integer.toHexString(k).toUpperCase());

              }

          }

    }

   return sb.toString();

}

 

   The next step is to overwrite the downloadFile() and downloadField(), merely wrapping the file name with toUtf8String(). For instance,

m_response.setHeader("Content-Disposition", "attachment; filename=" + destFileName);

will be changed into:

m_response.setHeader("Content-Disposition", "attachment; filename=" + toUtf8String(destFileName));

 

   After doing thus, now you can see the desired effect:

 15.bmp


修改后的JspSmartUpload.jar

posted on 2005-12-20 15:18 Guo Zhang 阅读(3334) 评论(5)  编辑  收藏 所属分类: Java

评论

# re: JspSmartUpload component 2005-12-20 16:20 keller

真TMD的长,看都看不懂。  回复  更多评论   

# re: JspSmartUpload component 2005-12-20 16:23 Guo Zhang

to keller:
Hehe. You should be more patient:)   回复  更多评论   

# re: JspSmartUpload component[未登录] 2009-03-24 02:05 Owen

写得太好了~~  回复  更多评论   

# re: JspSmartUpload component[未登录] 2009-10-08 01:17 溺水的鱼

very good!  回复  更多评论   

# re: JspSmartUpload component 2011-09-09 21:47 dianalenar

i dont understand any chinese
i see u have very well explained the componnent and its functionning
i am desperately searching for jspsmart.jar file
if u have a copy could u send me via mail @
dianatodidace@yahoo.com

it would be of a great healp to me

Regards,
Diana
  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 
<2011年9月>
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

导航

统计

常用链接

留言簿(1)

随笔档案

文章分类

文章档案

收藏夹

搜索

最新随笔

最新评论

阅读排行榜

评论排行榜