上传至数据库的参考代码

要求:

想了解文件上传/下载/显示的具体实现方法,并有以下一些要求:
1. 将文件上传到服务器以Blob对象保存到oracle, 直接读取输入流后写进数据库,
   不要采取"上传本地文件"->"在服务器端产生文件"->"读文件流"->"写库"的方式. 要求在写进库之前,得到文件的名称,大小,在判断文件是否存在。
  
2. 用Servlet实现文件显示。

3. 从数据库读出Blob对象,生成流直接下载到客户端。不要使用
   "读取blob对象"->"在服务器目录下生成下载文件"的方式. 最好在界面上
   对文件链接可以"左键显示","右键保存下载".

4. 请不要使用jspsmartupload组件

望大虾们能给出解决的办法.





这样你需要了解浏览器端的编码方式,在传到服务器端时你才能解码。也才可以得到上传文件的相关信息。下面是别处取来的代码,一直没时间去看看,正好你可以研究一下,看是否有用。
package mshtang.fileUpload;
import java.io.*;
/**一个存放文件信息的类,包括文件的名称(String),
**字段名(String), Content-Type(String)和内容(byte[])
**还提供了一个直接将文件内容保存到一个文件的函数 void saveTo(File f)
**可以调用 类{@link ContentFactory}中的适当方法,生成该类的实例。
** @see ContentFactory
** @see ContentFactory#getFileParameter
** @see ContentFactory#getFileParameterValues
**/

public class FileHolder
{
    String contentType;
    byte[] buffer;
    String fileName;
    String parameterName;

    FileHolder(byte[] buffer, String contentType, String fileName, String parameterName)
    {
        this.buffer = buffer;
        this.contentType = contentType;
        this.fileName = fileName;
        this.parameterName = parameterName;
    }
    /**把文件的内容存到指定的文件中,
    **<b>这个方法不会检查这个文件是否可写、是否已经存在。</b>
    **@param file  目的文件
    **@throws 在 I/O 操作中被抛出的 IOException
    **/
    public void saveTo(File file) throws IOException
    {
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
        out.write(buffer);
        out.close();
    }

    /**把文件的内容存到指定的文件中,
    **<b>这个方法不会检查这个文件是否可写、是否已经存在。</b>
    **@param name 目的文件名
    **@throws 在 I/O 操作中被抛出的 IOException
    **/
    public void saveTo(String name) throws IOException
    {
        saveTo(new File(name));
    }

   /**
    **返回一个文件内容的字节数组
    **@return 一个代表文件内容的字节数组
   **/
    public byte[] getBytes()
    {
        return buffer;
    }

   /**
    **返回该文件在文件上载前在客户端的名称
    **@return 该文件在文件上载前在客户端的名称
   **/
    public String getFileName()
    {
        return fileName;
    }

   /**
    **返回该文件的 Content-Type
    **@return 该文件的 Content-Type
   **/
    public String getContentType()
    {
        return contentType;
    }

   /**
    **返回上载该文件时,Html 页面窗体中 file 控件的 name 属性
    **@return 返回上载该文件时,Html 页面窗体中 file 控件的 name 属性
   **/
    public String getParameterName()
    {
        return parameterName;
    }
}
package mshtang.fileUpload;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

/**存放报文内容的类,提供类似于 ServletRequest 中的部分 get 方法
*你必须在 html 页面的窗体(form)中指定 enctype="multipart/form-data"。
*才可以正确的使用这个类。
**/
public class ContentFactory
{
    private Hashtable values;        //存放name=value,其中value存放在另一个类中
    private Hashtable files;         //存放文件内容的。
    private ContentFactory(Hashtable values, Hashtable files)
    {
        this.values=values;
        this.files=files;
    }
    public String getParameter(String name)
    {
        Vector v = (Vector)values.get(name);
        if( v != null)
        {
          return (String)v.elementAt(0);
        }
        return null;
    }
    public Enumeration getParameterNames()
    {
        return values.keys();
    }
    public String[] getParameterValues(String name)
    {
        Vector v = (Vector)values.get(name);
        if(v != null)
        {
          String[] result = new String[v.size()];
          v.toArray(result);
          return result;
        }
        return new String[0];
    }

