使用Struts 2控制文件下載
一般來說,文件下載只需要直接在頁面給出一個超級鏈接,該鏈接的href屬性值等于要下載文件的文件名,就可以實現文件下載,如:<a href=”checkbox.rar”>checkbox.rar</a>。但是這樣下載存在著一些缺陷:如果該文件的文件名是中文文件名時,下載則會導致下載失敗;如果在下載時需要對用戶的身份進行判斷,來驗證用戶是否有權限來下載該文件時,那么單獨的超級鏈接是不可能實現的。這個時候,我們需要用Struts 2來控制文件下載。</span> Struts 2提供了stream結果類型,該結果類型就是專門用于支持文件下載功能的。通過Struts 2的文件下載支持,允許系統控制瀏覽者下載文件的權限,實現文件名是非西歐字符的文件下載。
首先介紹利用Struts 2實現簡單的文件下載:
public class FileDownloadAction implements Action {
public InputStream getInputStream() throws Exception {
return new ByteArrayInputStream("Struts 2 下載示例".getBytes());
}
public String execute() throws Exception {
return SUCCESS;
}
}
該類只是一個簡單的Action處理類。它提供了一個返回inputStream輸入流的方法。該輸入流代表了下載文件的入口。這個方法用來給被下載的數據提供輸入流。
一、利用Struts 2實現文件名非西歐字符文件下載
有如下一個下載頁面代碼:
<a href="download1.action?image/美女_01.jpg" >下載圖片</a> <a href="download2.action?image/meinv_01.rar">下載壓縮文件</a>
上面頁面中包含了兩個下載的鏈接。但是第一個鏈接資源的文件名為中文,這時如果我們單擊第一個超級練級,將會出現如下頁面:

從上面的頁面中我們可以看到大量的%字符,很明顯,這種文件名師不能夠實現下載的。這時我們可以使用Struts 2的文件下載支持來下載該文件。
1、實現文件下載的Action
Struts 2的文件下載Action需要提供一個返回InputStream流的方法。
代碼如下:
public class FileDownloadAction extends ActionSupport{
//該屬性可以在配置文件中動態指定該屬性值
private String inputPath;
public void setInputPath(String inputPath) {
this.inputPath = inputPath;
}
/*定義一個返回inputStream的方法
* 該方法將作為下載文件的入口,且需要配置stream類型結果是指定inputName參數
* inputName參數的值就是方法去掉get前綴、首字母小寫的字符串
*/
public InputStream getTargetFile() throws Exception{
//servletContext提供getResourceAsStream()方法
//返回指定文件對應的輸入流
return ServletActionContext.getServletContext().getResourceAsStream(inputPath);
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
} 上面的Action中包含了一個getTargetFile()方法,該方法返回一個InputStream輸入流。這個輸入流返回的是下載目標文件的入口。該方法的方法名為getTargetFile,則stream類型的結果映射中inputName參數值是targetFile.
注:返回InputStream的方法需要配置Stream類型結果時指定inputName參數;該參數值就是方法嗎去掉get前綴,首字母小寫的字符串。
2、配置Action
配置文件下載的Action關鍵是需要配置一個類型為stream的結果,該stream類型的結果將使用文件下載作為響應。配置時需要指定以下四個屬性

由于Stream結果類型的邏輯試圖是返回給客服端一個輸入流,因此不需要指定location屬性。
配置如下:
<action name="download1" class="com.app.action.FileDownloadAction">
<!-- 指定被下載資源的位置 -->
<param name="inputPath">\image\美女_01.jpg</param>
<!-- 配置結果類型為stream的結果 -->
<result name="success" type="stream">
<!-- 指定下載文件的文件類型 -->
<param name="contentType">image/jpg</param>
<!-- 指定由getTargetFile()方法返回被下載文件的inputStream -->
<param name="inputName">targetFile</param>
<param name="contentDisposition">attachment;filename="meinv1_01.jpg"</param>
<!-- 指定下載文件的緩沖大小 -->
<param name="bufferSize">4096</param>
</result>
</action> 通過上面的配置后,就可以實現包含中文文件名的文件下載了。如果在點擊就可以實現下載了。如下:

二、下載前的授權控制
有時用戶下載文件之前,我們需要對用戶的身份進行驗證,判斷用戶是否具有權限來下載該文件。這時我們通過Struts 2 的文件下載支持,就可以實現下載前的授權控制。
下面的Action,首先通過判斷session里面的user屬性是否為chenssy,如果用戶通過了驗證就允許下載,否則直接返回登錄界面。
代碼如下:
public class AuthorityDownAction implements Action {
private String inputPath;
public void setInputPath(String inputPath) {
this.inputPath = inputPath;
}
public InputStream getTargetFile() throws Exception{
//ServletContext提供了getResourceAsStream()方法
return ServletActionContext.getServletContext().getResourceAsStream(inputPath);
}
public String execute() throws Exception {
//取得ActionContext實例
ActionContext ctx = ActionContext.getContext();
//通過ActionContext訪問用戶的HttpSession
Map session = ctx.getSession();
String user = (String) session.get("user");
//判斷session里的user是否通過檢查
if(user!=null&&user.equals("chenssy")){
return SUCCESS;
}
ctx.put("tip", "您還沒有登錄,或者登錄的用戶名不正確,請重新登錄!!!");
return LOGIN;
}
} 上面的Action在校驗失敗后,會返回一個login邏輯視圖名,所以在配置該Action時,還需要配置一個名為login的結果。
<action name="download2" class="com.app.action.AuthorityDownAction">
<!-- 定義被下載文件的物理資源 -->
<param name="inputPath">\image\meinv_01.rar</param>
<result name="success" type="stream">
<!-- 指定下載文件的文件類型 -->
<param name="contentType">application/rar</param>
<!-- 指定由getTargetFile()方法返回被下載文件的InputStream -->
<param name="inputName">targetFile</param>
<param name="contentDisposition">filename="meinv_01.rar"</param>
<!-- 指定下載文件的緩沖大小 -->
<param name="bufferSize">4096</param>
</result>
<result name="login">/login.jsp</result>
</action> 通過上面的配置后,就可以實現用戶的授權控制。如果用戶不登錄、或者用戶名不正確,在下載該資源時,就會返回到登錄界面。
如下:

對于處理登錄請求的Action如下:
public class LoginAction extends ActionSupport {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String execute() throws Exception {
return SUCCESS;
}
} 對于該Action,它只是一個簡單的處理類。它的execute方法沒有進行任何處理,直接返回success,表示任何用戶名都可以登錄成功,進入到下載界面,但是從AuthorityDownAction 處理類中可以看到只有用戶名為chengssy的用戶可以下載成功。其他任何用戶下載該資源都不會成功。
如果登錄成功了,需要返回到下載頁面,所以該Action的配置如下:
<action name="login" class="com.app.action.LoginAction">
<result name="success">/download.jsp</result>
</action> 通過上面的一些配置后,用戶再輸入"chengssy",一旦完成了登錄,用戶的session里username的值就會是:chenssy,這時就可以完成文件的下載了。
讀李剛《輕量級Java EE企業應用實戰》