当前位置: 首页 > 图文教程 > 网络编程 > JSP > 通用上载组件的原理及实现

JSP
Servlet及JSP中的多线程同步问题
使用Ant和Tomcat创建Web应用
如何直接在浏览器内运行SQL命令
Servlet、Jsp中的多国语言显示
html与jsp开发分离技术
通过Jsp发送动态图像
Servlets和JSP Pages最佳实践
学习在JSP中使用JavaBeans
JSP显示内容缓存技巧
应用JDOM处理数据库到XML转换的JSP实现
JSP中tomcat的SQL Server2000数据库连接池的配置
用JSTL实现JSP应用程序快速开发
浅谈4种类型的JDBC驱动程序
怎样设置 JSP 的虚拟目录
Java 中对文件的读写操作之比较
javamail在jsp中调用
jsp中任意文字转Unicode的通用模块
JSP与SQL SERVER的留言本
jspSmartUpload上传下载全攻略
Tomcat5.x中的虚拟主机配置方法

JSP 中的 通用上载组件的原理及实现


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-03   浏览: 44 ::
收藏到网摘: n/a

原创: 王思龙

JSP/SERVLET中关于文件上传的讨论已经很久了,网上的例程也很多,但大多都不系统,且限制很多,不能作为一个通用组件拿来既用,所以对大多数人来讲,仍然是一个很头疼的问题,究其原因,关键是JSP/SERVLET中并没有给出一个实现文件上传的标准方法,本文拟从原理的角度来系统阐述JSP/SERVLET的上传原理,并给出一个标准实现方法。


JSP/SERVLET上载的难点


1、支持任意格式、任意数量的文件上载;2、上载控制的实现;3、表单信息的取得;4、“即插即用”的应用方法;我个人认为,制约通用 上载组件的实现主要是这四个难点。

 

JSP/SERVLET上传的原理


JSP/SERVLET文件 上载是通过ServletInputStream类来实现的,ServletInputStrea
m类是java.io.InputStream的一个扩展抽象类,实质上也是一个输入流,通过ReadLine方
法从Request端一行一行读取,可见,JSP/SERVLET上载根本上是用流来实现的,理解了这个就不难理解整个 上载的原理。ServletInputStream实现文件 上载必须采用HTTP POST或者HTTP PUT协议,HTTP GET协议只能传递很少的数据,是不能实现文件上载的。

下面我们来看一下上传的数据流的结构,首先要在BROWSER端给出一个请求,我们的请求如下(文件名为test1.jsp):

 

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


<title>文件上载</title>
</head>
<body>
<form action="test2.jsp" enctype="MULTIPART/FORM-DATA" method=post>
说明一: <input type="text" name="explain1" />
<br />
说明二: <input type="text" name="explain2" />
<br />
请选择上载文件1 <input type="file" name="file1" />
<br />
请选择上载文件2 <input type="file" name="file2" />
<br />
说明三: <input type="text" name="explain3" />
<br />
<input type="submit" value=" 上  载 " />
</form>
</body>
</html>

显示如下:

说明一:


说明二:

请选择上载文件一:

请选择上载文件二:

说明三:




在上载请求页中混杂了表单的三个输入框,及两个上载文件,当然输入框可以更多、
更杂,可以有选择框、单选及多选按钮,待上传的文件也可以有三个、四个或所需要的更
多。

action="test2.jsp"表示表单将提交到"test2.jsp",另外注意表单属性中必须要有这句:enctype="MULTIPART/FORM-DATA",enctype指定 Form 输入资料的编码方式,“method”属性必须为“post”,这样表单才能提交大量数据,也表示本表单的数据传递将用流操作,“method=get”表示数据将通过地址栏进行传递,虽然方便快捷,但只适合很少的数据量。

响应端“test2.jsp”页面如下:



<%@ page contentType="text/html; charset=GBK" %>
<html>
<head>
<title>文件上载</title>
</head>
<body>
<jsp:useBean id="upBean" scope="page" class="com.upload.UpBean"/>
<%
upBean.doUpload(request);
out.println("上载已完成,请查看输出文件");
%>
</body>
</html>

test2.jsp收到请求后,调用一个java bean执行doUpload(request)操作,本操作将完成流(unicode格式)的接收并不做任何处理地将流顺序写入一个文本文件里,读写操作中用了一个缓冲区byte[] readByte,用了一个ServletInputStream 的一个方法readLine(byte[] b, int off,int len)方法读取流,请大家注意,ServletInputStream 流的read
Line方法是一次读入指定大小的行,java bean (UpBean.java)代码如下:

