除了标准的
org.apache.struts.action.Action
类外,在
Struts
中还提供了另外
7
个
Action
类来完成特殊的工作。本文及后面的文章中将介绍这些
Action
类的用法。
一、 DownloadAction 类简介
可能有时需要在 Web 程序中加入下载功能。如果要下载的是静态文件,可以直接交给 Web 服务器处理,但如果要对下载的文件做额外的功能,如统计文件的下载次数。就需要在下载文件之前先要调用相应的程序进行处理。
虽然我们可以直接在 Action 子类中来处理下载文件,但是如果这样的程序比较多时,就会写很多重复的代码。为了简化这个工作。 Struts 提供了一个新的 Action 类: DownloadAction 。所有继承了 DownloadAction 类的 Struts 动作都可以非常容易地完成下载文件的工作。
DownloadAction类有一个抽象方法getStreamInfo。这个方法的定义如下:
getStreamInfo方法返回一个StreamInfo对象。StreamInfo接口是DownloadAction类的一个内部接口,这个接口的定义如下:
一、 DownloadAction 类简介
可能有时需要在 Web 程序中加入下载功能。如果要下载的是静态文件,可以直接交给 Web 服务器处理,但如果要对下载的文件做额外的功能,如统计文件的下载次数。就需要在下载文件之前先要调用相应的程序进行处理。
虽然我们可以直接在 Action 子类中来处理下载文件,但是如果这样的程序比较多时,就会写很多重复的代码。为了简化这个工作。 Struts 提供了一个新的 Action 类: DownloadAction 。所有继承了 DownloadAction 类的 Struts 动作都可以非常容易地完成下载文件的工作。
DownloadAction类有一个抽象方法getStreamInfo。这个方法的定义如下:
protected
abstract
StreamInfo getStreamInfo(ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception;
ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception;
getStreamInfo方法返回一个StreamInfo对象。StreamInfo接口是DownloadAction类的一个内部接口,这个接口的定义如下:
public
static
interface
StreamInfo
{
public abstract String getContentType();
public abstract InputStream getInputStream() throws IOException;
}
{
public abstract String getContentType();
public abstract InputStream getInputStream() throws IOException;
}
从上面的代码可以看出,StreamInfo
接口有两个方法。其中getInputStream
方法返回了服务端要下载的文件的InputStream
对象。getContenttType
方法返回了HTTP
响应消息头字段Content-Type
的信息。在getStreamInfo
方法中只要返回了实现这两个方法的StreamInfo
对象,就可以自动完成下载工作。
为了方便起见,DownloadAction类中还提供了两个实现StreamInfo的内类:FileStreamInfo和ResourceStreamInfo。这两个类的构造方法的定义如下:
为了方便起见,DownloadAction类中还提供了两个实现StreamInfo的内类:FileStreamInfo和ResourceStreamInfo。这两个类的构造方法的定义如下:
public
FileStreamInfo(String contentType, File file);
public ResourceStreamInfo(String contentType, ServletContext context, String path);
public ResourceStreamInfo(String contentType, ServletContext context, String path);
我们可以使用FileStreamInfo
类来下载静态的文件。如果要下载的文件在Web
根目录,可以使用ResourceStreamInfo
类。其中path
参数表示文件相对于Web
根目录的路径,必须以“/
”开头,表示从Web
根目录开始。
二、实例:统计文件的下载次数
在本节中将使用DownloadAction 类实现一个统计文件下载次数的Web 程序。这个程序的基本原理是当一个文件下载完成后,加这个文件在数据库中的下载次数加1 ,如果某个文件是第一次下载,则在数据库中添加一条新记录,下载次数为1 。
二、实例:统计文件的下载次数
在本节中将使用DownloadAction 类实现一个统计文件下载次数的Web 程序。这个程序的基本原理是当一个文件下载完成后,加这个文件在数据库中的下载次数加1 ,如果某个文件是第一次下载,则在数据库中添加一条新记录,下载次数为1 。
为了实现这个Web程序,需要如下几步:
【第 1 步】 建立用于保存文件下载次数的数据表
在本例中我们使用名为struts数据库,并且在struts数据库中建立一个t_dcount表,代码如下:
【第 1 步】 建立用于保存文件下载次数的数据表
在本例中我们使用名为struts数据库,并且在struts数据库中建立一个t_dcount表,代码如下:
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;
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文件,代码如下:
在<samples工程目录>\src\action目录中建立一个FileDownloadAction.java文件,代码如下:
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 Connection conn;
private String path;
private String filename;
// 获得了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();
PreparedStatement pstmt = conn
.prepareStatement( " SELECT count FROM t_dcount WHERE id = " + String.valueOf(id));
ResultSet rs = pstmt.executeQuery();
while (rs.next())
{
return rs.getInt( 1 );
}
return 0 ;
}
// 在文件完成下载后,将该文件的下载次数加1
private void incDownloadCount() throws Exception
{
openConnection();
int id = filename.hashCode();
PreparedStatement pstmt = conn
.prepareStatement( " UPDATE t_dcount SET count = count + 1 WHERE id = "
+ String.valueOf(id));
if (pstmt.executeUpdate() == 0 )
{
pstmt.executeUpdate( " INSERT INTO t_dcount(id, count, filename) values( "
+ String.valueOf(id) + " ,1,' " + filename + " ') " );
}
}
// 下载文件时调用getStreamInfo方法
protected StreamInfo getStreamInfo(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
final FileInputStream fis = new FileInputStream(path + filename);
final String contentType = " application/file " ;
// 建议设置content-disposition响应信息头,否则Web浏览器在下载文件时
// 无法在保存文件对话框中显示正确的文件名
response.setHeader( " content-disposition " , " attachment; filename= "
+ filename);
incDownloadCount();
return new DownloadAction.StreamInfo() // 使用隐式的方法实现了StreamInfo接口
{
public String getContentType()
{
return contentType;
}
public InputStream getInputStream() throws IOException
{
return fis;
}
};
}
// 如果Struts动作不加file请求参数,则通过execute方法将指定目录中文件列表输出到客户端
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
path = this .getServlet().getInitParameter( " downloadPath " );
filename = request.getParameter( " file " );
if (filename == null )
{
File file = new File(path);
File[] files = file.listFiles();
response.setCharacterEncoding( " GBK " );
PrintWriter out = response.getWriter();
out.println( " <ul> " );
for (File f : files) // 开始向客户端浏览器输出文件列表
{
if (f.isFile() && ! f.isHidden())
{
out.println( " <li><a href=' " + request.getContextPath() + mapping.getPath()
+ " .do?file= " + f.getName() + " '> " + f.getName()
+ " </a> <font color='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);
}
}
}
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 Connection conn;
private String path;
private String filename;
// 获得了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();
PreparedStatement pstmt = conn
.prepareStatement( " SELECT count FROM t_dcount WHERE id = " + String.valueOf(id));
ResultSet rs = pstmt.executeQuery();
while (rs.next())
{
return rs.getInt( 1 );
}
return 0 ;
}
// 在文件完成下载后,将该文件的下载次数加1
private void incDownloadCount() throws Exception
{
openConnection();
int id = filename.hashCode();
PreparedStatement pstmt = conn
.prepareStatement( " UPDATE t_dcount SET count = count + 1 WHERE id = "
+ String.valueOf(id));
if (pstmt.executeUpdate() == 0 )
{
pstmt.executeUpdate( " INSERT INTO t_dcount(id, count, filename) values( "
+ String.valueOf(id) + " ,1,' " + filename + " ') " );
}
}
// 下载文件时调用getStreamInfo方法
protected StreamInfo getStreamInfo(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
final FileInputStream fis = new FileInputStream(path + filename);
final String contentType = " application/file " ;
// 建议设置content-disposition响应信息头,否则Web浏览器在下载文件时
// 无法在保存文件对话框中显示正确的文件名
response.setHeader( " content-disposition " , " attachment; filename= "
+ filename);
incDownloadCount();
return new DownloadAction.StreamInfo() // 使用隐式的方法实现了StreamInfo接口
{
public String getContentType()
{
return contentType;
}
public InputStream getInputStream() throws IOException
{
return fis;
}
};
}
// 如果Struts动作不加file请求参数,则通过execute方法将指定目录中文件列表输出到客户端
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
path = this .getServlet().getInitParameter( " downloadPath " );
filename = request.getParameter( " file " );
if (filename == null )
{
File file = new File(path);
File[] files = file.listFiles();
response.setCharacterEncoding( " GBK " );
PrintWriter out = response.getWriter();
out.println( " <ul> " );
for (File f : files) // 开始向客户端浏览器输出文件列表
{
if (f.isFile() && ! f.isHidden())
{
out.println( " <li><a href=' " + request.getContextPath() + mapping.getPath()
+ " .do?file= " + f.getName() + " '> " + f.getName()
+ " </a> <font color='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>标签中加入了如下内容:
在struts-config.xml文件中的<action-mappings>标签中加入了如下内容:
<
action
path
="/download"
scope
="request"
type
="action.FileDownloadAction"
/>
【第4步】
配置下载路径
在web.xml中找到一个叫action的Servlet,并在<servlet>标签中添加如下内容:
在web.xml中找到一个叫action的Servlet,并在<servlet>标签中添加如下内容:
<
init-param
>
< param-name > downloadPath </ param-name >
< param-value > D:\download\ </ param-value >
</ init-param >
< param-name > downloadPath </ param-name >
< param-value > D:\download\ </ param-value >
</ init-param >
读取可以设置自已的下载目录,但下载目录必须以“"
”结尾。
启动Tomcat 后,在IE 中输入如下的URL 来测试程序:
http://localhost:8080/samples/download.do
启动Tomcat 后,在IE 中输入如下的URL 来测试程序:
http://localhost:8080/samples/download.do
本文转自 androidguy 51CTO博客,原文链接:http://blog.51cto.com/androidguy/214854,如需转载请自行联系原作者