Java Web开发实战—文件上传和下载

发布时间 2023-09-10 12:52:19作者: Xproer-松鼠

首先讲解了文件上传的基本原理,然后介绍了文件上传的相关知识,包括Commons FileUpload组件的核心API、Commons FileUpload组件的下载、使用Commons FileUpload组件实现文件上传等,接着讲解了文件下载的具体步骤,最后介绍了文件下载的代码实现。通过对本章知识的学习,大家要理解文件上传、下载的原理,掌握Commons FileUpload组件的使用,能够根据业务需求熟练编写实现文件上传和下载功能的程序。

 

文件上传简介

文件上传是Web应用程序中的常见操作,简单来说,它指的是将本地文件通过数据流上传到服务器端的某一个特定的目录下。

在Java Web开发中,文件上传通常按照固定的流程进行,具体如图所示。

 

图 文件上传的流程

从图可以看出,文件上传要经过表单页面、浏览器、服务器三个环节。首先,浏览器提供给用户一个包含文件上传元素的表单页面,用户选择提交内容后提交请求,文件数据和其他表单信息被浏览器编码并上传至服务器端,服务器端解码上传的内容,提取出HTML表单中的信息,然后将文件数据存入磁盘。

这里需要注意的是,为了使服务器端程序能够正确地读取上传文件的数据,要将<form>元素的method属性设置为POST,enctype属性设置为multipart/form-data。multipart/form-data是一种编码方式,它会使用分界符将数据流中的数据段分开,从而帮助服务器端识别文件内容。在实现文件上传的功能时,表单页面的<form>元素的语法格式如下。

<form action="" method="post" enctype="multipart/form-data">

<input type="file" />

</form>

当文件以数据流的形式提交到服务器端之后,如果直接以Servlet程序获取并解析数据流是比较烦琐的。为了节省资源、简化操作,在实际开发中一般使用各种组件来完成数据流的获取和解析。这些组件中封装了许多底层操作并提供了相应的API,开发人员只需调用相应的API即可实现文件上传的功能。

目前比较常用的文件上传组件是Commons FileUpload,该组件是Apache组织提供的一个免费开源组件,它可以方便地将multipart/form-data类型请求中的各种表单域解析出来,并能实现一个或多个文件的上传,同时也可以限制上传文件的大小等。

 

文件上传的实现

² Commons FileUpload组件的核心API

为实现文件上传的功能,Commons FileUpload组件提供了一系列操作文件的API,其中最重要的是FileItem接口、DiskFileItemFactory类和ServletFileUpload 类,接下来将对Commons FileUpload组件的这三个类或接口进行详细的讲解。

1. FileItem接口

FileItem接口用于封装单个表单字段元素的数据,在程序运行时,实际完成数据封装的是FileItem接口的一个实现类,这里简称为FileItem类。开发人员无须关注FileItem类的封装细节,在使用时直接调用FileItem接口的方法即可获得相关表单字段元素的数据。

FileItem接口的方法

方法

说明

boolean isFormField()

用于判断封装的数据是否为普通表单字段,如果是普通表单字段返回True,如果是文件表单字段返回False

String getName()

用于获取文件表单字段中的文件名,如果封装的数据为普通表单字段,返回Null

String getFieldName()

用于获取表单元素的name属性值

void write(File file)

用于将FileItem对象存储的主体内容保存到某个指定的文件中

String getString()

使用默认的字符编码将FileItem对象存储的主体内容转换成字符串

String getString(String encoding)

使用指定的字符编码将FileItem对象存储的主体内容转换成字符串

String getContentType()

用于获取上传文件的类型,如果封装的数据为普通表单字段,返回Null

boolean isInMemory()

用于判断FileItem类对象封装的主体内容是否存储在内存中,如果存储在内存中则返回True

void delete()

清空FileItem类对象中存储的主体内容

 

2. DiskFileItemFactory

DiskFileItemFactory类用于将请求消息实体中的每一个文件封装成FileItem对象。在创建FileItem对象时,DiskFileItemFactory类会将较小的FileItem对象保存在内存中,将较大的FileItem对象缓存到磁盘上的临时文件中。这里需要注意的是,存储到磁盘上的内容的大小阈值和创建临时文件的目录是可以设置的。

DiskFileItemFactory类的方法

 

方法

说明

DiskFileItemFactory()

构造方法。采用默认临界值和系统临时文件夹构造文件项工厂对象

DiskFileItemFactory(int sizeThreshold,File repository)

构造方法。采用指定临界值和系统临时文件夹构造文件项工厂对象

FileItem createItem()

用于根据DiskFileItemFactory的相关配置创建FileItem对象

void setSizeThreshold(int sizeThreshold)

用于设置是否将上传文件以临时文件的形式保存在磁盘的临界值,参数是以字节为单位的int型数值

int getSizeThreshold()

用于获取将上传文件以临时文件的形式保存在磁盘的临界值

void setRepository(File repository)

用于设置将文件以临时文件形式保存在磁盘上的存放目录

File getRespository()

用于获取将文件以临时文件形式保存在磁盘上的存放目录

 

3. ServletFileUpload

ServletFileUpload类是Commons FileUpload组件处理文件上传的高级API,负责解析客户端请求并将封装好的FileItem对象以List集合的形式返回。

在使用ServletFileUpload对象解析请求时,需要设置解析客户端请求后获得数据的存储位置,存储位置有内存和临时文件两种方式,如果是临时文件,还需设置临时文件所在的目录。ServletFileUpload对象需要通过DiskFileItemFactory对象设置数据存储的位置,因此,在开始解析工作前要构造好DiskFileItemFactory对象,然后通过ServletFileUpload对象的构造方法或setFileItemFactory()方法设置ServletFileUpload对象的fileItemFactory属性。

ServletFileUpload类的方法

 

方法

说明

ServletFileUpload(FileItemFactory fileItemFactory)

构造方法。该构造方法会创建一个未初始化的对象,需要在解析请求前先调用setFileItemFactory()方法设置fileItemFactory属性

ServletFileUpload(FileItemFactory fileItemFactory)

构造方法。该构造方法会根据参数指定的FileItemFactory对象设置fileItemFactory属性

void setSizeMax(long sizeMax)

用于设置请求消息实体内容的最大尺寸,参数是以字节为单位的long型数值

long getSizeMax()

用于获取请求消息实体内容的最大尺寸

void setFileSizeMax(long fileSizeMax)

用于设置单个上传文件的最大尺寸,参数是以字节为单位的long型数值

long getFileSizeMax()

用于获取单个上传文件的最大尺寸

List parseRequest(HttpServletRequest request)

用于对请求消息体内容进行解析,将表单中的每个字段的数据分别封装成独立的FileItem对象,然后将这些FileItem对象存入一个List集合对象中返回

FileItemIterator getItemIterator(HttpServletRequest request)

与parseRequest()方法功能类似,返回封装FileItemStream对象的迭代器。与parseRequest()方法相比,getItemIterator是基于数据流的操作,性能更高,但后续处理略微繁琐

stiatc boolean isMultipartContent(HttpServletRequest request)

用于判断请求消息中的内容是否是“multipart/form-data”类型

setFileItemFactory(FileItemFactory factory)

用于设置fileItemFactory属性

FileItemFactory getFileItemFactory()

用于获取fileItemFactory属性

void setProgressListener(ProgressListener pListener)

用于设置文件上传进度监听器

ProgressListener getProgressListener()

用于获取文件上传进度监听器

void setHeaderEncoding(String encoding)

用于设置字符编码

String getHeaderEncoding()

用于获取字符编码

 

² Commons FileUpload组件的下载

由于Commons FileUpload组件由第三方组织提供,因此使用Commons FileUpload组件时需要导入相应的jar包,这些jar包可以从Apache官网下载。接下来将演示Commons FileUpload组件相关jar包的下载,具体步骤如下。

(1)打开浏览器,访问Commons FileUpload组件的官方下载地址http://commons.apache.org/proper/commons-fileupload/,浏览器显示的页面如图所示。

 

Commons FileUpload组件的下载页面

(2)单击FileUpload 1.3.2版本的here超链接,浏览器显示的界面如图所示。

 

Commons FileUpload组件的下载页面

(3)单击binaries/超链接,页面显示出Commons FileUpload组件的大部分版本的下载超链接,如图所示。

 

Commons FileUpload组件的下载页面

(4)单击commons-fileupload-1.3.2-bin.zip超链接,完成Commons FileUpload组件的下载。

(5)下载完成后,将得到名称为commons-fileupload-1.3.2-bin.zip的文件,将该文件解压,找到lib文件夹下的commons-fileupload-1.3.2.jar文件,这个文件即为使用Commons FileUpload组件时必需的jar包。

因为Commons FileUpload组件需要Commons IO组件的支持,因此,还需下载Commons IO组件的jar包,具体步骤如下。

(1)打开浏览器,访问Commons IO组件的官方下载地址:http://commons.apache.org/proper/commons-io/,浏览器显示的页面如图所示。

 

(2)单击Commons IO 2.6版本的Download now!超链接,浏览器显示的界面如图所示。

 

(3)单击commons-io-2.6-bin.zip超链接,完成Commons IO组件的下载。

(4)下载完成后,将得到名称为commons-io-2.6-bin.zip的文件,将该文件解压,找到commons-io-2.6.jar文件,这个文件即为使用Commons IO组件时必需的jar包。

² 实现单个文件上传

前文介绍过,Commons FileUpload组件提供了三个核心API用于文件上传,接下来,通过一个实例来演示使用Commons FileUpload组件实现文件上传的具体过程。

(1)打开Eclipse,新建Web工程chapter14,在工程chapter14的WebContent目录下新建upload01.html文件,具体代码如例14.1所示。

(2)将14.2.2节介绍的commons-io-2.6.jar文件和commons-fileupload-1.3.2.jar文件复制到工程chapter14的WebContent\WEB-INF\lib目录下,完成导包。

(3)在工程chapter14的src目录下新建com.qfedu.servlet包,在该包下新建Servlet类Servlet01,具体代码如例14.2所示。

(4)将工程chapter14添加到Tomcat,启动Tomcat,打开浏览器,访问http://localhost:8080/chapter14/upload01.html,浏览器显示的页面如图所示。

 

(5)在“用户名”文本框输入xiaoqian,单击“浏览”按钮,选择预先准备的图片,本次选择图片文件“千锋教育.png”,单击“提交”按钮,此时浏览器显示的页面如图所示。

 

从图可以看出,浏览器显示了用户名和上传文件的名称,这就说明,ServletFileUpload对象成功获取了请求对象中封装的数据。

(6)打开保存上传文件的目录。在<Tomcat安装目录展开webapps\chapter14\fileDir文件夹,发现图片文件“千锋教育.png”已上传成功,如图14.9所示。

 

文件上传的实现

² 实现多文件批量上传

14.2.3节介绍了使用Commons FileUpload组件完成单个文件的上传,接下来,通过一个实例来演示使用Commons FileUpload组件实现多文件批量上传。

(1)在工程chapter14的WebContent目录下新建upload02.html文件,具体代码如例14.3所示。

(2)重启Tomcat,打开浏览器,访问http://localhost:8080/chapter14/upload02.html,浏览器显示的页面如图14.10所示。

 

(3)在“用户名”文本框输入xiaofeng,依次单击三个“浏览”按钮,选择预先准备的图片,这里选择图片文件“千锋教育.png”、“千锋01.jpg”、“千锋02.png”,单击“提交”按钮,此时浏览器显示的页面如图14.11所示。

 

从图14.11中可以看出,浏览器显示了用户名和三个上传文件的名称,这就说明,当多个文件批量上传时,ServletFileUpload对象成功获取请求对象中封装的数据,并能够对多个上传文件进行批量处理。

(4)打开保存上传文件的目录。在Tomcat安装目录下展开\webapps\chapter14\fileDir文件夹,发现图片文件“千锋教育.png”、“千锋01.jpg”、“千锋02.png”已上传成功,如图14.12所示。

 

限制上传文件的类型和大小

在Web开发过程中,有时需要对上传文件的类型和大小进行限制,例如,以“.exe”结尾的可执行文件,它们可能给服务器带来安全隐患,这时就需要限制用户上传这类文件。

接下来,通过一个实例演示如何限制上传文件的类型和大小。

(1)在工程chapter14的WebContent目录下新建upload03.html文件,具体代码如书中例14.4所示。

