1.首先我们了解一些类的作用和方法。
1.DiskFileItemFactory类
属性:
(1) public static final int DEFAULT_SIZE_THRESHOLD :将文件保存在内存还是磁盘临时文件夹的默认临界值,值为10240,即10kb。
(2) private File repository:用于配置在创建文件项目时,当文件项目大于临界值时使用的临时文件夹,默认采用系统默认的临时文件路径,可以通过系统属性 java.io.tmpdir获取。如下代码:
System.getProperty("java.io.tmpdir");
(3) private int sizeThreshold:用于保存将文件保存在内存还是磁盘临时文件夹的临界值
构造方法:
1) public DiskFileItemFactory()
采用默认临界值和系统临时文件夹构造文件项工厂对象。
2) public DiskFileItemFactory(int sizeThreshold,File repository)
采用参数指定临界值和系统临时文件夹构造文件项工厂对象。
方法:
(1) FileItem createItem()
根据DiskFileItemFactory相关配置将每一个请求消息实体项目创建成DiskFileItem 实例,并返回。该方法从来不需要我们亲自调用,FileUpload组件在解析请求时内部使用。
(2) void setSizeThreshold(int sizeThreshold)
Apache文件上传组件在解析上传数据中的每个字段内容时,需要临时保存解析出的数据,以便在后面进行数据的进一步处理(保存在磁盘特定位置或插入数据库)。因为Java虚拟机默认可以使用的内存空间是有限的,超出限制时将会抛出“java.lang.OutOfMemoryError”错误。如果上传的文件很大,例如800M的文件,在内存中将无法临时保存该文件内容,Apache文件上传组件转而采用临时文件来保存这些数据;但如果上传的文件很小,例如600个字节的文件,显然将其直接保存在内存中性能会更加好些。
setSizeThreshold方法用于设置是否将上传文件已临时文件的形式保存在磁盘的临界值(以字节为单位的int值),如果从没有调用该方法设置此临界值,将会采用系统默认值10KB。对应的getSizeThreshold() 方法用来获取此临界值。
(3) void setRepository(File repository)
setRepositoryPath方法用于设置当上传文件尺寸大于setSizeThreshold方法设置的临界值时,将文件以临时文件形式保存在磁盘上的存放目录。有一个对应的获得临时文件夹的 File getRespository() 方法。
注意:当从没有调用此方法设置临时文件存储目录时,默认采用系统默认的临时文件路径,可以通过系统属性 java.io.tmpdir 获取。如下代码:
System.getProperty("java.io.tmpdir");
Tomcat系统默认临时目录为“<tomcat安装目录>/temp/”。
2.ServletFileUpload类
一、构造方法
(1) public ServletFileUpload()
构造一个未初始化的实例,需要在解析请求之前先调用setFileItemFactory()方法设置 fileItemFactory属性。
(2) public ServletFileUpload(FileItemFactory fileItemFactory)
构造一个实例,并根据参数指定的FileItemFactory 对象,设置 fileItemFactory属性。
二、常用方法
(1) public ServletFileUpload()
构造一个未初始化的实例,需要在解析请求之前先调用setFileItemFactory()方法设置 fileItemFactory属性。
(2) public ServletFileUpload(FileItemFactory fileItemFactory)
构造一个实例,并根据参数指定的FileItemFactory 对象,设置 fileItemFactory属性。
ServletFileUpload类常用方法:
(3) public void setSizeMax(long sizeMax)
setSizeMax方法继承自FileUploadBase类,用于设置请求消息实体内容(即所有上传数据)的最大尺寸限制,以防止客户端恶意上传超大文件来浪费服务器端的存储空间。其参数是以字节为单位的long型数字。
在请求解析的过程中,如果请求消息体内容的大小超过了setSizeMax方法的设置值,将会抛出FileUploadBase内部定义的SizeLimitExceededException异常(FileUploadException的子类)。该方法有一个对应的读方法:public long getSizeMax()方法。
(4) public void setFileSizeMax(long fileSizeMax)
setFileSizeMax方法继承自FileUploadBase类,用于设置单个上传文件的最大尺寸限制,以防止客户端恶意上传超大文件来浪费服务器端的存储空间。其参数是以字节为单位的long型数字。该方法有一个对应的读方法:public long geFileSizeMax()方法。
在请求解析的过程中,如果单个上传文件的大小超过了setFileSizeMax方法的设置值,将会抛出FileUploadBase内部定义的FileSizeLimitExceededException异常(FileUploadException的子类)。
(5) public List parseRequest(javax.servlet.http.HttpServletRequest req)
parseRequest 方法是ServletFileUpload类的重要方法,它是对HTTP请求消息体内容进行解析的入口方法。它解析出FORM表单中的每个字段的数据,并将它们分别包装成独立的FileItem对象,然后将这些FileItem对象加入进一个List类型的集合对象中返回。
该方法抛出FileUploadException异常来处理诸如文件尺寸过大、请求消息中的实体内容的类型不是“multipart/form-data”、IO异常、请求消息体长度信息丢失等各种异常。每一种异常都是FileUploadException的一个子类型。
(6) public FileItemIterator getItemIterator(HttpServletRequest request)
getItemIterator方法和parseRequest 方法基本相同。但是getItemIterator方法返回的是一个迭代器,该迭代器中保存的不是FileItem对象,而是FileItemStream 对象,如果你希望进一步提高新能,你可以采用getItemIterator方法,直接获得每一个文件项的数据输入流,做底层处理;如果性能不是问题,你希望代码简单,则采用parseRequest方法即可。
(7) public stiatc boolean isMultipartContent(HttpServletRequest req)
isMultipartContent方法方法用于判断请求消息中的内容是否是“multipart/form-data”类型,是则返回true,否则返回false。isMultipartContent方法是一个静态方法,不用创建ServletFileUpload类的实例对象即可被调用。
(8) getFileItemFactory()和setFileItemFactory(FileItemFactory)
方法继承自FileUpload类,用于设置和读取fileItemFactory属性。
(9) public void setProgressListener(ProgressListener pListener)
设置文件上传进度监听器。该方法有一个对应的读取方法:ProgressListener getProgressListener()。
(10) public void setHeaderEncoding()
在文件上传请求的消息体中,除了普通表单域的值是文本内容以外,文件上传字段中的文件路径名也是文本,在内存中保存的是它们的某种字符集编码的字节数组,Apache文件上传组件在读取这些内容时,必须知道它们所采用的字符集编码,才能将它们转换成正确的字符文本返回。
案例
环境:IDEA、JDK11、Tomcat
1.POM.xml (有JSTL表达式的依赖)
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- upload file -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jstl-impl</artifactId>
<version>1.2</version>
<!-- 去除依赖 -->
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 导入servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
2.JSP页面
test.jsp(引用了bootstrap)
注意:form标签必须要 method=“post” enctype="multipart/form-data"
<%--
User: guan
Date: 2020/6/7
Time: 6:42
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<link rel="stylesheet" href="/bootstrap-3.3.7-dist/css/bootstrap.min.css">
<script src="/bootstrap-3.3.7-dist/js/jquery-1.12.4.js"></script>
<script src="/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<h1>文件上传案例</h1>
</div>
<div class="row">
<form action="/TestServlet" method="post" enctype="multipart/form-data" >
<p>
<label class="sr-only"></label>
<input type="text" class="form-control" name="username" placeholder="请输入用户名">
</p>
<p>
<label class="sr-only"></label>
<input type="text" class="form-control" name="password" placeholder="请输入密码">
</p>
<p>
<label class="sr-only"></label>
<input type="file" name="uploadFile">
</p>
<input type="submit" value="提交" class="btn btn-primary">
</form>
</div>
</div>
</body>
</html>
标题3.TestServlet
package cn.guan.servlet;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
@Override
public void init() throws ServletException {
super.init();
String FILE_UPLOAD_DIR = null;
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// PrintWriter输出到页面中呈现乱码现象解决方案
response.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=utf-8");
String FILE_UPLOAD_DIR = this.getServletContext().getRealPath("test");
System.out.println(FILE_UPLOAD_DIR);
// 存储表单项数据源
List<Map<String, String>> list = new ArrayList<>();
// 1.先判断是否是文件上传选项
if (!ServletFileUpload.isMultipartContent(request)) {
PrintWriter printWriter = response.getWriter();
printWriter.write("<h1>你的不是表单项</h1>");
printWriter.flush();
printWriter.close();
return;
}
// 2.创建一个解析器工厂
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
// 3.实例化解析器对象,并传入解析器工厂对象
ServletFileUpload fileUpload = new ServletFileUpload(diskFileItemFactory);
// 设置编码格式
fileUpload.setHeaderEncoding("utf-8");
try {
// 初始化上传文件目录
File fileDirPath = new File(FILE_UPLOAD_DIR);
// 判断上传目录是否存在,不存在就创建
if (!fileDirPath.exists()) {
fileDirPath.mkdir();
}
// 4.解析请求数据
List<FileItem> fileItems = fileUpload.parseRequest(request);
//
// 判断list集合不为空
if (fileItems != null && fileItems.size() > 0) {
// 创建Map集合
Map<String, String> filedMap = new HashMap<>();
// 遍历List集合
for (FileItem item : fileItems) {
// 判断item是普通表单项还是文件上传项 如果是普通表单项,则返回true,如果是文件上传项,则返回false
if (item.isFormField()) {
// 获取字段名
String fieldName = item.getFieldName();
// 获取字段值 并设置编码
String filedValue = item.getString("UTF-8");
System.out.println("字段名:" + fieldName);
System.out.println("字段值:" + filedValue);
// 将字段名和值存入map集合中
filedMap.put(fieldName, filedValue);
} else {
// 文件上传项
// 1.获取上传文件的名称
String fileName = item.getName();
System.out.println("文件上传名称:" + fileName);
// 2.创建File对象,形成文件上传的路径
File filePath = new File(FILE_UPLOAD_DIR + File.separator + fileName);
System.out.println("文件上传全路径:" + filePath.getAbsolutePath());
// 3.写出文件
item.write(filePath);
// 清空FileItem对象中封装的主体内容,如果内容是被保存在临时文件中,该方法会把临时文件删除。
item.delete();
}
}
// 将map存入list集合中
list.add(filedMap);
System.out.println("集合:" + list);
response.getWriter().write("<h1>文件上传成功!</h1>");
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
}