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

Spring Boot无法上传文件至AWS S3:本地正常线上找不到文件路径

问题描述

实现了从HTML模板生成PDF文件、本地存储后上传至AWS S3再删除本地文件的功能,本地运行正常,但线上环境报错无法找到文件路径。

报错日志

2022-09-08 18:57:53,375 [http-nio-8081-exec-9] ERROR c.b.t.w.e.RestResponseEntityExceptionHandler - 500 Status Code
c.a.SdkClientException: Unable to calculate MD5 hash: src/main/resources/maxmind/tech_fee_agreement.pdf (No such file or directory)
    at c.a.s.s.AmazonS3Client.putObject(AmazonS3Client.java:1624)
    at c.b.t.s.S3FileStorage.uploadPdfFile(S3FileStorage.java:100)
    at c.b.t.s.S3FileStorage$$FastClassBySpringCGLIB$$7d744aa1.invoke(<generated>)
    at o.s.c.p.MethodProxy.invoke(MethodProxy.java:218)
    at o.s.a.f.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:685)
    ... 93 frames truncated
Caused by: j.i.FileNotFoundException: src/main/resources/maxmind/tech_fee_agreement.pdf (No such file or directory)
    at j.i.FileInputStream.open0(FileInputStream.java)
    at j.i.FileInputStream.open(FileInputStream.java:219)
    at j.i.FileInputStream.<init>(FileInputStream.java:157)
    at c.a.u.Md5Utils.computeMD5Hash(Md5Utils.java:97)
    at c.a.u.Md5Utils.md5AsBase64(Md5Utils.java:104)
    ... 1 frames truncated
    ... 97 common frames omitted

生成PDF方法代码

public void generatePdfFile(Map<String, Object> data, String pdfFileName) {
        Context context = new Context();
        context.setVariables(data);
        String htmlContent = templateEngine.process("pdf/tech_fee_agreement.html", context);
        try {
            String fileNameWithPath = pdfDirectory + pdfFileName;
            FileOutputStream fileOutputStream = new FileOutputStream(fileNameWithPath);
            ITextRenderer renderer = new ITextRenderer();
            renderer.setDocumentFromString(htmlContent);
            renderer.layout();
            renderer.createPDF(fileOutputStream, false);
            renderer.finishPDF();
        } catch (FileNotFoundException | DocumentException e) {
            logger.error(e.getMessage(), e);
        }
    }

配置文件(application.properties)

pdf.directory=src/main/resources/maxmind/
pdf.directory2=src/main/resources/maxmind/tech_fee_agreement.pdf

提问:为何线上环境无法识别该路径/找不到文件或目录?


原因分析与解决方案

核心原因

线上环境(如Docker容器、Tomcat部署等)不存在开发阶段的src/main/resources目录结构:

  1. 项目打包成JAR/WAR后,src/main/resources下的文件会被打包到JAR/WAR的BOOT-INF/classes(Spring Boot)或根目录下,原有的src/main/resources路径在运行时完全不存在。
  2. 即使强行指定该路径,线上应用通常没有权限往JAR/WAR包内部或不存在的开发目录写入文件。

解决方案

1. 改用可写的临时/外部目录存储PDF

不要将生成的PDF放到src/main/resources,改用系统临时目录或配置一个线上环境存在且可写的外部目录:

  • 修改application.properties:
    # 使用系统临时目录,或指定线上环境可访问的外部目录
    pdf.directory=${java.io.tmpdir}/maxmind/
    
  • 补充目录创建逻辑(防止目录不存在导致文件生成失败):
    在generatePdfFile方法中添加目录初始化代码:
    try {
        String fileNameWithPath = pdfDirectory + pdfFileName;
        File pdfFile = new File(fileNameWithPath);
        // 递归创建父目录
        if (!pdfFile.getParentFile().exists()) {
            pdfFile.getParentFile().mkdirs();
        }
        FileOutputStream fileOutputStream = new FileOutputStream(pdfFile);
        // 后续PDF生成逻辑保持不变
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
    

2. 检查线上环境目录权限

如果指定了自定义外部目录,必须确保应用程序对该目录拥有读写权限,避免因权限不足导致文件无法生成或读取。

3. 读取静态资源的正确方式(若涉及)

如果是读取已打包的静态资源文件(而非生成的文件),不能直接用文件路径,需通过ClassPathResource获取:

ClassPathResource resource = new ClassPathResource("maxmind/tech_fee_agreement.pdf");
InputStream inputStream = resource.getInputStream();

内容的提问来源于stack exchange,提问作者Mahmudul Hasan Shafin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 06:30:51