文件上传
一、通过FileUpload工具实现文件上传
要使用FileUpload工具,就得先导入Commons-fileuoload.jar和commons-io.jar
在Servlet3.0之前仅仅通过Java原生的api很难实现文件的上传,而通过引用外部jar包所提供的工具类可以解决这一问题
下面代码是利用FileUpload工具及时清除文件上传时产生的临时文件
package com.zyr1106.file;
import org.apache.commons.fileupload.FileItem;
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.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* 使用 commons fileupload 实现文件上传,并设置临时目录
*/
public class fileServlet02 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//判断当前表单是否满足文件上传
request.setCharacterEncoding("utf-8");
boolean multipartContent = ServletFileUpload.isMultipartContent(request);
if (!multipartContent) {
//不满足文件上传条件时,抛出一个异常
throw new RuntimeException("该请求无法支持文件上传!");
}
//创建DiskFileItemFactory对象
DiskFileItemFactory factory = new DiskFileItemFactory();
//获取临时文件存放路径
String path1 = this.getServletContext().getRealPath("/temp");
factory.setRepository(new File(path1));
//创建ServletFileUpload对象,该对象是文件上传的核心
ServletFileUpload upload = new ServletFileUpload(factory);
try {
List<FileItem> items = upload.parseRequest(request);
for (FileItem f : items) {
//FormField:表单域
if (f.isFormField()) {
//如果是单纯的表单,将他们获取并打印
String fieldName = f.getFieldName();
//getString可以获取表单中的值并设置编码为utf-8
String fieldValue = f.getString("UTF-8");
System.out.println(fieldName + ":" + fieldValue);
} else {
InputStream inputStream = null;
FileOutputStream fos = null;
try {
//fieldName1获取的是上传文件名称
String fieldName1 = f.getName();
//fieldName2获取的是jsp中<<input type="file" name="photo"> 的name
String fieldName2 = f.getFieldName();
System.out.println(fieldName1);
System.out.println(fieldName2);
//获取输入流对象
inputStream = f.getInputStream();
//获取输出路径
String path = this.getServletContext().getRealPath("/upload");
// System.out.println(path);
//创建File对象,并赋予路径path+fieldName1
File file = new File(path, fieldName1);
System.out.println(file);
//创建输出流
fos = new FileOutputStream(file);
//创建用于存放数据的byte数组
byte[] bytes = new byte[1024];
int len = -1;
while ((len = inputStream.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
inputStream.close();
}
if (fos!=null){
fos.close();
}
//调用FileItem中的delete方法删除临时文件
f.delete();
}
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
为什么会产生临时文件?
文件经由浏览器上传到服务器,并不是把一整个完整的文件传输过去,而是将文件分解为若干个数据包通过网络传输给服务器,因此服务器会在临时目录下创建一个临时文件存放发过来的数据包,当一个文件的所有数据包都传输到服务器后,再将这些数据包拼接,最后服务器获得经由浏览器上传的文件。简单来说是因为传输过程需要将文件分成若干数据包进行传输,因此会借助临时文件存放这些数据包,最后再拼接成文件
DiskFileItemFactory对象可以设置生成临时文件所需的大小
factory.setSizeThreshold(1024 * 1024 *3); //表示文件大于3MB之后再创建临时文件
二、使用UUID解决文件上传时文件名重名问题
当上传文件与服务器存在的文件名称重名时,上传的文件会覆盖服务器端的文件,解决这个问题可以使用java.util.UUID,UUID可以随机生成一串32位的随机数
UUID是Universally Unique Identifier的缩写,中文是通用统一识别码,uuid具有唯一性,uuid的生成跟系统的时间、mac地址、时间序列、随机数有关,所以通常所生成的uuid是不会重复的
所以文件的名称可以通过拼接UUID的方式存放
String fieldName1 = f.getName();//fieldName1获取的是上传文件名称
//为了获取文件名,有些IE浏览器会上传图片的本地路径
fieldName1 = fieldName1.substring(fieldName1.lastIndexOf("\\") + 1);
//在文件名前面添加当前时间
fieldName1 = System.currentTimeMillis() + "_" +fieldName1;
//使用UUID添加文件名的前缀
fieldName1 = UUID.randomUUID()+"_"+fieldName1;
//fieldName2获取的是jsp中<<input type="file" name="photo"> 的name
String fieldName2 = f.getFieldName();
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GH8hWt2p-1595233372522)(C:\Users\Administrator\Desktop\搜狗截图20200720151645.png)]
这样,文件就会以图上名称的形式保存在服务器上了
三、设置文件上传的大小
通过ServletFileUpload 中的setFileSizeMax()和setSizeMax()两个方法可以设置文件上传的大小
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//setFileSizeMax设置单个文件上传的大小,这里限制为2MB
upload.setFileSizeMax(1024*1024*2);
//setSizeMax设置单次上传的的大小,这里限制为5MB
upload.setSizeMax(1024*1024*5);
四、创建保存文件目录
上传的文件,应该分目录进行管理,下面是按年、月、日的层级目录来保存用户上传的文件
//获取输出路径
String path = this.getServletContext().getRealPath("/upload");
LocalDate now = LocalDate.now();
int year = now.getYear();
int month = now.getMonthValue();
int day = now.getDayOfMonth();
path = path + "/" + year + "/" + month + "/" + day;
File parentDir = new File(path);
if (!parentDir.exists()) {
//mkdirs方法创建此抽象路径名(path)指定的目录,包括创建必需但不存在的父目录。
parentDir.mkdirs();
}
//创建File对象,并赋予路径path+fieldName1
File file = new File(path, fieldName1);
);
if (!parentDir.exists()) {
//mkdirs方法创建此抽象路径名(path)指定的目录,包括创建必需但不存在的父目录。
parentDir.mkdirs();
}
//创建File对象,并赋予路径path+fieldName1
File file = new File(path, fieldName1);