上傳文件的表單要求html
Spring MVC實現上傳文件java
須要導入的jar包web
配置MultipartResolver解析器spring
編寫接收上傳文件的控制器apache
編寫文件下載的控制器瀏覽器
配置異常頁面的介紹服務器
對於普通表單來講,有幾個注意點:
一、action:表示要提交到哪裏;
二、method:表單提交的方式,經常使用的有post和get兩種,不寫的話,默認是get;提交文件是隻能使用post方式。
三、enctype:編碼類型,表示提交的數據是什麼格式。有三個值,
1)不顯式設置enctype時,默認是application/x-www-form-urlencoded,表示提交的是普通的數據;
2)text/plain,表示提交的是文本數據,數據量稍大一點。
3)multipart/form-data,這種方式能夠提交二進制數據(音頻、圖像等文件)
綜上,若是要上傳文件,必需要將method設置爲post,而後將enctype設置multipart/form-data。另外,上傳文件的input標籤的type屬性設置爲file。
<form action="upload" method="post" enctype="multipart/form-data"> <input type="file" name="myfile" /> <input type="submit" name="submit" value="upload" /> </form>
在看Spring MVC是怎麼實現文件上傳以前,能夠先看一下不是框架,使用原生的servlet開發是怎麼實現文件上傳的:Servlet 實現文件上傳與下載
在Servlet 3.0以後,Spring MVC實現文件上傳主要是使用一個叫MultipartResolver的解析器,該解析器依賴於apache的commons-io和commons-fileupload。MultipartResolver會自動解析文件,以後咱們在handlerMethod中,能夠很方便的操做上傳的文件。
必不可少的commons-io.jar和commons-fileupload.jar這兩個包,缺一不可。
MultipartResolver是一個interface,咱們只須要配置他的一個實現類,好比CommonsMultipartResolver這個實現類,配置的方法也很簡單,只須要配置一個id爲multipartResolver的<bean>便可。
在Spring MVC的配置文件中增長下面配置:
<!-- 建立MultipartResolver解析器 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 配置屬性,能夠省略不配置,設置上傳的文件maxSize,單位爲B(字節) --> <property name="maxUploadSize" value="1000000"></property> </bean>
package cn.ganlixin.controller; import java.io.File; import java.io.IOException; import java.util.UUID; import org.apache.commons.io.FileUtils; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile; @Controller public class UploadController { @RequestMapping("upload") // 注意表單中文件input的name要和這裏的參數名相同。 public String upload(MultipartFile myfile) throws IOException { // 上傳一張圖片 C:\Users\Administrator\Desktop\code.png // 獲取文件的原始名稱 String originalFileName = myfile.getOriginalFilename(); // code.png // 獲取上傳文件的表單中,input的name值,其實就是myfile(就是接收時的名稱) String fileName = myfile.getName(); // myfile // 獲取上傳的文件大小,單位爲字節 long fileSize = myfile.getSize(); // 5823(字節) String extensionName = originalFileName.substring(originalFileName.lastIndexOf(".")); /* 進行一些過濾判斷操做 */ // 利用apache的commons-io和commons-fileupload,將文件保存到硬盤中,文件名能夠根據本身的規則來定,這裏使用UUID String newFileName = UUID.randomUUID().toString(); FileUtils.copyInputStreamToFile( myfile.getInputStream(), new File("E:/uploads/" + newFileName + extensionName) ); return "/success.jsp"; } }
在原生servlet實現文件下載主要有兩步:
一、使用HttpServletRequest對象接收請求,獲取客戶端想要下載的文件名;
二、讀取須要下載的文件,而後使用HttpServletResponse對象向客戶端輸出文件的字節流。
其實Spring MVC實現文件下載和使用原生servlet實現文件下載的方式並無太大區別,甚至能夠說沒有任何區別。惟一的區別就是Spring MVC的控制器沒有繼承HttpServlet,可是卻能夠爲HandlerMethod注入HttpServletRequest和HttpServletResponse對象,以後就能夠進行和原生servlet相同的操做了。
先看一下提供下載文件的資源連接:
<a href="download?fileName=info.txt">點擊下載info.txt</a> <a href="download?fileName=data.rar">點擊下載data.rar</a>
若是仍舊按照之前的設置:Content-Type=text/html; charset=utf-8; 那麼當客戶端點擊下載連接時,發生的事情可能超乎預料。上面這兩個資源連接的文件的擴展名,擴展名指明瞭該文件的格式。若是沒有設置文件以附件形式下載,那麼對於不一樣的瀏覽器,對於文件的處理方式是不一樣的:
一、若是瀏覽器可以打開或者可以解析該類型文件,那麼,文件就會直接被瀏覽器打開(注意,不是下載,不會保存到用戶的本地磁盤);
二、若是瀏覽器不能打開或者不能解析該類型的文件,那麼,瀏覽器纔會將文件下載下來(保存到用戶磁盤)。
好比,當服務器響應info.txt以後,瀏覽器接收到info.txt,info.txt是文本文件,瀏覽器能夠打開,因而就會將info.txt的內容顯示在瀏覽器的頁面中,而沒有下載下來。而對於data.rar來講,瀏覽器沒法直接打開,因此會下載到本地。
爲了讓用戶請求下載的文件都能保存到用戶磁盤(即便瀏覽器可以打開文件,也不要讓他打開,而只是讓他進行下載),能夠設置Content-Disposition屬性爲attachment(通知瀏覽器以附件形式下載)。
package cn.ganlixin.controller; import java.io.File; import java.io.IOException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.FileUtils; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class DownloadController { @RequestMapping("/download") // 注入fileName、request、response public void download(String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException { // 設置響應是以附件形式,不用設置Content-Type了 response.setHeader("Content-Disposition", "attachment; filename=" + fileName); // 獲取文件的真實路徑(可供下載的文件都放在/project/WebContext/files/路徑下,可是部署到服務器後,files文件夾的路徑都會發生改變。 // 因此須要從新得到該文件從根目錄開始的路徑,而後讀取文件,並響應給客戶端。 String path = request.getServletContext().getRealPath("files"); // 文件下載時,是使用字節流格式,因此不能使用response.getWriter()-->返回PrintWriter是字符流 // 獲取輸出字節流惡意使用response. ServletOutputStream out = response.getOutputStream(); File downloadFile = new File(path, fileName); // 判斷文件是否存在 if (! downloadFile.exists()) { request.setAttribute("msg", "文件不存在"); response.sendError(404); return; } // 利用FileUtils將文件讀入字節數組,而後返回給客戶端。 out.write(FileUtils.readFileToByteArray(downloadFile)); out.flush(); out.close(); } }
咱們的服務器在運行過程當中可能會出現各類異常,當出現異常的時候,根據Java的脾氣,必定會打印堆棧信息,這個信息不能直接暴露給用戶,一個緣由是打印的堆棧信息並非用戶關心的內容,會影響用戶體驗;另外一方面,若是被黑客獲取到堆棧信息,也是一種安全隱患。
因此咱們在編程過程當中,使用了不少try{ } catch{ },每當出現異常XxxException,能夠根據異常的類型,返回給客戶一個特定的異常頁面。這個返回異常的部分若是直接寫在業務代碼中也是能夠的,可是卻不是推薦的。
Spring MVC提供了一個ExceptionResolver解析器,這個解析器能夠爲咱們作這麼一個事情:根據咱們自定義的配置,當出現某種Exception的時候,就直接跳轉到指定的頁面,不須要在邏輯代碼中進行處理。
舉個例子:當服務端接收客戶端上傳的文件時,發現文件的大小超過了設置的最大值,此時,若是配置MultipartResolver時設置了上傳文件的最大值,那麼此時就會出現org.springframework.web.multipart.MaxUploadSizeExceededException,出現異常時,異常堆棧信息也會顯示給客戶端,此時就能夠配置下ExceptionResolver,當出現這個錯誤,就跳轉到uploadFailed.jsp中。
配置ExceptionResolver解析器的方式也很簡單,只須要配置一個id爲exceptionResolver的<bean>便可,class能夠是ExceptionResolver的一個實現實現類。
<!-- 配置ExceptionResolver解析器 --> <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <!-- 配置異常與跳轉頁面的對應關係 --> <property name="exceptionMappings"> <props> <prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">/uploadFailed.jsp</prop> </props> </property> </bean>