目錄
上傳文件的表單要求
對於普通表單來說,有幾個注意點:
1、action:表示要提交到哪里;
2、method:表單提交的方式,常用的有post和get兩種,不寫的話,默認是get;提交文件是只能使用post方式。
3、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實現上傳文件
在看Spring MVC是怎么實現文件上傳之前,可以先看一下不是框架,使用原生的servlet開發是怎么實現文件上傳的:Servlet 實現文件上傳與下載
在Servlet 3.0之后,Spring MVC實現文件上傳主要是使用一個叫MultipartResolver的解析器,該解析器依賴於apache的commons-io和commons-fileupload。MultipartResolver會自動解析文件,之后我們在handlerMethod中,可以很方便的操作上傳的文件。
需要導入的jar包
必不可少的commons-io.jar和commons-fileupload.jar這兩個包,缺一不可。
配置MultipartResolver解析器
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"; } }
Spring MVC實現文件下載
在原生servlet實現文件下載主要有兩步:
1、使用HttpServletRequest對象接收請求,獲取客戶端想要下載的文件名;
2、讀取需要下載的文件,然后使用HttpServletResponse對象向客戶端輸出文件的字節流。
其實Spring MVC實現文件下載和使用原生servlet實現文件下載的方式並沒有太大區別,甚至可以說沒有任何區別。唯一的區別就是Spring MVC的控制器沒有繼承HttpServlet,但是卻可以為HandlerMethod注入HttpServletRequest和HttpServletResponse對象,之后就可以進行和原生servlet相同的操作了。
下載文件時的header設置
先看一下提供下載文件的資源鏈接:
<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; 那么當客戶端點擊下載鏈接時,發生的事情可能超乎預料。上面這兩個資源鏈接的文件的擴展名,擴展名指明了該文件的格式。如果沒有設置文件以附件形式下載,那么對於不同的瀏覽器,對於文件的處理方式是不同的:
1、如果瀏覽器能夠打開或者能夠解析該類型文件,那么,文件就會直接被瀏覽器打開(注意,不是下載,不會保存到用戶的本地磁盤);
2、如果瀏覽器不能打開或者不能解析該類型的文件,那么,瀏覽器才會將文件下載下來(保存到用戶磁盤)。
比如,當服務器響應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(); } }
Spring MVC配置異常跳轉的頁面
配置異常跳轉頁面的介紹
我們的服務器在運行過程中可能會出現各種異常,當出現異常的時候,根據Java的脾氣,一定會打印堆棧信息,這個信息不能直接暴露給用戶,一個原因是打印的堆棧信息並不是用戶關心的內容,會影響用戶體驗;另一方面,如果被黑客獲取到堆棧信息,也是一種安全隱患。
所以我們在編程過程中,使用了很多try{ } catch{ },每當出現異常XxxException,可以根據異常的類型,返回給客戶一個特定的異常頁面。這個返回異常的部分如果直接寫在業務代碼中也是可以的,但是卻不是推薦的。
Spring MVC提供了一個ExceptionResolver解析器,這個解析器可以為我們做這么一個事情:根據我們自定義的配置,當出現某種Exception的時候,就直接跳轉到指定的頁面,不需要在邏輯代碼中進行處理。
舉個例子:當服務端接收客戶端上傳的文件時,發現文件的大小超過了設置的最大值,此時,如果配置MultipartResolver時設置了上傳文件的最大值,那么此時就會出現org.springframework.web.multipart.MaxUploadSizeExceededException,出現異常時,異常堆棧信息也會顯示給客戶端,此時就可以配置下ExceptionResolver,當出現這個錯誤,就跳轉到uploadFailed.jsp中。
配置ExceptionResolver解析器
配置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>