首页 > 解决方案 > Heroku 类路径 FileNotFound 异常

问题描述

上下文:我有一个 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 以外的其他平台不是一个选择。

标签: spring-bootherokufilenotfoundexception

解决方案


正如 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();
}

推荐阅读