struts2 文件上傳與下載原理

文件上傳的原理:

  表單元素的enctype屬性指定的是表單數據的編碼方式,該屬性有3個值:
  1) application/x-www-form-urlencoded:這是默認編碼方式,它只處理表單域裏的value屬性值,採用這種編碼方式的表單會將表單域的
值處理成URL編碼方式。
  2) multipart/form-data:這種編碼方式的表單會以二進制流的方式來處理表單數據,這種編碼方式會把文件域指定文件的內容也封裝到
請求參數裏。
  3) text/plain:這種方式主要適用於直接通過表單發送郵件的方式。
  文件上傳是web應用經常用到的一個知識。原理是,通過爲表單元素設置enctype=”multipart/form-data”屬性,讓表單提交的數據以二
進制編碼的方式提交,在接收此請求的Servlet中用二進制流來獲取內容,就可以取得上傳文件的內容,從而實現文件的上傳。
  在Java領域中,有兩個常用的文件上傳項目:一個是Apache組織Jakarta的Common-FileUpload組件
([url]http://commons.apache.org/fileupload/[/url]),另一個是Oreilly組織的COS框架([url]http://www.servlets.com/cos/[/url])。利用這兩個框架都能很方便
的實現文件的上傳。

==================================
Struts2上傳文件

增加commons-fileupload-1.2.jar和commons-io-1.3.1.jar到lib
=====
jsp
=====
form 的 enctype 設置爲 multipart/form-data
==============
UploadAction
==============
private String username;
private String password;
private File file; // 對應文件域
private String fileFileName; // 前面的File屬性的名字 + FileName(固定的)
private String fileContent; // 前面的File屬性的名字 + Content
// setter... getter...
String execute() throws Exception {
InputStream is = new FileInputStream( file );
String root = ServletActionContext.getRequest().getRealPath("/upload");
File destFile = new File(root,this.getFileFileName());
OutputStream os = new FileOutputStream( destFile );
byte[] buffer = new byte[400];
int length = 0;
while( (length = is.read(buffer)) > 0 ) {
os.write(buffer,0,length);
}
is.close();
os.close();
return SUCCESS;
}
=================
中文問題
=================
不過我全部用UTF-8並未遇到中文問題
struts2-core包
struts-default.xml ----攔截器的設置
org.apache.struts2.default.properties ----全局屬性的設置
33行 strusts.i18n.encoding=UTF-8 默認UTF-8
可以在struts.xml下進行設置
<struts>
設置字符集
<constant name="struts.i18n.encoding" value="gbk"/>
設置上傳文件緩存
<constant name="struts.multipart.saveDir" value="c:/"/> 
</struts>
其他屬性
struts.multipart.parser=jakarta struts2採用那種方式上傳
pell
cos
struts.multipart.maxSize=2097152 默認上傳文件最大的請求大小2M
struts.action.extension=action 整個url的後綴名

================
上傳多個文件
================
有兩種方式:
1.數組
File[] file 文件
String[] fileFileName 文件名
String[] fileContentType 文件類型
2.集合
List<File> file 
List<String> fileFileName
List<String> fileContentType
--------
action中:
--------

String execute() {
for(int i = 0; i < file.size(); i++) {
InputStream is = new FileInputStream(file.get(i));
String root = ServletActionContext.getRequest().getRealPath("/upload");
File destFile = new File(root,this.getFileFileName().get(i)); 
... 
}
return SUCCESS;
}
------
jsp中:
------

多個file時,file的名字要一致,都要叫file,它會自動set到跟file名對應的List中去
<s:file name="file" />
<s:file name="file" />
<s:file name="file" />

========================
上傳任意個文件
========================
<td id="more">
<input type="button" value="添加" />
</td>
------
JS:
------

funcation addMore() {
var td = document.getElementById("more");
//生成一個換行符
var br = document.createElement("br");
//創建一個input組件
var input = document.createElement("input");
var button = document.createElement("input");
//指定類型 爲 file 爲文件上傳
input.type = "file";
//指定組件的名字
input.name = "file";
button.type = "button";
button.value = "刪除";
//爲刪除按鈕註冊一個事件 
button.onclick = function() {
//alert("刪除按鈕");
//刪除一行
td.removeChild(br);
td.removeChild(input);
td.removeChild(button);
}
//將創建的組件加到<td>中
td.appendChild(br);
td.appendChild(input);
td.appendChild(button);
}
=======================
限制上傳類型
=======================
org.apache.struts2.interceptor.FileUploadInterceptor類
Long maximumSize:最大上傳大小---每一個文件的大小,不是總和
String allowedTypes:允許的類型
-------------
struts.xml
-------------

<struts>
<action ...>
<result name="input">/upload.jsp</result>
<result .../>

加入一個上傳文件的攔截器並設置其屬性
<interceptor-ref name="fileUpload">

<param name="maximumSize">409600</param> 單個上傳文件最大不能超過400K
<param name="allowedTypes">...</param> mime類型,多個用逗號分開

</interceptor-ref>
** 加入默認的攔截器
<interceptor-ref name="defaultStack" />
</action> 
</struts>
注:後綴可以到tomcat/conf/web.xml中找<mime-type>中的字符串
--------------
upload.jsp
--------------
添加<s:fielderror />
----------------------
更改顯示的錯誤信息
----------------------
org.apache.struts2中 找到struts-messages.properties
-----------------------
上傳文件類型不匹配
struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" {2}
-----------------------
上傳文件大小超出規定
struts.messages.error.file.too.large=File too large: {0} "{1}" {2}
-----------------------
上傳文件出錯
struts.messages.error.uploading=Error uploading: {0}
創建一個全局的屬性文件 /src/messages.properties
struts.messages.error.content.type.not.allowed=不支持上傳該類型的文件
struts.messages.error.file.too.large=上傳文件過大,請重試
struts.messages.error.uploading=上傳文件時發生錯誤
---------
國際化
---------

<constant name="struts.custom.i18n.resources" value="messages"/>
messages_en_US.properties
messages_zh_CN.properties

==============================
下載
==============================
處理下載的類:org.apache.struts2.dispatcher.StreamResult
== 屬性 ==
String contentType = "text/plain"; 
String contentLength;
String contentDisposition = "inline"; 
String inputName = "inputStream"; 
InputStream inputStream
int bufferSize = 1024;
== 說明 ==
contentType
內容類型,和互聯網MIME標準中的規定類型一致,例如text/plain代表純文本,text/xml表示XML,image/gif代表GIF圖片,image/jpeg代表JPG圖片
用來做動態文件下載的,事先並不知道未來的文件類型是什麼,那麼我們可以把它的值設置成爲:application/octet-stream;charset=ISO8859-1 ,注意一定要加入charset,否則某些時候會導致下載的文件出錯
inputName
下載文件的來源流,對應着action類中某個類型爲Inputstream的屬性名,例如取值爲inputStream的屬性需要編寫getInputStream()方法
contentDisposition
文件下載的處理方式,包括內聯(inline)和附件(attachment)兩種方式,而附件方式會彈出文件保存對話框,否則瀏覽器會嘗試直接顯示文件。取值爲:attachment;filename="struts2.txt",表示文件下載的時候保存的名字應爲struts2.txt。如果直接寫filename="struts2.txt",那麼默認情況是代表inline,瀏覽器會嘗試自動打開它,等價於這樣的寫法:inline; filename="struts2.txt"
bufferSize
下載緩衝區的大小
# contentType屬性和contentDisposition分別對應着HTTP響應中的頭Content-Type和Content-disposition頭。
如:
HTTP頭內容:
HTTP/1.1 200 OK 
Server: Apache-Coyote/1.1 
Content-disposition: attachment;filename="struts2.txt" 
Content-Type: text/plain 
Transfer-Encoding: chunked 
Date: Sun, 02 Mar 2008 02:58:25 GMT
----------
action
----------

Class DownloadAction extends ActionSupport {
private String path;
// setter... getter...
//必須返回一個輸入流,該流是讓用戶下載的
public InputStream getDownloadFile() {

//從某個文件獲得流 --這裏是獲得項目root下upload下的文件
//也可以 new FileInputStream("c:/test.text");
return ServletActionContext.getServletContext().getResourceAsStream("/upload/struts2.ppt");

}
public String execute() throws Exception {
return SUCCESS;
}
}
-----------
struts.xml
-----------

<action name="download" class="org.scorpio.jh.struts2.upload.action.DownloadAction">

<!-- 依賴注入文件路徑 -->
<param name="path">/download/xhtml.txt</param>

<!-- 設置結果類型爲 流 -->
<result name="success" type="stream">

<!-- 設置內容類型 -->
<param name="contentType">text/plain</param>

<!-- 設置下載文件的名字 attachment:作爲附件,filename=:指定下載文件名-->
<param name="contentDisposition">attachment;filename="xhtml.txt"</param>

<!-- 設置下載文件的輸入流對應的方法 downloadFile對應DownloadAction中的getDownloadFile()-->
<param name="inputName">downloadFile</param>

<!-- 指定下載文件的緩衝大小 -->
<param name="bufferSize">4096</param>
</result>
</action>
==========================
解決下載文件名中文問題
==========================
1.在下載action獲取文件名的方法中先進行轉碼然後再返回
path = new String( path.getBytes(), "ISO-8859-1" );

2.xml配置文件動態的獲取path的值
<param name="contentDisposition">attachment;filename="${path}"</param>

${path} 用於動態的獲取所配置的action中path成員的值,相當於調用getPath()方法

3. /*解決中文亂碼問題,設置後產生一個新的String對象此對象以改變了編碼*/
         String newpath
=URLEncoder.encode(path,"utf-8");

-------
action
-------
private String path;

public String getPath() {

try { //轉換成西歐字符集
path = new String( path.getBytes(), "ISO-8859-1" );
} catch (UnsupportedEncodingException e) {
e.printStackTrace();


return path;
}
public void setPath(String path) {
this.path = path;
}
---------------
struts.xml
---------------
<action name="download" class="org.scorpio.jh.struts2.upload.action.DownloadAction">

<param name="path">/download/wmlscript實例.txt</param>
<result name="success" type="stream">
<param name="contentType">text/plain</param>
<!-- 動態的獲取 DownloadAction的path屬性 -->
<param name="contentDisposition">attachment;filename="${path}"</param>
<param name="inputName">downloadFile</param>
<param name="bufferSize">4096</param>
</result>
</action>
=================
安全隱患
=================
訪問者如果精通Struts 2的話,它可能使用這樣的帶有表單參數的地址來訪問:
[url]http://localhost:8080/struts2hello/download3.action?inputPath=/WEB-INF/web.xml[/url],這樣的結果就是下載後的文件內容是您系統裏面的web.xml的文件的源代碼,甚至還可以用這種方式來下載任何其它JSP文件的源碼。這對系統安全是個很大的威脅。作爲一種變通的方法,讀者最好是從數據庫中進行路徑配置,然後把Action類中的設置inputPath的方法統統去掉,簡言之就是刪除這個方法定義:
public void setPath(String path) {
this.path = path;
}
而實際情況則應該成爲 download.action?fileid=1 類似於這樣的形式來進行。或者呢,讀者可以在execute()方法中進行路徑檢查,如果發現有訪問不屬於download下面文件的代碼,就一律拒絕,不給他們返回文件內容。例如,我們可以把剛纔類中的execute()方法加以改進,成爲這樣:
public String execute() throws Exception {
// 文件下載目錄路徑
String downloadDir = ServletActionContext.getServletContext().getRealPath("/download");
// 文件下載路徑
String downloadFile = ServletActionContext.getServletContext().getRealPath(inputPath);
java.io.File file = new java.io.File(downloadFile);
downloadFile = file.getCanonicalPath();// 真實文件路徑,去掉裏面的..等信息
// 發現企圖下載不在 /download 下的文件, 就顯示空內容
if(!downloadFile.startsWith(downloadDir)) {
return null;
}
return SUCCESS;
}
這時候如果訪問者再企圖下載web.xml的內容,它只能得到一個空白頁,現在訪問者只能下載位於/download目錄下的文件
其他的一些資料:
Struts 2中實現文件上傳
Struts 2中實現文件下載(修正中文問題)

附:contentType類型.
'ez' => 'application/andrew-inset', 
'hqx' => 'application/mac-binhex40', 
'cpt' => 'application/mac-compactpro', 
'doc' => 'application/msword', 
'bin' => 'application/octet-stream', 
'dms' => 'application/octet-stream', 
'lha' => 'application/octet-stream', 
'lzh' => 'application/octet-stream', 
'exe' => 'application/octet-stream', 
'class' => 'application/octet-stream', 
'so' => 'application/octet-stream', 
'dll' => 'application/octet-stream', 
'oda' => 'application/oda', 
'pdf' => 'application/pdf', 
'ai' => 'application/postscript', 
'eps' => 'application/postscript', 
'ps' => 'application/postscript', 
'smi' => 'application/smil', 
'smil' => 'application/smil', 
'mif' => 'application/vnd.mif', 
'xls' => 'application/vnd.ms-excel', 
'ppt' => 'application/vnd.ms-powerpoint', 
'wbxml' => 'application/vnd.wap.wbxml', 
'wmlc' => 'application/vnd.wap.wmlc', 
'wmlsc' => 'application/vnd.wap.wmlscriptc', 
'bcpio' => 'application/x-bcpio', 
'vcd' => 'application/x-cdlink', 
'pgn' => 'application/x-chess-pgn', 
'cpio' => 'application/x-cpio', 
'csh' => 'application/x-csh', 
'dcr' => 'application/x-director', 
'dir' => 'application/x-director', 
'dxr' => 'application/x-director', 
'dvi' => 'application/x-dvi', 
'spl' => 'application/x-futuresplash', 
'gtar' => 'application/x-gtar', 
'hdf' => 'application/x-hdf', 
'js' => 'application/x-javas

cript', 
'skp' => 'application/x-koan', 
'skd' => 'application/x-koan', 
'skt' => 'application/x-koan', 
'skm' => 'application/x-koan', 
'latex' => 'application/x-latex', 
'nc' => 'application/x-netcdf', 
'cdf' => 'application/x-netcdf', 
'sh' => 'application/x-sh', 
'shar' => 'application/x-shar', 
'swf' => 'application/x-shockwave-flash', 
'sit' => 'application/x-stuffit', 
'sv4cpio' => 'application/x-sv4cpio', 
'sv4crc' => 'application/x-sv4crc', 
'tar' => 'application/x-tar', 
'tcl' => 'application/x-tcl', 
'tex' => 'application/x-tex', 
'texinfo' => 'application/x-texinfo', 
'texi' => 'application/x-texinfo', 
't' => 'application/x-troff', 
'tr' => 'application/x-troff', 
'roff' => 'application/x-troff', 
'man' => 'application/x-troff-man', 
'me' => 'application/x-troff-me', 
'ms' => 'application/x-troff-ms', 
'ustar' => 'application/x-ustar', 
'src' => 'application/x-wais-source', 
'xhtml' => 'application/xhtml+xml', 
'xht' => 'application/xhtml+xml', 
'zip' => 'application/zip', 
'au' => 'audio/basic', 
'snd' => 'audio/basic', 
'mid' => 'audio/midi', 
'midi' => 'audio/midi', 
'kar' => 'audio/midi', 
'mpga' => 'audio/mpeg', 
'mp2' => 'audio/mpeg', 
'mp3' => 'audio/mpeg', 
'aif' => 'audio/x-aiff', 
'aiff' => 'audio/x-aiff', 
'aifc' => 'audio/x-aiff', 
'm3u' => 'audio/x-mpegurl', 
'ram' => 'audio/x-pn-realaudio', 
'rm' => 'audio/x-pn-realaudio', 
'rpm' => 'audio/x-pn-realaudio-plugin', 
'ra' => 'audio/x-realaudio', 
'wav' => 'audio/x-wav', 
'pdb' => 'chemical/x-pdb', 
'xyz' => 'chemical/x-xyz', 
'bmp' => 'image/bmp', 
'gif' => 'image/gif', 
'ief' => 'image/ief', 
'jpeg' => 'image/jpeg', 
'jpg' => 'image/jpeg', 
'jpe' => 'image/jpeg', 
'png' => 'image/png', 
'tiff' => 'image/tiff', 
'tif' => 'image/tiff', 
'djvu' => 'image/vnd.djvu', 
'djv' => 'image/vnd.djvu', 
'wbmp' => 'image/vnd.wap.wbmp', 
'ras' => 'image/x-cmu-raster', 
'pnm' => 'image/x-portable-anymap', 
'pbm' => 'image/x-portable-bitmap', 
'pgm' => 'image/x-portable-graymap', 
'ppm' => 'image/x-portable-pixmap', 
'rgb' => 'image/x-rgb', 
'xbm' => 'image/x-xbitmap', 
'xpm' => 'image/x-xpixmap', 
'xwd' => 'image/x-xwindowdump', 
'igs' => 'model/iges', 
'iges' => 'model/iges', 
'msh' => 'model/mesh', 
'mesh' => 'model/mesh', 
'silo' => 'model/mesh', 
'wrl' => 'model/vrml', 
'vrml' => 'model/vrml', 
'css' => 'text/css', 
'html' => 'text/html', 
'htm' => 'text/html', 
'asc' => 'text/plain', 
'txt' => 'text/plain', 
'rtx' => 'text/richtext', 
'rtf' => 'text/rtf', 
'sgml' => 'text/sgml', 
'sgm' => 'text/sgml', 
'tsv' => 'text/tab-separated-values', 
'wml' => 'text/vnd.wap.wml', 
'wmls' => 'text/vnd.wap.wmlscript', 
'etx' => 'text/x-setext', 
'xsl' => 'text/xml', 
'xml' => 'text/xml', 
'mpeg' => 'video/mpeg', 
'mpg' => 'video/mpeg', 
'mpe' => 'video/mpeg', 
'qt' => 'video/quicktime', 
'mov' => 'video/quicktime', 
'mxu' => 'video/vnd.mpegurl', 
'avi' => 'video/x-msvideo', 
'movie' => 'video/x-sgi-movie', 
'ice' => 'x-conference/x-cooltalk'

發佈了18 篇原創文章 · 獲贊 112 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章