天天看點

Struts1.x系列教程(15):使用DownloadAction類統計檔案下載下傳次數

本文為原創,如需轉載,請注明作者和出處,謝謝!

    除了标準的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>  <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>