第十一章_文件下载

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>

这样就能避免其它站点使用爬虫等技术进行图片下载。直接复制图片地址是訪问不到图片的。

时间: 2024-10-05 12:30:37

第十一章_文件下载的相关文章

我的学习之路_第十一章_字符流

[字符流] IO流的分类 ★字节流 操作的文件不是文本文件 字节输入流: InputStream 抽象类 FileInputStream操作文件的字节输入流 字节输出流: OutputStream 抽象类 FileOutputStream操作文件的字节输出流 ★字符流 操作的文件是文本文件 字符输入流: Reader 抽象类 FileReader 用来操作文件的字符输入流 字符数出流: Writer 抽象类 FileWriter 用来操作文件的字符输出流 [转换流] ▲OutputStreamW

perl5 第十一章 文件系统

第十一章  文件系统 by flamephoenix 一.文件输入/输出函数  1.基本I/O函数    1)open函数    2)用open重定向输入    3)文件重定向    4)指定读写权限    5)close函数    6)print, printf和write函数    7)select函数    8)eof函数    9)间接文件变量  2.跳过和重读数据  3.系统读写函数  4.用getc读取字符  5.用binmode读取二进制文件二.目录处理函数  1.mkdir  2

计算机系统要素:第十一章 编译器:代码生成

一,项目介绍 终于来到了编译器部分的最后一个章节--代码生成阶段.本章的目标就是将Jack语言转化为VM语言,完成Jack编译器的构建. 刚刚接触这章的内容时,会比较难上手,最主要的问题就在于,这章的内容看起来和第十章没有什么关系.刚开始做这个项目时,我就很疑惑,第十章输出的不是一个结构化的xml文件吗?这个文件在第十一章根本不需要输出,那么这章的内容从何开始呢? 的确,这个xml文件是不需要输出的,但是第十章的目的并不单纯是输出这个xml文件,它更重要的目的是为了让我们了解如何对jack程序文

javascript高级程序设计 第十一章--DOM扩展

javascript高级程序设计 第十一章--DOM扩展DOM最主要的扩展就是选择符API.HTML5和Element Traversal Selectors API:定义了两个方法 querySelector() 和 querySelectorAll(),能够基于CSS选择符从DOM中取得元素.querySelector()方法接收一个CSS选择符,返回该模式匹配的第一个元素,querySelectorAll()接收的参数一样,但是返回NodeList实例: matchesSelector()

c++ primer 5th 笔记:第十一章

第十一章:关联容器 笔记 1. 关联容器和顺序容器有着根本的不同:关联容器中的元素是按关键字来保存和访问的.与之相对,顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的. 2. 关联容器支持高效的关键字查找和访问,两个主要的关联容器类型是map和set.map中的元素是一些关键字-值对:关键字起到索引的作用,值则表示与索引相关联的数据.set中每个元素只包含一个关键字:set支持高效的关键字查询操作--检查一个给定关键字是否在set中. 3. 当从map中提取一个元素时,会得到一个pair

zabbix专题:第十一章 zabbix proxy分布式监控配置

zabbix专题:第十一章 zabbix proxy分布式监控配置             对Linux有兴趣的朋友加入QQ群:476794643 在线交流 本文防盗链:http://zhang789.blog.51cto.co zabbix proxy分布式监控配置 zabbix proxy可以代替zabbix server检索客户端的数据,然后把数据汇报给zabbix server,并且在一定程度上分担了zabbix server的压力.zabbix proxy可以非常简便的实现了集中式.分

第十一章 执行查询算法

第十一章      执行查询算法 基本概念: 三类查找方法:线性查找.树形查找.哈希表查找 动态查找表:在查找的同时,对表做修改操作(如插入和删除),则相应的表称为动态查找表 静态查找表:与动态查找表相反 查找过程中对关键字需要执行的平均比较次数(也称平均比较长度作为衡量一个查找算法优劣的标准 平均比较长度: 其中:n是结点的个数:pi是查找第i个结点的概率.若不特别申明,认为每个结点的查找概率相等,都为1/n:ci是找到第i个结点所需进行的比较次数. 线性查找: 基本思想:从表的一端开始,顺序

Linux与云计算——第二阶段 第一十一章:代理Proxy服务器架设—Squid代理服务器正向代理和客户端配置

Linux与云计算--第二阶段Linux服务器架设 第一十一章:代理Proxy服务器架设-Squid代理服务器正向代理和客户端配置 安装Squid 安装Squid来配置代理服务器. [1] 这是一个通用的转发代理配置 [[email protected] ~]# yum -y install squid [[email protected] ~]# vi /etc/squid/squid.conf # line 26: 添加一条新的ACL acl lan src 192.168.96.0/24

第十一章 读书笔记

第十一章  Linux驱动程序中的 并发控制 并发(concurrency)指的是多个执行单元同时.并行被执行.而并发的执行单元对共享资 源〈如硬件资摞.程序中的全局变量.静态变量等〉的访问很容易导致竞态条件( race conditions). 自旋锁并不关心锁定的|临界区究竟是怎样的操作,不管是读还是写,都只允许同时只有一个执 行单元可以极取自旋锁, 即使有多个单元同时读取临界区资源也会被锁住.实际上,对于并发访问 共享资源时,多个执行单元同时读取它是不会有任何问题的.为了解决这个问题,自旋