ServletFileUpload 文件上傳

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.math.BigDecimal;
import java.util.List;
import java.util.UUID;

public class FileServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {

//判斷上傳的文件是普通表單還是帶文件的表單
if (!ServletFileUpload.isMultipartContent(request)) {
return;//終止方法運行,說明這是一個普通表單 直接返回
}

//創建上傳文件的保存路徑 建議在WEB-INF下 安全 用戶無法直接訪問上傳的文件
String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
File uploadFile = new File(uploadPath);
if (!uploadFile.exists()) {
//如果目錄不存在 則創建目錄
uploadFile.mkdir();
}
//快取 臨時文件
// 臨時路徑 假如文件超過了預期的大小,我們就把他放入一個臨時文件中,過幾天自動刪除,或者提醒用戶轉存為永久
// 例如qq上傳大文件 只會讓你存放幾天時間
String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
File tempFile = new File(tempPath);
if (!tempFile.exists()) {
tempFile.mkdir();//如果不存在 創建
}

//ServletFileupload負責處理上傳的文件數據,並將表單中每個輸入項封裝成一個FileItem對象
//在使用ServletFileUpload對象解析請求時 需要DiskFileItemFactory對象
//所以我們需要 先構造 DiskFileItemFactory對象
//再通過ServletFileupload對象的構造方法或setFileItemFactory()方法設置ServletFileUpload對象的fileItemFactory屬性

try {
//1.創建DiskFileItemFactory對象,處理文件上傳路徑或者大小限制
DiskFileItemFactory factory = getDiskFileItemFactory(uploadFile);
//2.獲取ServletFileUpload對象
ServletFileUpload servletFileUpload = getServletFileUpload(factory);
//3.處理上傳的文件
String msg = uploadParseRequest(servletFileUpload, request, uploadPath);
request.setAttribute("msg", msg);
request.getRequestDispatcher("result.jsp").forward(request, response);
} catch (FileUploadException | ServletException e) {
e.printStackTrace();
}
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws javax.servlet.ServletException, IOException {

}

public static DiskFileItemFactory getDiskFileItemFactory(File file) {
//1.創建一個DiskFileItemFactory對象 用於處理文件上傳路徑及大小限制
DiskFileItemFactory factory = new DiskFileItemFactory();
//通過工廠設置緩衝區 當上傳的文件大於緩衝區時 把文件放置臨時目錄
factory.setSizeThreshold(1024 * 1024); //緩衝區大小
factory.setRepository(file); //臨時文件的保存目錄
return factory;
}

public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
//2.獲取ServletFileUpload
ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
//上傳進度
servletFileUpload.setProgressListener(new ProgressListener() {
@Override
public void update(long RreadSize, long AllSize, int i) {
// System.out.println("總大小:"+AllSize+"kb\t已上傳:"+RreadSize+"kb");

// System.out.println("總大小:"+AllSize+"kb\t已上傳:"+((int)(RreadSize*10000.0/AllSize))*1.0/100+"%");

BigDecimal bd = new BigDecimal(String.valueOf(RreadSize * 100 / AllSize));
bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("總大小:" + AllSize + "kb\t已上傳:" + bd + "%");
}
});
//處理亂碼
servletFileUpload.setHeaderEncoding("utf8");
//設置單個文件的最大值
servletFileUpload.setFileSizeMax(1024 * 1024 * 10);
//設置總共能上傳文件的大小 1024 = 1kb -> 1024*1024 = 1m -> 1m*10 = 10m
servletFileUpload.setSizeMax(1024 * 1024 * 10);
return servletFileUpload;
}

public static String uploadParseRequest(ServletFileUpload upload, HttpServletRequest request, String uploadPath) throws FileUploadException, IOException {
String msg = "";
//3.處理上傳的文件
//,封裝成一個FileItem對象

List<FileItem> fileItems = upload.parseRequest(request);

//遍歷表單
for (FileItem fileItem : fileItems) {
//判斷上傳的表單是普通表單還是帶文件的表單
if (fileItem.isFormField()) { //普通表單
String fieldName = fileItem.getFieldName();//前端表單控制項的name
String value = fileItem.getString("utf8");//處理亂碼
System.out.println(fieldName + " : " + value);
} else { //帶文件的表單

// 處理文件
//獲取文件的名字
String uploadFileName = fileItem.getName();
System.out.println("上傳的文件名稱:" + uploadFileName);
//判斷是否存在名稱不合法的情況
if (uploadFileName.trim().equals("") || uploadFileName == null) {
continue;
}
//獲得上傳的文件名稱
String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
//獲取上傳文件的後綴名
String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);
//如果文件後綴名稱 不是我們想要的 就直接return 告訴用戶類型不對
System.out.println("文件資訊 [文件名稱:" + fileName + "\t文件類型:" + fileExtName + "]");
//可以使用UUID(唯一識別的通用碼) 保證文件名稱唯一 方法:UUID.randomUUID(),隨機生成一個唯一識別的通用碼
//網路傳輸的中的東西,都需要序列化 POJO,實體類,如果想要在多個電腦中運行, 傳輸->把對象序列化
/*
拓展:
implements Serializable: 標記介面
JVM --> 調用 native(本地方法棧) 調用C++ (D:\java\include)

(D:\java\include\jni.h)
jni:java native interface
*/
String uuidPath = UUID.randomUUID().toString();


// 存放地址 uploadPath
//文件真實存在的路徑 realPath
String realPath = uploadPath + "/" + uuidPath;
//給每個文件創建一個對應的文件夾
File realPathFile = new File(realPath);
if (!realPathFile.exists()) {
realPathFile.mkdir();
}


// 文件傳輸
//獲得文件上傳的流
InputStream inputStream = fileItem.getInputStream();
//創建一個文件輸出流
//realPath = 真實文件夾
//在後面加上輸出文件的名稱
FileOutputStream fos = new FileOutputStream(realPath + "/" + fileName);
//創建一個緩衝區
byte[] buffer = new byte[1024 * 1024];
//判斷是否讀取完畢
int len = 0;
//如果大於0說明還存在數據
while ((len = inputStream.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
//關閉流
fos.close();
inputStream.close();
msg = "文件上傳成功";
//上傳文件成功 清除臨時文件
fileItem.delete();
}

}
return msg;
}

}


index.jsp程式碼如下

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--通過表單上傳文件
get:有文件大小限制
post:沒有限制
--%>
<form action="${pageContext.request.contextPath}/upload.do" enctype="multipart/form-data" method="post">
上傳用戶:<input type="text" name="username"> <br/>
<p><input type="file" name="file1"></p>
<p><input type="file" name="file1"></p>

<p><input type="submit">| <input type="reset"></p>
</form>

</body>
</html>