struts2檔案的上傳與下載--超出指定檔案大小的校驗提示
在做B/S架構專案時,經常會遇到檔案上傳與下載的需求,在struts2框架中幫我們實現的檔案上傳與下載機制,能夠很好地實現專案需求。在使用的時候,需要匯入檔案上傳與下載需要的兩個jar,一個是commons-fileupload-x.x.x.jar,另一個是commons-io-x.x.x.jar.
一、檔案上傳的表單(多檔案上傳)
在做檔案上傳時,表單中的method方法必須是post,裡邊的enctype必須是multipart/form-data。不然會出現莫名其妙的異常。多檔案上傳的表單通過js技術來做控制。整個上傳檔案的頁面是:
<%@ page language="java" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s"%> <script type="text/javascript" language="JavaScript" src="${pageContext.request.contextPath }/script/calendar.js" charset="gb2312"></script> <script language="javascript"> function checkf() { var files = document.getElementsByName("file"); if (files[0].value.length != 0) { return true; } else { alert("請選擇檔案"); return false; } } //新增一行 function addMore() { var td = document.getElementById("more"); //換行 var br = document.createElement("br"); var input = document.createElement("input"); var button = document.createElement("input"); input.type = "file"; input.name = "file"; button.type = "button"; button.value = "Remove"; button.onclick = function() { td.removeChild(br); td.removeChild(input); td.removeChild(button); } td.appendChild(br); td.appendChild(input); td.appendChild(button); } </script> <html> <head> <title>測試檔案上傳的jsp</title> <link href="${pageContext.request.contextPath }/css/Style.css" type="text/css" rel="stylesheet"> </head> <body> <s:form action="upLoadAction_upload.do" method="post" theme="simple" enctype="multipart/form-data"> <table align="center" width="50%" border="1"> <tr> <td>選擇上傳檔案</td> <td id="more"><s:file name="file"></s:file> <input type="button" value="Add More.." onclick="addMore()"></td> </tr> <tr> <td><s:submit type="button" value="submit" onclick="return checkf()" /></td> <td><s:reset value="reset "></s:reset></td> </tr> </table> </s:form> </body> </html>
二、檔案上傳的Action
在檔案上傳的action中必須要有三個引數,分別是File型別的file-上傳的檔案;String型別的fileFileName-上傳檔案的名稱;String型別的fileContentType-檔案型別。如果是多檔案上傳,使用List集合去包裹,也就是List<File> file-上傳檔案集合;List<Sting> fileFileName-檔名稱集合;List<String> fileContentType-檔案型別集合。
package cn.ysu.zhy.devmanager.action; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.struts2.ServletActionContext; import org.springframework.stereotype.Controller; @Controller("upLoadAction") public class UpLoadAction extends BaseAction { /** * 1.做檔案上傳必須得三個引數:file,fileFileName,fileContentType */ /** * 對應jsp的file標籤,表示上傳的檔案(多檔案用集合表示) */ private List<File> file; /** * 檔名稱 */ private List<String> fileFileName; /** * 檔案的型別 */ private List<String> fileContentType; /** * 2.下載的檔名 */ private String fileName; private String fileUploadErrorMessage; public List<File> getFile() { return file; } public void setFile(List<File> file) { this.file = file; } public List<String> getFileFileName() { return fileFileName; } public void setFileFileName(List<String> fileFileName) { this.fileFileName = fileFileName; } public List<String> getFileContentType() { return fileContentType; } public void setFileContentType(List<String> fileContentType) { this.fileContentType = fileContentType; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } /** * @Name: home * @Description: 跳轉到上傳首頁upload.jsp * @Author: ZHY(作者) * @Version: V1.00 (版本號) * @Create Date: 2016-10-07 (建立日期) * @Parameters: 無 * @Return: String 跳轉到上傳首頁upload.jsp */ public String home() { return "home"; } /** * @throws Exception * @Name: upload * @Description: 處理檔案的上傳 * @Author: ZHY(作者) * @Version: V1.00 (版本號) * @Create Date: 2016-10-07 (建立日期) * @Parameters: 無 * @Return: String 上傳成功,重定向到upload.jsp */ public String upload() throws Exception { // 1.獲取上傳的檔案路徑 File filePath = new File(ServletActionContext.getServletContext().getRealPath("myUploadFile")); // 2.判斷目錄是否存在,如果不存在建立資料夾 if (!filePath.exists()) { filePath.mkdir();// 建立目錄 } System.out.println(filePath); if (file != null && file.size() > 0 && fileFileName != null && fileFileName.size() > 0) { for (int i = 0; i < file.size(); i++) { // 3.宣告檔案的輸入流,為輸入流指定路徑 FileInputStream is = new FileInputStream(file.get(i)); // 獲取上傳檔案的大小(單位是位元組1257114280--是1.17G),做資料狹小的限制,如果大於209715200,也就是200M,return // error,提示上傳檔案大小不能超過200M,2097152--2M int length = is.available();// 獲取上傳檔案的位元組大小 // 上傳的檔案超過200M if (length >= 209715200) { request.setAttribute("error", "您上傳的檔案超過200M"); return "error"; } // 4.獲取檔案輸出流,宣告輸出流的地址已及名稱 FileOutputStream out = new FileOutputStream(filePath + "\\" + fileFileName.get(i)); try { // 5.流對接 byte[] buffer = new byte[1024]; int len = 0; while ((len = is.read(buffer)) > 0) { // 將buffer裡的二進位制數,從0開始,每次寫len這麼長,寫入輸出流中 out.write(buffer, 0, len); } } catch (Exception e) { e.printStackTrace(); } finally { is.close(); out.close(); } } } request.setAttribute("fileName", fileFileName); return "upload"; } /** * @Name: upload * @Description: 處理檔案的下載 * @Author: ZHY(作者) * @Version: V1.00 (版本號) * @Create Date: 2016-10-07 (建立日期) * @Parameters: 無 * @Return: String 下載成功,重定向到upload.jsp */ public String download() { return "download"; } }
三、檔案下載的表單
檔案下載相對於檔案上傳要簡單一些,在JSP中唯一需要注意的就是中文亂碼問題,解決亂碼問題使用URLEncoder和URLDecoder基本上就能解決了。
<%@ page language="java" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s"%> <script type="text/javascript" language="JavaScript" src="${pageContext.request.contextPath }/script/calendar.js" charset="gb2312"></script> <html> <head> <title>測試檔案下載的jsp</title> <link href="${pageContext.request.contextPath }/css/Style.css" type="text/css" rel="stylesheet"> </head> <body> <table align="center" width="50%" border="1"> <s:if test="#request.fileName != null && #request.fileName.size() > 0"> <s:iterator value="#request.fileName" var="name"> <s:set value="name" id="names" name="names" scope="Request" /> <% //沒有進行編碼 String fname = (String) request.getAttribute("names"); //編碼之後的值 String fnameEncode = java.net.URLEncoder.encode(fname, "UTF-8"); %> <tr> <td><%=fname%></td> <td><a href="<s:url value='downLoadAction_download.do'><s:param name='fileName'><%=fnameEncode%></s:param> </s:url>">下載</a> </td> </tr> </s:iterator> </s:if> </table> </body> </html>
四、檔案下載的Action
在檔案下載的action中,必須有兩個引數,一個是String型別的fileName-檔名稱和InputStream型別的fileInput-檔案下載的流。
package cn.ysu.zhy.devmanager.action;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import org.apache.struts2.ServletActionContext;
import org.springframework.stereotype.Controller;
/**
* 檔案下載的action
*
* @author ZHY
*
*/
@Controller("downLoadAction")
public class DownLoadAction extends BaseAction {
/**
* 下載檔案的名稱
*/
private String fileName;
/**
* 下載的檔案
*/
private InputStream fileInput;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
try {
fileName = new String(fileName.getBytes("ISO8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
this.fileName = fileName;
}
public InputStream getFileInput() {
try {
fileName = URLDecoder.decode(fileName, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return ServletActionContext.getServletContext().getResourceAsStream("myUploadFile\\" + fileName);
}
public void setFileInput(InputStream fileInput) {
this.fileInput = fileInput;
}
/**
* 下載時,顯示中文名字
*
*/
public String getDownloadFileName() {
String downloadFileName = fileName;
try {
// 使用ISO8859-1編碼
downloadFileName = new String(downloadFileName.getBytes(), "ISO8859-1");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return downloadFileName;
}
/**
* @Name: download
* @Description: 處理檔案的上傳
* @Author: ZHY(作者)
* @Version: V1.00 (版本號)
* @Create Date: 2016-10-07 (建立日期)
* @Parameters: 無
* @Return: String 上傳成功,重定向到upload.jsp
*/
public String download() {
try {
fileName = URLDecoder.decode(fileName, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
fileInput = ServletActionContext.getServletContext().getResourceAsStream("myUploadFile\\" + fileName);
if (fileInput == null) {
return "error";
}
return "download";
}
}
OK了,至此,檔案上傳與下載的功能就實現了。但是存在一個問題,就是struts2中預設支援能夠上傳的檔案大小是2M,在專案開發過程中,一般上傳的檔案都要大於2M,這個問題也好解決,只需要在struts.xml中,配置一個constant常量,將檔案的最大值設定成想要的。
<!-- 允許檔案上傳的大小,預設為2M 2097152 在這裡設定成自己想要的-->
<constant name="struts.multipart.maxSize" value="2097152"></constant>
五、超出指定上傳檔案大小之後的提示
在專案中,往往有這種需求:當用戶上傳的檔案大於系統設定的值的時候,需要提示使用者,如果直接報錯,使用者體驗非常不好。我在做這部分需求的時候,走了不少彎路,也查閱了大量的網上的資料,但是最終還是遇到了一個跨不過去的坑(對於我來說的,可能是自己知識儲備不到位)。
我查閱了很多資料,都是說需要重寫action中的addActionError方法,將上傳檔案的錯誤轉變成action級別的錯誤,我這樣做了,也在addActionError中獲取到了相應的檔案大小,將錯誤資訊新增到supper.addActionError中之後,無論我如何,在jsp中也獲取不到我自己丟擲的錯誤資訊,而是頁面直接報錯了。這個問題困擾了我很久,也跟一些人討論過,但是最終還是沒有一個完美的解釋。於是,我想了一個比較笨的方法:
1、首先在constant中配置一個很大的最大值,這個值可以設定的大一點,我這裡設定成了2000M;
PS:我主要是最文件檔案上傳,也就是一些doc、pdf等,一幫不可能超過這麼大。我係統中的需求是不能大於200M。
2、在檔案上傳的action中,獲取上傳上來的檔案的大小,跟200M做一個比較,如果大於200M,那麼將錯誤資訊寫到request作用域中,然後return error。否則正常執行檔案上傳的操作。對應程式碼中的位置:
// 宣告檔案的輸入流,為輸入流指定路徑
FileInputStream is = new FileInputStream(file.get(i));
// 獲取上傳檔案的大小(單位是位元組1257114280--是1.17G),做資料狹小的限制,如果大於209715200,也就是200M,return
// error,提示上傳檔案大小不能超過200M,2097152--2M
int length = is.available();// 獲取上傳檔案的位元組大小
// 上傳的檔案超過200M
if (length >= 209715200) {
request.setAttribute("error", "您上傳的檔案超過200M");
return "error";
}
在錯誤頁面中,使用struts的標籤,得到自己丟擲的錯誤資訊,提示使用者。
<s:property value="#request.error" />
PS:我這個測試demo是在SSH框架的基礎上進行開發的,所以原始碼中會涉及到一些hibernate和spring相關的知識。