一、文件下载概述
例如图片或者HTML这类静态资源,只要在浏览器中打开正确的网址就可以下载。只要资源放在应用程序目录或者其下的子目录中,但不在WEB-INF下,Servlet/JSP容器就会将资源发送到浏览器。但有的时候,静态资源被保存在应用程序目录之外,或者保存在数据库中,或者有时候你需要控制让某些人能够看到这个资源,同时又要防止其他网站引用它。每当遇到这类情况时,就必须通过编程来发送资源。
通过编程的方式实现文件下载可是让我们有选择的将一个文件发送到浏览器。
为了将资源比如文件发送到浏览器,需要在Servlet中完成以下工作。这里说明以下,一般不用JSP页面,因为要发送的是浏览器不会显示的二进制代码。
1.将响应内容类型设置为“文件”的内容类型。
标头Content-Type用来规定实体主体中的数据类型,包含“媒体类型”和“子类型标示符”。如果希望浏览器总是显示为“Save as”对话框时,就将内容类型设置为:application/octetstream。
2.添加一个名为content-disposition的HTTP响应标头。
给上述响应标头赋值:attachment;filename="XXX"。这里的XXX是在文件下载对话框中显示的默认文件名。他可以与真实的文件名相同,也可以不同。
下面是一个文件下载的实例概述:
response.setContentType(contenttype); FileInputStream fis=new FileInputStream(file); BufferedInputStream bis=new BufferedInputStream(fis); byte[] bytes=new byte[1024]; OutputStream os=response.getOutputStream(); bis.read(bytes); os.write(bytes);
首先,将要下载的文件当成一个FileInputStream,并将内容添加到一个字节数组中;
然后获取HttpServletResponse的OutputStream,并调用它的write()方法,将字节数组传递给它。
二、下载隐藏文件实例
在下面这个示例中,secret.pdf文件放在WEB-INF/data里,不允许直接访问。用一个FileDownloadServlet将secret.pdf文件发送到浏览器,但是授权用户才能浏览。如果用户没有登录,应用程序就会跳转到login界面,这里,用户可以在表单中输入用户名和密码,这些内容都被提交到另一个LoginServlet处理。
下面是该应用程序的结构图:
1.用户提交登录表单
login.jsp页面,包含一个HTML表单,其中有两个输入域:userName和password
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!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=ISO-8859-1"> <title>Login</title> </head> <body> <form action="login" method="post"> <table> <tr> <td>User Name:</td> <td><input type="text" name="userName"/></td> </tr> <tr> <td>PassWord:</td> <td><input type="password" name="password"/></td> </tr> <tr> <td colspan="2"><input type="submit" value="login"/></td> </tr> </table> </form> </body> </html>
提交表单时会调用LoginServlet,它的类代码如下。在这个应用程序中,我假设用户名和密码必须是ken/secret。
package filedownload; import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Servlet implementation class LoginServlet */ public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public LoginServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub 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"); //must call return or else the code after this if //block,if any,will be executed return; }else{ RequestDispatcher dispatcher=request.getRequestDispatcher("/login.jsp"); dispatcher.forward(request, response); } } }<span style="font-size:14px;"> </span>
用户登录成功后,会设置一个loggedln会话属性,并将用户转到FileDownloadServlet。
在HttpServletResponse.sendRedirect之后,必须返回,以防止执行后面的代码行。登录失败后,则会将用户转到login.jsp页面。
2.进行文件下载
FileDownloadServlet展示了一个负责发送secret.pdf文件的Servlet。只有当用户的HttpSession中包含loggedlin属性时,表示用户已经成功登录,此时才允许访问。
package filedownload; 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.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Servlet implementation class FileDownloadServlet */ public class FileDownloadServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public FileDownloadServlet() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub HttpSession session=request.getSession(); if(session==null||session.getAttribute("loggedIn")==null){ RequestDispatcher dispatcher=request.getRequestDispatcher("/login.jsp"); dispatcher.forward(request, response); return;//must return after dispatcher.forward(),Otherwise the code below will be executed } String dataDirectory =request.getServletContext().getRealPath("/WEB-INF/data/secret.pdf"); //System.out.println(dataDirectory); File file=new File(dataDirectory); if(file.exists()){ response.setContentType("application/pdf"); response.addHeader("Content-Disposition", "attachment;filename=secret.pdf"); byte[] buffer=new byte[1024]; FileInputStream fis=null; BufferedInputStream bis=null; 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 e){ System.out.println(e.toString()); }finally{ if(bis!=null){ bis.close(); } if(fis!=null){ fis.close(); } } }else{ System.out.println("secret.pdf does not exit!"); } } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub } }
doGet方法会检查HttpSession中是否有loggedIn属性。如果没有,则会将用户带到登录界面。
HttpSession session=request.getSession(); if(session==null||session.getAttribute("loggedIn")==null){ RequestDispatcher dispatcher=request.getRequestDispatcher("/login.jsp"); dispatcher.forward(request, response); return;//must return after dispatcher.forward(),Otherwise the code below will be executed }
注意,在RequestDispatcher中调用forward会将控制权转移到不同的资源。但是,它不会中止当前在调用对象的代码执行,因此,跳转之后必须返回。
如果用户已经登录成功,doGet方法就会打开索要的资源,并将它引到ServletResponse的OutputStream。
String dataDirectory =request.getServletContext().getRealPath("/WEB-INF/data/secret.pdf"); //System.out.println(dataDirectory); File file=new File(dataDirectory); if(file.exists()){ response.setContentType("application/pdf"); response.addHeader("Content-Disposition", "attachment;filename=secret.pdf"); byte[] buffer=new byte[1024]; FileInputStream fis=null; BufferedInputStream bis=null; 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 e){ System.out.println(e.toString()); }finally{ if(bis!=null){ bis.close(); } if(fis!=null){ fis.close(); } } }else{ System.out.println("secret.pdf does not exit!"); }
利用下面的URL调用FileDownloadServlet,可以对该应用程序进行测试:
http://localhost:8080/app12a/download
3.PS:web.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>app12a</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <description></description> <display-name>FileDownloadServlet</display-name> <servlet-name>FileDownloadServlet</servlet-name> <servlet-class>filedownload.FileDownloadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FileDownloadServlet</servlet-name> <url-pattern>/download</url-pattern> </servlet-mapping> <servlet> <description></description> <display-name>LoginServlet</display-name> <servlet-name>LoginServlet</servlet-name> <servlet-class>filedownload.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping> </web-app>
4.测试截图
摘录自:《Servlet和JSP学习指南》