package com.upload;



import java.io.*;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.ServletInputStream;

public class UpBean {

public void doUpload(HttpServletRequest req) throws ServletException, IOExcept
ion{
//首先定义一个文本文件
File file = new File("out.txt");
//readCount 记录从输入流中实际读取的字符数
int readCount;
//输入流缓冲区
byte[] readByte = new byte[1024];
//初始化输入流
ServletInputStream servletInputStream = req.getInputStream();
//初始化一个输出流(到文件)
FileOutputStream fileOutputStream = new FileOutputStream(file);
//循环从读取输入流中读取字节
readCount = servletInputStream.readLine(readByte, 0,readByte.length);


while(readCount != -1){
fileOutputStream.write(readByte,0,readCount);
readCount = servletInputStream.readLine(readByte, 0, 1024);
}
//关闭文件流
fileOutputStream.flush();
}
}


为了便于我们阅读流,上载的两个文件为两个简单的文本文件(有格式的文件,不便
于直接分析):one.txt及two.txt,文件内容如下,实验时请建立对应文本文件,内容请直
接copy以下所示:

one.txt:

one
one one
one one one

two.txt



two
two two
two two two

都准备好以后,我们就可以运行了,运行时请注意,文本部分及文件部分最好不要出现汉字,或其他双字符集字符,尽量采用英文,因为接收是采用的Unicode字符集,我们未对输入做任何处理。 我们在三个输入框输入的字符为,说明一:explain1;说明二:explain2;说明三:explain3,out.txt接收到如下字符:

-----------------------------7d2623a3e0286
Content-Disposition: form-data; name="explain1"

explain1
-----------------------------7d2623a3e0286
Content-Disposition: form-data; name="explain2"

explain2
-----------------------------7d2623a3e0286
Content-Disposition: form-data; name="file1"; filename="C:\test\one.txt"
Content-Type: text/plain

one


one one
one one one
-----------------------------7d2623a3e0286
Content-Disposition: form-data; name="file2"; filename="C:\test\two.txt"
Content-Type: text/plain

two
two two
two two two
-----------------------------7d2623a3e0286
Content-Disposition: form-data; name="explain3"

explain3
-----------------------------7d2623a3e0286--
 

可以很明显的看到,out.txt被“-----------------------------7d2623a3e0286”分成了五 节,即表单的每个输入部分都对应一节,结尾部分是“-----------------------------7d2623a3e0286--”,刚好比开始的一段字符在最后多出两个“-”, 每节的第一行是输入内容的说明“Content-Disposition: form-data”,“name="explain1"”表示 上载请求项的name,文本输入部分仅这两个说明,如果输入的是文件还用两项说明:“file
name="C:\test\one.txt"”,表示输入源,基于ms-windows的ie上载带有完整的路径,netscape及其他浏览器可能只有一个文件名;还有一项是关于输入格式的“Content-Type:text/plain”;表示输入格式是文本类型,如果我们上载的是bmp文件则为“Content-Type: image/bmp”,word文件为“application/msword”...,说明的下面紧接着是一个空行
,然后下面才是我们所需的内容。

仔细分析未加修改的输入流格式,有助于我们实现文件与输入文本的准确分离。
通过以上的分析可以看出,准确分离上载的文件及文本信息需要以下要素:1、数据段分割符、结束符(比分割符多出两个“-”);2、输入文本及上载的文件区分标志(文本为“name=”,文件为“filename=”);3、编码格式,可以通过HttpServletRequest 类getCharacterEncoding() 方法取得。4、表单文本部分名称及内容,名称为“name=”后面
的字符,内容为该段第三行及以后的内容;5、文件名称及内容,名称为“filename=”后面的字符,内容为该段第三行及以后的内容。

下面我们将讨论输入流的分离。

程序实现分析

我们首先画出程序实现的主体结构图,请注意判断文件标志(indexOf("filename=")>0),与判断文本标志(indexOf("name=")>0)的顺序,当(indexOf("filename=")>0)成立时,(indexOf("name=")>0)一定也是成立的,所以判断文件要在判断文本前。


分离文件及输入文本,为完整保存上载的文件信息及输入的文本信息,本程序建立了两个类:public class FileInfo 、public class InputField,及两个线性表private ArrayList upFilesList、private ArrayList inputFieldList,用于动态增加文件信息及文本信息,定义如下:

