IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> JavaWeb—文件上传下载—Eclipse版动力节点学习笔记 -> 正文阅读

[开发工具]JavaWeb—文件上传下载—Eclipse版动力节点学习笔记

JavaWeb—文件上传下载

哔哩哔哩蛙课网【动力节点】JavaWeb-Eclipse版学习视频网址
文章只为分享学习经验和自己复习用,学习还是该去查看正规视频网站和官方文档才更有效

解析归属备注
mutipart/form-data多部分请求/表单数据文件上传enctype 特殊请求
getInputStream()获得输入流IO
FileUploadapache上传工具文件上传apache上传工具
ServletFileUploadServlet文件上传文件上传
.isMultipartContent()是多部分内容请求文件上传
DiskFileItemFactory()磁盘 文件项目 工厂FileUpload
ServletFileUpload()Servlet 文件上传 组件FileUpload
.parseRequest()利用工具解析请求基本上传
.isFormField()是普通表单字节基本上传
.getInputStream()获得输入流上传内容基本上传
.getRealPath获得真实路径基本上传
FileOutputStream文件输出流输出基本上传
setSizeThreshold设置临时目录门槛大小临时目录
setRepository设置临时存储库临时目录
.delete()临时文件删除临时目录
.setHeaderEncoding(“UTF-8”)解决文件中文名参数名问题
System.currentTimeMillis()当前系统时间参数名问题
.setFileSizeMax上传文件大小参数名问题
.setSizeMax上传所有文件总大小参数名问题
Calendar.getInstance()获得当前系统时间参数名问题
Calendar.YEAR,.MONTH年,月参数名问题MONTH是从0开始算的
Calendar.DAY_OF_MONTH参数名问题
.mkdir()创建目录参数名问题.mkdirs() 多级目录
new SimpleDateFormat(“yyyyMMdd”)格式化日期Servlet 下载
format()格式化日期Servlet 下载
setHeader头部信息Servlet 下载
“content-disposition”,"attachment“下载的头部信息Servlet 下载
filename下载后的文件名Servlet 下载

文件上传与下载

1、 文件上传

1.1、什么是上传与下载?

数据上传是指客户端向服务器上传数据,客户端向服务器发送的所有请求都属于数据上传。文件上传是数据上传的一种特例,指客户端向服务器上传文件。即将保存在客户端的文件上传至服务器中一个副本,保存到服务器中。

数据下载是指客户端从服务器上获取数据的过程。文件下载是数据下载的一种特例,指客户端从服务器下载文件,即将原本保存在服务器中的文件下载到到客户端中一个副本保存。通常我们对服务器所发出的请求,大多是文件下载请求,从服务器中下载文本、图片、声音、视频等文件,然后由客户端浏览器对这些文件进行解析后,才可能看到这些多媒体信息。

但我们这里所说的文件下载,指的是文件从服务器下载到浏览器后,浏览器并不直接解析,而是以附件的形式保存到客户端。

上传与下载的文件可以是文本文件、图片、声音、视频等各种类型。

在这里插入图片描述

1.2、文件上传的实现

1.2.1、上传表单要求

文件上传要求客户端表单提交特殊的请求 ---- multipart 请求,即包含多部分数据的请求。所以文件上传表单对于表单数据的编码类型要求,必须为 mutipart/form-data。即要为<form/>标签指定 enctype 属性值为“mutipart/form-data”。enctype,即 encoding type,编码类型。

由于客户端上传文件的大小是不确定的,所以 HTTP 协议规定,文件上传的数据要存放于请求正文中,而不能出现在 URL 的地址栏中,因为地址栏中可以存放的数据量太小。也就是说,文件上传的表单,必须提交 POST 请求,而不能提交 GET 请求。

在这里插入图片描述

1.2.2、multipart/form-data 协议

multipart/form-data 的编码类型,是一种固定格式的编码方案,是 HTTP 请求协议规定好的一种通信格式。该编码方案首先告诉服务器,现在发送的请求是一个来自表单数据的多部分请求,请求体中包含多部分数据。

