javascript
Spring MVC-10循序渐进之文件下载
- 概述
- 文件下載概覽
- 隱藏資源
- 防止交叉引用
- 源碼
概述
像靜態(tài)資源,我們在瀏覽器中打開正確的URL即可下載,只要該資源不是放在WEB-INF目錄下,Servlet/JSP容器就會將該資源發(fā)送到瀏覽器。 然而有的時候靜態(tài)資源是保存在應(yīng)用程序目錄外或者存在數(shù)據(jù)庫中,或者有的時候需要控制它的訪問權(quán)限,防止其他網(wǎng)站交叉引用它。 如果出現(xiàn)上述任意一種情況,都必須通過編程來發(fā)送資源。
文件下載概覽
為了將像文件這樣的資源發(fā)送到瀏覽器,需要在控制器中完成以下工作
1. 隊請求處理方法使用void返回類型,并在方法中添加HttpServletRespinse參數(shù)
2. 將響應(yīng)的內(nèi)容設(shè)置為文件的內(nèi)容類型。 Content-Type標(biāo)題在某個實體的body中定義數(shù)據(jù)的類型,并包含沒提類型和子類型標(biāo)示符。如果不清楚內(nèi)容類型,并且希望瀏覽器始終顯示Save As(另存為)對話框,則將它設(shè)置為APPLICATION/OCTETPSTREAM ,不區(qū)分大小寫
3. 添加一個名為Content-Dispositionde HTTP響應(yīng)標(biāo)題,并賦值attachment;filename=fileName.這里的fileName是默認文件名,應(yīng)該出現(xiàn)在File Download對話框中,它通常與文件名同名,但是也并非一定如此
下面的代碼是將一個文件發(fā)送到瀏覽器
FileInputStream fis = new FileInputStream(); BufferedInputStream bis = new BufferedInputStream(fis); byte[] bytes = new byte[bis.available()]; response.setContentType(contentType); OutputStream os = response.getOutputStream(); bis.read(bytes); os.write(bytes);為了通過編程將一個文件發(fā)送到瀏覽器,首先要讀取該文件作為FileInputStream,并將內(nèi)容加載到一個字節(jié)數(shù)組。 隨后,獲取HttpServletResponse的OutputStream,并調(diào)用其write方法傳入字節(jié)數(shù)組。
隱藏資源
該示例演示如何向瀏覽器發(fā)送文件,由ResourceController類處理用戶登錄請求,并將WEB-INF/data目錄下的artisan.pdf發(fā)送給瀏覽器。因為文件放到了WEB-INF目錄下,所以不能夠直接訪問,只有得到授權(quán)的用戶才能看到,如果未登錄,返回登錄頁面。
ResourceController, 這里模擬下用戶登錄,只有當(dāng)用戶的HttpSession中包含一個loggedIn屬性時,表明登錄成功。
package com.artisan.controller;import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.OutputStream;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession;import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping;import com.artisan.domain.Login;@Controller public class ResourceController {@RequestMapping(value = "/login")public String login(@ModelAttribute Login login, HttpSession httpSession, Model model) {model.addAttribute("login", new Login());if ("artisan".equals(login.getUserName()) && "artisan123".equals(login.getPassword())) {httpSession.setAttribute("loggedIn", Boolean.TRUE);return "Main";} else {return "LoginForm";}}@RequestMapping(value = "/resource_download")public String downLoadResource(HttpSession session, HttpServletRequest request, HttpServletResponse response) {if (session == null && session.getAttribute("loggedIn") == null) {return "LoginForm";}String dataDirectory = request.getServletContext().getRealPath("/WEB-INF/data");File file = new File(dataDirectory, "artisan.pdf");if (file.exists()) {response.setContentType("application/pdf");response.addHeader("Content-Disposition", "attachment; filename=artisan.pdf");byte[] buffer = new byte[1024];FileInputStream fis = null;BufferedInputStream bis = null;// JDK7 以前的寫法// try {// fis = new FileInputStream(file);// bis = new BufferedInputStream(fis);// OutputStream os = response.getOutputStream();// int i = bis.read(buffer);// while (i != -1) {// os.write(buffer, 0, i);// i = bis.read(buffer);// }// } catch (IOException ex) {// // do something,// // probably forward to an Error page// } finally {// if (bis != null) {// try {// bis.close();// } catch (IOException e) {// }// }// if (fis != null) {// try {// fis.close();// } catch (IOException e) {// }// }// }//// Java 7, use try-with-resources,自動釋放資源try (OutputStream os = response.getOutputStream();) {fis = new FileInputStream(file);bis = new BufferedInputStream(fis);int i = bis.read(buffer);while (i != -1) {os.write(buffer, 0, i);i = bis.read(buffer);}} catch (Exception e) {// do something, // probably forward to an Error page}}return null;} }login方法,將用戶帶到登錄表單頁面
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE HTML> <html> <head> <title>Login</title> <style type="text/css">@import url("<c:url value="/css/main.css"/>");</style> </head> <body> <div id="global"> <form:form commandName="login" action="login" method="post"><fieldset><legend>Login</legend><p><label for="userName">User Name: </label><form:input id="userName" path="userName" cssErrorClass="error"/></p><p><label for="password">Password: </label><form:password id="password" path="password" cssErrorClass="error"/></p><p id="buttons"><input id="reset" type="reset" tabindex="4"><input id="submit" type="submit" tabindex="5" value="Login"></p></fieldset> </form:form> </div> </body> </html>用戶名和密碼在login方法中使用硬編碼的方式模擬用戶登錄,成功后跳轉(zhuǎn)到Main.jsp頁面,該頁面包含一個超鏈接,點擊下載文件。
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE HTML> <html> <head> <title>Download Page</title> <style type="text/css">@import url("<c:url value="/css/main.css"/>");</style> </head> <body> <div id="global"><h4>Please click the link below.</h4><p><a href="resource_download">Download</a></p> </div> </body> </html>測試
點擊鏈接
查看下載的文件
防止交叉引用
為了防止他人引用我們網(wǎng)站的資源,可以通過編程的方式,只有當(dāng)請求的報頭referer標(biāo)題中包含你的域名時才發(fā)出資源,當(dāng)然了這種方式也不能完全阻止。
該示例中,ImageController類中,只有referer標(biāo)題不為空時,才將圖片發(fā)送給瀏覽器
package com.artisan.controller;import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;@Controller public class ImageController {@RequestMapping("/imageList")public String getImageList(){return "Image"; }@RequestMapping(value = "/image_get/{id}", method = RequestMethod.GET)public void getImage(@PathVariable String id, HttpServletRequest request, HttpServletResponse response,@RequestHeader String referer) {// 判斷請求頭中的Refererif (referer != null) {String imageDirectory = request.getServletContext().getRealPath("/WEB-INF/image");File file = new File(imageDirectory, id + ".jpg");if (file.exists()) {response.setContentType("image/jpg");byte[] buffer = new byte[1024];FileInputStream fis = null;BufferedInputStream bis = null;// if you're using Java 7, use try-with-resourcestry {fis = new FileInputStream(file);bis = new BufferedInputStream(fis);OutputStream os = response.getOutputStream();int i = bis.read(buffer);while (i != -1) {os.write(buffer, 0, i);i = bis.read(buffer);}} catch (IOException ex) {// do something here} finally {if (bis != null) {try {bis.close();} catch (IOException e) {}}if (fis != null) {try {fis.close();} catch (IOException e) {}}}}}} }前臺頁面
<!DOCTYPE HTML> <html> <head> <title>Images</title> </head> <body> <img src="image_get/1"/> <img src="image_get/2"/> <img src="image_get/3"/> <img src="image_get/4"/> <img src="image_get/5"/> <img src="image_get/6"/> <img src="image_get/7"/> <img src="image_get/8"/> <img src="image_get/9"/> <img src="image_get/10"/> </body> </html>測試:
源碼
代碼已提交到github
https://github.com/yangshangwei/SpringMvcTutorialArtisan
總結(jié)
以上是生活随笔為你收集整理的Spring MVC-10循序渐进之文件下载的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring MVC-09循序渐进之文件
- 下一篇: Java was started but