FileInfo.java(记录上载文件信息)

package com.upload;

public class FileInfo {
private String fileName;
private boolean validFlag;
private String filePath;
private long fileSize;


//设置文件信息
//上载文件是否有效标志
public void setValidFlag(boolean validFlag){


this.validFlag = validFlag;
}
//文件名
public void setFileName(String filename){
this.fileName = filename;
}
//存贮路径
public void setFilePath(String filePath){
this.filePath = filePath;
}
//文件大小
public void setFileSize(long fileSize){
this.fileSize = fileSize;
}
//上载文件是否有效标志
public boolean getValidFlag(){
return validFlag;
}
//取得文件名
public String getFileName(){
return fileName;
}


//取得存贮路径
public String getFilePath() {
return filePath;
}
//取得文件大小
public long getFileSize(){
return fileSize;
}
}


        InputField.java(记录输入文本信息)

package comupload;

public class InputField{
private String inputName;      //输入框名
private String inputContent;   //输入框内容
//设置输入框名称及内容
public void setInputName(String inputName){
this.inputName = inputName;
}


public void setInputContent(String inputContent){
this.inputContent = inputContent;
}
//返回输入框名称及内容
public String getInputName(){
return inputName;
}
public String getInputContent(){
return inputContent;
}
}


private ArrayList upFilesList = new ArrayList(); //上载文件信息链表
private ArrayList inputFieldList = new ArrayList(); //输入文本信息链表


分离文件及及分离文本输入的流程图如下:
对于框图更详细的描述请大家自己去做,需要指出的是,在输入流中,每个自然换行
段或每节内容的尾部都还有两个特殊的字符“/r/n”即换行回车符,当我们取得输入内容时一定要考虑到这两个字符,不然得不到正确的结果,以下是过滤文件名的程序段:

filename = line.substring(i + 10,line.length() - 3);
filename = getFileName(filename);

line是文件名所在行的整行内容,i是 “filename=”在此行中的位置,最后减三个字
符,除了“\r\n”还减去了一个冒号“"”,第一句运行后,取得的是带完整路径的文件名
,第二行是分离单纯文件名的子程序。

取得文件内容最后一行的程序段为:

//对最后一行进行处理
if(line != null && writeByte[0] != 45 && writeCount[0] > 2)
fileOutputStream.write(writeByte, 0, writeCount[0] - 2);

if(lineContent != null && readByte[0] != 45 && readCount[0] > 2)
fileOutputStream.write(readByte, 0, readCount[0] - 2);

可以清楚地看到,最后写入到文件的行去掉了二个byte。

程序实现代码



最终的完整程序包含三个类:UploadBean,上载实现类;FileInfo,上载文件信息类;
InputField,表单文本信息类;及一个请求上载页、一个JSP调用示例及一个Servlet调用
示例。

上载实现类,UploadBean.java:

package com.upload;

import java.io.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletException;
import java.util.ArrayList;
import com.upload.FileInfo.*;
import com.upload.InputField.*;

