CentOS 8 安装 Apache Commons FileUpload 指南

在 CentOS 8 上从零安装 Apache Commons FileUpload 2.0.0-M5:dnf 安装 JDK17 与 Maven、官方 bin 包与 Maven 坐标两种方案、multipart 上传验证与卸载清理。

Apache Commons FileUploadApache Commons FileUpload2026/10/14

CentOS 8 安装 Apache Commons FileUpload 指南

目标:在 CentOS 8 服务器上从零搭建 Apache Commons FileUpload 2.x 可用环境(JDK17 + Maven + 官方 bin 包 / Maven 坐标两种引入方式),并跑通 multipart 表单文件上传的最小验证,已在 CentOS 8.4.2105 服务器实测通过。

一、环境信息

本节列出文档实测的服务器基础信息,便于读者对照自身环境。

  • 操作系统:CentOS Linux release 8.4.2105(x86_64)
  • JDK:OpenJDK 17.0.1(dnf 安装,路径 /usr/lib/jvm/java-17-openjdk)
  • 构建工具:Apache Maven 3.5.4(dnf 安装,/usr/share/maven)
  • 组件版本:Apache Commons FileUpload 2.0.0-M5(commons-fileupload2-core + commons-fileupload2-jakarta-servlet5)
  • 依赖:commons-io 2.21.0、jakarta.servlet-api 5.0.0(编译期 provided)、Jetty 11.0.26(仅验证 Servlet 场景用)
  • 下载源:downloads.apache.org(bin 包与 sha512)、repo1.maven.org(Maven 坐标)
  • 实验目录:/opt/fu-lab(bin 包解压与源码示例目录)、/opt/fu-lab/jetty-demo-c8(Maven 工程目录)

二、前置条件

本节说明在 CentOS 8 上安装 FileUpload 之前需要先准备好的环境要素。

FileUpload 2.x 是 Java 库,安装本质是:装好 JDK 与构建工具 → 引入 commons-fileupload2-* jar(bin 包直引或 Maven 坐标)→ 编译运行最小上传程序验证。与 Ubuntu 篇的唯一差异在于包管理器(dnf)与 JDK 路径,其余 Java 侧流程完全一致。

2.1 安装 JDK 17

CentOS 8 的 dnf 仓库提供 java-17-openjdk-devel(含 javac 与完整 JDK,区别于仅 JRE 的 java-17-openjdk):

dnf install -y java-17-openjdk-devel

验证 JDK 版本:

java -version

实测回显:

openjdk version "17.0.1" 2021-10-19 LTS
OpenJDK Runtime Environment 21.9 (build 17.0.1+12-LTS)
OpenJDK 64-Bit Server VM 21.9 (build 17.0.1+12-LTS, mixed mode, sharing)

2.2 安装 Maven 与常用工具

dnf install -y maven curl unzip

⚠️ 注意:CentOS 8 的 Maven 3.5.4 默认使用系统默认 Java(可能被 alternatives 指向 Java 8),必须显式把 JAVA_HOME 指向 JDK 17 才能编译运行 FileUpload 2.x。验证方式见 2.3。

2.3 设置 JAVA_HOME 并验证 Maven 使用 JDK17

export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
export PATH=$JAVA_HOME/bin:$PATH
mvn -version

实测回显:

Apache Maven 3.5.4 (Red Hat 3.5.4-5)
Maven home: /usr/share/maven
Java version: 17.0.1, vendor: Red Hat, Inc., runtime: /usr/lib/jvm/java-17-openjdk-17.0.1.0.12-2.el8_5.x86_64
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "6.8.0-138-generic", arch: "amd64", family: "unix"

Java version: 17.0.1 确认 Maven 已运行在 JDK 17 上。建议将以上两行 export 写入 /etc/profile.d/java17.sh 使登录会话自动生效:

cat > /etc/profile.d/java17.sh <<'EOF'
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
export PATH=$JAVA_HOME/bin:$PATH
EOF
chmod +x /etc/profile.d/java17.sh

💡 技术拓展:JDK 多版本共存的管理方式不止一种——

方式原理适用场景
alternatives(CentOS/Red Hat)系统级符号链接切换默认 java单机全局默认版本管理
JAVA_HOME + PATH export按会话/脚本指定 JDK多项目不同 JDK 版本
sdkman / jenv用户级版本管理器开发者日常切换

