本文为原创,如需转载,请注明作者和出处,谢谢!
上一篇:Struts1.x系列教程(14):动态Form
除了标准的org.apache.struts.action.Action类外,在Struts中还提供了另外7个Action类来完成特殊的工作。本文及后面的文章中将介绍这些Action类的用法。
一、DownloadAction类简介
可能有时需要在Web程序中加入下载功能。如果要下载的是静态文件,可以直接交给Web服务器处理,但如果要对下载的文件做额外的功能,如统计文件的下载次数。就需要在下载文件之前先要调用相应的程序进行处理。
虽然我们可以直接在Action子类中来处理下载文件,但是如果这样的程序比较多时,就会写很多重复的代码。为了简化这个工作。Struts提供了一个新的Action类:DownloadAction。所有继承了DownloadAction类的Struts动作都可以非常容易地完成下载文件的工作。
DownloadAction类有一个抽象方法getStreamInfo。这个方法的定义如下:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
protected
abstract
StreamInfogetStreamInfo(ActionMappingmapping,
ActionFormform,HttpServletRequestrequest,
HttpServletResponseresponse)
throws
Exception;
getStreamInfo方法返回一个StreamInfo对象。StreamInfo接口是DownloadAction类的一个内部接口,这个接口的定义如下:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
public
static
interface
StreamInfo
{
public
abstract
StringgetContentType();
public
abstract
InputStreamgetInputStream()
throws
IOException;
}
从上面的代码可以看出,StreamInfo接口有两个方法。其中getInputStream方法返回了服务端要下载的文件的InputStream对象。getContenttType方法返回了HTTP响应消息头字段Content-Type的信息。在getStreamInfo方法中只要返回了实现这两个方法的StreamInfo对象,就可以自动完成下载工作。
为了方便起见,DownloadAction类中还提供了两个实现StreamInfo的内类:FileStreamInfo和ResourceStreamInfo。这两个类的构造方法的定义如下:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
public
FileStreamInfo(StringcontentType,Filefile);
public
ResourceStreamInfo(StringcontentType,ServletContextcontext,Stringpath);
我们可以使用FileStreamInfo类来下载静态的文件。如果要下载的文件在Web根目录,可以使用ResourceStreamInfo类。其中path参数表示文件相对于Web根目录的路径,必须以“/”开头,表示从Web根目录开始。
二、实例:统计文件的下载次数
在本节中将使用DownloadAction类实现一个统计文件下载次数的Web程序。这个程序的基本原理是当一个文件下载完成后,加这个文件在数据库中的下载次数加1,如果某个文件是第一次下载,则在数据库中添加一条新记录,下载次数为1。
为了实现这个Web程序,需要如下几步:
【第1步】建立用于保存文件下载次数的数据表
在本例中我们使用名为struts数据库,并且在struts数据库中建立一个t_dcount表,代码如下:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
CREATE
TABLE
struts.t_dcount(
id
INT
NOT
NULL
,
count
INT
NOT
NULL
,
filename
VARCHAR
(
256
)
NOT
NULL
,
PRIMARY
KEY
(id)
)ENGINE
=
InnoDB
DEFAULT
CHARSET
=
gbk;
【第2步】编写Struts动作类
这个Struts动作类负责完成文件的下载工作。如果在访问Struts动作类时不加file参数,会将指定目录下的所有文件(不包括隐藏文件)和已经下载的次数发送到客户端浏览器。如果通过file参数指定了下载文件,这个Struts动作就会下载这个文件。
在<samples工程目录>\src\action目录中建立一个FileDownloadAction.java文件,代码如下:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
package
chapter6.action;
import
javax.servlet.http.
*
;
import
org.apache.struts.action.
*
;
import
org.apache.struts.actions.
*
;
import
java.io.
*
;
import
java.sql.
*
;
public
class
FileDownloadAction
extends
DownloadAction
{
private
Connectionconn;
private
Stringpath;
private
Stringfilename;
//
获得了Connection对象
private
void
openConnection()
throws
Exception
{
if
(conn
==
null
)
{
Class.forName(
"
com.mysql.jdbc.Driver
"
);
conn
=
DriverManager.getConnection(
"
jdbc:mysql://localhost/struts?characterEncoding=GBK
"
,
"
root
"
,
"
1234
"
);
}
}
//
获得某个文件的下载次数,其中id是文件名的hashcode
private
int
getDownloadCount(
int
id)
throws
Exception
{
openConnection();
PreparedStatementpstmt
=
conn
.prepareStatement(
"
SELECTcountFROMt_dcountWHEREid=
"
+
String.valueOf(id));
ResultSetrs
=
pstmt.executeQuery();
while
(rs.next())
{
return
rs.getInt(
1
);
}
return
0
;
}
//
在文件完成下载后,将该文件的下载次数加1
private
void
incDownloadCount()
throws
Exception
{
openConnection();
int
id
=
filename.hashCode();
PreparedStatementpstmt
=
conn
.prepareStatement(
"
UPDATEt_dcountSETcount=count+1WHEREid=
"
+
String.valueOf(id));
if
(pstmt.executeUpdate()
==
0
)
{
pstmt.executeUpdate(
"
INSERTINTOt_dcount(id,count,filename)values(
"
+
String.valueOf(id)
+
"
,1,'
"
+
filename
+
"
')
"
);
}
}
//
下载文件时调用getStreamInfo方法
protected
StreamInfogetStreamInfo(ActionMappingmapping,ActionFormform,
HttpServletRequestrequest,HttpServletResponseresponse)
throws
Exception
{
final
FileInputStreamfis
=
new
FileInputStream(path
+
filename);
final
StringcontentType
=
"
application/file
"
;
//
建议设置content-disposition响应信息头,否则Web浏览器在下载文件时
//
无法在保存文件对话框中显示正确的文件名
response.setHeader(
"
content-disposition
"
,
"
attachment;filename=
"
+
filename);
incDownloadCount();
return
new
DownloadAction.StreamInfo()
//
使用隐式的方法实现了StreamInfo接口
{
public
StringgetContentType()
{
return
contentType;
}
public
InputStreamgetInputStream()
throws
IOException
{
return
fis;
}
};
}
//
如果Struts动作不加file请求参数,则通过execute方法将指定目录中文件列表输出到客户端
public
ActionForwardexecute(ActionMappingmapping,ActionFormform,
HttpServletRequestrequest,HttpServletResponseresponse)
throws
Exception
{
path
=
this
.getServlet().getInitParameter(
"
downloadPath
"
);
filename
=
request.getParameter(
"
file
"
);
if
(filename
==
null
)
{
Filefile
=
new
File(path);
File[]files
=
file.listFiles();
response.setCharacterEncoding(
"
GBK
"
);
PrintWriterout
=
response.getWriter();
out.println(
"
<ul>
"
);
for
(Filef:files)
//
开始向客户端浏览器输出文件列表
{
if
(f.isFile()
&&
!
f.isHidden())
{
out.println(
"
<li><ahref='
"
+
request.getContextPath()
+
mapping.getPath()
+
"
.do?file=
"
+
f.getName()
+
"
'>
"
+
f.getName()
+
"
</a> <fontcolor='blue'>下载次数:
"
+
String.valueOf(getDownloadCount(f.getName().hashCode()))
+
"
</color></li>
"
);
}
}
out.println(
"
</ul>
"
);
return
null
;
}
else
{
//
当file参数存在时,则调用DownloadAction中的execute方法
//
实际上,在DownloadAction类中的execute方法调用了getStreamInfo方法
//
这条语句就相当于调用了getStreamInfo方法
return
super
.execute(mapping,form,request,response);
}
}
}
【第3步】配置Struts动作类
在struts-config.xml文件中的<action-mappings>标签中加入了如下内容:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
<
action
path
="/download"
scope
="request"
type
="action.FileDownloadAction"
/>
【第4步】配置下载路径
在web.xml中找到一个叫action的Servlet,并在<servlet>标签中添加如下内容:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
<
init-param
>
<
param-name
>
downloadPath
</
param-name
>
<
param-value
>
D:\download\
</
param-value
>
</
init-param
>
读取可以设置自已的下载目录,但下载目录必须以“"”结尾。
启动Tomcat后,在IE中输入如下的URL来测试程序:
http://localhost:8080/samples/download.do
下一篇:Struts1.x系列教程(16):使用LocaleAction类实现国际化的Web程序
国内最棒的Google Android技术社区(eoeandroid),欢迎访问!
《银河系列原创教程》发布
《Java Web开发速学宝典》出版,欢迎定购