You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker容器运行Java应用时文件路径异常问题排查与解决

MultipartFile转File在Docker容器中报错的问题解决

问题现象

以下是将MultipartFile转换为java.io.File的代码:

public File convert(MultipartFile multipartFile) {
        byte[] bytes;
       try {
           bytes = multipartFile.getBytes();
           try (FileOutputStream fos = new FileOutputStream("files/" + multipartFile.getOriginalFilename())) {
               fos.write(bytes);
           }
       } catch(IOException e) {
           System.out.println("Exception when converting multipart file to array of bytes");
           System.out.println(e.getCause());
           System.out.println(e.getMessage());
       }
        return new File("files/" + multipartFile.getOriginalFilename());
    }

该代码在本地Ubuntu 22系统运行正常,但在Docker容器中调用时抛出IOException:

file-exchange-web-1       | Exception when converting multipart file to array of bytes
file-exchange-web-1       | null
file-exchange-web-1       | files/zip.png (No such file or directory)

后续尝试访问文件时触发:

file-exchange-web-1       | java.io.FileNotFoundException: file [/apps/files/zip.png] cannot be resolved in the file system for checking its content length

原Dockerfile内容:

FROM openjdk:21-slim

WORKDIR /apps
ARG JAR_FILE
COPY target/${JAR_FILE} /apps/app.jar
COPY /entrypoint.sh /apps/entrypoint.sh

RUN adduser --system servuser
RUN chmod +x /apps/entrypoint.sh
RUN chown -R servuser /apps

USER servuser
EXPOSE 8080 8080
CMD ["/apps/entrypoint.sh"]

原因解析

  1. 目录缺失问题:Docker容器是完全隔离的环境,镜像构建时未创建的目录不会自动生成。本地环境中files/目录可能已手动创建或由项目生成,但Docker镜像中没有这个目录,导致代码写入文件时失败。
  2. WORKDIR的作用说明:
    • WORKDIR /apps会在容器根目录(/)下创建apps目录,并将后续所有Docker指令的工作目录切换至/apps。
    • 容器中Java应用的当前工作目录就是/apps,代码中使用相对路径files/时,实际指向/apps/files/,该目录在原Dockerfile中未被创建,因此触发“找不到文件或目录”的错误。

解决方法

修改Dockerfile,添加RUN mkdir files指令,在/apps目录下创建files目录。修改后的Dockerfile:

FROM openjdk:21-slim

WORKDIR /apps
ARG JAR_FILE
COPY target/${JAR_FILE} /apps/app.jar
COPY /entrypoint.sh /apps/entrypoint.sh

RUN adduser --system servuser
RUN chmod +x /apps/entrypoint.sh
RUN chown -R servuser /apps
RUN mkdir files

USER root
EXPOSE 8080 8080
CMD ["/apps/entrypoint.sh"]

优化建议:创建files目录后,最好同步修改目录权限,确保运行应用的servuser有读写权限,可添加RUN chown servuser:servuser files指令,避免权限问题。

额外优化建议

  • 路径优化:代码中使用相对路径存在不确定性,建议通过System.getProperty("user.dir")动态获取当前工作目录,拼接成绝对路径使用:
    String workingDir = System.getProperty("user.dir");
    String filePath = workingDir + "/files/" + multipartFile.getOriginalFilename();
    try (FileOutputStream fos = new FileOutputStream(filePath)) {
        fos.write(bytes);
    }
    
  • 持久化文件:如果需要保留容器中的上传文件,建议使用Docker卷(Volume)挂载/apps/files目录,避免容器重启或销毁后文件丢失。

内容的提问来源于stack exchange,提问作者Onurjan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 23:22:15