文件上传下载概述

news2024/11/15 17:52:30

So Easy系列之文件上传下载教程

  1. 文件上传下载概述
    1. 什么是文件上传下载

所谓文件上传下载就是将本地文件上传到服务器端,从服务器端下载文件到本地的过程。例如目前网站需要上传头像、上传下载图片或网盘等功能都是利用文件上传下载功能实现的。

文件上传下载实际上是两步操作,第一是文件上传,就是将本地文件上传到服务器端,实现文件多用户之间的共享,第二是文件下载,就是将服务器端的文件下载到本地磁盘。

下面就文件上传与下载功能,分别学习。

    1. 文件上传下载实现原理

首先,需要知道文件是如何实现上传及下载的。文件上传及下载实现原理如下:

 

文件上传实现原理分析

文件上传实现流程如下:

  • 客户端浏览器通过文件浏览框,选择需要上传的文件内容(其中包括文件路径及文件内容)。
  • 客户端浏览器通过点击上传按钮,将本地文件上传到服务器端。
  • 服务器端通过程序接收本地文件内容,并将其保存在服务器端磁盘中。

 

文件下载实现原理分析

文件下载实现流程如下:

  • 客户端浏览器通过点击下载按钮,将服务器端保存的文件下载到本地磁盘。
  • 服务器端通过程序将服务器端文件响应给客户端。
  1. 文件上传实现
    1. 文件上传客户端页面实现

在Web应用程序中实现文件上传功能,只需要在客户端页面中添加需要上传输入项,在服务器端Servlet中读取上传文件的数据,并保存在服务器端硬盘中即可。

客户端浏览器页面实现文件上传功能,具体代码如下:

需要注意的是:

 

  • <input type=”file”>标签必须指定name属性值,否则需要上传的文件数据是不会上传至服务器端。
  • 完成文件上传功能的表单的请求类型必须是POST方式。
  • 完成文件上传功能的表单的enctype属性值设置为“multipart/form-data”,该值的作用是将需要上传的文件数据添加到Http请求体中,并使用MIME协议对上传的文件进行描述。
    1. commons-fileupload工具

完成客户端的文件上传功能之后,主要是在服务器端完成接收上传文件的数据内容。为了方便实现文件上传逻辑,可以使用第三方提供的文件上传包,具体如下:

  • jsp-smartupload.jar:使用JSP模型一时使用的,目前基本不再使用。
  • commons-fileupload.jar:由Apache基金会提供的,用来实现Java环境下的文件上传功能。
  • Servlet 3.0规范中提供对文件上传的支持。

commons-fileupload组件的官网地址:http://commons.apache.org/proper/commons-fileupload/。需要注意的是:在使用commons-fileupload组件时,需要依赖于commons-io包。commons-fileupload组件工作流程如下:

 

如何使用commons-fileupload组件实现文件上传功能,可以参考其官网的User Guide内容。

 

  • 创建DiskFileItemFactory文件项工厂对象。
  • 通过工厂对象获取文件上传请求核心解析类ServletFileUpload。
  • 使用ServletFileUpload对应Request对象进行解析。
  • 遍历每个fileItem,判断是否为上传项。
  • IOUtils.copy(inputStream,OutputStream)(将上传的数据拷贝到服务器的硬盘上的简单方法)

具体实现代码如下:

 

 

    1. 动态多文件上传表单

上述案例实现的是单文件上传,如果想实现多文件上传功能的话,服务器端的逻辑是一样的,也就是说,只需要在客户端页面实现多文件上传控件即可。动态实现多文件上传表单代码如下:

 

    1. 上传文件至WEB-INF目录

到目前步骤,已经可以成功从客户端浏览器向服务器端上传文件。但是上传的路径存在一些问题,上述上传路径是自定义的文件夹,而上传至这种自定义的文件夹后,通过浏览器可以正常访问,这是非常危险的。

