除了标准的orgapachestrutsactionAction类外在Struts中还提供了另外个Action类来完成特殊的工作本文及后面的文章中将介绍这些Action类的用法
一DownloadAction类简介
可能有时需要在Web程序中加入下载功能如果要下载的是静态文件可以直接交给Web服务器处理但如果要对下载的文件做额外的功能如统计文件的下载次数就需要在下载文件之前先要调用相应的程序进行处理
虽然我们可以直接在Action子类中来处理下载文件但是如果这样的程序比较多时就会写很多重复的代码为了简化这个工作Struts提供了一个新的Action类DownloadAction所有继承了DownloadAction类的Struts动作都可以非常容易地完成下载文件的工作
DownloadAction类有一个抽象方法getStreamInfo这个方法的定义如下
protectedabstractStreamInfogetStreamInfo(ActionMappingmapping
ActionFormformHttpServletRequestrequest
HttpServletResponseresponse)throwsException;
getStreamInfo方法返回一个StreamInfo对象StreamInfo接口是DownloadAction类的一个内部接口这个接口的定义如下
publicstaticinterfaceStreamInfo
{
publicabstractStringgetContentType();
publicabstractInputStreamgetInputStream()throwsIOException;
}
从上面的代码可以看出StreamInfo接口有两个方法其中getInputStream方法返回了服务端要下载的文件的InputStream对象getContenttType方法返回了HTTP响应消息头字段ContentType的信息在getStreamInfo方法中只要返回了实现这两个方法的StreamInfo对象就可以自动完成下载工作
为了方便起见DownloadAction类中还提供了两个实现StreamInfo的内类FileStreamInfo和ResourceStreamInfo这两个类的构造方法的定义如下
publicFileStreamInfo(StringcontentTypeFilefile);
publicResourceStreamInfo(StringcontentTypeServletContextcontextStringpath);
我们可以使用FileStreamInfo类来下载静态的文件如果要下载的文件在Web根目录可以使用ResourceStreamInfo类其中path参数表示文件相对于Web根目录的路径必须以/开头表示从Web根目录开始
二实例统计文件的下载次数
在本节中将使用DownloadAction类实现一个统计文件下载次数的Web程序这个程序的基本原理是当一个文件下载完成后加这个文件在数据库中的下载次数加如果某个文件是第一次下载则在数据库中添加一条新记录下载次数为
为了实现这个Web程序需要如下几步
【第步】建立用于保存文件下载次数的数据表
在本例中我们使用名为struts数据库并且在struts数据库中建立一个t_dcount表代码如下
CREATETABLEstrutst_dcount(
idINTNOTNULL
countINTNOTNULL
filenameVARCHAR()NOTNULL
PRIMARYKEY(id)
)ENGINE=InnoDBDEFAULTCHARSET=gbk;
【第步】编写Struts动作类
这个Struts动作类负责完成文件的下载工作如果在访问Struts动作类时不加file参数会将指定目录下的所有文件(不包括隐藏文件)和已经下载的次数发送到客户端浏览器如果通过file参数指定了下载文件这个Struts动作就会下载这个文件
在<samples工程目录>\src\action目录中建立一个FileDownloadActionjava文件代码如下
packagechapteraction;
importjavaxservlethttp*;
importorgapachestrutsaction*;
importorgapachestrutsactions*;
importjavaio*;
importjavasql*;
publicclassFileDownloadActionextendsDownloadAction
{
privateConnectionconn;
privateStringpath;
privateStringfilename;
//获得了Connection对象
privatevoidopenConnection()throwsException
{
if(conn==null)
{
ClassforName(commysqljdbcDriver);
conn=DriverManagergetConnection(
jdbc:mysql://localhost/struts?characterEncoding=GBK
root);
}
}
//获得某个文件的下载次数其中id是文件名的hashcode
privateintgetDownloadCount(intid)throwsException
{
openConnection();
PreparedStatementpstmt=conn
prepareStatement(SELECTcountFROMt_dcountWHEREid=+StringvalueOf(id));
ResultSetrs=pstmtexecuteQuery();
while(rsnext())
{
returnrsgetInt();
}
return;
}
//在文件完成下载后将该文件的下载次数加
privatevoidincDownloadCount()throwsException
{
openConnection();
intid=filenamehashCode();
PreparedStatementpstmt=conn
prepareStatement(UPDATEt_dcountSETcount=count+WHEREid=
+StringvalueOf(id));
if(pstmtexecuteUpdate()==)
{
pstmtexecuteUpdate(INSERTINTOt_dcount(idcountfilename)values(
+StringvalueOf(id)++filename+));
}
}
//下载文件时调用getStreamInfo方法
protectedStreamInfogetStreamInfo(ActionMappingmappingActionFormform
HttpServletRequestrequestHttpServletResponseresponse)
throwsException
{
finalFileInputStreamfis=newFileInputStream(path+filename);
finalStringcontentType=application/file;
//建议设置contentdisposition响应信息头否则Web浏览器在下载文件时
//无法在保存文件对话框中显示正确的文件名
responsesetHeader(contentdispositionattachment;filename=
+filename);
incDownloadCount();
returnnewDownloadActionStreamInfo()//使用隐式的方法实现了StreamInfo接口
{
publicStringgetContentType()
{
returncontentType;
}
publicInputStreamgetInputStream()throwsIOException
{
returnfis;
}
};
}
//如果Struts动作不加file请求参数则通过execute方法将指定目录中文件列表输出到客户端
publicActionForwardexecute(ActionMappingmappingActionFormform
HttpServletRequestrequestHttpServletResponseresponse)
throwsException
{
path=thisgetServlet()getInitParameter(downloadPath);
filename=requestgetParameter(file);
if(filename==null)
{
Filefile=newFile(path);
File[]files=filelistFiles();
responsesetCharacterEncoding(GBK);
PrintWriterout=responsegetWriter();
outprintln(<ul>);
for(Filef:files)//开始向客户端浏览器输出文件列表
{
if(fisFile()&&!fisHidden())
{
outprintln(<li><a+requestgetContextPath()+mappinggetPath()
+do?file=+fgetName()+>+fgetName()
+</a> <fontcolor=blue>下载次数
+StringvalueOf(getDownloadCount(fgetName()hashCode()))
+</color></li>);
}
}
outprintln(</ul>);
returnnull;
}
else
{
//当file参数存在时则调用DownloadAction中的execute方法
//实际上在DownloadAction类中的execute方法调用了getStreamInfo方法
//这条语句就相当于调用了getStreamInfo方法
returnsuperexecute(mappingformrequestresponse);
}
}
}
【第步】配置Struts动作类
在strutsconfigxml文件中的<actionmappings>标签中加入了如下内容
<actionpath=/downloadscope=requesttype=actionFileDownloadAction/>
【第步】配置下载路径
在webxml中找到一个叫action的Servlet并在<servlet>标签中添加如下内容
<initparam>
<paramname>downloadPath</paramname>
<paramvalue>D:\download\</paramvalue>
</initparam>
读取可以设置自已的下载目录但下载目录必须以结尾
启动Tomcat后在IE中输入如下的URL来测试程序