在这里插入图片描述

请求的具体格式可以通过火狐浏览器的“网络/参数”查看到。打开火狐浏览器的开发者工具栏窗口,当请求发出后,点击该请求,然后选择“网络/参数”即可看到发送的请求正文内容。注意,不要在 IE 下使用 HttpWatch 来查看文件上传的请求正文,因为 HttpWatch会拦截下请求,使请求无法发送成功。

在这里插入图片描述

就本例而言,表单中包含 name、age,与要上传的文件 img 三部分数据。其中 name 值为 zhangsan,age 值为 23,而文件 img 则为一个文本文件,文本文件在客户端的文件名为abc.txt。

HTTP 协议规定,multipart/form-data 的请求正文包含以下几部分:

请求正文头

其中包含请求的类型 Content-Type,当然,固定为 multipart/form-data。multipart 请求各部分间的分隔符 boundary,这个分隔符由若干中划线和一个随机数构成。请求正文的内容长度 Content-Length。

请求正文体

请求正文头与请求正文体,及请求正文体间都使用前面指定的分隔符进行分隔,将请求正文分隔为了多部分,即 multipart。每一部分,我们称其为一个 Item。

每个 Item 又由三部分构成:

  • 参数信息:参数信息包含内容来源 Content-Disposition,form-data 为表单数据;参数名称;若参数为要上传的文件,还包含文件原始名称 filename,文件的 MIME 类型Content-Type,text/plain 表示普通的文本文件。
  • 分隔空行:就一个空行,用于分隔参数信息与参数值。
  • 参数值:具体上传的参数的值。若上传的文件为文本文件,则会将正常的文本上写入到这里。若上传的文件为图片、视频、音频等,则会将其二进制文件上传。下图为上传的图片文件的参数值。

在这里插入图片描述

1.2.3、服务端手工接收上传文件

服务端接收上传的文件,可以通过输入流来完成。而输入流可以通过 HttpServletRequest的 **getInputStream()**获取到。

接收到后,可以对输入流中的数据进行解析,然后响应给客户端。 multipart/form-data对协议的解析,手工完成比较麻烦,这里就不手工完成了。仅仅是接收到,在控制台显示一下即可。

定义表单页面 index.jsp

在这里插入图片描述

定义 UploadServlet

在这里插入图片描述

注册 UploadServlet

在这里插入图片描述

1.2.4、使用第三方工具上传

可以完成上传功能的第三方工具很多,但比较著名的是 Apache 的 FilterUpload 工具。该工具可以 Apache 的官网上下载。Apache 的官网为:http://apache.org

FileUpload 工具下载

FileUpload 工具存放在 Apacher 的 Commons 中,所以需要在 Commons 下下载。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在链接上右击,选择“将链接另存为”,即可下载。

在这里插入图片描述

IO 包下载

进一步跟踪该 Jar 包的信息,会看到如下注意:该版本需要依赖于 Apache 的 Commons下的 IO2.2 的包。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

官网用户向导

打开 Apache 官网的文件上传主页的用户向导 User guide,其中就有使用 FileUpload 工具实现文件上传的示例。

在这里插入图片描述

在这里插入图片描述

1、代码实现-版本 1-基本上传

该版本完成了基本的文件上传功能。

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;

public class RegisterServlet extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		//1.判断请求是否为为multipart请求
		if (!ServletFileUpload.isMultipartContent(request)) {
			throw new RuntimeException("当前请求不支持文件上传");
		}
		try {
			//创建一个 FileItem工厂
			DiskFileItemFactory factory = new DiskFileItemFactory();
			//创建文件上传核心组件
			ServletFileUpload upload = new ServletFileUpload(factory);
			//利用工具解析请求,获取到所有的item
			List<FileItem> items = upload.parseRequest(request);
			//遍历item
			for (FileItem item : items) {
				if (item.isFormField()) {	//若item为普通表单项
					String fieldName = item.getFieldName();   // 获取表单项名称
					String fieldValue = item.getString();      // 获取表单项的值
					System.out.println(fieldName + " = " + fieldValue);
				}else {						//若item为文件表单项
					String fileName = item.getName();    // 获取上传文件原始名称
					// 获取输入流,其中有上传文件的内容
					InputStream is = item.getInputStream();
					// 获取文件保存在服务器的路径
					String path = this.getServletContext().getRealPath("/images");
					// 创建目标文件,将来用于保存上传文件
					File descFile = new File(path, fileName);
					// 创建文件输出流
					OutputStream os = new FileOutputStream(descFile);
					// 将输入流中的数据写入到输出流中\
					int len = -1;
					byte[] buf = new byte[1024];
					while((len = is.read(buf)) != -1) {
						os.write(buf, 0, len);
					}
					// 关闭流
					os.close();
					is.close();
				}
			}
		} catch (FileUploadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}
}
2、代码实现-版本 2-临时目录

文件由浏览器通过网络上传到服务器,并不是直接通过一条网络线路将所有请求数据发送到了服务器的。

而是将这些数据分为了很多个数据包,这些数据包分别编号后,经由不同的网络线路最终发送到了同一台机器 ---- 服务器。

这些数据包到达服务器的时间会根据不同的网络线路的情况不同,分别先后到达服务器,不一定是按照编号顺序到达的,或者是大多数情况下是不会按照编号顺序到达的。那么,服务器就会在其临时目录中,创建一个临时文件,将这些数据包进行拼接组装。


// 设置使用临时文件的边界值,大于该值,上传文件会先保存在临时文件中,否则,上传文件将直接写入到内存。
// 单位:字节。本例设置边界值为1M
factory.setSizeThreshold(1024 * 1024 * 1);
			
// 设置临时文件
String tempPath = this.getServletContext().getRealPath("/temp");
File temp = new File(tempPath);
factory.setRepository(temp);

Tomcat 默认情况下的临时目录是 Tomcat 服务器安装目录的 temp 子目录。当然,我们也可以修改临时目录的默认位置。

Apache 的 FileUpload 支持设置创建临时文件的最小临界值,即只有上传的文件大小超出这个值,才会创建临时文件。通过 DiskFileItemFactory 的 setSizeThreshold() 方法可以设置临界值,单位为字节。

通过 DiskFileItemFactory 的 setRepository() 方法可以指定临时目录。

临时文件一旦用完,就可将其删除了,否则占用服务器的硬盘空间。而对临时文件的删除,使用的是 FileItem 的 delete() 方法。

需要注意的是,对于临时文件的删除,需要在 IO 流关闭后,否则,无法删除。

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;

public class RegisterServlet extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		//1.判断请求是否为为multipart请求
		if (!ServletFileUpload.isMultipartContent(request)) {
			throw new RuntimeException("当前请求不支持文件上传");
		}
		try {
			//创建一个 FileItem工厂
			DiskFileItemFactory factory = new DiskFileItemFactory();
            
            // 设置使用临时文件的边界值,大于该值,上传文件会先保存在临时文件中,否则,上传文件将直接写入到内存。
			// 单位:字节。本例设置边界值为1M
			factory.setSizeThreshold(1024 * 1024 * 1);
			
			// 设置临时文件
			String tempPath = this.getServletContext().getRealPath("/temp");
			File temp = new File(tempPath);
			factory.setRepository(temp);
                      
			//创建文件上传核心组件
			ServletFileUpload upload = new ServletFileUpload(factory);
			//利用工具解析请求,获取到所有的item
			List<FileItem> items = upload.parseRequest(request);
			//遍历item
			for (FileItem item : items) {
				if (item.isFormField()) {	//若item为普通表单项
					String fieldName = item.getFieldName();   // 获取表单项名称
					String fieldValue = item.getString();      // 获取表单项的值
					System.out.println(fieldName + " = " + fieldValue);
				}else {						//若item为文件表单项
					String fileName = item.getName();    // 获取上传文件原始名称
					// 获取输入流,其中有上传文件的内容
					InputStream is = item.getInputStream();
					// 获取文件保存在服务器的路径
					String path = this.getServletContext().getRealPath("/images");
					// 创建目标文件,将来用于保存上传文件
					File descFile = new File(path, fileName);
					// 创建文件输出流
					OutputStream os = new FileOutputStream(descFile);
					// 将输入流中的数据写入到输出流中\
					int len = -1;
					byte[] buf = new byte[1024];
					while((len = is.read(buf)) != -1) {
						os.write(buf, 0, len);
					}
					// 关闭流
					os.close();
					is.close();
                    
                    // 删除临时文件
					item.delete();
				}
			}
		} catch (FileUploadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}
}
3、代码实现-版本 3-参数名问题

当前的程序存在如下问题:

  • 当用户从表单中提交的普通参数包含中文字符时,会出现乱码问题

  • 当上传文件的文件名包含中文时,上传到服务器的文件名会出现乱码。

  • 不同的浏览器,向服务器上传的文件名是不同的,即 FileItem 的 getName()方法获取到的文件名是不同的。

    例如,用户从客户端上传了 D:\abc\xxx.jpg 文件,火狐浏览器上传的文件名为 xxx.jpg,而 IE 浏览器上传的文件名为 D:\abc\xxx.jpg。

  • 不同的用户若提交了相同的文件名的文件,后面的用户的文件将无法上传。

解决这些问题的思路:

(1)解决普通参数的中文乱码问题,只需使用 FileItem 的带参 getString(String Encoding)方法获取参数名即可。

// 设置每一个item的头部字符编码,其可以解决文件名的中文乱码问题
	upload.setHeaderEncoding("UTF-8");

(2)上传文件名的中文乱码问题,需要通过 ServletFileUpload 的方法 setHeadEncoding()指定上传文件请求头部编码的方式解决。不过,需要注意的是,该设置方式不会改变普通参数请求头部的编码。

String fieldName = item.getFieldName();           // 获取表单项名称
String fieldValue = item.getString("UTF-8");      // 获取表单项的值

(3)为了解决浏览器向服务器发送文件名不同这个问题,需要使用 String 的 substring()方法截取出文件名。因为文件名一定是最后一个”\”后面部分。

(4)对于相同文件名的上传问题,只需要使保存在服务器端的文件名称唯一即可。例如,为原始文件名前添加一个当前系统时间 System.currentTimeMillis()。

String fileName = item.getName();    // 获取上传文件原始名称
//System.currentTimeMillis() 系统时间+原文件名字
fileName = System.currentTimeMillis() + fileName;

(7) 代码实现-版本 4-文件大小

对于上传文件的大小,可以通过 ServletFileUpload 的 setFileSizeMax()setSizeMax() 方法进行控制。setFileSizeMax()用于设置单个文件上传的最大值,而 setSizeMax()用于设置单次上传的最大值。即若一次上传多个文件,每个文件的大小边界值与所有文件加起来的最大小值。

// 设置单个上传文件的最大边界值为2M
	upload.setFileSizeMax(1024 * 1024 * 2);
			
// 设置一次上传所有文件的总和最大值为5M(对于上传多个文件时起作用)
	upload.setSizeMax(1024 * 1024 * 5);

(8) 代码实现-版本 5-自建目录

无论是 Windows 系统、Linux 系统,还是其它系统,其目录中所包含的文件数量是有上限的。所以对于上传的文件,应该分目录进行管理。若文件不是太多,可以在 images 下按照 yyyyMMdd 日期格式再建一级子目录。若文件较多,则可按照年、月、日创建多级子目录。这样,即方便管理,又不会超出目录的文件数量上限。

下面实现了以 yyyyMMdd 格式命名的一级子目录。

			// 获取文件保存在服务器的路径
					String path = this.getServletContext().getRealPath("/images");
					
			// 获取当前系统时间
					Date date = new Date();
			// 格式化日期
					SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
					String now = sdf.format(date);
			//以天为标准的一级目录
					path = path + "/" + now;
					
			// 若该目录不存在,则创建这个目录
					File dirFile = new File(path);
					if (!dirFile.exists()) {
                        //mkdir() 创建目录
						dirFile.mkdir();
					}