例如一个用户上传一个JSP页面,然后通过浏览器访问该JSP页面,而该JSP页面中可以包含一些恶意代码。这时如果允许用户运行该JSP页面的话,可能会对服务器端造成很大影响。

所以,通常情况下,会将上传目录创建在Web工程的WEB-INF目录下。因为该目录下的内容,是无法通过浏览器访问到的。

获取文件上传路径的代码,应该修改为如下内容:

 

    1. 上传文件名称的处理

对于上传文件的名称,可能是文件的完整路径,例如:C:\upload\aaa.jpg。在服务器端只需要保存其上传文件的名称即可,所以需要对上传文件的名称进行进一步地处理,具体处理代码如下:

 

目前绝大多数的浏览器都不存在这个问题,仅仅只有一些比较老的浏览器版本存在,例如IE6.0版本。为保证兼容更多浏览器产品,这个问题依旧需要解决。

    1. 上传文件中文乱码问题

如果现在上传文件的名称为中文的话,会引起中文乱码问题。commons-fileupload组件为解决中文乱码问题提供了两种解决方案,如下:

  • 利用Request对象的setCharacterEncoding(“UTF-8”)方法,该方法尽量编写在Servlet的doGet()或doPost()方法的顶端。
  • 利用ServletFileUpload类提供的setHeaderEncdoing(“UTF-8”)方法来解决。

一般情况下,不关心上传文件的内容,因为上传文件会保存在服务器端的磁盘中。但是,如果需要在控制台打印上传文件的内容,而刚好该上传文件的内容中包含中文的话,可以使用FileItem的getString(“UTF-8”)来处理编码。

    1. 上传文件同名问题的处理

如果同一个用户上传多个同名的文件,默认情况下会出现被覆盖的情况,即前一次上传的文件会被后一次上传的文件覆盖。而这种情况是不希望看到的,解决这个问题的方法就是可以为每一个上传的文件名称增加UUID,因为UUID类的randomUUID()可以生成一个唯一标识符。具体做法如下:

 

    1. 一个目录不能存放过多文件

如果上传文件过多时,会导致上传目录中的文件过多,内容过大。这时可以考虑将不同文件存储在不同的目录中,而生成不同目录的规则参考如下:

  • 按照上传时间进行目录分离,例如2014-12-12为一个目录。
  • 按照上传用户进行目录分离,为每一个用户创建一个上传目录。
  • 按照固定数量进行目录分离,设定当一个上传目录包含文件超过指定数量,创建新的上传目录。
  • 按照唯一文件名的hashcode 进行目录分离。

这里以hashcode进行目录分离方式为例演示,具体思路如下:

  • 使用UUID类的randomUUID()方法生成唯一标识符。

 

其值为2dab369c-1e4f-4e58-8b61-13c7aef855b0

  • 通过hashCode()方法获取其唯一标识符的hashcode值。

 

其值为:166846237,转换成二进制后的值为:1001111100011101111100011101

  • 按照每4位值“与”二进制1111(F)后,生成一级目录。

 

  • 以此类推,每4位值“与”二进制1111后,生成一个级别的目录。

 

根据上述步骤,可以编写一个按照hashcode方式生成目录的工具类,具体代码如下:

 

上述程序代码可以改写如下:

 

    1. 上传单个文件的大小限制

上传文件时,用户可能上传非常大的文件,可能导致上传时占用过多资源。所以,对于用户上传的单个文件大小,应做出相应限制。利用ServletFileUpload的setFileSizeMax(long)方法进行设置,其中参数表示设置的大小,单位为字节数,例如servletFileUpload.setFileSizeMax(1024*10)表示上限为10KB。

一旦上传的单个文件大小超过限制大小时,会抛出FileUploadBase.FileSizeLimitExceededException异常,可以捕获该异常后向页面输出相应的错误信息。具体实现代码如下:

 

 

    1. 上传文件的总大小的限制