public class UploadBean{
private String savePath = "c:/"; //服务器端存放路径
private String strSectFlag = ""; //上传数据区域段标记
private String CharacterEncoding = ""; // //编码方法
private byte readByte[] = new byte[4096]; //读入流缓冲区
private byte writeByte[] = new byte[4096]; //写入流缓冲区


private int readCount[] = new int[1]; //readCount[]为行字符数
private int writeCount[] = new int[1];//设置指针变量
private int upFilesCount = 0; //当前实际上载文件数
private int pageFileCount = 0;//请求页面存在的文件项数
private int upFilesMaxCount=10; //最大可上载文件数默认值
private boolean totalCountOverflowFlag=false; //文件个数溢出标志
private long totalFilesMaxSize=1024*1024*100; //可上载全部文件容量总和最大值,单
位KB
private long singleFileMaxSize=1024*1024*10;//可上载单个文件容量最大值
private long upFilesTotalSize = 0 ; //当前实际上载容量
private boolean totalSizeOverflowFlag = false ;//上传文件容总长溢出标志
private boolean fileSizeOverflowFlag = false; //文件超长溢出标志
private ArrayList upFilesList = new ArrayList(); //上载成功文件链表
private ArrayList inputFieldList = new ArrayList(); //输入框内容链表

//设置最大可上载文件数
public void setTotalFilesMaxCount(int count){
upFilesMaxCount = count;
}
//设置可上载全部文件容量总和最大值,单位byte
public void setTotalFilesMaxSize(long size){
totalFilesMaxSize = size;


}
//设置单个上载文件最大容量
public void setSingleFileMaxSize(long size){
singleFileMaxSize = size;
}
//返回上载成功的文件个数
public int getUpFilesCount(){
return upFilesCount;
}
//返回请求页面的文件项数
public int getPageFileCount(){
return pageFileCount;
}
//返回上载成功的文件总长度
public long getUpFilesToatalSize(){
return upFilesTotalSize;
}
//返回是否存在文件总长超长标志
public boolean isTotalSizeOverFlow(){
return totalSizeOverflowFlag;
}
//返回是否存在单个文件长度溢出标志


public boolean isSizeOverFlow(){
return fileSizeOverflowFlag;
}
//返回是否存在文件个数超过溢出
public boolean isTotalCountOverFlow(){
return totalCountOverflowFlag;
}

//返回对应输入项内容 参数为输入项名称
public String getParameter(String inputName){
int i = 0;
for(i=0;i<inputFieldList.size();i++){
InputField inputField = new InputField();
inputField = (InputField)inputFieldList.get(i);
if(inputName.compareTo(inputField.getInputName())==0){
return inputField.getInputContent();
}
}
return null;
}
//返回输入项数量
public int getInputFieldCount(){


return inputFieldList.size();
}
//返回输入项指针
public InputField getInputField(int i){
if(i < 0 || i > inputFieldList.size() - 1){
return null;
}
return (InputField)inputFieldList.get(i);
}

//返回已上载文件属性链表指针
public FileInfo getUpFilesInfo(int i){
if (i < 0 || i > pageFileCount){
return null;
}else return (FileInfo)upFilesList.get(i);
}
//以请求名形式返回FileInfo
public FileInfo getUpFilesInfo(String reqName){
int i = 0;
FileInfo fileInfo = new FileInfo();
for(i=0;i<upFilesList.size();i++){
fileInfo = (FileInfo)upFilesList.get(i);


if(reqName.compareTo(fileInfo.getReqName())==0){
return fileInfo;
}
}
return null;
}

//设置上载存贮路径
public void setSavePath(String savePath){
File file = new File(savePath);
if(file.isDirectory())
this.savePath = savePath;
else {
try{
if(file.mkdir()) this.savePath = savePath;
}catch(Exception e){
this.savePath = ".";
}
}
}

//由请求上载文件


public void uploadFile( HttpServletRequest req) throws ServletException, IOExc
eption{
//清空两个表
init();
inputFieldList.clear();
upFilesList.clear();
//设置Request端字符编码方式
setCharacterEncoding(req.getCharacterEncoding());
//设置Request端strSectFlag
setSectFlag(req.getContentType());
//从输入流读入数据并写入到文件
read$writeFile(req.getInputStream());
}
private void init(){
//清空两个表
upFilesCount = 0 ;
upFilesTotalSize = 0 ;
pageFileCount = 0 ;
totalSizeOverflowFlag = false ;
fileSizeOverflowFlag = false ;
totalCountOverflowFlag = false ;
inputFieldList.clear();


upFilesList.clear();
}

//取得文件名称(不带路径)
private String getFileName(String fileName){
if(fileName.length()==0) return null;
int i = fileName.lastIndexOf("\\");
if(i < 0 || i >= fileName.length() - 1){
i = fileName.lastIndexOf("/");
if(i < 0 || i >= fileName.length() - 1)
return fileName;
}
return fileName.substring(i + 1);
}

//设置节标志
private void setSectFlag(String sectFlag){
strSectFlag = sectFlag;
int j;
if((j = strSectFlag.indexOf("boundary=")) != -1){
//定义数据块起始段标志
strSectFlag = strSectFlag.substring(j + 9);


strSectFlag = "--" + strSectFlag;
}
}

//设置字符编码方式
public void setCharacterEncoding(String str){
CharacterEncoding = str;
}

//从输入流读取文件并写入服务器端,完成上载操作
public void read$writeFile(ServletInputStream servletInputStream)
throws ServletException, IOException{

String filename = null;
String line;
//从输入流中查找 "filename"标志 即此处以下部分将为输入流的文件数据
//i 在此为"filename"标志在行中的位置
//实际读取的字符数放在readCount[0]中 readCount在此处为指针操作
while((line = readLine(readByte, readCount, servletInputStream,
CharacterEncoding)) != null){

//处理文件上传


int i = line.indexOf("filename=");
if(i >= 0){
pageFileCount++;//代表页面的文件上载请求项数
//分离请求名
String reqName = line;
int j = reqName.indexOf("name=");
reqName = reqName.substring(j + 6,reqName.length()-1);
j = reqName.lastIndexOf("filename=");
reqName = reqName.substring(0, j-3);
//该行在"filename"标志后十位处为上载的源文件字串
//取"filename"标志后十位以后的字串为子串
filename = line.substring(i + 10,line.length() - 3);
filename = getFileName(filename);
if(filename != null ){
//新建文件 存贮位置为savePath ,名称为filename
File file = new File(savePath, filename);
//写文件操作前首先检查上传文件个数是否超过上限
if (!((upFilesCount>=upFilesMaxCount) ||
(upFilesTotalSize>=totalFilesMaxSize))){
//没有超过上限(文件上载总个数、总长度)
//将数据写入文件
writeFile(file,servletInputStream,CharacterEncoding);


}
//文件正确性验证
int validate = validateFile(file);
if(validate == 1){
setUpFilesInfo(file,reqName); //记录上传成功的文件列表
upFilesCount++;
}else{
file.delete();
setUpFilesInfo(null,reqName);
}
}else setUpFilesInfo(null,reqName);//记录空文件信息
}
//处理input内容
int j = line.indexOf("name=\"");
if(j>0 && i<0){
String inputName = line.substring(j+6, line.length()-3);
String inputContent="";
//读过一空行
line = readLine(readByte, readCount, servletInputStream, CharacterEncoding);
while((line = readLine(readByte, readCount, servletInputStream,
CharacterEncoding)).indexOf(strSectFlag)<0){
//去结尾部分的/r/n符号(回车换行符)


inputContent = inputContent+line.substring(0,line.length()-2);
}
setInputContent(inputName,inputContent);
}
}
}


private void writeFile(File file,ServletInputStream servletInputStream,
String CharacterEncoding)
throws ServletException, IOException{
String line = null;
//创建文件输出流
FileOutputStream fileOutputStream = new FileOutputStream(file);
//读入下一行,该行为写入内容类型行
String lineContent = readLine(readByte, readCount, servletInputStream,
CharacterEncoding);
if(lineContent.indexOf("Content-Type") >= 0){
//本行空处理
readLine(readByte, readCount, servletInputStream, CharacterEncoding);
}




//循环从输入流读入并写入文件 readCount[0]为实际写入的字符数
while((lineContent = readLine(readByte, readCount, servletInputStream,
CharacterEncoding)) != null){
//读到最后一行结束标志 strSectFlag 则退出循环
if(lineContent.indexOf(strSectFlag) == 0 && readByte[0] == 45)
break;

if(line != null){
fileOutputStream.write(writeByte, 0, writeCount[0]);
fileOutputStream.flush();
}

//readCount[0]为实际读入的字符数
line = readLine(writeByte, writeCount, servletInputStream, CharacterEncoding);

if(line == null || line.indexOf(strSectFlag) == 0
&& writeByte[0] == 45)
break;
fileOutputStream.write(readByte, 0, readCount[0]);
fileOutputStream.flush();
}


//对最后一行进行处理
if(line != null && writeByte[0] != 45 && writeCount[0] > 2)
fileOutputStream.write(writeByte, 0, writeCount[0] - 2);

if(lineContent != null && readByte[0] != 45 && readCount[0] > 2)
fileOutputStream.write(readByte, 0, readCount[0] - 2);
fileOutputStream.close();
}

//从输入流中读入行数据 readLine(byte[] buffer, int offset, int length)
private String readLine(byte readByte[], int readCount[],
ServletInputStream servletInputStream,
String CharacterEncoding){

try{
//readLine(byte[] buffer, int offset, int length)
//从输入流读取数据 读取的数据最大长度为readByte缓冲数组的长度
//readCount[0]为实际读入的字符串长度
readCount[0] = servletInputStream.readLine(readByte, 0, readByte.length);
//如果读入的长度为 -1 ,即输入流数据已读完
if(readCount[0] == -1)
return null;


}catch(IOException _ex){
return null;
}
try{
if(CharacterEncoding == null){
//用缺省的编码方式把给定的byte数组转换为字符串
return new String(readByte, 0, readCount[0]);
}else{
//用给定的编码方式把给定的byte数组转换为字符串
return new String(readByte, 0, readCount[0], CharacterEncoding);
}
}catch(Exception e){
return null;
}
}

//文件上载有效性检查
//合法返回 1;单个文件超长返回2;
//总长超长返回3;上传文件数量溢出返回4
private int validateFile(File file){
if((upFilesTotalSize+file.length())>totalFilesMaxSize){
//总长溢出标志置1


totalSizeOverflowFlag=true;
return 3;
}
if(file.length()>singleFileMaxSize){
//单个文件长度溢出位置1
fileSizeOverflowFlag=true;
return 2;
}
//文件数量是否溢出
if(upFilesCount > upFilesMaxCount){
//个数溢出标志置1
totalCountOverflowFlag = true;
return 4;
}
upFilesTotalSize=upFilesTotalSize+file.length();
return 1;
}

//取得的文本项加入文本输入项链表
private void setInputContent(String inputName,String inputContent){
InputField inputField = new InputField();
inputField.setInputName(inputName);


inputField.setInputContent(inputContent);
inputFieldList.add(inputField);
}


//设置已上载文件属性
private void setUpFilesInfo(File file,String reqName){
FileInfo fileInfo = new FileInfo();
if(file==null){
fileInfo.setSuccess(false);
fileInfo.setFileName(null);
fileInfo.setFilePath (null);
fileInfo.setFileSize(0);
}else{
fileInfo.setSuccess(true);
fileInfo.setFileName(file.getName());
fileInfo.setFilePath (file.getPath());
fileInfo.setFileSize(file.length());
}
fileInfo.setReqName(reqName);
upFilesList.add(fileInfo);
}


}