下面实现了是多级目录

    // 获取文件保存在服务器的路径
    String path = this.getServletContext().getRealPath("/images");

    // 获取当前系统时间
    Calendar now = Calendar.getInstance();
    // 获取年、月、日
    int year = now.get(Calendar.YEAR);
    int month = now.get(Calendar.MONTH) + 1;	//MONTH从0开始,所以需要+1
    int day = now.get(Calendar.DAY_OF_MONTH);

    path = path + "/" + year + "/" + month + "/" + day;

    // 若该目录不存在,则创建这个目录
    File dirFile = new File(path);
    if (!dirFile.exists()) {
        dirFile.mkdirs();		//多级目录使用mkdirs
    }

全部代码

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class RegisterServlet extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("执行上传");
		
		// 判断请求是否为multipart请求
		if( !ServletFileUpload.isMultipartContent(request) ) {
			throw new RuntimeException("当前请求不支持文件上传");
		}
		try {
			// 创建一个FileItem工厂
			DiskFileItemFactory factory = new DiskFileItemFactory();
			
			// 设置使用临时文件的边界值,大于该值,上传文件会先保存在临时文件中,否则,上传文件将直接写入到内存。
			// 单位:字节。本例设置边界值为1M
			factory.setSizeThreshold(1024 * 1024 * 1);
			
			// 设置临时文件
			String tempPath = this.getServletContext().getRealPath("/temp");
			File temp = new File(tempPath);
			factory.setRepository(temp);
			
			// 创建文件上传核心组件
			ServletFileUpload upload = new ServletFileUpload(factory);
			
			// 设置每一个item的头部字符编码,其可以解决文件名的中文乱码问题
			upload.setHeaderEncoding("UTF-8");
			
			// 设置单个上传文件的最大边界值为2M
			upload.setFileSizeMax(1024 * 1024 * 2);
			
			// 设置一次上传所有文件的总和最大值为5M(对于上传多个文件时起作用)
			upload.setSizeMax(1024 * 1024 * 5);
			
			// 解析请求,获取到所有的item
			List<FileItem> items = upload.parseRequest(request);
			// 遍历items
			for (FileItem item : items) {
				if(item.isFormField()) {   // 若item为普通表单项
					String fieldName = item.getFieldName();           // 获取表单项名称
					String fieldValue = item.getString("UTF-8");      // 获取表单项的值
					System.out.println(fieldName + " = " + fieldValue);
				} else {                   // 若item为文件表单项
					String fileName = item.getName();    // 获取上传文件原始名称
					fileName = System.currentTimeMillis() + fileName;
					// 获取输入流,其中有上传文件的内容
					InputStream is = item.getInputStream();
					// 获取文件保存在服务器的路径
					String path = this.getServletContext().getRealPath("/images");
					
					// 获取当前系统时间
					Calendar now = Calendar.getInstance();
					// 获取年、月、日
					int year = now.get(Calendar.YEAR);
					int month = now.get(Calendar.MONTH) + 1;	//MONTH从0开始,所以需要+1
					int day = now.get(Calendar.DAY_OF_MONTH);
					
					path = path + "/" + year + "/" + month + "/" + day;
					
					// 若该目录不存在,则创建这个目录
					File dirFile = new File(path);
					if (!dirFile.exists()) {
						dirFile.mkdirs();		//多级目录使用mkdirs
					}
					
					// 创建目标文件,将来用于保存上传文件
					File descFile = new File(path, fileName);
					// 创建文件输出流
					OutputStream os = new FileOutputStream(descFile);
					// 将输入流中的数据写入到输出流中
					int len = -1;
					byte[] buf = new byte[1024];
					while((len = is.read(buf)) != -1) {
						os.write(buf, 0, len);
					}
					
					// 关闭流
					os.close();
					is.close();
					
					// 删除临时文件
					item.delete();
				}
			}			
		} catch (FileUploadException e) {
			e.printStackTrace();
		}
		
	}

}