在实现多文件上传时,还需要设置上传文件的总大小。利用ServletFileUpload的setSizeMax(long)方法进行设置,其中参数表示设置的大小,单位为字节数,例如servletFileUpload. setSizeMax(1024*10)表示上限为10KB。

一旦上传的文件大小超过限制大小时,会抛出FileUploadBase.SizeLimitExceededException异常,可以捕获该异常后向页面输出相应的错误信息。具体实现代码如下:

 

 

    1. 文件缓存大小与临时目录

一般情况下,上传文件默认都是先存储在内存中,然后在拷贝到服务器端的磁盘中。但是这样会有一些问题出现,例如单个文件过大时,占用服务器端资源会过多,导致服务器性能变差。这时可以通过手动设置文件缓存大小和上传文件的临时目录来解决。如果不设置上传的文件缓存大小,默认值为10KB,其表示如果上传文件小于10KB的话,会先存储在服务器端的内存中,如果上传文件大小大于10KB的话,会先存储在服务器端默认指定的临时目录中,而上传文件的默认临时目录为System.getProperty("java.io.tmpdir")。

手动修改上传文件缓存大小及临时目录的方式如下:

  • 手动修改上传文件缓存大小:DiskFileItemFactory.setSizeThreshold(缓存字节数);
  • 手动修改上传文件临时目录:

DiskFileItemFactory.setRepository(new File(getServletContext().getRealPath(临时目录相对路径)));

具体实现代码如下:

 

 

想要删除临时目录下的临时文件的话,只需要调用FileItem的delete()方法即可。

    1. 文件上传进度监听器

目前大部分具有文件上传功能的,在文件上传过程中,可以实时看到上传进度。可以使用ServletFileUpload提供的setProgressListener()方法实现,在客户端配置Ajax技术即可实现。由于目前没有掌握Ajax异步交互技术,所以只能在服务器端完成查看进度功能。

其中除使用setProgressListener()方法实现外,还需要计算如下几个结果:

  • 已用时间:当前时间 – 开始时间
  • 速度:已经上传大小 / 已用时间
  • 剩余大小:总大小 – 已经上传大小
  • 剩余时间:剩余大小 / 速度

根据上述内容,具体查看上传进度功能如下:

 

 

  1. 文件下载实现
    1. 实现文件下载

实现文件上传功能后,需要做的就是文件下载功能。文件下载不需要第三方组件支持,自定义完成即可,具体操作步骤如下:

  • 创建一个JSP页面用于显示下载文件列表。

 

  • 创建一个Servlet用于文件下载功能。

 

  • 配置Web工程的web.xml文件。

 

    1. 中文乱码解决

下载文件功能实现后,还需要解决中文乱码问题。由于下载页面中的文件名是使用GET方式提交请求的,所以可以使用如下代码解决:

 

而上述代码只能解决服务器端接收客户端请求时参数的中文乱码问题,但是点击文件下载时的文件名称依旧是乱码的。这个问题是由于浏览器本身的问题,不同浏览器的解决方式不同:

  • IE浏览器:使用URL编码。

 

  • 其他浏览器,使用BASE64编码。

 

可以通过Http请求协议的请求头中的“User-Agent”内容,判断客户端当前使用的浏览器是哪个产品。

 

  1. 文件上传下载案例

通过网盘案例实现文件上传和下载功能,并且将文件上传相关信息保存到MySQL数据库表中。该案例实现原理分析如下:

 

MySQL数据库建表语句如下:

 

创建一个JSP页面用于网盘案例的主页面(提供文件上传功能和文件下载列表功能)。

 

    1. 文件上传功能

首先实现网盘中的文件上传功能,具体实现步骤如下:

  • 创建一个JSP页面用于文件上传功能。

 

 

  • 创建一个Servlet用于处理文件上传功能。

 

 

 

 

 

  • 配置Web工程的web.xml文件。

 

  • 创建UploadUtils工具类用于封装文件上传依赖逻辑。

 

  • 创建一个JavaBean用于封装保存数据库相关信息。

 

 

    1. 文件下载功能

