文章目录
Java Servlet Technology
Uploading Files with Java Servlet Technology
Supporting file uploads is a very basic and common requirement for many web applications. In prior versions of the Servlet specification, implementing file upload required the use of external libraries or complex input processing. The Java Servlet specification now helps to provide a viable solution to the problem in a generic and portable way. Java Servlet technology now supports file upload out of the box, so any web container that implements the specification can parse multipart requests and make mime attachments available through the HttpServletRequest
object.
A new annotation, javax.servlet.annotation.MultipartConfig
, is used to indicate that the servlet on which it is declared expects requests to be made using the multipart/form-data
MIME type. Servlets that are annotated with @MultipartConfig
can retrieve the Part
components of a given multipart/form-data
request by calling the request.getPart(String name)
or request.getParts()
method.
The @MultipartConfig Annotation
The @MultipartConfig
annotation supports the following optional attributes.
location
: An absolute path to a directory on the file system. Thelocation
attribute does not support a path relative to the application context. This location is used to store files temporarily while the parts are processed or when the size of the file exceeds the specifiedfileSizeThreshold
setting. The default location is""
.fileSizeThreshold
: The file size in bytes after which the file will be temporarily stored on disk. The default size is 0 bytes.MaxFileSize
: The maximum size allowed for uploaded files, in bytes. If the size of any uploaded file is greater than this size, the web container will throw an exception (IllegalStateException
). The default size is unlimited.maxRequestSize
: The maximum size allowed for amultipart/form-data
request, in bytes. The web container will throw an exception if the overall size of all uploaded files exceeds this threshold. The default size is unlimited.
For, example, the @MultipartConfig
annotation could be constructed as follows:
@MultipartConfig(location="/tmp", fileSizeThreshold=1024*1024,
maxFileSize=1024*1024*5, maxRequestSize=1024*1024*5*5)
Instead of using the @MultipartConfig
annotation to hard-code these attributes in your file upload servlet, you could add the following as a child element of the servlet configuration element in the web.xml
file:
<multipart-config>
<location>/tmp</location>
<max-file-size>20848820</max-file-size>
<max-request-size>418018841</max-request-size>
<file-size-threshold>1048576</file-size-threshold>
</multipart-config>
The getParts and getPart Methods
The Servlet specification supports two additional HttpServletRequest
methods:
Collection<Part> getParts()
Part getPart(String name)
The request.getParts()
method returns collections of all Part
objects. If you have more than one input of type file, multiple Part
objects are returned. Because Part
objects are named, the getPart(String name)
method can be used to access a particular Part
. Alternatively, the getParts()
method, which returns an Iterable<Part>
, can be used to get an Iterator
over all the Part
objects.
The javax.servlet.http.Part
interface is a simple one, providing methods that allow introspection of each Part
. The methods do the following:
- Retrieve the name, size, and content-type of the
Part
- Query the headers submitted with a
Part
- Delete a
Part
- Write a
Part
out to disk
For example, the Part
interface provides the write(String filename)
method to write the file with the specified name. The file can then be saved in the directory that is specified with the location
attribute of the @MultipartConfig
annotation or, in the case of the fileupload
example, in the location specified by the Destination field in the form.
实践
环境
操作系统:
Windows 10 x64
集成开发环境:
Eclipse IDE for Enterprise Java and Web Developers (includes Incubating components)
Version: 2021-09 (4.21.0)
Build id: 20210910-1417
服务器:
apache-tomcat-9.0.55
客户端:
谷歌浏览器:版本 96.0.4664.93(正式版本) (64 位)
新建项目
新建 Dynamic Web Project:
上传单个文件
新建 FileUploadServlet
类,继承自 HttpServlet
:
package com.mk.servlet;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@WebServlet(urlPatterns = "/upload")
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(FileUploadServlet.class.getCanonicalName());
private static final String path = "D:/F/file";
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
Part part = request.getPart("file");
String submittedFileName = part.getSubmittedFileName();
logger.log(Level.INFO, "Name: {0}", part.getName());
logger.log(Level.INFO, "Submitted File Name: {0}", submittedFileName);
logger.log(Level.INFO, "Size: {0}", part.getSize());
InputStream in = part.getInputStream();
OutputStream out = new FileOutputStream(new File(path + File.separator + submittedFileName));
int length = 0;
byte[] bytes = new byte[1024];
while((length = in.read(bytes)) != -1) {
out.write(bytes, 0, length);
}
logger.log(Level.INFO, "File {0} being uploaded to {1}", new Object[] {submittedFileName, path});
close(out);
close(in);
}
public static void close(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
基于表单上传单个文件
src/main/webapp/index.html 文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<form method="POST" action="upload" enctype="multipart/form-data">
<input type="file" name="file" />
<br />
<input type="submit" value="Upload" />
</form>
</body>
</html>
测试
启动服务器,访问 http://localhost:8080/hello-servlet/index.html,选择文件并上传:
控制台输出:
12月 23, 2021 7:41:49 下午 com.mk.servlet.FileUploadServlet doPost
信息: Name: file
12月 23, 2021 7:41:49 下午 com.mk.servlet.FileUploadServlet doPost
信息: Submitted File Name: 冬兵.png
12月 23, 2021 7:41:49 下午 com.mk.servlet.FileUploadServlet doPost
信息: Size: 506,421
12月 23, 2021 7:41:49 下午 com.mk.servlet.FileUploadServlet doPost
信息: File 冬兵.png being uploaded to D:/F/file
基于 AJAX 上传单个文件
编辑 src/main/webapp/index.html 文件,使用 AJAX 上传单个文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>上传单个文件</title>
</head>
<body>
<input type="file" accept="*.*" />
<script type="text/javascript">
window.onload = (event) => {
const input = document.querySelector("input[type=file]");
input.onchange = (event) => {
const files = event.target.files;
if (files.length > 0) {
const formData = new FormData();
formData.append("file", files[0]);
const xhr = new XMLHttpRequest()
xhr.addEventListener("load", function(event) {
// console.log(event)
const DONE = 4
if (xhr.readyState == DONE && xhr.status == 200) {
console.log(xhr)
console.log(xhr.response)
}
})
xhr.open("POST", "/hello-servlet/upload", true)
xhr.responseType = "json";
xhr.send(formData);
}
}
}
</script>
</body>
</html>
测试
启动服务器,访问 http://localhost:8080/hello-servlet/index.html,选择文件并上传:
控制台输出:
12月 24, 2021 10:44:25 上午 com.mk.servlet.FileUploadServlet doPost
信息: Name: file
12月 24, 2021 10:44:25 上午 com.mk.servlet.FileUploadServlet doPost
信息: Submitted File Name: 冬兵.jpg
12月 24, 2021 10:44:25 上午 com.mk.servlet.FileUploadServlet doPost
信息: Size: 34,394
12月 24, 2021 10:44:25 上午 com.mk.servlet.FileUploadServlet doPost
信息: File 冬兵.jpg being uploaded to D:/F/file
上传多个文件
编辑 FileUploadServlet
类,遍历用户上传的多个文件:
package com.mk.servlet;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@WebServlet(urlPatterns = "/upload")
@MultipartConfig
public class FileUploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(FileUploadServlet.class.getCanonicalName());
private static final String path = "D:/F/file"; // 文件的存储位置
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
Collection<Part> parts = request.getParts();
Iterator<Part> iterator = parts.iterator();
while (iterator.hasNext()) {
Part part = iterator.next();
String submittedFileName = part.getSubmittedFileName();
logger.log(Level.INFO, "Name: {0}", part.getName());
logger.log(Level.INFO, "Submitted File Name: {0}", submittedFileName);
logger.log(Level.INFO, "Size: {0}", part.getSize());
InputStream in = part.getInputStream();
OutputStream out = new FileOutputStream(new File(path + File.separator + submittedFileName));
byte[] buffer = new byte[1024];
for (int length = in.read(buffer); length != -1; length = in.read(buffer)) {
out.write(buffer, 0, length);
}
logger.log(Level.INFO, "File {0} being uploaded to {1}", new Object[] {submittedFileName, path});
close(out);
close(in);
}
}
public static void close(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
基于表单上传多个文件
编辑 src/main/webapp/index.html 文件,使用表单上传多个文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>基于表单上传多个文件</title>
</head>
<body>
<form method="POST" action="upload" enctype="multipart/form-data">
<!-- 通过使用 multiple 属性,允许用户选择多个文件 -->
<input type="file" name="file" multiple />
<br />
<input type="submit" value="上传" />
</form>
</body>
</html>
测试
启动服务器,访问 http://localhost:8080/hello-servlet/index.html,选择多个文件并上传:
控制台输出:
12月 24, 2021 11:28:10 上午 com.mk.servlet.FileUploadServlet doPost
信息: Name: file
12月 24, 2021 11:28:10 上午 com.mk.servlet.FileUploadServlet doPost
信息: Submitted File Name: OHR.MotherCheetah_ZH-CN6992630248_1920x1080.jpg
12月 24, 2021 11:28:10 上午 com.mk.servlet.FileUploadServlet doPost
信息: Size: 341,567
12月 24, 2021 11:28:10 上午 com.mk.servlet.FileUploadServlet doPost
信息: File OHR.MotherCheetah_ZH-CN6992630248_1920x1080.jpg being uploaded to D:/F/file
12月 24, 2021 11:28:10 上午 com.mk.servlet.FileUploadServlet doPost
信息: Name: file
12月 24, 2021 11:28:10 上午 com.mk.servlet.FileUploadServlet doPost
信息: Submitted File Name: th.jpg
12月 24, 2021 11:28:10 上午 com.mk.servlet.FileUploadServlet doPost
信息: Size: 338,455
12月 24, 2021 11:28:10 上午 com.mk.servlet.FileUploadServlet doPost
信息: File th.jpg being uploaded to D:/F/file
12月 24, 2021 11:28:10 上午 com.mk.servlet.FileUploadServlet doPost
信息: Name: file
12月 24, 2021 11:28:10 上午 com.mk.servlet.FileUploadServlet doPost
信息: Submitted File Name: 冬兵.jpg
12月 24, 2021 11:28:10 上午 com.mk.servlet.FileUploadServlet doPost
信息: Size: 34,394
12月 24, 2021 11:28:10 上午 com.mk.servlet.FileUploadServlet doPost
信息: File 冬兵.jpg being uploaded to D:/F/file
基于 AJAX 上传多个文件
编辑 src/main/webapp/index.html 文件,使用 AJAX 上传多个文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>基于 AJAX 上传多个文件</title>
</head>
<body>
<input type="file" accept="*.*" multiple />
<script type="text/javascript">
window.onload = (event) => {
const input = document.querySelector("input[type=file]");
input.onchange = (event) => {
const files = event.target.files;
if (files.length > 0) {
const formData = new FormData();
for (let i = 0; i < files.length; i++) {
const file = files[i];
console.log(file);
formData.append("file", files[i]);
}
const xhr = new XMLHttpRequest();
xhr.addEventListener("load", function(event) {
// console.log(event)
const DONE = 4;
if (xhr.readyState == DONE && xhr.status == 200) {
console.log(xhr);
console.log(xhr.response);
}
})
xhr.open("POST", "/hello-servlet/upload", true);
xhr.send(formData);
}
}
}
</script>
</body>
</html>
测试
启动服务器,访问 http://localhost:8080/hello-servlet/index.html,选择多个文件并上传:
控制台输出:
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Name: file
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Submitted File Name: OHR.DenaliDall_ZH-CN9952652691_1920x1080.jpg
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Size: 343,674
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: File OHR.DenaliDall_ZH-CN9952652691_1920x1080.jpg being uploaded to D:/F/file
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Name: file
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Submitted File Name: OHR.MistyTor_ZH-CN7520952555_1920x1080.jpg
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Size: 344,134
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: File OHR.MistyTor_ZH-CN7520952555_1920x1080.jpg being uploaded to D:/F/file
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Name: file
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Submitted File Name: OHR.MotherCheetah_ZH-CN6992630248_1920x1080.jpg
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Size: 341,567
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: File OHR.MotherCheetah_ZH-CN6992630248_1920x1080.jpg being uploaded to D:/F/file
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Name: file
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Submitted File Name: th.jpg
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Size: 338,455
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: File th.jpg being uploaded to D:/F/file
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Name: file
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Submitted File Name: 冬兵.jpg
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: Size: 34,394
12月 24, 2021 11:31:31 上午 com.mk.servlet.FileUploadServlet doPost
信息: File 冬兵.jpg being uploaded to D:/F/file
参考
Java Servlet Technology - Uploading Files with Java Servlet Technology
Java Servlet Technology - The fileupload Example Application