ZetCode

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 用于非 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

这是项目结构。

pom.xml
<?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 服务器,并将应用程序部署到服务器上。

com/zetcode/web/UploadFile.java
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");

最后,我们向客户端写回一条消息。

webapp/index.html
<!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 上传单个文件。

作者

我叫 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已撰写了 1400 多篇文章和 8 本电子书。我在教学编程方面拥有十多年的经验。

列出 所有 Java Servlet 教程