上载文件信息类,FileInfo.java:

package com.upload;

public class FileInfo {
private String reqName;
private String fileName;
private boolean success;
private String filePath;
private long fileSize;
//设置文件信息
//上载文件是否有效标志
public void setSuccess(boolean success){
this.success = success;
}
//设置表单请求名
public void setReqName(String reqName){
this.reqName = reqName;
}
//文件名


public void setFileName(String filename){
this.fileName = filename;
}
//存贮路径
public void setFilePath(String filePath){
this.filePath = filePath;
}
//文件大小
public void setFileSize(long fileSize){
this.fileSize = fileSize;
}
//返回表单请求名
public String getReqName(){
return reqName;
}
//上载文件是否有效标志
public boolean isSuccess(){
return success;
}
//取得文件名
public String getFileName(){
return fileName;


}
//取得存贮路径
public String getFilePath() {
return filePath;
}
//取得文件大小
public long getFileSize(){
return fileSize;
}
}

表单文本信息类,InputField.java:

package com.upload;

public class InputField{
private String inputName; //输入区名
private String inputContent; //输入内容

public void setInputName(String inputName){
this.inputName = inputName;
}


public void setInputContent(String inputContent){
this.inputContent = inputContent;
}

public String getInputName(){
return inputName;
}
public String getInputContent(){
return inputContent;
}
}

