利用Servlet实现文件安全下载
利用Servlet实现文件的下载功能,今天就利用上班时间做了一个小小的demo.在这里先说明一下:在实现Servlet下载的时候,大家可能会习惯性的在html页面直接写一个URL链接,如:
http://127.0.0.1:7001/TestFileUpload/fileDownLoadServlet?filename=mm.txt&file_path=/day1/xiu.txt。这是一种很不友好的方式,它容易暴露主机系统的文件路径,很不安全,别有用心的人如果知道了主机系统文件的目录结构,就很轻易的在浏览器的地址栏中输入这样的URL链接随意的下载系统文件。所以那种方式我就不建议采用了.
首先写一个Servlet下载类,为了安全,我采用了post提交方式。
public class FileDownLoadServlet extends HttpServlet{ private static final long serialVersionUID = 1L; @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); //获得文件名 String fileName=request.getParameter("filename"); //获得文件所在的路径 String filePath=request.getParameter("file_path"); download(fileName,filePath,request,response); } public HttpServletResponse download(String fileName,String filePath,HttpServletRequest request, HttpServletResponse response) { try { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); ServletContext application=this.getServletContext(); //application.getRealPath("/") 得到web应用的绝对路径 File file = new File(application.getRealPath("/")+filePath); System.out.println("request path: "+application.getRealPath("/")); //返回URL请求的URL路径 System.out.println("getContextPath :"+request.getContextPath()); // 以流的形式下载文件。 InputStream fis = new BufferedInputStream(new FileInputStream(file)); byte[] buffer = new byte[fis.available()]; fis.read(buffer); fis.close(); // 清空response response.reset(); // 设置response的Header response.addHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes("utf-8"),"ISO-8859-1")); response.addHeader("Content-Length", "" + file.length()); response.setContentType("application/octet-stream"); OutputStream out = new BufferedOutputStream(response.getOutputStream()); out.write(buffer); out.flush(); out.close(); } catch (IOException ex) { ex.printStackTrace(); } return response; } }
之所以采用post提交方式,是因为get方式非常的不安全(虽然get()方式比较方便、直观)。
之后就配置web.xnl文件,把Servlet配置进去.
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>attach</servlet-name> <servlet-class>com.future.zfs.util.FileDownLoadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>attach</servlet-name> <url-pattern>/attach</url-pattern> </servlet-mapping> </web-app>
最后就写一个test.html文件啦.采用了URL链接方式提交表单,因为form表单自身的type="submit"方式在网页显示的是一个按钮,呵呵,本来下载应该是一个URL链接才是,个人想法。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>test.html</title> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="this is my page"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <!--<link rel="stylesheet" type="text/css" href="./styles.css">--> <script type="text/javascript"> function download(){ document.getElementById("form").submit(); } </script> </head> <body> <form id="form" action="attach" method="post"> <input type="hidden" name="filename" value="mm.txt" /> <input type="hidden" name="file_path" value="/day1/xiu.txt"/> </form> <a href="javascript:void(0)" onclick="download()">文件下载</a> </body> </html>
当你把鼠标移到文件下载这个链接上时,在浏览器的状态栏显示的时:javascript:void(0) ,而不是文件的系统路径了。就算知道了文件路径在浏览器的地址输入地址也不会进行下载.。因为在地址栏的都是get()方式,而我们在下载类里写的是Post()方法。
好了,一个安全下载的小demo就这样完成了.关于文件名的中文问题,我还没有找到解决办法,有知道的分享下呗.
为了方便大家,我把我做的demo路径贴出来: