文件上传与下载

文件上传与下载

1. 文件上传

为了能上传文件,必须将表单的 method 设置为 POST,并将 enctype 设置为 multipart/form-data

有两种实现文件上传的方式:

  • 底层使用 Apache Commons FileUpload 包

  • 底层使用 Servlet 3.1 内置的文件上传功能

无论是哪种方式,其使用方式都是一样的,将 file 类型的请求参数绑定到请求处理方法的特定类型的参数上:

  • CommonsMultipartFile(commons-fileupload)

  • MultipartFile(Servlet 3.1)

Web 3.0 的文件上传

普通的表单(form)元素无法直接上传文件,必须通过「特殊处理」。

对上传文件功能而言,有些特殊的地方:

  • form 表单内,要添加控件 <input type="file" name="myfile">
  • form 表单的提交方式必须是 post 方式
  • form 表单的内容格式要定义成 multipart/form-data 格式
<form action="..." method="post" enctype="multipart/form-data">...
</form>

enctype="multipart/form-data" 表示表单元素中的 input 数据以二进制的方式发送到服务端。此时如果是普通的 input 数据,无法像之前一样从 request 中直接获得。

对于上传文件的的大小问题,惯例是:

  • 足够小的文件,先接收到内存中,最后写入磁盘。
  • 稍大的文件,写入磁盘临时文件,最后写入最终目的地。
  • 大型文件,禁止上传。

在 Web 3.0 之前 使用 commons-fileupload 库是最常见的上传办法。当 Servlet 的设计者意识到文件上传的重要性后,在 Web 3.0 中它就成了一项内置的特性。

Web 3.0 中的文件上传主要围绕着 MultipartConfig 注解和 Part 接口。

@MultipartConfig 注解
属性说明
fileSizeThreshold
可选属性
超过该值大小的文件,在上传过程中,将被写入磁盘临时文件,而不是保存在内存中。
maxFileSize
可选属性
每个上传文件的大小上限。
maxRequestSize
可选属性
一次请求(可能包含多个上传)的大小上限。
@WebServlet(urlPatterns="/hello.do")
@MultipartConfig(maxFileSize = 5*1024*1024)
public class HelloServlet extends HttpServlet  {...
}
Part 接口

在一个表单(Form)中,无论是否有文件上传控件,Servlet 3.0 都会将这些表单控件对应成代码中的一个 Part 对象。

通过 request 对象的 .getParts() 方法可以获得所有的这些 Part 对象。

Collection<Part> parts = request.getParts();

在一个或多个部分组成的请求中,每一个表单域(包括非文本域),都将被转换成一个 Part 。

普通文本域和文件上传域的区别在于,其 Part 对象的 .getContentType() 方法返回值的不同。对于普通文本域的 Part 对象而言,该方法返回 null 。

for (Part part : parts) {if (part.getContentType() == null) {System.out.println("普通文本域");}else {System.out.println("文件上传域");}
}

补充,如果是要获取普通文本域的值,其实直接使用正常 request.getParameter() 就行。

每一个 Part 分为「头」和「体」两部分。普通文本域只有头部,而文件上传域则有头有体。

普通文本域的头部形式为:

content-disposition:form-data; name="域名"

上传文本域的头部形式为:

content-type:内容类型
content-disposition:form-data; name="域名"; filename="文件名"

对我们而言,需要的是文本上传域中的 content-disposition 中的 filename 部分。

String header = part.getHeader("content-disposition"); 
// 内容为 form-data; name="域名"; filename="文件名"

通常会使用工具类,将 content-disposition 中的 filename 中的值截取出来。

private String getFileName(String header) {String[] arr = header.split("; ");String item = null;for (String cur : arr) {// System.out.println("debug: " + cur);if (cur.startsWith("filename=")) {item = cur;break;}}int start = item.indexOf('"')+1;int end = item.lastIndexOf('"');String filename = item.substring(start, end);// System.out.println(filename);return filename;
}

Part 对象直接提供了方法将上传文件的内容写入盘:

String savePath = request.getServletContext().getRealPath("/WEB-INF/uploadFile/");
String filePathName = savePath + File.separator + fileName; // 目标文件路径名
part.write(filePathName); // 把文件写到指定路径

Part 的其它常用方法

方法说明
getContentType()获得 Part 的内容类型。如果 Part 是普通文本,那么返回 null 。
该方法可以用于区别是普通文本域,还是文件上传域。
getHeader()该方法用于获取指定的标头的值。
对于上传文本域的 Part,该参数有 content-type 和 content-disposition
对于普通文本域,则只有 content-disposition 一种。
getName()无论是普通文本域 Part ,还是文件上传域 Part ,都是获得域名值。
write()将上传文件写入磁盘中。
delete()手动删除临时文件
getInputStream()以 InputStream 形式返回上传文件的内容。
利用 commons-fileupload 文件上传

利用 commons-fileupload 文件上传需要利用引入 commons-fileupload 包(它依赖于 commons-io 包)

<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version>
</dependency>

作为 Servlet 内置上传功能之前的『准标准』,Servlet 在引入内置上传功能时借鉴了 commons-fileupload 的实现方式。因此,在了解 Servlet 内置上传功能之后,再回头看 commons-fileupload 文件上传时,你会发现它们的基本逻辑/大道理时一样的,只不过 commons-fileupload 的实现会罗嗦一些

在 Servlet 内置的上传功能中,从 request 中获得的是一个 Part[],其中的每一个 Part 对象对应着表单中的一个表单域(Form Field)。而 commons-fileupload 中我们从 request 中获得的是一个 List<FileItem>,commons-fileupload 中使用 FileItem 来对应每一个表单域,起到和 Part 一样的作用。

commons-fileupload 的罗嗦体现在以下几个方面:

  • commons-fileupload 不能对 Servlet 使用注解,因此相关的上传配置需要通过编码实现。
  • commons-fileupload 不能使用 request.getParameter()

为了能够从 request 中获得 List<FileItem>,你需要两个对象:

// 创建上传所需要的两个对象
DiskFileItemFactory factory = new DiskFileItemFactory();  // 磁盘文件对象
ServletFileUpload sfu = new ServletFileUpload(factory);   // 文件上传对象

如果不做出设置,那么相关设置则采用默认值。

// 设置上传过程中所收到的数据是『存内存』还是『存磁盘』的阈值
factory.setSizeThreshold(100 * 1024); 
// 设置磁盘临时文件的保存目录
factory.setRepository(new File("D:/upload"));// 设置解析文件上传中的文件名的编码格式,解决上传文件名中文乱码问题
sfu.setHeaderEncoding("utf-8");
// 限制单个文件的大小
sfu.setFileSizeMax(10*1024);
// 限制上传的总文件大小
sfu.setSizeMax(100*1024);

在创建文件上传对象(并作出相应设置)之后,我们可以通过它从 request 中获取我们所需要的 List<FileItem>

List<FileItem> list = sfu.parseRequest(request);

FileItem 自带了方法,可以判断当前的 FileItem 对应的是页面上的普通文本域,还是文件上传域:

for (FileItem item : list) {if (item.isFormField()) {System.out.println("普通文本域");}else {    System.out.println("文件上传域");}
}

由于 commons-fileupload 中无法使用 request.getParameter(),因此,为了获得普通文本域中的数据,需要使用 FileItem 自己的方法:

for (FileItem item : list) {if (item.isFormField()) {String fieldName = item.getFieldName();         // 例如:username / passwordString fieldValue = item.getString("UTF-8");    // 例如,tom / 123456System.out.println(fieldName + ": " + fieldValue);}else {    System.out.println("文件上传域");}
}

由于 commons-fileupload 引用了 commons-io,所以,将上传的文件内容写入磁盘倒是十分简单:

for (FileItem item : list) {if (item.isFormField()) {...}else {    System.out.println("文件上传域");// 创建输出文件String name = item.getName();// 获取上传文件的名字String outPath = "D:/upload/" + name;FileOutputStream output = new FileOutputStream(new File(outPath));// 获得上传文件字节流InputStream input = item.getInputStream(); // 使用 IOUtils 工具将输入流中的数据写入到输出流。IOUtils.copy(input, output);System.out.println("上传成功!保存的路径为:" + outPath);input.close();      // 关闭输入流output.close();     // 关闭输出流item.delete();      // 删除处理文件上传时生成的临时文件}
}

2. 文件下载

内容类型文件扩展名描述
text/plaintxt文本文件(包括但不仅包括txt)
application/msworddocMicrosoft Word
application/pdfpdfAdobe Acrobat
application/zipzipwinzip
audio/mpegmp3mp3 音频文件
image/gifgifCOMPUSERVE GIF 图像
image/jpegjpeg jpgJPEG 图像
image/pngpngPNG 图像

详细 MIME 参见 网址 。

相对于上传而言,下载文件较为简单,只需要完成两步:

  1. 设置响应的内容类型。
  2. 添加一个 content-disposition 到响应标头(addHeader()方法),其值为:attachment; filename=文件名
  3. 通过 resp 对象获得输出流,将文件内容发送至客户端。
resp.setContentType("text/plain");      // step 1
resp.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode("D:/note.txt", "UTF-8")); // step 2InputStream is = new FileInputStream(new File("D:/note.txt"));
OutputStream out = resp.getOutputStream();byte[] buffer = new byte[1024];
int n = 0;
while ((n = is.read(buffer)) > 0) {out.write(buffer, 0, n);            // step 3
}is.close();
out.close();
System.out.println("下载成功");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/696954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何计算文件哈希值(MD5值)

生成文件hash值的用途 哈希值&#xff0c;即HASH值&#xff0c;是通过对文件内容进行加密运算得到的一组二进制值&#xff0c;主要用途是用于文件校验或签名。正是因为这样的特点&#xff0c;它常常用来判断两个文件是否相同。 比如&#xff0c;从网络上下载某个文件&#xff0…

MySQL主从同步

MySQL主从同步&#xff08;复制&#xff09;是一种数据复制技术&#xff0c;用于将数据从一个MySQL数据库&#xff08;称为“主”&#xff09;复制到另一个或多个MySQL数据库&#xff08;称为“从”&#xff09;。这个过程通常用于负载均衡、数据备份、灾难恢复和其他类似场景。…

C++ Primer Plus 笔记(持续更新)

编译器的正解 数据&#xff0b;算法程序 赋值从右向左进行 cin&#xff0c;cout的本质也是对象 类和对象的解释

centerOS docker搭建flowable,流程引擎

1、准备一个mysql数据库&#xff0c;库名为flowable 2、mysql驱动下载&#xff0c;下载地址为&#xff1a; https://mvnrepository.com/artifact/mysql/mysql-connector-java此处使用的是8.0.22版本的驱动&#xff0c;且数据库必须使用版本8&#xff0c;否则第二次启动报错 3、…

OpenAI文生视频大模型Sora概述

Sora&#xff0c;美国人工智能研究公司OpenAI发布的人工智能文生视频大模型&#xff08;但OpenAI并未单纯将其视为视频模型&#xff0c;而是作为“世界模拟器” &#xff09;&#xff0c;于2024年2月15日&#xff08;美国当地时间&#xff09;正式对外发布。 Sora可以根据用户…

samber/lo 库的使用方法:type

samber/lo 库的使用方法&#xff1a;type samber/lo 是一个 Go 语言库&#xff0c;提供了一些常用的集合操作函数&#xff0c;如 Filter、Map 和 FilterMap。 这个库函数太多&#xff0c;因此我决定按照功能分别介绍&#xff0c;本文介绍的是 samber/lo 库中type相关的函数。汇…

Redis中的AOF重写到底是怎么一回事

首先我们知道AOF和RDB都是Redis持久化的方法。RDB是Redis DB&#xff0c;一种二进制数据格式&#xff0c;这样就是相当于全量保存数据快照了。AOF则是保存命令&#xff0c;然后恢复的时候重放命令。 AOF随着时间推移&#xff0c;会越来越大&#xff0c;因为不断往里追加命令。…

哪些行业适合做小程序?零售电商、餐饮娱乐、旅游酒店、教育生活、医疗保健、金融社交、体育健身、房产汽车、企管等,你的行业在其中么?

引言 在当今数字化时代&#xff0c;小程序成为了各行各业快速发展的数字工具之一。它的轻便、灵活的特性使得小程序在多个行业中找到了广泛的应用。本文将探讨哪些行业适合开发小程序&#xff0c;并介绍各行业中小程序的具体应用。 一、零售和电商 在当今数字化的商业环境中&…

C++ RAII

RAII定义 RAII&#xff08;Resource Acquisition Is Initialization&#xff09;是C编程中的一种重要的资源管理技术。它的核心思想是&#xff1a;资源的获取应该在对象的构造阶段进行&#xff0c;而资源的释放则应该在对象的析构阶段进行。通过利用C对象的生命周期和析构函数…

C#之WPF学习之路(2)

目录 控件的父类 DispatcherObject类 DependencyObject类 DependencyObject 类的关键成员和方法 Visual类 Visual 类的主要成员和方法 UIElement类 UIElement 类的主要成员和功能 FrameworkElement类 FrameworkElement 类的主要成员和功能 控件的父类 在 WPF (Windo…

谷粒商城篇章9 ---- P248-P261/P292-P294 ---- 消息队列【分布式高级篇六】

目录 1 消息队列(Message Queue)简介 1.1 概述 1.2 消息服务中两个重要概念 1.3 消息队列主要有两种形式的目的地 1.4 JMS和AMQP对比 1.5 应用场景 1.6 Spring支持 1.7 SpringBoot自动配置 1.7 市面上的MQ产品 2 RabbitMQ 2.1 RabbitMQ简介 2.1.1 RabbitMQ简介 2…

什么是Elasticsearch SQL

什么是Elasticsearch SQL 一. 介绍二. SQL 入门 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 一. 介绍 Elasticsearch SQL 是一个 X-Pack 组件&#xff0c;允许针对 Elasticsea…

通俗易懂理解G-GhostNet轻量级神经网络模型

一、参考资料 原始论文&#xff1a;[1] IJCV22 | 已开源 | 华为GhostNet再升级&#xff0c;全系列硬件上最优极简AI网络 二、G-GhostNet相关介绍 G-GhostNet 又称为 GhostNetV1 的升级版&#xff0c;是针对GPU优化的轻量级神经网络。 1. 摘要 GhostNetV1 作为近年来最流行…

Leetcode 611.有效三角形的个数

题目 给定一个包含非负整数的数组 nums &#xff0c;返回其中可以组成三角形三条边的三元组个数。 示例 1: 输入: nums [2,2,3,4] 输出: 3 解释:有效的组合是: 2,3,4 (使用第一个 2) 2,3,4 (使用第二个 2) 2,2,3示例 2: 输入: nums [4,2,3,4] 输出: 4提示: 1 < nums…

Android的LiveData

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同&#xff0c;LiveData 具有生命周期感知能力&#xff0c;意指它遵循其他应用组件&#xff08;如 activity、fragment 或 service&#xff09;的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的…

ChatGPT在医学领域的应用与前景

标题&#xff1a; ChatGPT在医学领域的应用与前景 正文&#xff1a; 随着人工智能技术的不断进步&#xff0c;ChatGPT等语言模型在医学领域的应用逐渐深入&#xff0c;展现出其巨大的潜力和广阔的发展前景。作为一个高级的自然语言处理工具&#xff0c;ChatGPT能够理解和生成…

WPF 开发调试比较:Visual Studio 原生和Snoop调试控制台

文章目录 前言运行环境简单的WPF代码实现一个简单的ListBoxVisual Studio自带代码调试热重置功能测试实时可视化树查找窗口元素显示属性 Snoop调试使用Snoop简单使用调试控制台元素追踪结构树Visual/可视化结构树Logical/本地代码可视化树AutoMation/自动识别结构树 WPF元素控制…

基于springboot+vue的房屋租赁管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

【OpenAI官方课程】第四课:ChatGPT文本推断Summarizing

欢迎来到ChatGPT 开发人员提示工程课程&#xff08;ChatGPT Prompt Engineering for Developers&#xff09;&#xff01;本课程将教您如何通过OpenAI API有效地利用大型语言模型&#xff08;LLM&#xff09;来创建强大的应用程序。 本课程由OpenAI 的Isa Fulford和 DeepLearn…

手拉手Vite+Vue3+TinyVue+Echarts+TailwindCSS

技术栈springboot3hutool-alloshi-coreVue3viteTinyVueEchartsTailwindCSS软件版本IDEAIntelliJ IDEA 2022.2.1JDK17Spring Boot3.1hutool-all5.8.18oshi-core6.4.1Vue35.0.10vite5.0.10axios1.6.7echarts5.4.3 ECharts是一个使用 JavaScript 实现的开源可视化库&#xff0c;可…