目錄
- 準備工作
- 使用類介紹
- 檔案上傳注意事項
- 需要用到的類詳解
- ServletFileUpload類
- FileItem類
- 常用方法介紹
- 編寫代碼
- maven庫下載下傳依賴包并引入
- 配置Tomcat
- 在gitee建立遠端倉庫并關聯
- 編寫表單
- 編寫檔案上傳Servlet,web.xml中注冊
- 編寫轉發頁面
對于檔案上傳,浏覽器在上傳的過程中是将檔案以流的形式送出到伺服器端的。
一般采用Apache的開源工具common-fileupload這個檔案上傳元件。
common-fileupload是依賴于common-io這個包的,是以還需要下載下傳這個包。
- 為保證伺服器的安全,上傳的檔案應放在外界無法通路的目錄下,如WEB-INF。
- 為防止同名檔案産生覆寫現象,要為檔案指定一個唯一的檔案名。
- 要對上傳檔案的大小進行限制。
- 限制上傳檔案的類型,收到檔案時,判斷檔案名是否合法。
ServletFileUpload負責處理上傳的檔案資料,并将表單中的每個輸入項封裝成一個FileItem對象,在使用ServletFileUpload對象解析請求時需要DiskFileItemFactory對象。是以,我們需要在進行解析工作前構造好DiskFileItemFactory對象,通過ServletFileItem對象的構造方法或setFileItemFactory()設定ServletFileUpload對象的fileItemFactory屬性。
在HTML頁面中input必須要有name:
<input type="file" name="fileName">
上傳檔案表單中如果包含一個檔案上傳項的話,這個表單的entype屬性必須設定為
multipart/form-data
浏覽器的表單類型為
multipart/form-data
的話,伺服器想擷取資料就要通過流。
commons-fileupload-1.4.jar
commons-io-2.8.0.jar
出現問題提示:打包時不會打入lib目錄下的jar,點選fix處理
處理成功
建立遠端倉庫
建立本地倉庫
Administrator@L87Y12K91TH8M2R MINGW64 /d/code/fileUpAndDown
$ git init
Initialized empty Git repository in D:/code/fileUpAndDown/.git/
Administrator@L87Y12K91TH8M2R MINGW64 /d/code/fileUpAndDown (main)
$ ll -a
total 24
drwxr-xr-x 1 Administrator 197121 0 Jun 2 23:25 ./
drwxr-xr-x 1 Administrator 197121 0 May 27 08:48 ../
drwxr-xr-x 1 Administrator 197121 0 Jun 2 23:25 .git/
drwxr-xr-x 1 Administrator 197121 0 Jun 2 23:26 .idea/
-rw-r--r-- 1 Administrator 197121 968 May 15 00:03 fileUpAndDown.iml
drwxr-xr-x 1 Administrator 197121 0 May 15 00:01 lib/
drwxr-xr-x 1 Administrator 197121 0 May 24 23:33 out/
drwxr-xr-x 1 Administrator 197121 0 May 14 23:56 src/
drwxr-xr-x 1 Administrator 197121 0 May 15 00:04 web/
Administrator@L87Y12K91TH8M2R MINGW64 /d/code/fileUpAndDown (main)
關聯遠端倉庫,并拉取遠端倉庫檔案
Administrator@L87Y12K91TH8M2R MINGW64 /d/code/fileUpAndDown (main)
$ git remote add origin [email protected]:wl3pbzhyq/fileUpAndDown.git
Administrator@L87Y12K91TH8M2R MINGW64 /d/code/fileUpAndDown (main)
$ git pull origin master
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (5/5), 1.42 KiB | 7.00 KiB/s, done.
From gitee.com:wl3pbzhyq/fileUpAndDown
* branch master -> FETCH_HEAD
* [new branch] master -> origin/master
Administrator@L87Y12K91TH8M2R MINGW64 /d/code/fileUpAndDown (main)
配置忽略檔案
# target
target/
# idea
.idea/
*.iml
送出main分支到遠端倉庫
D:\code\fileUpAndDown>git add .
warning: LF will be replaced by CRLF in out/artifacts/fileUpAndDown_war_exploded/WEB-INF/web.xml.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in out/artifacts/fileUpAndDown_war_exploded/index.jsp.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in web/WEB-INF/web.xml.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in web/index.jsp.
The file will have its original line endings in your working directory
D:\code\fileUpAndDown>git status
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: .gitignore
new file: .idea/vcs.xml
new file: lib/commons-fileupload-1.4.jar
new file: lib/commons-io-2.8.0.jar
D:\code\fileUpAndDown>git commit -m "初始化"
[main 0680e1f] 初始化
31 files changed, 105 insertions(+)
create mode 100644 .idea/vcs.xml
create mode 100644 lib/commons-fileupload-1.4.jar
create mode 100644 lib/commons-io-2.8.0.jar
D:\code\fileUpAndDown>git push --set-upstream origin main
Enumerating objects: 38, done.
Counting objects: 100% (38/38), done.
Delta compression using up to 4 threads
Compressing objects: 100% (27/27), done.
Writing objects: 100% (36/36), 662.53 KiB | 5.22 MiB/s, done.
Total 36 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Powered by GITEE.COM [GNK-5.0]
remote: Create a pull request for 'main' on Gitee by visiting:
remote: https://gitee.com/wl3pbzhyq/fileUpAndDown/pull/new/wl3pbzhyq:main...wl3pbzhyq:master
To gitee.com:wl3pbzhyq/fileUpAndDown.git
* [new branch] main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.
D:\code\fileUpAndDown>
input必須要有name:
<input type="file" name="fileName">
表單中如果包含檔案上傳項的話,這個表單的entype屬性必須設定為
multipart/form-data
multipart/form-data
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<%--
通過表單上傳檔案
get:上傳檔案大小有限制
post:上傳檔案大小沒有限制
表單中如果包含檔案上傳項的話,這個表單的entype屬性必須設定為multipart/form-data
浏覽器的表單類型為multipart/form-data的話,伺服器想擷取資料就要通過流
--%>
<%--${pageContext.request.contextPath}擷取伺服器路徑--%>
<form action="${pageContext.request.contextPath}/upload.do" method="post" enctype="multipart/form-data">
<p>上傳使用者:<input type="text" name="username"></p>
<p><input type="file" name="file1"></p>
<p><input type="file" name="file2"></p>
<p><input type="submit"> | <input type="reset"></p>
</form>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>FileUploadServlet</servlet-name>
<servlet-class>com.qing.servlet.FileUploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FileUploadServlet</servlet-name>
<url-pattern>/upload.do</url-pattern>
</servlet-mapping>
</web-app>
package com.qing.servlet;
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.time.LocalDate;
import java.util.List;
import java.util.UUID;
public class FileUploadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
// 判斷上傳的表單是普通表單還是帶檔案的表單
if (! ServletFileUpload.isMultipartContent(request)) {
return; // 終止方法運作,這是一個普通表單
}
// 建立上傳檔案的儲存目錄,建議在WEB-INF路徑下,安全,使用者無法直接通路上傳的檔案
String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
File uploadDir = new File(uploadPath);
if (! uploadDir.exists()) {
uploadDir.mkdir(); // 建立檔案上傳目錄
}
// 緩存,臨時檔案
// 臨時路徑,假如檔案超過了預期的大小,我們就把它放到一個臨時目錄中,過幾天自動删除或者提醒使用者轉存為永久
String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmp");
File tmpDir = new File(tmpPath);
if (! tmpDir.exists()) {
tmpDir.mkdir(); // 建立臨時目錄
}
/*
處理上傳的檔案,一般都需要通過流來擷取,可以使用request.getInputStream(),原生态的檔案上傳流擷取,十分麻煩
建議使用Apache的檔案上傳元件來實作,common-fileupload,它需要依賴common-io元件
*/
// 1.建立DiskFileItemFactory對象,負責處理檔案上傳路徑或者大小限制
DiskFileItemFactory factory = getDiskFileItemFactory(tmpDir);
// 2.擷取ServletFileUpload
ServletFileUpload upload = getServletFileUpload(factory);
// 3.處理上傳的檔案
try {
String msg = uploadParseRequest(request, uploadPath, upload);
// Servlet請求轉發消息
request.setAttribute("msg",msg);
request.getRequestDispatcher("info.jsp").forward(request,response);
} catch (IOException e) {
e.printStackTrace();
} catch (FileUploadException e) {
e.printStackTrace();
} catch (ServletException e) {
e.printStackTrace();
}
}
/**
* 處理上傳的檔案
* @param request
* @param uploadPath
* @param upload
* @return
* @throws IOException
*/
private String uploadParseRequest(HttpServletRequest request, String uploadPath, ServletFileUpload upload) throws IOException, FileUploadException {
StringBuilder msg = new StringBuilder();
// 把前端請求解析,封裝成一個FileItem對象(表單對象)
List<FileItem> fileItems = upload.parseRequest(request);
for (FileItem fileItem : fileItems) {
// 判斷表單是普通表單還是檔案表單,普通表單傳回true,檔案表單傳回false
if (fileItem.isFormField()) {
String name = fileItem.getFieldName();
String vlaue = fileItem.getString("UTF-8");// 處理亂碼
System.out.println(name + ":" + vlaue);
} else {
System.out.println("=================處理檔案==============================");
String name = fileItem.getFieldName();
String fileName = fileItem.getName();
System.out.println(name + ":" + fileName);
// 過濾檔案名不合法的檔案
if (fileName == null || "".equals(fileName.trim())) {
continue;
}
// 擷取檔案字尾名,如果檔案字尾名不是我們需要的檔案類型,就直接return,告訴使用者檔案類型錯誤
String fileExtName = fileName.substring(fileName.lastIndexOf(".") + 1);
System.out.println("=================檔案存放位址==============================");
// 生成日期目錄
String datePath = LocalDate.now().toString();
// 生成唯一目錄
String uuidPath = UUID.randomUUID().toString();
// 組成檔案實際路徑
String realPath = uploadPath + "/" + datePath + "/" + uuidPath;
File realDir = new File(realPath);
if (! realDir.exists()) {
// 注:建立多層目錄使用mkdirs,mkdir隻能建立一層目錄
realDir.mkdirs();// 建立檔案實際路徑
}
System.out.println("=================檔案傳輸==============================");
// 擷取檔案上傳輸入流
InputStream inputStream = fileItem.getInputStream();
// 建立檔案輸出流
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.append(fileName).append("檔案上傳成功!");
fileItem.delete(); // 上傳成功,清除臨時檔案
}
}
return msg.toString();
}
/**
* 擷取ServletFileUpload
* @param factory
* @return
*/
private ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
ServletFileUpload upload = new ServletFileUpload(factory);
// 監聽檔案上傳進度
upload.setProgressListener(new ProgressListener() {
@Override
public void update(long read, long total, int i) {
// read 已讀取的檔案大小
// total 檔案總大小
System.out.println("總大小:" + total + ",已上傳:" + read);
}
});
// 處理亂碼問題
upload.setHeaderEncoding("UTF-8");
// 設定單個檔案的最大值
upload.setFileSizeMax(1024 * 1024 * 10); // 10M
// 設定總共能夠上傳檔案的大小
upload.setSizeMax(1024 * 1024 * 1000); // 1000M
return upload;
}
/**
* 建立DiskFileItemFactory對象,負責處理檔案上傳路徑或者大小限制
* @param tmpDir
* @return
*/
private DiskFileItemFactory getDiskFileItemFactory(File tmpDir) {
DiskFileItemFactory factory = new DiskFileItemFactory();
// 通過工廠設定一個緩沖區,當上傳的檔案大于緩沖區的時候,将它放到臨時目錄
factory.setSizeThreshold(1024 * 1024); // 緩沖區大小為1M
factory.setRepository(tmpDir); // 設定臨時目錄
return factory;
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
${msg}
</body>
</html>