(2)在工程chapter14的com.qfedu.servlet包下新建Servlet类Servlet02,具体代码如书中例14.5所示。

在代码中,SuffixFileFilter对象将对上传文件的扩展名进行检测,当文件的扩展名为.exe或.bat时,文件上传将被终止,同时,浏览器页面将显示禁止这些文件上传的提示信息,当文件的扩展名不是.exe或.bat时,文件上传会继续进行。

除此之外,当上传文件的大小超过10M时,文件上传将被终止,同时,浏览器页面将显示文件大小不能超过10M的提示信息。最终,如果文件上传完成,浏览器页面将显示文件上传成功的提示信息。

(3)重启Tomcat,打开浏览器,访问http://localhost:8080/chapter14/upload03.html,浏览器显示的页面如图所示。

 

(4)单击“浏览”按钮,选择预先准备的.exe文件,这里选择QQ.exe文件,单击“上传”按钮,此时浏览器显示的页面如图所示。

 

(5)打开保存上传文件的目录,在Tomcat安装目录下展开webapps\chapter14\fileDir文件夹,发现QQ.exe文件没有被上传,由此可见,Servlet02类实现了对.exe文件的上传限制。

(6)通过浏览器重新访问http://localhost:8080/chapter14/upload03.html,旦击“浏览”按钮,选择任意一个大于10M的文件,这里选择“压缩.rar”文件,点击“上传”按钮,此时浏览器显示的页面如图所示。

 

(7)打开保存上传文件的目录。在Tomcat安装目录下展开webapps\chapter14\fileDir文件夹,发现“压缩.rar”文件没有被上传,由此可见,Servlet02类实现了对大于10M的文件的上传限制。

(8)通过浏览器重新访问http://localhost:8080/chapter14/upload03.html,选择预先准备的图片,本次选择图片文件“千锋03.jpg”,单击“提交”按钮,此时浏览器显示的页面如图所示。

 

从图中可以看出,浏览器显示了上传文件的名称,这就说明,ServletFileUpload对象成功获取了请求对象中封装的数据。

(9)打开保存上传文件的目录,在Tomcat安装目录下展开webapps\chapter14\fileDir文件夹,发现图片文件“千锋03.jpg”已上传成功,如图所示。

 

文件下载简介

文件下载是将服务器端特定目录下的文件通过IO流下载到本地磁盘。与文件上传相比,文件下载相对简单,在编写文件下载程序时,开发人员无须关注表单元素的操作,直接使用Servlet类和IO流即可实现相关功能。

通常情况下,实现文件下载功能要经过以下几个步骤。

l 获取文件在服务器端存储的绝对路径;

l 将文件读入数据流;

l 设置编码格式;

l 设置响应头;

l 循环取出数据流中的数据;

l 关闭数据流。

当Web应用运行时,如果用户单击下载超链接,那么发送的请求会被提交到处理下载操作的Servlet中,该Servlet首先获取目标文件的存储路径,然后通过文件输入流读取目标文件,最后通过文件输出流将读取到的内容响应到客户端。

文件下载的实现

接下来,通过一个实例来演示如何实现文件的下载功能。

(1)在工程chapter14的WebContent目录下新建download.html文件,具体代码如例14.6所示。

(2)在工程chapter14的WebContent目录下新建download目录,将文件“千锋01.jpg”复制到download目录下。

(3)在工程chapter14的com.qfedu.servlet包下新建Servlet类Servlet03,具体代码如例14.7所示。

(4)重启Tomcat,打开浏览器,访问http://localhost:8080/chapter14/download.html,浏览器显示的页面如图14.13所示。

 

(5)单击“文件下载”超链接,此时浏览器显示的页面如图14.19所示。

 

(6)单击“保存”按钮,将文件下载到指定目录,至此,文件下载功能最终完成。

 

参考文章:http://blog.ncmem.com/wordpress/2023/09/10/java-web%e5%bc%80%e5%8f%91%e5%ae%9e%e6%88%98-%e6%96%87%e4%bb%b6%e4%b8%8a%e4%bc%a0%e5%92%8c%e4%b8%8b%e8%bd%bd/

欢迎入群一起讨论