一、前言
随着Internet的普及,网络共享逐渐成为了广大网民传递信息、共享资源的一种常用方式,不管是社交软件中用户将计算机中或者手机中的文件上传至服务器以便他人浏览、欣赏,还是电商网站/软件中商家上传商品图片,都涉及到文件上传,今天就聊聊Web应用中的文件上传。实现文件上传,最底层还是对文件的读写操作,在以前实现起来要编写大量的代码,而且容易引发各式各样的异常。幸运的是现在有好多很实用的上传工具,可以帮助我们实现这些功能,而目前应用的比较多的,就是我们今天要介绍的Commons-FileUpload组件。
二、Commons-FileUpload简介
Commons是Apache开发源代码组织的一个Java子项目,该项目主要涉及一些开发中常用的模块,如文件上传、命令行处理、数据库连接池等等,FileUpload就是Commons其中的一个用于处理HTTP文件上传的子项目,其主要特点:
- 使用简单:Commons-FileUpload组件可以方便地嵌入JSP文件或Java文件中,只需要编写少量的代码即可完成文件的上传功能,十分方便。
- 全程控制上传内容:使用Commons-FileUpload组件提供的对象及操作方法,可以获得上传文件的全部信息,包括文件类型、大小、名称等,方便操作、实现逻辑控制。
- 对上传文件的大小、类型进行控制:有时候需要对用户上传的文件进行控制筛选,避免服务器臃肿,基于第二点获取文件信息,编写逻辑代码进行控制。
三、Commons-FileUpload组件的API
- ServletFileUpload类,主要用于解析form表单提交的数据、设置请求信息实体内容的最大允许字节数,常用方法:
方法名称 方法描述 void setSizeMax(long sizeMax) 设置请求信息内容的最大允许字节数 List parseRequest(HttpServletRequest request) 解析form表单提交的数据,返回一个FileItem实例的集合 static final boolean isMultipartContent(HttpServletRequest request) 判断请求提交的方式是否是“multipart/form-data”类型 void setHeaderEncoding(String encoding) 设置转换时所使用的字符集编码 -
FileItem接口,用于封装单个表单字段元素的数据,每一个表单字段都对应一个FileItem实例,在应用程序中使用的是其实现类DiskFileItem。FileItem接口提供的常用方法如下:
方法名称 方法描述 public boolean isFormField() 判断FileItem对象所封装的数据类型,普通表单字段返回true,文件表单字段返回false public String getName() 获得文件字段中所上传的文件名,普通表单字段调用此方法返回null public String getFieldName() 返回表单字段元素的name属性值 public void write(File file) 将FileItem对象中保存的文件数据内容写入到指定的文件中 public String getString() 将FileItem对象中保存的主体内容以一个字符串返回,其有一个重载方法getString(String encoding),可指定所采用的编码集 public long getSize() 返回单个上传文件的字节数 -
FileItemFactory接口与其实现类DiskFileItemFactory,创建ServletFileUpload实例需要依赖FileItemFactory工厂接口,DiskFileItemFactory是此接口的实现类,主要有两个常用方法:
方法名称 方法描述 public void setSizeThreshold(int sizeThreshold) 设置内存缓冲区的大小 public void setRepositoryPath(String path) 设置临时文件存放的目录
四、准备工作
1、从官网下载Commons-FileUpload组件,将解压包解压,将commons-fileupload-1.3.3.jar即是Commons-FileUpload组件的类库,复制到项目的lib文件夹下。下载地址:http://commons.apache.org/proper/commons-fileupload/
2、从官网下载Commons-IO组件(主要处理文件上传所依赖的I/O操作),同上,解压,复制commons-io-2.6.jar包到项目的lib文件夹下。下载地址:http://commons.apache.org/proper/commons-io/download_io.cgi
五、Commons-FileUpload组件的应用
1、前端代码
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>使用Commons-FileUpload组件实现文件上传</title>
</head>
<body>
<!--
一、上传文件时,form表单的method属性必须设置为post,不能是get
二、上传文件时,需要在表单属性中添加enctype属性,该属性用于设置表单提交数据的编码方式,
由于文件传至服务器时与一般文本类型的编码方式不同,需要设置为multipart/form-data。
PS:enctype属性共有三个值,如下
1、application/x-www-form-urlencoded,默认值,该属性值主要用于处理少量文本数据的传递,处理二进制数据、非ASCII编码文本时,效率低;
2、multipart/form-data,上传二进制数据,只有使用了multipart/form-data属性值才能完整地传递文件数据;
3、text/plain,主要用于向服务器传递大量文本数据,如电子邮件、发布长篇新闻等。
-->
<form action="FileUploadServlet" method="post" enctype="multipart/form-data">
我叫:<input type="text" name="userName">
<!--<input type="file" name="myFile" multiple>,加上multiple属性,可以一次上传多个文件-->
选择文件:<input type="file" name="myFile" multiple>
<input type="submit" value="上传">
</form>
</body>
</html>
2、服务器端(后台)代码
package ServletControl;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
public class FileUpload extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");
boolean isMultipart= ServletFileUpload.isMultipartContent(request); //enctype属性是否是multipart/form-data
PrintWriter writer=response.getWriter();
String userName=""; //上传者
StringBuffer fileStr=new StringBuffer(); //上传的文件名,最后输出用
try {
if (isMultipart){
FileItemFactory factory=new DiskFileItemFactory(); //工厂实例
ServletFileUpload upload=new ServletFileUpload(factory); //ServletFileUpload实例依赖于FileItemFactory工厂
List<FileItem> itemList=upload.parseRequest(request); //解析表单字段,封装成一个FileItem实例的集合
Iterator<FileItem> iterator=itemList.iterator(); //迭代器
while (iterator.hasNext()){
FileItem fileItem=iterator.next(); //依次解析每一个FileItem实例,即表单字段
if (fileItem.isFormField()){
//普通表单字段
if (fileItem.getFieldName().equals("userName")){
userName=fileItem.getString("UTF-8"); //如果表单属性name的值的userName,就获取这个表单字段的值
}
}else {
//文件表单字段
String fileUpName=fileItem.getName(); //用户上传的文件名
File file=new File("C:\\Users\\***\\Desktop\\"+fileUpName); //要保存到的文件
if (!file.exists()){
file.createNewFile(); //一开始肯定是没有的,所以先创建出来
}
fileItem.write(file); //写入,保存到目标文件
fileStr.append(fileUpName+"、");
}
}
fileStr.replace(fileStr.lastIndexOf("、"),fileStr.length(),"");
writer.print("<script>alert('用户"+userName+"上传了文件"+fileStr+"')</script>");
}
}catch (Exception e){
}
}
}
3、运行结果