1、概述
-
均是简易案例。
-
后端使用的第三方库是:Apache Commons FileUpload、Apache Commons IO
2、HTML 原生提交
2.1、单个文件
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>File Upload</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="http://localhost:8080/receive-data/receive/file-upload/1">
<input type="text" name="my_text" autocomplete="false" />
<input type="file" name="my_file" />
<input type="submit" value="提交" />
</form>
</body>
</html>
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.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
@WebServlet(name = "FileUploadServlet1", urlPatterns = "/receive/file-upload/1")
public class FileUploadServlet1 extends HttpServlet {
private static final String CHARSET_ENCODING = "UTF-8";
private static final long UPLOAD_FILE_MAX_BYTES = 5 * 1024 * 1024;
private static final String UPLOAD_FILE_TARGET_PATH = "E:\\";
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding(CHARSET_ENCODING);
response.setCharacterEncoding(CHARSET_ENCODING);
try {
// 1. Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();
// 2. Create a new file upload handler
ServletFileUpload uploadHandler = new ServletFileUpload(factory);
// 3. Set constraints (约束)
// 文件名编码
uploadHandler.setHeaderEncoding(CHARSET_ENCODING);
// 文件最大不超过 5MB
// 单位是字节
uploadHandler.setFileSizeMax(UPLOAD_FILE_MAX_BYTES);
// 4. Parse the request, get a item list parsed from the form
List<FileItem> formItemList = uploadHandler.parseRequest(request);
// 5. Process
for (FileItem item : formItemList) {
if (item.isFormField()) {
// item.isFormField() == false
// item is not a file
String fieldName = item.getFieldName();
String value = item.getString(CHARSET_ENCODING);
System.out.println(fieldName + "=" + value);
} else {
// item.isFormField() == true
// item is a file
String fieldName = item.getFieldName();
String fileName = item.getName();
System.out.println(fieldName + "=" + fileName);
String newFileName = UUID.randomUUID().toString().replaceAll("-", "") + fileName.substring(fileName.lastIndexOf("."));
InputStream in = item.getInputStream();
FileOutputStream fos = new FileOutputStream(UPLOAD_FILE_TARGET_PATH + newFileName);
IOUtils.copy(in, fos);
if (fos != null) {
fos.close();
}
if (in != null) {
in.close();
}
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
2.2、多个文件 — 使用一个<input type="file" multiple />
实现
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>File Upload</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="http://localhost:8080/receive-data/receive/file-upload/2">
<input type="text" name="my_text" autocomplete="false" />
<input type="file" name="my_file" multiple />
<input type="submit" value="提交" />
</form>
</body>
</html>
// 后端代码没有变化
- “后端代码没有变化”的原因是:按照常规理解,每一个
<input />
中的内容最终在 HTTP 请求报文的报文主体中被boundary
分隔,第三方库会根据boundary
切分字节流。尽管多个文件因为multiple
属性被写在了一个<input type="file"/>
中,但是最终形成的 HTTP 请求报文中,一个<input />
中的多个文件是照常被boundary
分隔开的(只不过name
相同罢了)。HTTP 请求报文:
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarywQ0kklBQk2mrySAH
------WebKitFormBoundarywQ0kklBQk2mrySAH
Content-Disposition: form-data; name="my_text"
₩ネム¥メフ¦ᄑᅠ
------WebKitFormBoundarywQ0kklBQk2mrySAH
Content-Disposition: form-data; name="my_file"; filename="1.pdf"
Content-Type: application/pdf
------WebKitFormBoundarywQ0kklBQk2mrySAH
Content-Disposition: form-data; name="my_file"; filename="2.pdf"
Content-Type: application/pdf
------WebKitFormBoundarywQ0kklBQk2mrySAH--
2.3、多个文件 — 使用多个<input type="file" />
实现
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>File Upload</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="http://localhost:8080/receive-data/receive/file-upload/2">
<input type="text" name="my_text" autocomplete="false" />
<input type="file" name="my_file1" />
<input type="file" name="my_file2" />
<input type="submit" value="提交" />
</form>
</body>
</html>
// 后端代码没有变化
3、jQuery Ajax 提交
3.1、<input type="file" />
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>File Upload</title>
</head>
<body>
<form enctype="multipart/form-data">
<input type="text" name="my_text" id="my_text" autocomplete="false" />
<br />
<br />
<input type="file" name="my_file1" id="my_file1" />
<br />
<br />
<input type="file" name="my_file2" id="my_file2" />
<br />
<br />
<input type="button" id="my_btn" value="提交" />
</form>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script>
$("#my_btn").on('click', function() {
let formData = new FormData();
formData.append("myText", $("#my_text").val());
formData.append("myFile1", $("#my_file1")[0].files[0]);
formData.append("myFile2", $("#my_file2")[0].files[0]);
$.ajax({
url: 'http://localhost:8080/receive-data/receive/file-upload/3',
type: 'POST',
contentType: false,
processData: false,
data: formData,
success: function(data, status, xhr) {
console.log(status);
},
error: function(xhr, status, error) {}
});
});
</script>
</body>
</html>
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.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
@WebServlet(name = "FileUploadServlet3", urlPatterns = "/receive/file-upload/3")
public class FileUploadServlet3 extends HttpServlet {
private static final String CHARSET_ENCODING = "UTF-8";
private static final long UPLOAD_FILE_MAX_BYTES = 5 * 1024 * 1024;
private static final String UPLOAD_FILE_TARGET_PATH = "E:\\";
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding(CHARSET_ENCODING);
response.setCharacterEncoding(CHARSET_ENCODING);
try {
// 1. Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();
// 2. Create a new file upload handler
ServletFileUpload uploadHandler = new ServletFileUpload(factory);
// 3. Set constraints (约束)
// 文件名编码
uploadHandler.setHeaderEncoding(CHARSET_ENCODING);
// 文件最大不超过 5MB
// 单位是字节
uploadHandler.setFileSizeMax(UPLOAD_FILE_MAX_BYTES);
// 4. Parse the request, get a item list parsed from the form
List<FileItem> formItemList = uploadHandler.parseRequest(request);
// 5. Process
for (FileItem item : formItemList) {
if (item.isFormField()) {
// item.isFormField() == false
// item is not a file
String fieldName = item.getFieldName();
String value = item.getString(CHARSET_ENCODING);
System.out.println(fieldName + "=" + value);
} else {
// item.isFormField() == true
// item is a file
String fieldName = item.getFieldName();
String fileName = item.getName();
System.out.println(fieldName + "=" + fileName);
String newFileName = UUID.randomUUID().toString().replaceAll("-", "") + fileName.substring(fileName.lastIndexOf("."));
InputStream in = item.getInputStream();
FileOutputStream fos = new FileOutputStream(UPLOAD_FILE_TARGET_PATH + newFileName);
IOUtils.copy(in, fos);
if (fos != null) {
fos.close();
}
if (in != null) {
in.close();
}
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
}
3.1、<input type="file" multiple />
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>File Upload</title>
</head>
<body>
<form enctype="multipart/form-data">
<input type="text" name="my_text" id="my_text" autocomplete="false" />
<br />
<br />
<input type="file" name="my_file" id="my_file" multiple />
<br />
<br />
<input type="button" id="my_btn" value="提交" />
</form>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script>
$("#my_btn").on('click', function() {
let formData = new FormData();
formData.append("myText", $("#my_text").val());
let fileArr = $("#my_file")[0].files;
for (let i = 0; i < fileArr.length; i++) {
formData.append("myFile", fileArr[i]);
}
$.ajax({
url: 'http://localhost:8080/receive-data/receive/file-upload/3',
type: 'POST',
contentType: false,
processData: false,
data: formData,
success: function(data, status, xhr) {
console.log(status);
},
error: function(xhr, status, error) {}
});
});
</script>
</body>
</html>
// 后端代码不用变
- 需要注意的是,
FormData
的append
方法,FormData
虽然像 Java 中的 Map,但是FormData
中允许存在重复的“键”,所以当使用append
方法时,“键”相同也不存在被覆盖的问题。
当然,具体使用上是否允许“重复”存在,取决于开发约定。
网友评论