本文采用 JAVA_HOME + PATH 方式,把 Maven 构建指向 JDK 17,不动系统全局默认版本。

三、版本选型说明

本节说明当前各版本情况与本文选定的版本(与 Ubuntu 篇同源,此处给出 CentOS 侧实测确认)。

3.1 官方发布目录实测

curl -s https://downloads.apache.org/commons/fileupload/binaries/ | grep -oE 'href="[^"]+\.tar\.gz"' | sort -u

实测回显(输出节选):

href="commons-fileupload-1.6.0-bin.tar.gz"
href="commons-fileupload2-2.0.0-M5-bin.tar.gz"

2.x 最新发布为 2.0.0-M5。

3.2 Maven Central 坐标版本

curl -s https://repo1.maven.org/maven2/org/apache/commons/commons-fileupload2-core/maven-metadata.xml | grep -E '<(latest|release)>'
curl -s https://repo1.maven.org/maven2/org/apache/commons/commons-fileupload2-jakarta-servlet5/maven-metadata.xml | grep -E '<(latest|release)>'

实测回显:

<latest>2.0.0-M5</latest>
<release>2.0.0-M5</release>
<latest>2.0.0-M5</latest>
<release>2.0.0-M5</release>

💡 技术拓展:FileUpload 1.x 与 2.x 的坐标与 API 差异——

维度FileUpload 1.xFileUpload 2.x
Maven 构件单一 commons-fileuploadcore + jakarta-servlet5/servlet6 + javax 多构件
包名org.apache.commons.fileuploadorg.apache.commons.fileupload2
工厂构造new DiskFileItemFactory()DiskFileItemFactory.builder().get()
FileItem 取文件名getFileName()getName()
大小上限参数setSizeMax / setFileSizeMaxsetMaxSize / setMaxFileSize

本文实测采用 2.0.0-M5 + Jakarta Servlet 5.0 组合,适配 Tomcat 10.0 / Jetty 11 等 Servlet 5 服务器。

3.3 版本选型结论

构件版本说明
commons-fileupload2-core2.0.0-M5核心解析,必引
commons-fileupload2-jakarta-servlet52.0.0-M5Servlet 5.0(Tomcat 10.0/Jetty 11)
commons-fileupload2-jakarta-servlet62.0.0-M5Servlet 6.0(Tomcat 10.1/Jetty 12)
commons-fileupload2-javax2.0.0-M5兼容旧 javax.servlet(Tomcat 9 及以下)
commons-io2.21.02.x 运行期传递依赖

四、方案 A:官方 bin 包安装(离线直引 jar)

本节介绍在 CentOS 8 上通过官网 bin 包引入 FileUpload 2.x 并编译运行最小验证程序。

4.1 下载 bin 包与 sha512 校验文件

mkdir -p /opt/fu-lab && cd /opt/fu-lab
curl -LO https://downloads.apache.org/commons/fileupload/binaries/commons-fileupload2-2.0.0-M5-bin.tar.gz
curl -LO https://downloads.apache.org/commons/fileupload/binaries/commons-fileupload2-2.0.0-M5-bin.tar.gz.sha512
ls -la

实测回显(输出节选):

-rw-r--r-- 1 root root 1309645 Oct 13 18:04 commons-fileupload2-2.0.0-M5-bin.tar.gz
-rw-r--r-- 1 root root     129 Oct 13 18:04 commons-fileupload2-2.0.0-M5-bin.tar.gz.sha512

4.2 校验 sha512 完整性

sha512sum commons-fileupload2-2.0.0-M5-bin.tar.gz
cat commons-fileupload2-2.0.0-M5-bin.tar.gz.sha512

实测回显:

7e050be0187813dfa6fac3e9679a9be71a7956a97ff3e8e762ad2fd5552f3883ecfbe92c013c2f66409a998600c7167d8749eecbdf61ba50f69472af8a9ec533  commons-fileupload2-2.0.0-M5-bin.tar.gz
7e050be0187813dfa6fac3e9679a9be71a7956a97ff3e8e762ad2fd5552f3883ecfbe92c013c2f66409a998600c7167d8749eecbdf61ba50f69472af8a9ec533

与 Ubuntu 篇一致,哈希完全匹配,校验通过。

4.3 解压并确认 jar 构件

tar xzf commons-fileupload2-2.0.0-M5-bin.tar.gz
ls commons-fileupload2-2.0.0-M5/ | grep -E '\.jar$'

