Spring MVC 框架的文件上傳是基於 commons-fileupload 組件的文件上傳,只不過 Spring MVC 框架在原有文件上傳組件上作了進一步封裝,簡化了文件上傳的代碼實現,取消了不一樣上傳組件上的編程差別。
html
因爲 Spring MVC 框架的文件上傳是基於 commons-fileupload 組件的文件上傳,所以須要將 commons-fileupload 組件相關的 JAR(commons-fileupload-1.3.1.jar 和 commons-io-2.4.jar)複製到 Spring MVC 應用的 WEB-INF/lib 目錄下。下面講解如何下載相關 JAR 包。
Commons 是 Apache 開放源代碼組織中的一個 Java 子項目,該項目包括文件上傳、命令行處理、數據庫鏈接池、XML 配置文件處理等模塊。fileupload 就是其中用來處理基於表單的文件上傳的子項目,commons-fileupload 組件性能優良,並支持任意大小文件的上傳。
commons-fileupload 組件能夠從「http://commons.apache.org/proper/commons-fileupload/」下載,本教程採用的版本是 1.2.2。下載它的 Binares 壓縮包(commons-fileupload-1.3.1-bin.zip),解壓縮後的目錄中有兩個子目錄,分別是 lib 和 site。
在 lib 目錄下有一個 JAR 文件——commons-fileupload-1.3.1.jar,該文件是 commons-fileupload 組件的類庫。在 site 目錄中是 commons-fileupload 組件的文檔,也包括 API 文檔。
commons-fileupload 組件依賴於 Apache 的另一個項目——commons-io,該組件能夠從「http://commons.apache.org/proper/commons-io/」下載,本教程採用的版本是 2.4。下載它的 Binaries 壓縮包(commons-io-2.4-bin.zip),解壓縮後的目錄中有 4 個 JAR 文件,其中有一個 commons-io-2.4.jar 文件,該文件是 commons-io 的類庫。java
標籤 <input type="file"/> 會在瀏覽器中顯示一個輸入框和一個按鈕,輸入框可供用戶填寫本地文件的文件名和路徑名,按鈕可讓瀏覽器打開一個文件選擇框供用戶選擇文件。
文件上傳的表單例子以下:web
<form method="post" action="upload" enctype="multipart/form-data">
<input type="file" name="myfile"/>
</form>spring
對於基於表單的文件上傳,不要忘記使用 enctype 屬性,並將它的值設置爲 multipart/form-data,同時將表單的提交方式設置爲 post。爲何要這樣呢?下面從 enctype 屬性提及。
表單的 enctype 屬性指定的是表單數據的編碼方式,該屬性有如下 3 個值。數據庫
由上面 3 個屬性的解釋可知,在基於表單上傳文件時 enctype 的屬性值應爲 multipart/form-data。
apache
在 Spring MVC 框架中上傳文件時將文件相關信息及操做封裝到 MultipartFile 對象中,所以開發者只須要使用 MultipartFile 類型聲明模型類的一個屬性便可對被上傳文件進行操做。該接口具備以下方法。
編程
名稱 | 做用 |
---|---|
byte[] getBytes() | 以字節數組的形式返回文件的內容 |
String getContentType() | 返回文件的內容類型 |
InputStream getInputStream() | 返回一個InputStream,從中讀取文件的內容 |
String getName() | 返回請求參數的名稱 |
String getOriginalFillename() | 返回客戶端提交的原始文件名稱 |
long getSize() | 返回文件的大小,單位爲字節 |
boolean isEmpty() | 判斷被上傳文件是否爲空 |
void transferTo(File destination) | 將上傳文件保存到目標目錄下 |
在上傳文件時須要在配置文件中使用 Spring 的 org.springframework.web.multipart.commons.CommonsMultipartResolver 類配置 MultipartResolver 用於文件上傳。
數組
建立應用 springMVCDemo11,將 Spring MVC 相關的 JAR 包、commons-fileupload 組件相關的 JAR 包以及 JSTL 相關的 JAR 包導入應用的 lib 目錄中,如圖 1 所示。
瀏覽器
在 WEB-INF 目錄下建立 web.xml 文件。爲防止中文亂碼,須要在 web.xml 文件中添加字符編碼過濾器,這裏再也不贅述。
spring-mvc
在 WebContent 目錄下建立 JSP 頁面 oneFile.jsp,在該頁面中使用表單上傳單個文件,具體代碼以下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <form action="${pageContext.request.contextPath }/onefile" method="post" enctype="multipart/form-data"> 選擇文件:<input type="file" name="myfile"><br> 文件描述:<input type="text" name="description"><br> <input type="submit" value="提交"> </form> </body> </html>
在 src 目錄下建立 pojo 包,在該包中建立 POJO 類 FileDomain。而後在該 POJO 類中聲明一個 MultipartFile 類型的屬性封裝被上傳的文件信息,屬性名與文件選擇頁面 oneFile.jsp 中的 file 類型的表單參數名 myfile 相同。具體代碼以下:
package pojo; import org.springframework.web.multipart.MultipartFile; public class FileDomain { private String description; private MultipartFile myfile; public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public MultipartFile getMyfile() { return myfile; } public void setMyfile(MultipartFile myfile) { this.myfile = myfile; } }
在 src 目錄下建立 controller 包,並在該包中建立 FileUploadController 控制器類。具體代碼以下:
package controller; import java.io.File; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import pojo.FileDomain; @Controller public class FileUploadController { // 獲得一個用來記錄日誌的對象,這樣在打印信息時可以標記打印的是哪一個類的信息 private static final Log logger = LogFactory.getLog(FileUploadController.class); /** * 單文件上傳 */ @RequestMapping("/onefile") public String oneFileUpload(@ModelAttribute FileDomain fileDomain, HttpServletRequest request) { /* * 文件上傳到服務器的位置「/uploadfiles」,該位置是指 * workspace\.metadata\.plugins\org.eclipse * .wst.server.core\tmp0\wtpwebapps, 發佈後使用 */ String realpath = request.getServletContext() .getRealPath("uploadfiles"); String fileName = fileDomain.getMyfile().getOriginalFilename(); File targetFile = new File(realpath, fileName); if (!targetFile.exists()) { targetFile.mkdirs(); } // 上傳 try { fileDomain.getMyfile().transferTo(targetFile); logger.info("成功"); } catch (Exception e) { e.printStackTrace(); } return "showOne"; } }
在上傳文件時須要在配置文件中使用 Spring 的 CommonsMultipartResolver 類配置 MultipartResolver 用於文件上傳,應用的配置文件 springmvc-servlet.xml 的代碼以下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 使用掃描機制掃描包 --> <context:component-scan base-package="controller" /> <!-- 完成視圖的對應 --> <!-- 對轉向頁面的路徑解析。prefix:前綴, suffix:後綴 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean> <!-- 配置MultipartResolver,用於上傳文件,使用spring的CommonsMultipartResolver --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="5000000" /> <property name="defaultEncoding" value="UTF-8" /> </bean> </beans>
在 WEB-INF 目錄下建立 JSP 文件夾,並在該文件夾中建立單文件上傳成功顯示頁面 showOne.jsp。具體代碼以下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> ${fileDomain.description } <br> <!-- fileDomain.getMyFile().getOriginalFilename()--> ${fileDomain.myfile.originalFilename } </body> </html>
發佈 springMVCDemo11 應用到 Tomcat 服務器並啓動 Tomcat 服務器,而後經過地址「http://localhost:8080/springMVCDemo11/oneFile.jsp」運行文件選擇頁面,運行結果如圖 2 所示。
在圖 2 中選擇文件並輸入文件描述,而後單擊「提交」按鈕上傳文件,若成功則顯示如圖 3 所示的結果。
在 WebContent 目錄下建立 JSP 頁面 multiFiles.jsp,在該頁面中使用表單上傳多個文件,具體代碼以下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <form action="${pageContext.request.contextPath }/multifile" method="post" enctype="multipart/form-data"> 選擇文件1:<input type="file" name="myfile"><br> 文件描述1:<input type="text" name="description"><br /> 選擇文件2:<input type="file" name="myfile"><br> 文件描述2:<input type="text" name="description"><br /> 選擇文件3:<input type="file" name="myfile"><br> 文件描述3:<input type="text" name="description"><br /> <input type="submit" value="提交"> </form> </body> </html>
在上傳多文件時須要 POJO 類 MultiFileDomain 封裝文件信息,MultiFileDomain 類的具體代碼以下:
package pojo; import java.util.List; import org.springframework.web.multipart.MultipartFile; public class MultiFileDomain { private List<String> description; private List<MultipartFile> myFile; // 省略setter和getter方法 }
在控制器類 FileUploadController 中添加多文件上傳的處理方法 multiFileUpload,具體代碼以下:
/** * 多文件上傳 */ @RequestMapping("/multifile") public String multiFileUpload(@ModelAttribute MultiFileDomain multiFileDomain,HttpServletRequest request) { String realpath = request.getServletContext().getRealPath("uploadfiles"); File targetDir = new File(realpath); if (!targetDir.exists()) { targetDir.mkdirs(); } List<MultipartFile> files = multiFileDomain.getMyFile(); for (int i = 0; i < files.size(); i++) { MultipartFile file = files.get(i); String fileName = file.getOriginalFilename(); File targetFile = new File(realpath, fileName); // 上傳 try { file.transferTo(targetFile); } catch (Exception e) { e.printStackTrace(); } } logger.info("成功"); return "showMulti"; }
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <table> <tr> <td>詳情</td> <td>文件名</td> </tr> <!-- 同時取兩個數組的元素 --> <c:forEach items="${multiFileDomain.description}" var="description" varStatus="loop"> <tr> <td>${description}</td> <td>${multiFileDomain.myfile[loop.count-1].originalFilename}</td> </tr> </c:forEach> <!-- fileDomain.getMyfile().getOriginalFilename() --> </table> </body> </html>
發佈 springMVCDemo11 應用到 Tomcat 服務器並啓動 Tomcat 服務器,而後經過地址「http://localhost:8080/springMVCDemo11/multiFiles.jsp」運行多文件選擇頁面,運行結果如圖 1 所示。
在圖 1 中選擇文件並輸入文件描述,而後單擊「提交」按鈕上傳多個文件,若成功則顯示如圖 2 所示的結果。
實現文件下載有如下兩種方法:
經過超連接實現下載當然簡單,但暴露了下載文件的真實位置,而且只能下載存放在 Web 應用程序所在的目錄下的文件。
利用程序編碼實現下載能夠增長安全訪問控制,還能夠從任意位置提供下載的數據,能夠將文件存放到 Web 應用程序之外的目錄中,也能夠將文件保存到數據庫中。
利用程序實現下載須要設置兩個報頭:
1)Web 服務器須要告訴瀏覽器其所輸出內容的類型不是普通文本文件或 HTML 文件,而是一個要保存到本地的下載文件,這須要設置 Content-Type 的值爲 application/x-msdownload。
2)Web 服務器但願瀏覽器不直接處理相應的實體內容,而是由用戶選擇將相應的實體內容保存到一個文件中,這須要設置 Content-Disposition 報頭。
該報頭指定了接收程序處理數據內容的方式,在 HTTP 應用中只有 attachment 是標準方式,attachment 表示要求用戶干預。在 attachment 後面還能夠指定 filename 參數,該參數是服務器建議瀏覽器將實體內容保存到文件中的文件名稱。
設置報頭的示例以下:
response.setHeader("Content-Type", "application/x-msdownload");
response.setHeader("Content-Disposition", "attachment;filename="+filename);
下面繼續經過 springMVCDemo11 應用講述利用程序實現下載的過程,要求從《Spring MVC單文件上傳》上傳文件的目錄(workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\springMVCDemo11\uploadfiles)中下載文件,具體開發步驟以下:
首先編寫控制器類 FileDownController,在該類中有 3 個方法,即 show、down 和 toUTF8String。其中,show 方法獲取被下載的文件名稱;down 方法執行下載功能;toUTF8String 方法是下載保存時中文文件名的字符編碼轉換方法。
FileDownController 類的代碼以下:
package controller; import java.io.File; import java.io.FileInputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller public class FileDownController { // 獲得一個用來記錄日誌的對象,在打印時標記打印的是哪一個類的信息 private static final Log logger = LogFactory .getLog(FileDownController.class); /** * 顯示要下載的文件 */ @RequestMapping("showDownFiles") public String show(HttpServletRequest request, Model model) { // 從 workspace\.metadata\.plugins\org.eclipse.wst.server.core\ // tmp0\wtpwebapps\springMVCDemo11\下載 String realpath = request.getServletContext() .getRealPath("uploadfiles"); File dir = new File(realpath); File files[] = dir.listFiles(); // 獲取該目錄下的全部文件名 ArrayList<String> fileName = new ArrayList<String>(); for (int i = 0; i < files.length; i++) { fileName.add(files[i].getName()); } model.addAttribute("files", fileName); return "showDownFiles"; } /** * 執行下載 */ @RequestMapping("down") public String down(@RequestParam String filename, HttpServletRequest request, HttpServletResponse response) { String aFilePath = null; // 要下載的文件路徑 FileInputStream in = null; // 輸入流 ServletOutputStream out = null; // 輸出流 try { // 從workspace\.metadata\.plugins\org.eclipse.wst.server.core\ // tmp0\wtpwebapps下載 aFilePath = request.getServletContext().getRealPath("uploadfiles"); // 設置下載文件使用的報頭 response.setHeader("Content-Type", "application/x-msdownload"); response.setHeader("Content-Disposition", "attachment; filename=" + toUTF8String(filename)); // 讀入文件 in = new FileInputStream(aFilePath + "\\" + filename); // 獲得響應對象的輸出流,用於向客戶端輸出二進制數據 out = response.getOutputStream(); out.flush(); int aRead = 0; byte b[] = new byte[1024]; while ((aRead = in.read(b)) != -1 & in != null) { out.write(b, 0, aRead); } out.flush(); in.close(); out.close(); } catch (Throwable e) { e.printStackTrace(); } logger.info("下載成功"); return null; } /** * 下載保存時中文文件名的字符編碼轉換方法 */ public String toUTF8String(String str) { StringBuffer sb = new StringBuffer(); int len = str.length(); for (int i = 0; i < len; i++) { // 取出字符中的每一個字符 char c = str.charAt(i); // Unicode碼值爲0~255時,不作處理 if (c >= 0 && c <= 255) { sb.append(c); } else { // 轉換 UTF-8 編碼 byte b[]; try { b = Character.toString(c).getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); b = null; } // 轉換爲%HH的字符串形式 for (int j = 0; j < b.length; j++) { int k = b[j]; if (k < 0) { k &= 255; } sb.append("%" + Integer.toHexString(k).toUpperCase()); } } } return sb.toString(); } }
下載文件示例須要一個顯示被下載文件的 JSP 頁面 showDownFiles.jsp,代碼以下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <table> <tr> <td>被下載的文件名</td> </tr> <!--遍歷 model中的 files--> <c:forEach items="${files}" var="filename"> <tr> <td> <a href="${pageContext.request.contextPath }/down?filename=${filename}">${filename}</a> </td> </tr> </c:forEach> </table> </body> </html>
發佈 springMVCDemo11 應用到 Tomcat 服務器並啓動 Tomcat 服務器,而後經過地址「http://localhost:8080/springMVCDemo11/showDownFiles」測試下載示例,運行結果如圖 1 所示。