然后实现文件下载功能,具体实现步骤如下:

  • 创建一个Servlet用于显示下载文件列表。

 

  • 配置Web工程的web.xml文件。

         

 

  • 创建一个JSP页面用于显示文件下载列表。

 

  • 创建一个Servlet用于文件下载功能。

 

 

 

  • 配置Web工程的web.xml文件。

 

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

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

相关文章

Shell运行原理以及Linux中的权限问题

目录 一、shell的运行原理 二、Linux权限的概念 2.1 用户账号切换 2.2 仅提升当前指令的权限 2.3 将普通用户添加到信任列表 三、Linux权限管理 3.1 文件访问者的分类 3.2 文件类型和访问权限 3.3 字符权限值的表示方法 3.3.1 字符表示方法 3.3.2 八进制表示法 3.4…

CSS学习04

文章目录 1.精灵图1.1 为什么需要精灵图1.2 精灵图&#xff08;sprites&#xff09;的使用 2.字体图标2.1 字体图标的产生2.2 字体图标的优点**2.3** **字体图标的下载****2.4** **字体图标的引入**2.5 字体图标的追加 3.CSS 三角3.1 介绍 4.CSS 用户界面样式4.1 鼠标样式 curs…

openGauss学习笔记-11 openGauss 简单数据管理-INSERT INTO语句

文章目录 openGauss学习笔记-11 openGauss 简单数据管理-INSERT INTO语句11.1 语法格式11.2 参数说明11.3 示例 openGauss学习笔记-11 openGauss 简单数据管理-INSERT INTO语句 在创建一个表后&#xff0c;表中并没有数据&#xff0c;使用这个表之前&#xff0c;需要向表中插入…

【Go|第8期】Lorca读取HTML的三种方式

日期&#xff1a;2023年7月16日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

【云原生】K8S单节点搭建

Kubernetes Kubernetes基础概念架构1、基础环境2、安装kubelet、kubeadm、kubectl 2、使用kubeadm引导集群1、下载各个机器需要的镜像2、初始化主节点 Kubernetes核心实战Pod Kubernetes基础概念 kubernetes具有以下特性&#xff1a; ● 服务发现和负载均衡 Kubernetes 可以使…

leetcode 669. 修剪二叉搜索树

2023.7.15 知道了如何删除二叉树节点的逻辑之后&#xff0c;这题就不难了。 可以参考删除二叉搜索树中的节点这篇文章。 下面直接上代码&#xff1a; class Solution { public:TreeNode* trimBST(TreeNode* root, int low, int high) {if(root nullptr) return root;root->…

MacOS使用USB接口与IPhone进行Socket通信

演示效果如下: 开源地址: GitHub - rsms/peertalk: iOS and Mac Cocoa library for communicating over USB 克隆源码: git clone https://github.com/rsms/peertalk.git 克隆后打开peertalk然后启动xcode工程 先启动MacOS服务端工程,再启动iOS客户端工程 客户端 服务端

[java安全]URLDNS

文章目录 [java安全]URLDNS前言HashMapURLURLStreamHandler调用过程调用链流程图POC [java安全]URLDNS 前言 URLDNS利用链是一条很简单的链子&#xff0c;可以用来查看java反序列化是否存在反序列化漏洞&#xff0c;如果存在&#xff0c;就会触发dns查询请求 它有如下优点&a…

spring复习:(35)在getBean时,在哪里根据普通bean和工厂bean进行区分处理来返回的?

在AbstractBeanFactory的doGetBean方法&#xff1a; 调用的getObjectForBeanInstance方法部分代码如下&#xff1a; 如果不是工厂bean,则直接将实例返回&#xff0c;否则调用getObjectFromFactoryBean方法获取工厂bean的getObject方法返回的对象 protected Object getObjectF…

Gradle和Aritifactory