实测回显(输出节选):

commons-fileupload2-core-2.0.0-M5.jar
commons-fileupload2-jakarta-servlet5-2.0.0-M5.jar
commons-fileupload2-jakarta-servlet6-2.0.0-M5.jar
commons-fileupload2-javax-2.0.0-M5.jar
commons-fileupload2-portlet-2.0.0-M5.jar

4.4 准备运行期依赖 jar

mkdir -p /opt/fu-lab/deps && cd /opt/fu-lab/deps
curl -LO https://repo1.maven.org/maven2/commons-io/commons-io/2.21.0/commons-io-2.21.0.jar
ls -la

实测回显:

-rw-r--r-- 1 root root 585274 Oct 13 18:05 commons-io-2.21.0.jar

4.5 编写最小 multipart 解析程序并编译运行

验证程序与 Ubuntu 篇同源(core 的 FileItemFactory 直接解析本地构造的 multipart 请求体):

// /opt/fu-lab/src/FileUpload2CoreDemo.java
import org.apache.commons.fileupload2.core.AbstractFileUpload;
import org.apache.commons.fileupload2.core.DiskFileItem;
import org.apache.commons.fileupload2.core.DiskFileItemFactory;
import org.apache.commons.fileupload2.core.FileItemInputIterator;
import org.apache.commons.fileupload2.core.RequestContext;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

public class FileUpload2CoreDemo {
    public static void main(String[] args) throws Exception {
        String boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW";
        String body = "--" + boundary + "\r\n"
            + "Content-Disposition: form-data; name=\"author\"\r\n\r\n"
            + "Apache Commons FileUpload 2.0.0-M5\r\n"
            + "--" + boundary + "\r\n"
            + "Content-Disposition: form-data; name=\"report\"; filename=\"demo.txt\"\r\n"
            + "Content-Type: text/plain\r\n\r\n"
            + "hello from commons-fileupload2-core\r\n"
            + "--" + boundary + "--\r\n";
        byte[] bytes = body.getBytes(StandardCharsets.UTF_8);

        RequestContext ctx = new RequestContext() {
            public String getCharacterEncoding() { return "UTF-8"; }
            public long getContentLength() { return bytes.length; }
            public String getContentType() { return "multipart/form-data; boundary=" + boundary; }
            public InputStream getInputStream() { return new ByteArrayInputStream(bytes); }
            public boolean isMultipartRelated() { return false; }
        };

        DiskFileItemFactory factory = DiskFileItemFactory.builder().get();
        AbstractFileUpload<Object, DiskFileItem, DiskFileItemFactory> upload = new AbstractFileUpload<>() {
            public FileItemInputIterator getItemIterator(Object request) { throw new UnsupportedOperationException(); }
            public Map<String, List<DiskFileItem>> parseParameterMap(Object request) { throw new UnsupportedOperationException(); }
            public List<DiskFileItem> parseRequest(Object request) { throw new UnsupportedOperationException(); }
        };
        upload.setFileItemFactory(factory);

        List<DiskFileItem> items = upload.parseRequest(ctx);
        System.out.println("Parsed FileItem count: " + items.size());
        for (DiskFileItem item : items) {
            System.out.println("  fieldName=" + item.getFieldName()
                + " | isFormField=" + item.isFormField()
                + " | fileName=" + item.getName()
                + " | contentType=" + item.getContentType()
                + " | value=" + item.getString(StandardCharsets.UTF_8));
        }
    }
}

编译运行(注意先加载 JAVA_HOME):

export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
export PATH=$JAVA_HOME/bin:$PATH
mkdir -p /opt/fu-lab/out
javac -encoding UTF-8 -cp "/opt/fu-lab/commons-fileupload2-2.0.0-M5/commons-fileupload2-core-2.0.0-M5.jar:/opt/fu-lab/deps/commons-io-2.21.0.jar" -d /opt/fu-lab/out /opt/fu-lab/src/FileUpload2CoreDemo.java
java -cp "/opt/fu-lab/out:/opt/fu-lab/commons-fileupload2-2.0.0-M5/commons-fileupload2-core-2.0.0-M5.jar:/opt/fu-lab/deps/commons-io-2.21.0.jar" FileUpload2CoreDemo

实测回显:

Parsed FileItem count: 2
  fieldName=author | isFormField=true | fileName=null | contentType=null | value=Apache Commons FileUpload 2.0.0-M5
  fieldName=report | isFormField=false | fileName=demo.txt | contentType=text/plain | value=hello from commons-fileupload2-core

CentOS 8 上 multipart 解析链路验证通过:普通字段 author 与文件字段 report 均正确解析并回显内容。

五、方案 B:Maven 坐标安装(在线工程引入)

本节介绍在 CentOS 8 上用 Maven 坐标引入 FileUpload 2.x,并以嵌入式 Jetty + curl -F 实测真实 HTTP 上传。

5.1 创建 Maven 工程与 pom.xml

mkdir -p /opt/fu-lab/jetty-demo-c8/src/main/java/upload
cd /opt/fu-lab/jetty-demo-c8

pom.xml 依赖与 Ubuntu 篇一致:

<dependencies>
  <dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-fileupload2-jakarta-servlet5</artifactId>
    <version>2.0.0-M5</version>
  </dependency>
  <dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-server</artifactId>
    <version>11.0.26</version>
  </dependency>
  <dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-servlet</artifactId>
    <version>11.0.26</version>
  </dependency>
  <dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>5.0.0</version>
    <scope>provided</scope>
  </dependency>
</dependencies>

5.2 编写上传 Servlet 与启动类

// /opt/fu-lab/jetty-demo-c8/src/main/java/upload/UploadServlet.java
package upload;

import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload2.core.DiskFileItem;
import org.apache.commons.fileupload2.core.DiskFileItemFactory;
import org.apache.commons.fileupload2.jakarta.servlet5.JakartaServletDiskFileUpload;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;

@WebServlet("/upload")
public class UploadServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/plain; charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            DiskFileItemFactory factory = DiskFileItemFactory.builder().get();
            JakartaServletDiskFileUpload upload = new JakartaServletDiskFileUpload(factory);
            upload.setMaxSize(1024L * 1024 * 10);
            upload.setMaxFileSize(1024L * 1024 * 5);
            List<DiskFileItem> items = upload.parseRequest(request);
            out.println("Parsed FileItem count: " + items.size());
            for (DiskFileItem item : items) {
                out.println("  fieldName=" + item.getFieldName()
                    + " | isFormField=" + item.isFormField()
                    + " | fileName=" + item.getName()
                    + " | contentType=" + item.getContentType()
                    + " | size=" + item.getSize()
                    + " | value=" + item.getString(StandardCharsets.UTF_8));
            }
        } catch (Exception e) {
            out.println("ERROR: " + e.getClass().getName() + ": " + e.getMessage());
        }
    }
}
// /opt/fu-lab/jetty-demo-c8/src/main/java/upload/UploadServer.java
package upload;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

public class UploadServer {
    public static void main(String[] args) throws Exception {
        Server server = new Server(18080);
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        context.addServlet(new ServletHolder(new UploadServlet()), "/upload");
        server.setHandler(context);
        server.start();
        System.out.println("Jetty started on http://0.0.0.0:18080/upload");
        server.join();
    }
}

5.3 构建工程

export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
export PATH=$JAVA_HOME/bin:$PATH
cd /opt/fu-lab/jetty-demo-c8 && mvn -q -DskipTests package
echo $?

实测回显:

0

CentOS 8 的 Maven 3.5.4 在 JDK 17 下正常完成依赖拉取与打包。

5.4 启动 Jetty 并实测 curl -F 上传

cd /opt/fu-lab/jetty-demo-c8
mvn -q dependency:build-classpath -Dmdep.outputFile=cp.txt
printf "hello from centos8 jetty test\nline2 ok\n" > /opt/fu-lab/REPORT.txt
nohup java -Xms256m -Xmx256m -cp "target/classes:$(cat cp.txt)" upload.UploadServer > /opt/fu-lab/jetty.log 2>&1 &
sleep 6
tail -2 /opt/fu-lab/jetty.log
curl -s http://127.0.0.1:18080/upload -F "author=CentOS8-FileUpload2-M5" -F "report=@/opt/fu-lab/REPORT.txt;type=text/plain"

实测回显:

Jetty started on http://0.0.0.0:18080/upload
Parsed FileItem count: 2
  fieldName=author | isFormField=true | fileName=null | contentType=null | size=22 | value=CentOS8-FileUpload2-M5
  fieldName=report | isFormField=false | fileName=REPORT.txt | contentType=text/plain | size=39 | value=hello from centos8 jetty test