   /**
     *返回一个 FileHolder 实例,该实例包含了通过字段名为name的file控件上载的文件信息,
     *如果不存在这个字段或者提交页面时,没有选择上载的文件,则返回 null。
     * <p>如果 Html 页面中存在不止一个字段名为name的file控件,
     * 返回值等于{@link #getFileParameterValues}中的第一个元素。
     *
     * @param name:一个<code>String</code>,对应于Html页面窗体中file控件
     *的name 属性。
     *
     * @return返回:一个 FileHolder 实例,该实例包含了通过字段名为 name 的 file 控件上载的文件信息,
     *如果不存在这个字段或者提交页面是,没有选择上载的文件,则返回 null。
     *
     * @see   #getFileParameterValues
     *
     */
    public FileHolder getFileParameter(String name)
    {
        Vector v = (Vector)files.get(name);
        if(v != null)
        {
          return (FileHolder)v.elementAt(0);
        }
        return null;
    }
    /**
     * 返回一个 由 String 对象构成的 Enumeration ,包含了 Html 页面
     *窗体中所有 file 控件的 name 属性。
     *如果窗体中没有 file 控件,则返回一个空的 Enumeration
     * @return       返回一个 由 String 对象构成的 Enumeration ,包含了 Html 页面
     *窗体中所有 file 控件的 name 属性。
     *如果窗体中没有 file 控件,则返回一个空的 Enumeration
     */
    public Enumeration getFileParameterNames()
    {
        return files.keys();
    }
   /**
     *返回一个 FileHolder 数组,该数组包含了所有通过字段名为 name 的 file 控件上载的文件信息,
     *如果不存在这个字段或者提交页面时,没有选择任何上载的文件,则返回一个 零元素的数组(不是 null )。
     * @param name  一个 <code>String</code> ,对应于 Html 页面窗体中 file 控件
     *的name 属性。
     *
     * @return  返回一个 FileHolder 数组,该数组包含了所有通过字段名为 name 的 file 控件上载的文件信息,
     *如果不存在这个字段或者提交页面时,没有选择任何上载的文件,则返回一个 零元素的数组(不是 null )。
     *
     * @see   #getFileParameter
     */
    public FileHolder[] getFileParameterValues(String name)
    {
        Vector v=(Vector)files.get(name);
        if(v!=null)
        {
            FileHolder[] result=new FileHolder[v.size()];
            v.toArray(result);
            return result;
        }
        return new FileHolder[0];
    }
    //------------->Factory 部分
    /**
    **返回根据当前请求生成的一个 ContentFactory 实例
    **@param request 提交的请求
    **@return 返回根据当前请求生成的一个 ContentFactory 实例,如果 request
    数据包的内容不是以 mutilpart/form-data 型编码,则返回 null。
    **@throws ContentFactoryException 当提交的数据和文件太大时抛出,
    **根据 Content-Length 判断,默认的许可值为 1024* 1024。
    **/
    public static ContentFactory getContentFactory(HttpServletRequest request) throws ContentFactoryException,IOException
    {
        // default maxLength is 1MB.
        return getContentFactory(request, 1024*1024);
    }
        /**
    **返回根据当前请求生成的一个 ContentFactory 实例
    **@param request 提交的请求
    **@param maxLength 数据包的最大长度,默认为1024*1024
    **@return 返回根据当前请求生成的一个 ContentFactory 实例,如果 request
    数据包的内容不是以 mutilpart/form-data 型编码,则返回 null。
    **@throws ContentFactoryException 当提交的数据和文件太大时抛出,
    **根据 Content-Length 判断,默认的许可值为 1024* 1024。
    **/
    public static ContentFactory getContentFactory(HttpServletRequest request, int maxLength) throws ContentFactoryException, IOException
    {
      Hashtable values = new Hashtable();
      Hashtable files = new Hashtable();
      String contentType = request.getContentType();
      int contentLength = request.getContentLength();
      if (contentLength > maxLength)
      {
        ContentFactoryException e=new ContentFactoryException("上传数据太多,请不要选择太大的文件");
        throw e;
      }
      if(contentType == null || !contentType.startsWith("multipart/form-data"))
      {
        return null;
      }
//get out the boudary from content-type
      int start = contentType.indexOf("boundary=");
//这里应该
      int boundaryLen = new String("boundary=").length();
      String boundary = contentType.substring(start + boundaryLen);
      boundary = "--" + boundary;
//用字节表示,以免 String  和 byte 数组的长度不一致
      boundaryLen = bytesLen(boundary);
//把request 中的数据读入一个byte数组
      byte buffer[] = new byte[contentLength];
      int once = 0;
      int total = 0;
      DataInputStream in = new DataInputStream(request.getInputStream());
      while((total < contentLength) && (once >= 0))
      {
        once = in.read(buffer, total, contentLength);
        total += once;
      }
//对buffer中的数据进行拆分
      int pos1 = 0;                  //pos1 记录 在buffer 中下一个 boundary 的位置
//pos0,pos1 用于 subBytes 的两个参数
      int pos0 = byteIndexOf(buffer, boundary, 0);//pos0 记录 boundary 的第一个字节在buffer 中的位置
      do
      {
        pos0 += boundaryLen;                                 //记录boundary后面第一个字节的下标
        pos1 = byteIndexOf(buffer, boundary, pos0);
        if(pos1==-1)
        {
          break;
        }//
        pos0 += 2;//考虑到boundary后面的 \r\n
        parse(subBytes(buffer, pos0, pos1-2), values, files);      //考虑到boundary后面的\r\n
        pos0=pos1;
      }while(true);
      return new ContentFactory(values,files);
    }
private static void parse(byte[] buffer, Hashtable values, Hashtable files)
    {
            /* this is a smiple to parse
            [boundary]
            Content-Disposition: form-data; name="file3"; filename="C:\Autoexec.bat"
            Content-Type: application/octet-stream

            @echo off
            prompt $d $t [ $p ]$_$$

            [boundary]
            Content-Disposition: form-data; name="Submit"

            Submit
            [boundary]
            */
        String[] tokens={"name=\"","\"; filename=\"", "\"\r\n","Content-Type: ","\r\n\r\n"};
           //                          0           1                               2          3                         4
        int[] position=new int[tokens.length];

        for (int i=0;i<tokens.length ;i++ )
        {
            position[i]=byteIndexOf(buffer,tokens[i],0);
        }
        if (position[1]>0 && position[1]<position[2])
        {
            //包含tokens 中的第二个元素,说明是个文件数据段
            //1.得到字段名
            String name =subBytesString(buffer,position[0]+bytesLen(tokens[0]),position[1]);
            //2.得到文件名
            String file= subBytesString(buffer,position[1]+bytesLen(tokens[1]),position[2]);
            if (file.equals("")) return;
            file=new File(file).getName();     //this is the way to get the name from a path string
            //3.得到 Content-Type
            String contentType=subBytesString(buffer,position[3]+bytesLen(tokens[3]),position[4]);
           //4.得到文件内容
            byte[] b=subBytes(buffer,position[4]+bytesLen(tokens[4]),buffer.length);
            FileHolder f=new FileHolder(b,contentType,file,name);
            Vector v=(Vector)files.get(name);
            if (v==null)
            {
                v=new Vector();
            }
            if (!v.contains(f))
            {
                v.add(f);
            }
            files.put(name,v);
            //同时将 name 属性和 file 属性作为普通字段,存入values;
            v=(Vector)values.get(name);
            if (v==null)
            {
                v=new Vector();
            }
            if (!v.contains(file))
            {
                v.add(file);
            }
            values.put(name,v);
        }else
        {
//            String[] tokens={"name=\"","\"; filename=\"", "\"\r\n","Content-Type: ","\r\n\r\n"}
//             index                      0           1                               2          3                         4
            //不包含tokens 中的第二个元素,说明是个 name/value 型的数据段
            //所以没有tokens[1]和 tokens[3]
            //name 在 tokens[0] 和 tokens[2] 之间
            //value 在 tokens[4]之后
            //1.得到name
            String name =subBytesString(buffer,position[0]+bytesLen(tokens[0]),position[2]);
            String value= subBytesString(buffer,position[4]+bytesLen(tokens[4]),buffer.length);
            Vector v=(Vector)values.get(name);
            if (v==null)
            {
                v=new Vector();
            }
            if (!v.contains(value))
            {
                v.add(value);
            }
            values.put(name,v);
        }
    }
   /**字节数组中的 indexof 函数,与 String 类中的 indexOf类似
    **@para source 源字节数组
    **@para search 目标字符串
    **@para start 搜索的起始点
    **@return 如果找到,返回search的第一个字节在buffer中的下标,没有则返回-1
    **/
    private static int byteIndexOf (byte[] source,String search,int start)
    {
        return byteIndexOf(source,search.getBytes(),start);
    }

