關於Struts2的文件下載


首先先來說下關於文件下載的原理:

服務端為客戶端提供了一個下載服務,所以服務端需要一個輸出流(把客戶請求下載的文件輸出),相對於服務端來說,客戶端需要下載接收一個文件,所以它需要一個輸入流(接收文件)。

服務器讀取要下載文件的內容,用一個Response響應流寫回並設置HTTP頭信息ContentType(文件類型)、 ContentDisposition(以什么方式打開)

下面給出一個小Demo,具體代碼具體分析吧

 

1、首先是提供下載的頁面:download.jsp

給出超鏈接到Action並用Get方式傳遞一個文件名進行屬性注入

 1 <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
 2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 3 <html>
 4 <head>
 5 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 6 <title>下載文件示例</title>
 7 </head>
 8 <body>
 9 <h2>下載文件</h2>
10 <a href="download.action?filename=照片文件.jpg">點擊下載照片文件</a>
11 <a href="download.action?filename=admin.rar">點擊下載壓縮包文件</a>
12 <a href="download.action?filename=總結.txt">點擊下載文本文件</a>
13 </body>
14 </html>

 

2、處理下載文件的Action:DowloadAction.java

這里提供了一個成員變量屬性來接收頁面傳遞過來的文件名,由於文件名是以Get方式傳遞過來的,中文會出現亂碼問題,所以在setter方法里需要做一些處理,也就是重新編碼。

 1 package com.lcw.struts2.dowload;
 2 
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.io.FileNotFoundException;
 6 import java.io.IOException;
 7 import java.io.InputStream;
 8 import java.io.UnsupportedEncodingException;
 9 import java.net.URLEncoder;
10 
11 import org.apache.struts2.ServletActionContext;
12 
13 import sun.misc.BASE64Encoder;
14 
15 import com.opensymphony.xwork2.ActionSupport;
16 /**
17  * 對於客戶端來說它需要下載接收一個文件,也就是說它需要一個輸入流
18  * 對於服務端來說它需要對外提供一個下載的服務,也就是說它需要一個輸出流
19  */
20 
21 public class DowloadAction extends ActionSupport {
22 
23     private String filename;//下載頁面傳遞了該參數,需提供setter方法接收
24 
25     public void setFilename(String filename) {
26         //由於是get方式傳遞的,中文會出現亂碼,不能直接獲取,需轉碼
27         try {
28             this.filename = new String(filename.getBytes("ISO-8859-1"),"utf-8");
29         } catch (UnsupportedEncodingException e) {
30             e.printStackTrace();
31         }
32     }
33     
34     public String execute(){
35         System.out.println("正在下載文件:"+filename);
36         return SUCCESS;
37     }
38     
39     //為客戶端提供輸入流
40     public InputStream getInputStream() throws FileNotFoundException{
41         String srcFile=ServletActionContext.getServletContext().getRealPath("/download")+"/"+filename;
42         File file=new File(srcFile);//得到一個file對象
43         return new FileInputStream(file);//返回一個文件輸入流
44     }
45     
46     //根據不同的文件動態給出MIME文件類型
47     public String getContentType(){
48         //在Tomcat Conf里的web.xml有對應的映射文件
49         return ServletActionContext.getServletContext().getMimeType(filename);
50     }
51     
52     //返回一個文件名
53     public String getFilename() throws IOException{
54         String agent=ServletActionContext.getRequest().getHeader("user-agent");//根據http頭信息獲取對應的瀏覽器類型
55         return encodeDownloadFilename(filename,agent);
56     }
57     
58     
59     //下載附件名亂碼問題 , IE和火狐 解決不同   IE默認是Url編碼 火狐默認是base64編碼
60     public String encodeDownloadFilename(String filename, String agent)
61             throws IOException {
62         if (agent.contains("Firefox")) { // 火狐瀏覽器
63             filename = "=?UTF-8?B?"
64                     + new BASE64Encoder().encode(filename.getBytes("utf-8"))
65                     + "?=";
66         } else { // IE及其他瀏覽器
67             filename = URLEncoder.encode(filename, "utf-8");
68         }
69         return filename;
70     }
71 }

看了上面的代碼,如果不清楚這塊知識點的朋友可能會有點蒙,別急,下面我來解析下這段代碼是怎么來的

首先Struts2的文件下載是通過一個結果集stream來完成的,在Struts2核心包里的struts-default.xml里我們可以找到這樣的一句話:

<result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>

我們來看下這個類(org.apache.struts2.dispatcher.StreamResult)里面有什么,Ctrl+Shift+T關聯下源代碼

這個類里面給出了很多參數,因為都有默認值,所以我們不需要全部到去改動它,只需要改變我們需要的地方就可以了。

這里來解釋下上面畫紅色框的參數內容:contentType,contentDisposition,inputName

contetType:是下載文件對應的MIME協議類型,比如:text/html,text/plain等,這個參數我們不能寫死,因為我們的下載文件的類型有很多,有時是圖片,有時是文檔等。

contentDisposition:是下載文件的打開方式,這里默認是inline也就是內聯在瀏覽器打開,如果不想關聯瀏覽器我們可以把它設置成attment以附件的形式打開。

inputNmae:這是定義一個返回流(客戶端需要的輸入流)的名稱,屬性值為inputStream。

 

所以我們需要在Action里面提供這些東西,利用JAVA的反射機制讓Struts2的配置文件(壓入值棧,並給出getter方法)讀取到就行了。

這里我們的下載附件名依舊會亂碼,因為IE等瀏覽器默認的編碼是URL而火狐瀏覽器默認的編碼是BASE64,我們需要在這里判斷客戶端使用的是什么瀏覽器,這個很簡單,只需要得到客戶端的HTTP頭信息Agment就行了,具體代碼在上面encodeDownloadFilename方法里以給出,拿來用便是了。

 

3、再來看下配置文件struts.xml的配置:

由於Action里已給出我們所需參數的getter方法,我們在這邊這需要用Ognl表達式取出,就可以根據我們要下載的文件,動態給出所需參數了,沒有設置的參數就意味着保持默認值。

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE struts PUBLIC
 3     "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
 4     "http://struts.apache.org/dtds/struts-2.0.dtd">
 5 <struts>
 6     <constant name="struts.devMode" value="true" />
 7     
 8     <!-- 全局國際化配置 -->
 9     <constant name="struts.custom.i18n.resources" value="messages"></constant>
10 
11     <package name="struts2test" extends="struts-default">
12         <action name="download" class="com.lcw.struts2.dowload.DowloadAction">
13             <result type="stream">
14                 <!-- 一個流二個頭 -->
15                 <!-- ognl表達式,動態給出不同下載文件相相對應的MIME協議規定的類型 比如:text/html-->
16                 <!-- 在Action里給出getContentType壓棧 -->
17                     <param name="contentType">${contentType}</param>
18                 <!-- 下載文件打開方式 inline瀏覽器內部打開, attachment 以附件形式打開 -->
19                 <!-- 在Action里動態返回文件名 getFilename -->
20                     <param name="contentDisposition">attachment;filename=${filename}</param>
21             </result>
22         </action>
23     </package>
24 
25 </struts>

 

然后我們新建一個文件夾download,把要下載的文件和web頁面提供的文件名一樣放入

到這里就大功告成了,看下頁面效果吧:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM