【问题标题】:Heroku classpath FileNotFound ExceptionHeroku 类路径 FileNotFoundException
【发布时间】:2021-07-28 13:38:45
【问题描述】:

上下文:我有一个 Spring Boot 应用程序,我想在创建帐户后向用户发送电子邮件。我的资源文件夹中有一个 newUser.html 文件,我在其中编辑“电子邮件”和“密码”字段,以及一些我想发送的图像。我使用 Jsoup 来做到这一点:

@Override
public void sendUserCreatedMail(CreateUserRequest createUserRequest) throws MessagingException, IOException {
    //Get JavaMailSender
    JavaMailSenderImpl mailSenderImpl = mailMapper.mapMailSender();

    //set the html elements with Jsoup
    Document doc = buildHtmlDocument(Main.class.getClassLoader().getResource("html/newUser.html").getPath());
    Element loginElement = doc.getElementById("login");
    Element passwordElement = doc.getElementById("password");

    loginElement.text("Login: " + createUserRequest.getEmail());
    passwordElement.text("Password: " + createUserRequest.getPassword());

    String html = doc.toString();

    // Add inline images, key + value
    Map<String, String> inlineImages = new HashMap<String, String>();

    if(Main.class.getClassLoader().getResource("images/rea-logo-rond.png").getPath() != null){
        //Get Email images Path
        String logoPath = Main.class.getClassLoader().getResource("images/rea-logo-rond.png").getPath();
        inlineImages.put("logo", logoPath);
    }

    //Create email instance  & send mail
    MimeMessage mimeMessage = mailMapper.mapCreateUserRequestToSender(createUserRequest, inlineImages, html);
    mailSenderImpl.send(mimeMessage);
}

在我的 IDE 中运行程序时,一切正常。 然而,当我在 Heroku 上运行它时,我得到一个“FileNotFound”异常:

[java.io.FileNotFoundException: file:/app/rea-backend/target/rea-backend-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/html/newUser.html (No such file or directory)]

我偶然发现了这个SO Article,但它没有适合我的情况的解决方案。 我希望我可以将 newUser.html 作为 Blop 保存在我的数据库中,并且每次都获取它(尽管这并不是一个很好的解决方法..);但是“文档”构造函数的工作方式是,它是否需要您尝试使用的文件的 PATH 字符串,而不是实际文件本身……所需的图像也是如此。

必须有另一种方法来使用 Heroku 访问资源文件夹中的文件吗? 还是我做错了什么?我不明白为什么它适用于本地,但不适用于 Heroku。

此时不能选择 Heroku 以外的其他平台。

【问题讨论】:

  • 因为它不是java.util.File,而是一种资源。 java.util.File 必须代表文件系统上的物理文件,当它被打包为 jar 时,该图像不再是物理文件,而只是 jar 中的资源。因此这行不通。您需要使用InputStream 并将字节写入附件。
  • 好的,但是我正在使用的 MimeMessage 需要一个 Map 的“inlineImages”,它包含文件的名称和路径,而不是 InputStream 本身。所以你的意思是我应该重新审视我的整个邮件发送实现?我觉得必须有一种方法..如果这不起作用,那么为什么要创建 MimeMessage 只接收文件的路径而不接收文件本身?
  • MimeMessage 有其他方法可以包含内联图像,所以是的,您必须重新考虑您的逻辑,因为这根本行不通。我建议使用 Spring MimeMessageHelper,它有各种采用不同元素的 addInline 方法,其中一个是 InputStreamSource 甚至是 Resource(然后您可以使用 ClassPathResource)。
  • 当您看不到它时,您需要有人为您指出正确的方向。非常感谢您,您一直是救生员。

标签: spring-boot heroku filenotfoundexception


【解决方案1】:

正如 M.Deinum 指出的那样,没有办法做到这一点,因为当这些文件被打包为 jar 时,这些图像不再是物理文件,只是 jar 中的资源。

我遵循 M. Deinum 的建议并使用 messageHelper.addInline()(用于图像)和 InputStream 用于 html 文件,得到了解决方案。东西现在很好用!

@Override
public void sendUserCreatedMail(CreateUserRequest createUserRequest) throws MessagingException, IOException {
    //Get JavaMailSender
    JavaMailSenderImpl mailSenderImpl = mailMapper.mapMailSender();

    //Create email instance  & send mail
    MimeMessage mimeMessage = mailMapper.mapCreateUserRequestToMimeMessage(createUserRequest, mailSenderImpl.createMimeMessage());
    mailSenderImpl.send(mimeMessage);
}

public MimeMessage mapCreateUserRequestToMimeMessage(CreateUserRequest createUserRequest, MimeMessage mimeMessage) throws MessagingException, IOException {
    //set meta data using "MimeMessageHelper"
    MimeMessageHelper helper = getMessageHelper(mimeMessage, createUserRequest.getEmail(),"Uw Real Estate Academy Account", "Real Estate Academy <" + this.emailConfiguration.getUsernameInfo()+">");

    String htmlMessage = buildCreateUserRequestHtmlDocument("html/newUser.html", createUserRequest);
    InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("images/rea-logo-rond.png");
    helper.setText(htmlMessage, true);
    helper.addInline("logo", new ByteArrayResource(IOUtils.toByteArray(inputStream)), "image/png");

    return mimeMessage;
}

public String buildCreateUserRequestHtmlDocument(String filePath, CreateUserRequest createUserRequest) throws IOException {
    InputStream inputStream = Main.class.getClassLoader().getResourceAsStream(filePath);
    Document doc = Jsoup.parse(inputStream, "UTF-8", "https://www.realestateacademy.be");

    Element loginElement = doc.getElementById("login");
    Element passwordElement = doc.getElementById("password");

    loginElement.text("Login: " + createUserRequest.getEmail());
    passwordElement.text("Password: " + createUserRequest.getPassword());

    return doc.toString();
}

【讨论】:

    猜你喜欢
    • 2013-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-21
    • 2011-05-24
    • 2017-07-11
    相关资源
    最近更新 更多