2、文件下载

2.1、超链接下载

所谓超链接下载是指,将下载资源作为超链接的链接目的文件出现。

若浏览器可以解析该资源文件,则将在浏览器上直接显示文件内容;若浏览器不支持该文件的解析,则会弹出另存为对话框,要求用户保存。

缺点:不同的浏览器,以及相同的浏览器所安装的插件不同,那么其对于资源的解析能力也就不同,其是否弹出另存为对话框的情况也就不一样,决定权由浏览器掌握。

存放资源

在项目的 WebRoot 下新建一个目录 resources,在其中存放各类资源文件。

编写链接

在 index.jsp 页面中编写如下超链接。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<!-- 超链接方式的文件下载 -->
	<a href="${pageContext.request.contextPath }/resources/aaa.jpg">aaa.jpg</a> <br>
	<a href="${pageContext.request.contextPath }/resources/bbb.jar">bbb.jar</a> <br>
	<a href="${pageContext.request.contextPath }/resources/ccc.zip">ccc.zip</a> <br>
	<a href="${pageContext.request.contextPath }/resources/ddd.pdf">ddd.pdf</a> <br>
	<a href="${pageContext.request.contextPath }/resources/eee.exe">eee.exe</a> <br>
	<a href="${pageContext.request.contextPath }/resources/fff.txt">fff.txt</a> <br>
</body>
</html>

2.2、Servlet 下载

若要使下载的文件以附件的形式出现在浏览器,则需要设置响应头的属性content-disposition 的值为 attachment,且需要指定浏览器下载后显示的文件名。

即需要 response.setHeader 指定 content-disposition 的值为 attachment ; filename=文件名

2.2.1、下载的实现

定义 index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<!-- 超链接方式的文件下载 -->
	<a href="${pageContext.request.contextPath }/downloadServlet">跑车</a> <br>
</body>
</html>

定义 DownloadServlet

package com.bjpowernode.servlets;

import java.io.IOException;
import java.io.InputStream;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DownloadServlet extends HttpServlet {
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		String fileName = "超跑.jpg";
		
		// 打散:按当前的字符编码进行打散
		byte[] bytes = fileName.getBytes("UTF-8");
		// 组装:按目标字符编码进行组装
		fileName = new String(bytes, "ISO8859-1");
		
		// 修改响应的头部属性content-disposition值为attachment
		response.setHeader("content-disposition", "attachment;filename=" + fileName);
		
		// 获取连接服务端资源文件的输入流
		InputStream is = this.getServletContext().getResourceAsStream("/resources/aaa.jpg");
		// 获取输出流 
		ServletOutputStream os = response.getOutputStream();
		// 将输入流中的数据写入到输出流中
		int len = -1;
		byte[] buf = new byte[1024];
		while((len = is.read(buf)) != -1) {
			os.write(buf, 0, len);
		}
		
		// 关闭流
		os.close();
		is.close();
	}

}

注册 DownloadServlet

<?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>08-download-1</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>DownloadServlet</display-name>
    <servlet-name>DownloadServlet</servlet-name>
    <servlet-class>com.bjpowernode.servlets.DownloadServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>DownloadServlet</servlet-name>
    <url-pattern>/downloadServlet</url-pattern>
  </servlet-mapping>
</web-app>
2.2.2、解决文件名乱码问题
  • 将当前收到的字符编码进行打散

  • 再按目标字符编码进行组装

  • 最后根据浏览器设定的编码呈现

	String fileName = "超跑.jpg";
// 打散:按当前的字符编码进行打散
	byte[] bytes = fileName.getBytes("UTF-8");
// 组装:按目标字符编码进行组装
	fileName = new String(bytes, "ISO8859-1");

apache帮助文档网址

http://commons.apache.org/proper/commons-fileupload/using.html

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2021-09-02 11:35:04  更:2021-09-02 11:37:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/23 1:51:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计