11.1、文件下载概述
1、将响应的内容类型设置为文件的内容类型。标头Content-type用来规定实体主体中的数据类型,包括媒体类型和子类型标识符。
2、加入一个名为Content-Disposition的HTTP响应头,给它赋值attachment;filename=filename,这里的fileName是指在文件下载对话框中显示出来的默认文件名称。
它通常与文件名称同样,可是也能够不同。
比如,下面就是将一个文件发送到浏览器的代码范例。
FileInputStream fis = new FileInputStream(file) ;
BufferedInputStream bis = new BufferedInputStream(fis) ;
byte[] bytes = new byte[bis.available()] ;
response.setContentType(contentType) ;
OutputStream os = response.getOutputStream() ;
bis.read(bytes) ;
os.write(bytes) ;
警告:一定要确保你没有在无意中发送超出实际文件内容以外的不论什么字符。
这有可能在你毫不知情的情况下发生。比如,假设须要在JSP页面中使用page指令,能够这么写:
<%@ page import=”java.io.FileInputStream”%>
<jsp:useBean id=”DBBeanId” scope=”page” class=”MyBean”>
在你毫不察觉的情况下,page指令后面的回车换行符就会被发送给浏览器。为了防止发送多余的字符。须要像以下这样编写这个指令:
<%@ page import=”java.io.FileInputStream”
%><jsp:useBean id=”DBBeanId” scope=”page” class=”MyBean”>
11.2、范例1:隐藏资源
在以下这个程序中,我们用一个FileDownloadServlet servlet将secret.pdf文件发送到浏览器。可是,仅仅有授权用户才干浏览。假设用户没有登录,应用程序就会跳转到Login页面。在这里,用户能够在表单中输入username和password,这些内容都将被提交给还有一个Servlet:LoginServlet。
LoginServlet.java
package filedownloaded; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet(urlPatterns = {"/login"}) public class LoginServlet extends HttpServlet{ private static final long serialVersionUID = 1L; public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String userName = request.getParameter("userName") ; String password = request.getParameter("password") ; if(userName != null && userName.equals("ken") && password != null && password.equals("secret")){ HttpSession session = request.getSession(true) ; session.setAttribute("loggedIn", Boolean.TRUE); response.sendRedirect("download"); return ; }else{ RequestDispatcher dispatcher = request.getRequestDispatcher("/login.jsp") ; dispatcher.forward(request, response); } } }
login.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP ‘login.jsp‘ starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <form action="login" method="post"> <table> <tr> <td>User name: </td> <td><input name="userName"/></td> </tr> <tr> <td>Password: </td> <td><input name="password" type="password"/></td> </tr> <tr> <td colspan="2"> <input type="submit" value="login"/> </td> </tr> </table> </form> </body> </html>
FileDownloadServlet.java
package filedownloaded; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet(urlPatterns = {"/download"}) public class FileDownloadServlet extends HttpServlet{ private static final long serialVersionUID = 1L; @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession() ; if(session == null || session.getAttribute("loggedIn") == null){ RequestDispatcher dispatcher = req.getRequestDispatcher("/login.jsp") ; dispatcher.forward(req, resp); return ; } String dataDirectory = req.getServletContext().getRealPath("/WEB-INF/data") ; File file = new File(dataDirectory, "secret.pdf") ; if(file.exists()){ resp.setContentType("application/pdf"); resp.addHeader("Content-Disposition", "attachment; filename=secret.pdf"); byte[] buffer = new byte[1024] ; try(FileInputStream fis = new FileInputStream(file) ; BufferedInputStream bis = new BufferedInputStream(fis); OutputStream os = resp.getOutputStream()){ int i = bis.read(buffer) ; while(i != -1){ os.write(buffer, 0, i); i = bis.read(buffer) ; } }catch(IOException e){ e.printStackTrace(); } } } }
12.3、范例2:防止跨站引用
竞争对手非常可能试图通过跨站引用来“窃取”你的网络资产,比如将你的贵重物品显示在他们的站点上,好像哪些东西就是他们的一样。假设通过编程的方式。仅当referer标头中包括你的域名时才发送资源,那么就能够防止上述情况的发生。当然。那种意志坚定的窃贼还是有可能下载到你的资产,可是那就要费一番功夫了。
以下的应用使用了一个Servlet。当且仅当referer标头不为空时,才将图片发送到浏览器。这样就能够防止直接在浏览器中输入其网址就能下载到图片。
ImageServlet.java
package filedownloaded; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(urlPatterns = {"/getImage"}) public class ImageServlet extends HttpServlet{ private static final long serialVersionUID = 1L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{ String referer = request.getHeader("referer") ; if(referer != null){ String imageId = request.getParameter("id") ; String imageDirectory = request.getServletContext().getRealPath("/WEB-INF/image") ; File file = new File(imageDirectory, imageId + ".jpg") ; if(file.exists()){ response.setContentType("image/jpg"); byte[] buffer = new byte[1024] ; try(FileInputStream fis = new FileInputStream(file) ; BufferedInputStream 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 e){ e.printStackTrace(); } } } } }
images.html
<!DOCTYPE html> <html> <head> <title>images.html</title> <meta name="keywords" content="keyword1,keyword2,keyword3"> <meta name="description" content="this is my page"> <meta name="content-type" content="text/html; charset=UTF-8"> <!--<link rel="stylesheet" type="text/css" href="./styles.css">--> </head> <body> <img src="getImage? id=1"/> <img src="getImage?id=2"/> <img src="getImage?id=3"/> <img src="getImage?id=4"/> <img src="getImage? id=5"/> <img src="getImage?id=6"/> <img src="getImage?id=7"/> <img src="getImage? id=8"/> <img src="getImage?id=9"/> <img src="getImage?id=10"/> </body> </html>
这样就能避免其它站点使用爬虫等技术进行图片下载。直接复制图片地址是訪问不到图片的。