1、需要导入的包
- commons-io
- commons-fileupload
- maven仓库
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
2、使用类介绍
2.1 文件上传注意事项
- 为了保证服务器安全,上传的文件应该放在外界无法直接访问的目录下,比如WEB-INF下
- 防止文件覆盖,上传的文件都应有唯一的文件名
- 限制文件上传的最大值
- 限制文件上传的类型,判断收到的文件后缀是否合法
2.2 需要用到的类详解
- ServletFileUpload处理上传的文件数据,将表单中每个输入项封装成一个FileItem对象
- 在使用ServletFileUpload对象解析请求需要DiskFileItemFactory(磁盘文件迭代)
- 在进行解析工作前构造好DiskFileItemFactory对象,通过ServletFileUpload对象的构造方法或者setFileItemFactory()方法设置ServletFileUpload对象的fileItemFactory属性
2.3 Form表单
- form表单必须是post类型,因为get方法传递的参数有大小限制
- form中需要添加 enctype=“multipart/form-data”, 这样服务器想获取数据就需要通过流的方式
2.4常用方法
// 判断FileItem封装的是一个普通表单还是文件表单,普通表单就是没有文件的表单只有username,password等字段
boolean isFormField();
// 返回表单标签name属性的值
String getFiledName();
// 将FileItem对象中保存的数据流内容以一个字符串返回
String getString();
// 获取文件上传字段中的文件名
String getName();
// 以流的形式返回上传文件的数据内容
// 清空FileItem类对象的主题内容
void delete();
2.5 ServletFileUpload类
- ServletFileUpload负责处理上传文件数据,讲表单中的输入项封装成一个FileItem对象
- 使用parseRequest(HttpServletRequest)将form表单提交的每个数据封装成一个FileItem对象,以list形式返回
3. 代码编写
- 文件处理servlet
package main.com.cw.servlet;
import com.sun.deploy.util.StringUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
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;
import java.util.UUID;
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String message = "";
// 判断文件是否为普通表单
if(!ServletFileUpload.isMultipartContent(req)){
return; // 终止方法的运行
}
// 创建上传文件的保存路径,建议保存在WEB-INF下,用户无法直接访问
String basePath = this.getServletContext().getRealPath("/WEB-INF/upload");
// 如果路径不存在则创建
File uploadFile = new File(basePath);
if(!uploadFile.exists()){
uploadFile.mkdir(); // 如果文件不存在则创建这个目录
}
// 缓存,临时文件
// 如果用户上传的文件大小超过了预期,则将文件临时存储(过几天删除)或者询问是否永久存储
String temPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
File temFile = new File(temPath);
if(!temFile.exists()){
temFile.mkdir();
}
// 处理上传的文件可以使用 req.getInputStream(),原生态的文件上传处理流,但是比较麻烦
// 这里使用commons-fileupload(需要依赖于 commons-io)
// req.getInputStream(); // 这种方法需要自己解析所有上传上来的内容
// 1.创建DiskFileItemFactory,处理文件上传路径或者大小的限制
DiskFileItemFactory factory = getDiskFac(temFile);
// 2.获取ServletFileUpload (初始化需要一个DiskFileItemFactory对象)
// 处理上传文件数据,将表单的每一项封装为FileItem
ServletFileUpload upload = new ServletFileUpload(factory);
// 监听文件上传的进度
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long pBytesRead, long pContentLength, int pItems) {
System.out.println("文件总大小:" + pContentLength + " 已经上传了:" + pBytesRead);
}
});
//处理文件乱码
upload.setHeaderEncoding("utf-8");
// 设置单个文件最大值 3M
upload.setFileSizeMax( 3 * 1024 * 1024);
// 设置总大小 100M
upload.setSizeMax(100 * 1024 * 1024);
// 处理上传的文件
try {
List<FileItem> fileItemList = upload.parseRequest(req);
for (FileItem fileItem : fileItemList) {
// 判断form中item是否为文件
if(fileItem.isFormField()){
// 如果不是文件,则输出标签名和内容就行
String name = fileItem.getName(); // 获取标签的name值
String value = fileItem.getString("utf-8"); // 获取标签内容,并且设置编码格式
System.out.println("上传为名称和内容: " + name + "------" + value);
}else{
String uploadName = fileItem.getName();
System.out.println("上传文件的标签名是: " + uploadName);
// 判断上传的文件是否为空
if(uploadName == null || uploadName.trim().equals("")){
continue;
}
String fileName = uploadName.substring(uploadName.lastIndexOf("/") + 1);
String fileType = uploadName.substring(uploadName.lastIndexOf(".") + 1);
System.out.println("存储的文件名为:" + fileName + fileType);
// 使用UUID保证随机生成的文件名唯一
String fileId = UUID.randomUUID().toString();
String realPath = basePath+"/"+fileId;
File realFile = new File(realPath);
if(!realFile.exists()){
realFile.mkdir(); // 不存在该目录则创建
}
// 输入流
InputStream inputStream = fileItem.getInputStream();
// 输出流
FileOutputStream out = new FileOutputStream(realPath + "/" + fileName);
byte[] bytes = new byte[1024];
int len = 0;
while((len = inputStream.read(bytes)) > 0){
out.write(bytes, 0, len);
}
// 关闭输入输出流
out.close();
inputStream.close();
message = "上传成功";
// 删除临时读取的文件,防止占用内存
fileItem.delete();
}
}
} catch (FileUploadException e) {
message = "上传失败";
e.printStackTrace();
}
req.setAttribute("message", message);
req.getRequestDispatcher("info.jsp").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
public DiskFileItemFactory getDiskFac(File path){
DiskFileItemFactory factory = new DiskFileItemFactory();
// 设置一个缓冲区,当上传文件大于这个缓冲区,则文件被放到临时文件存储区
factory.setSizeThreshold(1024*1024); // 大小为1M
factory.setRepository(path); // 临时保存的目录
return factory;
}
}
-
info.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> 结果====> ${message} </body> </html>```
-
index.jsp
<%@page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <%--通过表单上传文件 get:上传有大小限制因此form必须设置成post --%> <form action="/upload.do" enctype="multipart/form-data" method="post"> 上传用户: <input type="text" name="username"><br> <input type="file" name="file1"> <br> <input type="file" name="file2"> <br> <input type="submit"> </form> </body> </html>