line2 ok

CentOS 8 上真实 HTTP multipart 上传解析成功:字段与文件内容均正确回显,方案 B 验证通过。

六、方案对比与选择建议

本节对两种方案做横向对比并给出选型建议。

维度方案 A:官方 bin 包方案 B:Maven 坐标
是否需联网下载一次后可离线使用每次构建需访问 Maven 仓库
依赖管理手工下载 commons-io坐标自动带入传递依赖
工程适配无构建工具/老式工程标准 Maven/Gradle 工程
版本锁定固定 bin 包内 jarpom 显式 version 锁定
适用场景内网隔离、严格审计日常开发、CI/CD

选型建议:可联网的常规工程优先方案 B;内网隔离或需严格离线审计的环境选方案 A。两种方案产出的 jar 完全一致。

七、配置说明

本节说明 FileUpload 2.x 关键参数在 CentOS 8 上的设置位置与默认值(逐项解读见《Apache Commons FileUpload 配置参数详解》篇)。

  • DiskFileItemFactory.builder().setThreshold(10240):内容超 10 KB 写临时文件,默认 10240 字节;setRepository(Path) 指定临时目录(默认 /tmp)。
  • upload.setMaxSize(long):整请求上限,默认 -1(不限制)。
  • upload.setMaxFileSize(long):单文件上限,默认 -1(不限制)。
  • upload.setMaxFileCount(long):单请求文件数上限,默认 -1(不限制)。
  • upload.setHeaderCharset(Charset):part 头字符集,默认 null(回退请求编码/平台默认)。
  • upload.setMaxPartHeaderSize(int):单 part 头部上限,默认 512 字节。

⚠️ 注意:CentOS 8 服务器若无 UTF-8 locale(如 LANG=POSIX),Java 程序输出中文可能出现乱码;建议 localectl set-locale LANG=en_US.UTF-8 或程序内显式指定 -Dfile.encoding=UTF-8。

八、常见问题

Q1:Maven 构建时 java: Unsupported class file major version 61 之类报错?

定位:Maven 使用的还是系统默认 Java(如 Java 8),与 JDK 17 编译产物不匹配。 解决:先 export JAVA_HOME=/usr/lib/jvm/java-17-openjdk && export PATH=$JAVA_HOME/bin:$PATH 再执行 mvn(见 2.3 节持久化配置),并用 mvn -version 确认 Java version 为 17。

Q2:commons-fileupload2-jakarta 坐标只有 M1?

定位:旧构件名在 Maven Central 仅发布到 2.0.0-M1。 解决:改用 commons-fileupload2-jakarta-servlet5 / -servlet6 坐标。

Q3:运行期 NoSuchMethodError: FileUtils.getTempDirectoryPath()?

定位:classpath 混入旧版 commons-io。 解决:统一使用 commons-io 2.21.0,Maven 工程用 mvn dependency:build-classpath 生成的 classpath,勿手工拼接本地仓库目录。

Q4:上传超限抛什么异常?

定位:抛 org.apache.commons.fileupload2.core.FileUploadSizeException,消息形如 the request was rejected because its size (20104) exceeds the configured maximum (1000)。 解决:捕获后按实际场景返回 413 或自定义提示。

九、卸载与清理

本节说明如何移除本指南安装的环境(按需执行)。

  • 删除验证工程与下载产物:
rm -rf /opt/fu-lab
  • 卸载 JDK 与 Maven:
dnf remove -y java-17-openjdk-devel maven
  • 清理 Maven 本地仓库(可选):
rm -rf /root/.m2/repository
  • 删除 JAVA_HOME 环境配置文件(可选):
rm -f /etc/profile.d/java17.sh

十、参考链接

  1. Apache Commons FileUpload 官网:https://commons.apache.org/proper/commons-fileupload/
  2. 官方 bin 发布目录:https://downloads.apache.org/commons/fileupload/binaries/
  3. Maven Central 构件目录:https://repo1.maven.org/maven2/org/apache/commons/commons-fileupload2-core/
  4. FileUpload 2.0.0-M5 发布说明:https://downloads.apache.org/commons/fileupload/RELEASE-NOTES.txt
  5. Jakarta Servlet 规范:https://jakarta.ee/specifications/servlet/