目錄
文件上傳系統
1. 主要需求
- 在用戶註冊頁面,輸入用戶名,可以選擇要上傳的文件;
- 點擊提交按鈕,可以將用戶輸入的內容和選擇的文件保存到服務器上。
2. 技術分析
a. 客戶端將文件轉爲文本
i. 要求
- 表單提交方式必須爲 post,即
action="post"
。因爲 get 方式的地址欄會有大小的限制。 - 表單的 enctype 屬性值必須爲 multipart/form-data 多組件表單數據,即
enctype="multipart/form-data"
。 - 必須在表單中提供文件上傳項,即
<input type="file" name="pic">
。
ii. 多組件表單數據
- Chrome 無法查看多組件文件上傳信息:
- 推薦使用 FireFox 查看:
- 在消息頭(請求頭)中獲得黃金分割線:
enctype="multipart/form-data"
的作用:將請求體通過黃金分割線分割爲單項內容:
- 文件上傳項中會將上傳內容轉爲文本輸出。
b. 服務器將文本轉爲字節流
i. 獲取瀏覽器上傳的數據
- 如果直接通過 Request 對象,效率就會變得非常低,所以可以借用第三方技術來實現:
ii. 處理 IO 流的 3 種方式
- 使用 Apache 提供工具類 commons-fileupload。(這裏用到的方式)
- 使用 Servlet3.0 版本。(通過註解實現)
- 使用 SpringMVC 框架。(底層使用了 commons-fileupload)
3. 代碼實現
a. 導入文件上傳相關 Jar 包
相關 Jar 包已上傳至 CSDN:文件上傳相關 Jar 包。
b. index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>${NAME}</title>
<script src="${pageContext.request.contextPath}/js/jquery-3.2.1.js"></script>
</head>
<body>
<h3>文件上傳</h3>
<form action="${pageContext.request.contextPath}/UploadServlet" method="post" enctype="multipart/form-data">
用戶名:<input type="text" name="username" id="username"><br>
上傳圖片:<input type="file" name="pic"><br>
<input type = "submit" value="提交表單">
</form>
</body>
</html>
- 訪問首頁 http://localhost:8080/webappPractice2/,頁面顯示:
c. 指定服務器保存文件路徑
d. UploadServlet 接收文件並保存
i. 步驟分析
- 創建磁盤文件項工廠;
- 創建核心解析對象(依賴工廠對象);
- 解析 Request 對象,返回上傳項 List 集合;
- 遍歷 List,獲取每一個上傳項;
- 判斷:
- 普通上傳項:保存 name 和 value;
- 文件上傳項:保存文件名和文本字節輸入流到服務器端。
ii. UploadServlet
package com.company;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
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.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;
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// 1.創建磁盤文件項工廠
DiskFileItemFactory factory = new DiskFileItemFactory();
// 2.創建上傳解析器對象(依賴工廠對象)
ServletFileUpload fileUpload = new ServletFileUpload(factory);
// 3.解析Request請求,返回上傳項List集合
List<FileItem> fileItems = fileUpload.parseRequest(request);
// 4.遍歷List
for (FileItem fileItem : fileItems) {
// 5.判斷是文件項還是普通項
if (fileItem.isFormField()) {// 普通上傳項
// 獲取name屬性名
String name = fileItem.getFieldName();
// 獲取value屬性值
String value = fileItem.getString();
System.out.println("普通上傳項:" + name + "=" + value);
} else {// 文件上傳項
// a.獲取文件名 Regino.txt
String fileName = fileItem.getName();
// b.獲取文件字節輸入流
InputStream in = fileItem.getInputStream();
// c.獲取文件擴展名
String extName = FileUtil.extName(fileName);
// d.生成隨機文件名,解決服務器端保存的文件出現文件名重複問題
fileName = IdUtil.simpleUUID() + "." + extName; // UUID 全球唯一
// 此文件名會保存數據庫一份,給用戶查詢使用...
// 獲取upload目錄在服務器真實路徑
String realPath = request.getServletContext().getRealPath("/upload/");
// 判斷此目錄是否存在,解決IDEA沒有上傳空的upload文件夾導致找不到輸出目錄的問題
File dirFile = new File(realPath);
if (!dirFile.exists()) {
dirFile.mkdirs(); // 如果不存在自己創建
}
// 設置文件字節輸出流
FileOutputStream out = new FileOutputStream(realPath + fileName);
// 流的拷貝
IoUtil.copy(in, out);
// 關流
out.close();
in.close();
response.getWriter().write("success");
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
e. 測試
- 上傳文件,提交表單:
- 頁面顯示:
- 控制檯顯示:
- 上傳文件已保存: