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目录结构:
- 项目打包成JAR/WAR后,
src/main/resources下的文件会被打包到JAR/WAR的BOOT-INF/classes(Spring Boot)或根目录下,原有的src/main/resources路径在运行时完全不存在。 - 即使强行指定该路径,线上应用通常没有权限往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
相关产品推荐
相关产品推荐

