实现以下文件上传
要实现一个文件的上传
- 请求的方式必须是post
- 必须要设置 enctype=“multipart/form-data” (设置分割线)
表单的提交的时候会分成多个部分提交,多个部分之间使用分割线来分割 - 选择文件必须要使用file
jsp代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="<%=request.getContextPath()%>/upload" method="post" enctype="multipart/form-data">
<input type="text" name="username"><br>
<input type="file" name="fileupload"><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
servlet代码:
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 org.apache.commons.io.IOUtils;
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.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
// 演示文件上传的Servlet
@WebServlet("/upload")
public class FileUploadServlet extends HttpServlet {
// 要接收文件上传的信息,必须要使用post类型的请求
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// commons-fileupload 接收文件
// 1) 创建FileItem操作工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
// 2) 创建一个解析类
// 解析表单中多部分提交的内容(按照分割线解析)
ServletFileUpload sfu = new ServletFileUpload(factory);
try {
// 3) 解析请求
List<FileItem> fileItems = sfu.parseRequest(req);
// 4) 迭代FileItem
// 每一个FileItem对象都表示表单的一项内容
for (FileItem fileItem : fileItems) {
// 5) 区分表单的普通项还是上传项
if (fileItem.isFormField()) { // 判断当前的表单项是不是一个普通项
// true: 就是一个普通项
// 普通项打印到控制台上
String fieldName =fileItem.getFieldName(); // 获取普通项的参数名称
String fieldValue = fileItem.getString(); // 获取普通项的参数值
// 就算是设置了过滤器,提交中文一样会出现乱码的情况
// 需要手动解码
// 先将数据转化成 ISO-8859-1的字符串 , 在转化成UTF-8的字符集
String result = new String(fieldValue.getBytes("ISO-8859-1"), "UTF-8");
System.out.println("fieldName:" + fieldName + " fieldValue:" + fieldValue + " result: " + result);
} else {
// 就是一个上传项
// 上传项保存到硬盘上
// 获取文件的名称
String filename = fileItem.getName();
// 获取文件的输入流
InputStream inputStream = fileItem.getInputStream();
// 给硬盘上写数据
// 接下来要完成的功能 , 就是将上传的文件放到当前项目的输入目录下
String realPath = super.getServletContext().getRealPath("upload"); // 获取当前项目的输出目录(硬盘目录)
// 判断目录是否存在 , 不存在则创建一下目录
File dir = new File(realPath);
// dir.exists()判断目录或文件是否存在 true:表示文件或目录已经存在 false:不存在
if (dir.exists() == false) {
// 创建一下目录
dir.mkdirs();
}
// 生成文件的绝对路径
String newFileName = realPath + "/" + filename; // 新的硬盘目录 + 上传文件的名称
System.out.println("newFileName: " + newFileName);
// 方式一: 写如到固定的目录下
// String dstDir = "D:\\fileupload"; // 目标输入目录
// String dstFile = dstDir + "/" + filename; // 生成文件的输出目录
// // 实现流复制 将输入流的数据 写入到输出流内
// try (FileOutputStream out = new FileOutputStream(dstFile)) {
// IOUtils.copy(inputStream, out);
// }
// 方式二: 上传的文件生成到项目的发布目录下
// 实现流复制 将输入流的数据 写入到输出流内
try (FileOutputStream out = new FileOutputStream(newFileName)) {
IOUtils.copy(inputStream, out);
}
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
文件上传的注意事项:
1) 要对文件的名称进行重新命名,否则可能会导致文件名重复
UUID 每秒生成在1千万以下 是不会重复的 , 每秒生成在1千万以上 有一定概率会重复 (概率很低)
我: avator.jpg -> {UUID}.jpg
小明: avator.jpg -> {UUID}.jpg
2) 上传文件要放在不同的目录下
Linux 对单个文件夹下的文件数量有要求 通常是不会大于 65535个文件
可以通过专业运维解除这个限制