Servlet调用文件,ResultServlet.java:

package com.upload;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import com.upload.UploadBean;
import com.upload.FileInfo;
import com.upload.InputField;



public class ResultServlet extends HttpServlet {
static final private String CONTENT_TYPE = "text/html; charset=GBK";
UploadBean upload = new UploadBean();

//Process the HTTP Get request
public void doPost(HttpServletRequest request, HttpServletResponse response) t
hrows ServletException, IOException {
response.setContentType(CONTENT_TYPE);
PrintWriter out = response.getWriter();
result(request,out);
}

private void result(HttpServletRequest request,PrintWriter out)
throws ServletException, IOException{
//以下演示说明调用方法
//请注意本页注释
//实例化 servlet 调用与以下方法相同
FileInfo fileInfo = new FileInfo();

//设置单个文件长度上限值,参数为:long
upload.setSingleFileMaxSize(1024*1024*10);


//设置文件总长度上限值 参数为:long
upload.setTotalFilesMaxSize(1024*1024*100);
//设置上传文件数量上限值 参数为:int
upload.setTotalFilesMaxCount(10);

//设置服务器端存放路径 参数为:string 请注意路径格式
//若不设置,将默认放在主页根目录下,以下是防于根目录下
String savePath = "c:/jsp";
upload.setSavePath(savePath);

//上载操作 参数为:request servlet中调用与此相同
upload.uploadFile(request);
out.print("<br><br><font face='黑体' size='5'><center>已成功上载" + upload.get
UpFilesCount() + "个文件</center>");
out.print("<center>以下为所有上载请求的文件列表</font></center>");
out.print("<br><br>");
out.print("<div align='center'><table border=1 cellpadding=0 cellspacing=0 sty
le='border-collapse: collapse' bordercolor='#111111' width='80%' >");
out.print("<tr><td>上载序号</td><td>上载请求名</td><td>文件名称</td><td>访问路
径</td><td>文件大小(Byte)</td><td>是否成功</td></tr>");
int i;
//得到上载的文件数


int j = upload.getPageFileCount();
for(i=0;i<j;i++){
out.print("<tr>");
//得到文件信息前首先得到文件信息对象
//取得访问的文件对象upload.getUpFilesInfo(i) i为上载文件的序号
//对应类为 com.top.web.upload.FileInfo
fileInfo = upload.getUpFilesInfo(i);
//上载序号
out.print("<td>" + (new Integer(i).toString()+"") + "</td>");
//取得上载请求名
out.print("<td>" + fileInfo.getReqName() + "</td>");
//取得文件名称
out.print("<td>" + fileInfo.getFileName() + "</td>");
//取得文件访问路径
out.print("<td>" + fileInfo.getFilePath() + "</td>");
//取得文件大小
out.print("<td>" + fileInfo.getFileSize() + "</td>");
if(fileInfo.isSuccess())
out.print("<td>" + "是" + "</td>");
else
out.print("<td>" + "否" + "</td>");
out.print("</tr>");


}
out.print("</table></div><br>");

//判断是否存在文件总长度溢出情况
if(upload.isTotalSizeOverFlow())
out.println("请检查您的上载文件,您准备上载的文件总长超过设置的上限!"+"<br>")
;
//判断是否存在文件数量溢出情况
if(upload.isTotalCountOverFlow())
out.println("请检查您的上载文件,您准备上载的文件数量超过设置的上限!"+"<br>")
;
//判断是否存在单个文件超长情况
if(upload.isSizeOverFlow())
out.println("请检查您的上载文件,您准备上载的某个文件超过单个文件长度的上限!"
+"<br>");


//以下演示输入区的取值
//一、按输入区name取,推荐使用 请输入您需要取的内容
out.println("以下演示按输入区name取,推荐使用!"+"<br>");
out.println("您所输入的摘要内容为:");
out.println(upload.getParameter("explain1"));


out.println("<br><br>");
//以下演示按输入项的顺序号取,不推荐使用
out.println("以下演示按输入项的顺序号取,不推荐使用!"+"<br>");
out.println("您在以下输入区域输入的内容为:"+"<br>");
for(i=0;i<upload.getInputFieldCount();i++){
//取得输入区域的的指针对象
InputField inputField = new InputField();
inputField = upload.getInputField(i);
//取得输入区的name
out.println(inputField.getInputName()+":");
//取得输入区的内容
out.println(inputField.getInputContent()+"<br>");

}
}
//Clean up resources
public void destroy() {
}
}

JSP调用页面请大家自己写,甚至可以完全照搬上面的Servlet程序。



以下是请求页面,这里是一个活动页面,可以动态增加上载文件数,upload.jsp:

<%@ page contentType="text/html; charset=GBK" %>
<html>
<head>
<meta http-equiv="content-Type" content="text/html">
<title>上载文件请求页</title>
</head>
<BODY >
<center><b>请动态增加\删除上载文件请求</b></center>
<form name="upform" action="/resultservlet" enctype="MULTIPART/FORM-DATA" meth
od=post>
<DIV id="mybag0" ALIGN="CENTER">
<!--在这里是开始加入第一个-->
</DIV>
<DIV ALIGN="CENTER">
<TABLE WIDTH="100%" BORDER="1" CELLSPACING="1" CELLPADDING="1" BORDERCOLOR="to
mato">
<tr>
<td colspan="16" align="center">
<input type="button" name="cmdAddItm" value="增加一个文件" onclick="AddItm();"
>


<input type="button" name="cmdDelItm" value="删除一个文件" onclick="DelItm();"
>
<input type="submit" value=" 开始上载 " />
</td>
</tr>
</TABLE>
</DIV>
</form>
</BODY>

<script language= "javascript">
var StraddItem="";
var ItemNo=1; //,1,2,3,4......

function AddItm()
{

var mybag="Mybag"+(ItemNo-1); //look for last Bag
//StraddItem=Table+define new Bag
StraddItem="<table id=TblItm"+ItemNo+" WIDTH=100% BORDER=0 CELLSPACING=1 CELLP
ADDING=1 BORDERCOLOR=red><TR><TD COLSPAN=6 >&nbsp;</TD></TR><tr colspan=6 heigh
t=1align=center> <td align=center colspan=13 width=100% bgcolor=mistyrose>选中


<INPUT TYPE=CHECKBOX name=chkAppIt"+ ItemNo +" value=Y>&nbsp; &nbsp;说明"+ Ite
mNo +"<INPUT TYPE=text name=explain"+ ItemNo +" >&nbsp; &nbsp; 文件"+ ItemNo +
":<input type=file name=file"+ ItemNo + " size=35> </td> </tr> <TR><TD COLSPA
N=6 >&nbsp;</TD></TR></table><div id=mybag"+ItemNo+" > </div>";
//将(Table+define new Bag)放入上一个袋囊,形成链表
document.all(mybag).innerHTML=StraddItem;
ItemNo++;
}

function DelItm()
{
var i;
var bSel;
var strURL;

for(i=1;i<ItemNo;i++) //chkAppitx, forbidden Show TblItmx
{
chkAppItx="chkAppIt"+i;
TblItmx="TblItm"+i;
if (document.all(chkAppItx).checked==true)
{document.all(TblItmx).style.display="none"
bSel=true;


}
}

if (bSel != true) {alert("请首先选中您要删除的文件行") ; return false; }
else return true;
}

</script>
</html>

类接口说明

本组件通过两种方式获得表单上载文件集及文本类集:指针方式及参数查询式,引用
本组件时,首先要在import部分加入:

import com.upload.UploadBean;
import com.upload.FileInfo;
import com.upload.InputField;

应用之前先初始化,格式为:

UploadBean upload = new UploadBean();


FileInfo fileInfo = new FileInfo();

//设置单个上传文件长度上限值,参数为:long
upload.setSingleFileMaxSize(1024*1024*10);
//设置上传文件总长度上限值 参数为:long
upload.setTotalFilesMaxSize(1024*1024*100);
//设置上传文件数量上限值 参数为:int
upload.setTotalFilesMaxCount(10);

//设置服务器端存放路径 参数为:string 请注意路径格式
//若不设置,将默认放在主页根目录下
upload.setSavePath("c:/jsp");
//执行上载操作!(一定要有这句) 参数为:HttpServletRequest request
upload.uploadFile(request);
 


指针输出上载文件信息:请一定注意指针不要越界,该操作为危险操作,不推荐使用


int i=0;
//得到上载的文件数


int j = upload.getPageFileCount();
for(i=0;i<j;i++){
out.print("<tr>");
//得到文件信息前首先得到文件信息对象
//取得访问的文件对象upload.getUpFilesInfo(i) i为上载文件的序号
//对应类为 com.top.web.upload.FileInfo
fileInfo = upload.getUpFilesInfo(i);
//上载序号
out.print("<td>" + (new Integer(i).toString()+"") + "</td>");
//取得上载请求名
out.print("<td>" + fileInfo.getReqName() + "</td>");
//取得文件名称
out.print("<td>" + fileInfo.getFileName() + "</td>");
//取得文件访问路径
out.print("<td>" + fileInfo.getFilePath() + "</td>");
//取得文件大小
out.print("<td>" + fileInfo.getFileSize() + "</td>");
if(fileInfo.isSuccess())
out.print("<td>" + "是" + "</td>");
else
out.print("<td>" + "否" + "</td>");
out.print("</tr>");


}
out.print("</table></div><br>");

查询式输出结果:比较安全,但要判定得返回的对象是否为null的情况,本操作uplo
ad.getUpFilesInfo("file1")返回的其实也是指针,但我们得到这个指针的方式是安全的


fileInfo = upload.getUpFilesInfo("file1");
if(fileInfo!=null){
out.print(fileInfo.getFileName());
out.print(fileInfo.getFilePath());
out.print(fileInfo.isSuccess());
out.print(fileInfo.getFileSize());
}

指针输出请求表单文本类信息:请一定注意指针不要越界,该操作为危险操作,不推
荐使用;

int i;
InputField inputField = new InputField();
for(i=0;i<upload.getInputFieldCount();i++){
//取得输入区域的的指针对象


//InputField inputField = new InputField();
inputField = upload.getInputField(i);
//取得输入区的name
out.println(inputField.getInputName()+":");
//取得输入区的内容
out.println(inputField.getInputContent()+"<br>");

}

请求方式输出表单文本类信息:完全安全操作,请放心使用;

out.println(upload.getParameter("expain1"));