   /**字节数组中的 indexof 函数,与 String 类中的 indexOf类似
    **@para source 源字节数组
    **@para search 目标字节数组
    **@para start 搜索的起始点
    **@return 如果找到,返回search的第一个字节在buffer中的下标,没有则返回-1
    **/
    private static int byteIndexOf (byte[] source,byte[] search,int start)
    {
        int i;
        if (search.length==0)
        {
            return 0;
        }
        int max=source.length-search.length;
        if (max<0)
            return -1;
        if (start>max)
            return -1;
        if (start<0)
            start=0;
    // 在source中找到search的第一个元素
    searchForFirst:
        for (i=start;i<=max ; i++)
        {
            if (source[i]==search[0])
            {
                //找到了search中的第一个元素后,比较剩余的部分是否相等
                int k=1;
                while(k<search.length)
                {
                    if (source[k+i]!=search[k])
                    {
                        continue searchForFirst;
                    }
                    k++;
                }
                return i;
            }
        }
        return -1;
    }
    /**
    **用于从一个字节数组中提取一个字节数组
    **类似于 String 类的substring()
    **/
    private static byte[] subBytes(byte[] source,int from,int end)
    {
        byte[] result=new byte[end-from];
        System.arraycopy(source,from,result,0,end-from);
        return result;
    }
    /**
    **用于从一个字节数组中提取一个字符串
    **类似于 String 类的substring()
    **/
    private static String subBytesString(byte[] source,int from,int end)
    {
        return new String(subBytes(source,from,end));
    }
    /**
    **返回字符串S转换为字节数组后的长度
    **/
    private static int bytesLen(String s)
    {
        return s.getBytes().length;
    }
}

posted on 2005-07-27 11:16  轻松逍遥子  阅读(529)  评论(0编辑  收藏  举报