Gradle和Aritifactory 本文链接&#xff1a;https://blog.csdn.net/feather_wch/article/details/131746580 文章目录 Gradle和AritifactoryGradle基本介绍Gradle插件开发流程本地仓库artifactory搭建添加仓库使用本地仓库gradle插件仓库引入 Gradle基本介绍 1、Gradle是一种…

node使用fluent-ffmpeg把webm格式的音频转成mp3

下载并安装ffmpeg http://ffmpeg.org/download.html?aemtntg-on https://www.gyan.dev/ffmpeg/builds/ 配置环境变量&#xff1a; 查询版本 装包&#xff1a; yarn add fluent-ffmpeg const ffmpeg require(fluent-ffmpeg)ffmpeg(/temp/ai/hello.webm).output(/temp/ai/h…

leetcode 542. 01 矩阵

给定一个由 0 和 1 组成的矩阵 mat &#xff0c;请输出一个大小相同的矩阵&#xff0c;其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。 两个相邻元素间的距离为 1 。 示例 1&#xff1a; 输入&#xff1a;mat [[0,0,0],[0,1,0],[0,0,0]] 输出&#xff1a;[[0,0,0],…

TaskExecutor和ExecutorService的简单整合

文章目录 一、遇到问题二、达成目的三、开始调研1、使用Async获取线程池流程2、查看中间件线程池工具类3、观察AsyncConfigurer接口4、查看TaskExecutorAdapter源码 四、复盘总结 一、遇到问题 自己负责的项目想通过引入一个中间件&#xff0c;达到在业务场景维度的全链路日志…

【【51单片机的蜂鸣器-11】】

51单片机的蜂鸣器 DS1302我一直有问题搁置了几百天了 先来看看蜂鸣器 搞了一个礼拜verilog然后出去吃饭 估计自己得有10多天没看c语言和51单片机了 现在先处理一下蜂鸣器的问题 蜂鸣器 蜂鸣器分为有源蜂鸣器和无源蜂鸣器 有源内部自带震荡源&#xff0c;将正负极接上直流电压…

类之间的关系

1. 关系强弱顺序&#xff08;由强到弱&#xff09; 泛化实现组合聚合关联依赖 图中&#xff0c;组合和聚合标错了 2. 依赖 虚线箭头&#xff0c;箭头指向被依赖类依赖关系描述了两个类之间的临时关系。通常不会持续整个对象的生命周期&#xff0c;而是创建一个临时的关系以满…

string【1】介绍与使用(超详解哦)

string的介绍与使用 引言string类常用接口构造函数容量操作size与lengthcapacityresizereserveclearempty 元素访问迭代器访问beginendrbeginrend范围for 下标访问 字符串修改insertappendpush_backoperatorpop_backerase 字符串查找findrfind 非成员函数operator>>opera…

光场成像2.0——聚焦型光场相机

光场2.0 1. 发展历程 由于光场1.0从结构上子图像的分辨率严重依赖MLA子透镜的数量&#xff0c;因此分辨率一直受限&#xff0c;限制了光场1.0结构的广泛应用。针对此不足&#xff0c;在2008年&#xff0c;又一篇伟大的论文出现了&#xff0c;该论文提出了全分辨率光场渲染的概…

CS拒绝连接,Cobalt Strike连接失败,Cobalt Strike使用方法(一)

拒绝连接 connection refused:connect。 kali端&#xff08;服务器端&#xff09;和本地端win10。看看端口开启状态 先启动服务器端 查看端口开启状态&#xff0c;确定50050端口开启&#xff0c;可以参阅本文章点击跳转 没问题再往下看。 使用步骤 chmod 777 ./teamserver…

【运维工程师学习】Centos中MySQL替换MariaDB

【运维工程师学习】Centos8中MySQL替换MariaDB 1、查看已有的mysql2、MySQL官网tar包下载3、找到下载路径解压4、移动解压后的文件夹到/usr/local/mysql5、创建data文件夹&#xff0c;一般用于存放数据库文件数据6、创建用户组7、更改用户文件夹权限8、生成my.cnf文件9、编辑my…