package upload; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import java.util.*; /**存放报文内容的类,提供类似于 ServletRequest 中的部分 get 方法 *你必须在 html 页面的窗体(form)中指定 enctype="multipart/form-data"。 *才可以正确的使用这个类。 **@author kammi(coid@sina.com) **Mail to me
**my home

**/ public class ContentFactory { //成员变量 private Hashtable values; //存放name=value,其中value存放在另一个类中 private Hashtable files; //存放文件内容的。 private ContentFactory(Hashtable values,Hashtable files) { this.values=values; this.files=files; } /** * Returns the value of a request parameter as a String, * or null if the parameter does not exist. * parameters are contained in the posted form data. * *

* This method can only be used with a from encoding by multipart/form-data *To deal with an normal encoding form, you may use the same method declared *in interface ServletRequest. * *

You should only use this method when you are sure the * parameter has only one value. If the parameter might have * more than one value, use {@link #getParameterValues}. * *

If you use this method with a multivalued * parameter, the value returned is equal to the first value * in the array returned by getParameterValues. * * @param name a String specifying the * name of the parameter * * @return a String representing the * single value of the parameter, *if the input type is file, then the filename will returned. * @see #getParameterValues * */ public String getParameter(String name) { Vector v=(Vector)values.get(name); if(v!=null) return (String)v.elementAt(0); return null; } /** * * Returns an Enumeration of String * objects containing the names of the parameters contained * in this request. If the request has * no parameters, the method returns an * empty Enumeration. * *

* This method can only be used with a from encoding by multipart/form-data * To deal with an normal encoding form, you may use the same method declared *in interface ServletRequest. * * @return an Enumeration of String * objects, each String containing * the name of a request parameter; or an * empty Enumeration if the * request has no parameters * */ public Enumeration getParameterNames() { return values.keys(); } /** * Returns an array of String objects containing * all of the values the given request parameter has, or * null if the parameter does not exist. * *

* This method can only be used with a from encoding by multipart/form-data * To deal with an normal encoding form, you may use the same method declared *in interface ServletRequest. * *

If the parameter has a single value, the array has a length * of 1. * * @param name a String containing the name of * the parameter whose value is requested * * @return an array of String objects * containing the parameter's values * * @see #getParameter * */ 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。 *

如果 Html 页面中存在不止一个字段名为 name 的 file 控件, * 返回值等于 {@link #getFileParameterValues} 中的第一个元素。 * * @param name 一个 String ,对应于 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 一个 String ,对应于 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=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;i0 && position[1]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