本文為原創,如需轉載,請注明作者和出處,謝謝!
除了标準的org.apache.struts.action.Action類外,在Struts中還提供了另外7個Action類來完成特殊的工作。本文及後面的文章中将介紹這些Action類的用法。
一、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;
getStreamInfo方法傳回一個StreamInfo對象。StreamInfo接口是DownloadAction類的一個内部接口,這個接口的定義如下:
public static interface StreamInfo
{
public abstract String getContentType();
public abstract InputStream getInputStream() throws IOException;
}
從上面的代碼可以看出,StreamInfo接口有兩個方法。其中getInputStream方法傳回了服務端要下載下傳的檔案的InputStream對象。getContenttType方法傳回了HTTP響應消息頭字段Content-Type的資訊。在getStreamInfo方法中隻要傳回了實作這兩個方法的StreamInfo對象,就可以自動完成下載下傳工作。
為了友善起見,DownloadAction類中還提供了兩個實作StreamInfo的内類:FileStreamInfo和ResourceStreamInfo。這兩個類的構造方法的定義如下:
public FileStreamInfo(String contentType, File file);
public ResourceStreamInfo(String contentType, ServletContext context, String path);
我們可以使用FileStreamInfo類來下載下傳靜态的檔案。如果要下載下傳的檔案在Web根目錄,可以使用ResourceStreamInfo類。其中path參數表示檔案相對于Web根目錄的路徑,必須以“/”開頭,表示從Web根目錄開始。
二、執行個體:統計檔案的下載下傳次數
在本節中将使用DownloadAction類實作一個統計檔案下載下傳次數的Web程式。這個程式的基本原理是當一個檔案下載下傳完成後,加這個檔案在資料庫中的下載下傳次數加1,如果某個檔案是第一次下載下傳,則在資料庫中添加一條新記錄,下載下傳次數為1。
為了實作這個Web程式,需要如下幾步:
【第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;
【第2步】編寫Struts動作類
這個Struts動作類負責完成檔案的下載下傳工作。如果在通路Struts動作類時不加file參數,會将指定目錄下的所有檔案(不包括隐藏檔案)和已經下載下傳的次數發送到用戶端浏覽器。如果通過file參數指定了下載下傳檔案,這個Struts動作就會下載下傳這個檔案。
在<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
int id = filename.hashCode();
.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,
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>&nbsp;&nbsp;<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>标簽中加入了如下内容:
<action path="/download" scope="request" type="action.FileDownloadAction" />
【第4步】配置下載下傳路徑
在web.xml中找到一個叫action的Servlet,并在<servlet>标簽中添加如下内容:
<init-param>
<param-name>downloadPath</param-name>
<param-value>D:/download/</param-value>
</init-param>
讀取可以設定自已的下載下傳目錄,但下載下傳目錄必須以“"”結尾。
啟動Tomcat後,在IE中輸入如下的URL來測試程式:
<a href="http://localhost:8080/samples/download.do">http://localhost:8080/samples/download.do</a>
<a href="http://www.eoeandroid.com/forumdisplay.php?fid=4">國内最棒的Google Android技術社群(eoeandroid),歡迎通路!</a>