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

原创: 王思龙

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"));

posted @ 2011-01-23 23:13  琥珀光  阅读(411)  评论(0编辑  收藏  举报