Java Servlet 上传文件
最后修改于 2023 年 8 月 24 日
Java Servlet 上传文件演示了如何使用 Servlet 技术在 Java Web 应用程序中上传单个文件。
Java Servlet
Servlet 是一个 Java 类,它响应特定类型的网络请求——最常见的是 HTTP 请求。Java Servlet 用于创建 Web 应用程序。它们运行在 Tomcat 或 Jetty 等 Servlet 容器中。现代 Java Web 开发使用构建在 Servlet 之上的框架。
HTML 表单编码类型
POST 请求有三种编码 HTML 表单的方法:
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
application/x-www-form-urlencoded 是默认编码。值被编码为由 & 分隔的键值对。键和值之间使用 = 字符。非字母数字字符会被百分比编码。此编码类型不适用于二进制文件。
multipart/form-data 用于非 ASCII 数据和二进制文件。input 元素的 type 属性设置为 file。
text/plain 用于调试。
Java Servlet 上传文件示例
在以下应用程序中,我们有一个 Web 表单用于选择要上传到服务器的文件。该表单调用一个 Java Servlet,该 Servlet 读取文件并将其保存在目录中。
上传目录
/var/www/ 目录是 Debian Linux 中 Web 内容的标准目录。
$ ls -ld /var/www/upload/ drwxr-xr-x 2 www-data www-data 4096 Jul 24 11:36 /var/www/upload/
我们将把文件上传到 /var/www/upload/ 目录。该目录文件可以由属于 www-data 组的用户修改。因此,运行 Web 服务器的用户必须属于此组。
应用程序
这是一个 Maven Web 应用程序;它部署在嵌入式 Jetty 服务器上。
pom.xml
src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ └── web
│ │ └── UploadFile.java
│ ├── resources
│ └── webapp
│ └── index.html
└── test
└── java
这是项目结构。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zetcode</groupId>
<artifactId>JavaServletUploadFile</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>14</maven.compiler.source>
<maven.compiler.target>14</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.30.v20200611</version>
</plugin>
</plugins>
</build>
</project>
这是 Maven POM 文件。javax.servlet-api 伪像是用于 Servlet 的。
maven-war-plugin 负责收集 Web 应用程序的所有伪像依赖项、类和资源,并将它们打包成 Web 应用程序档案 (WAR)。jetty-maven-plugin 是一个用于快速开发和测试的有用 Maven 插件。它创建一个 Web 应用程序,启动一个 Jetty Web 服务器,并将应用程序部署到服务器上。
package com.zetcode.web;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebInitParam;
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;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
@WebServlet(name = "UploadFile", urlPatterns = {"/UploadFile"},
initParams = { @WebInitParam(name = "uploadpath", value = "/var/www/upload/") })
@MultipartConfig
public class UploadFile extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
response.setContentType("text/plain;charset=UTF-8");
ServletOutputStream os = response.getOutputStream();
ServletConfig sc = getServletConfig();
String path = sc.getInitParameter("uploadpath");
Part filePart = request.getPart("myfile");
String fileName = filePart.getSubmittedFileName();
InputStream is = filePart.getInputStream();
Files.copy(is, Paths.get(path + fileName),
StandardCopyOption.REPLACE_EXISTING);
os.print("File successfully uploaded");
}
}
UploadFile 将文件上传到 /var/www/upload/ 目录。
@WebServlet(name = "UploadFile", urlPatterns = {"/UploadFile"},
initParams = { @WebInitParam(name = "uploadpath", value = "/var/www/upload/") })
使用 @WebServlet 注解,我们将 Servlet 映射到 /UploadFile URL 模式,并定义一个初始的 uploadpath 变量。
@MultipartConfig
Servlet 还用 @MultipartConfig 进行装饰。@MultipartConfig 注解表示 Servlet 期望使用 multipart/form-data MIME 类型进行请求。
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
POST 请求由 doPost() 方法处理。
ServletOutputStream os = response.getOutputStream();
我们使用 getOutputStream() 方法获取 Servlet 输出流。
ServletConfig sc = getServletConfig();
String path = sc.getInitParameter("uploadpath");
我们检索初始参数。这是我们要上传文件的目录。
Part filePart = request.getPart("myfile");
文件部分通过 getPart() 方法检索。
String fileName = filePart.getSubmittedFileName(); InputStream is = filePart.getInputStream();
我们获取部分的文件名和输入流。
Files.copy(is, Paths.get(path + fileName),
StandardCopyOption.REPLACE_EXISTING);
使用 Files.copy(),我们将文件复制到目标目录。
os.print("File successfully uploaded");
最后,我们向客户端写回一条消息。
<!DOCTYPE html>
<html>
<head>
<title>Uploading a file</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/purecss@2.0.3/build/pure-min.css"
crossorigin="anonymous">
<style>
main { margin:1em }
</style>
</head>
<body>
<main>
<form class="pure-form pure-form-stacked" method="post" action="UploadFile"
enctype="multipart/form-data">
<fieldset>
<legend>File:</legend>
<input type="file" name="myfile">
<button type="submit" class="pure-button pure-button-primary">Upload</button>
</fieldset>
</form>
</main>
</body>
</html>
这是用于选择要上传文件的首页。它包含一个 HTML 表单。提交表单后,处理被发送到 UploadFile。
<link rel="stylesheet" href="https://unpkg.com/purecss@2.0.3/build/pure-min.css"
crossorigin="anonymous">
我们包含了 Pure.css 库,用于创建响应式页面。
<form class="pure-form pure-form-stacked" method="post" action="UploadFile"
enctype="multipart/form-data">
method 属性为 post,因为我们将数据发送到服务器。action 属性指定了处理请求的 Servlet 的名称。enctype 属性指定了 multipart/form-data 编码类型,这对于使用 HTML 表单上传文件是必需的。
<input type="file" name="myfile">
input 标签的 type 属性允许用户选择单个文件。
<button type="submit" class="pure-button pure-button-primary">Upload</button>
这是提交按钮。
在本文中,我们展示了如何使用 Java Servlet 上传单个文件。