如何在Spring Boot中获取.jar中的文档路径?

时间:2019-03-19 09:37:53

标签: java spring spring-boot

我正在使用jar文件运行spring boot应用程序。

此应用程序发送带有附件的邮件。附件是jar文件的一部分。我正在使用下面的代码来获取附件。我已引用此链接Classpath resource not found when running as jar

    public boolean sendEmail(String content, String subject, String from, String to, String cc, boolean isAttach, List<String> attachFiles, Session session) {

            try {

                Message message = new MimeMessage(session);
                message.setFrom(new InternetAddress(from, "XXX"));
                message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to));
                if(cc!=null && !cc.equals("")) {
                    message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(cc));
                }

                message.setSubject(subject);

                MimeBodyPart messageBodyPart = new MimeBodyPart();
                messageBodyPart.setContent(content, "text/html; charset=utf8");

                // creates multipart
                Multipart multipart = new MimeMultipart();
                multipart.addBodyPart(messageBodyPart);

                if (isAttach) {
                    // adds attachments
                    if (!attachFiles.isEmpty()) {
                        for (String filePath : attachFiles) {
                            try {

                                ClassPathResource classPathResource = new ClassPathResource("Brochure.pdf");
                                InputStream inputStream = classPathResource.getInputStream();

                                MimeBodyPart attachPart = new MimeBodyPart();

                                attachPart.attachFile(IOUtils.toString(inputStream));

                                multipart.addBodyPart(attachPart);
                            } catch (IOException ex) {
                                ex.printStackTrace();
                            }
                        }
                    }
                }

                // sets the multipart as email's content
                message.setContent(multipart);
                Transport.send(message);
                System.out.println("sent email for " + to);
                return true;
            } catch (MessagingException | UnsupportedEncodingException e) {
                System.out.println("email sending failed for " + to);
                e.printStackTrace();
                // throw new RuntimeException(e);
                return false;
            }
        }

我正在使用getInputStream()函数本身来搜索jar文件中的文件。但出现以下错误:

    javax.mail.MessagingException: IOException while sending message;
      nested exception is:
        java.io.FileNotFoundException: Invalid file path
        at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1365)
        at javax.mail.Transport.send0(Transport.java:255)
        at javax.mail.Transport.send(Transport.java:124)
        at com.inversation.app.integration.service.mail.clients.GenericMailClient.sendEmail(GenericMailClient.java:95)
        at com.inversation.app.jobs.CronJob.executeInternal(CronJob.java:62)
        at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:75)
        at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
    Caused by: java.io.FileNotFoundException: Invalid file path
        at java.base/java.io.FileInputStream.<init>(FileInputStream.java:152)
        at javax.activation.FileDataSource.getInputStream(FileDataSource.java:110)
        at javax.activation.DataHandler.writeTo(DataHandler.java:318)
        at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1694)
        at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:996)
        at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:561)
        at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:84)
        at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:901)
        at javax.activation.DataHandler.writeTo(DataHandler.java:330)
        at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1694)
        at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1913)
        at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1315)
        ... 7 more

在这里提出这个问题之前,我已经做过研究,但是仍然无法解决问题。任何帮助,将不胜感激。

我可以使用以下代码解决问题。希望它能帮助别人。请参阅此问题-Similar issue

attachPart.setDataHandler(new DataHandler(new ByteArrayDataSource(this.getClass().getResourceAsStream("/"+filePath),"application/pdf")));

3 个答案:

答案 0 :(得分:0)

(警告:您正在对"Brochure.pdf"进行硬编码,并且在循环中完全忽略了filePath。我假设您要附加filePath的每个值。)

the documentation for the attachFile method中可以看到,String参数必须是有效的文件名。

将InputStream中的字节转换为String当然不会产生文件名。

.jar中的资源不是文件。它是.jar文件的一部分,而不是单独的文件。

您需要手动设置MimeBodyPart的内容和文件名,而不是使用attachFile:

URL content = GenericMailClient.class.getResource("/" + filePath);
attachPart.setDataHandler(new DataHandler(content));

URI uri = content.toURI();
String path = uri.getPath();
String fileName = path.substring(path.lastIndexOf('/') + 1);

attachPart.setDisposition(Part.ATTACHMENT);
attachPath.setFileName(fileName);

请勿尝试使用URL的getFile()方法。getFile()方法将 not 返回有效的文件名,两者都是因为URL不会t是file: URL,因为不允许直接出现在URL中的字符(如空格)将被转义,而URI类则正确地解析URI组件并返回其未转义的形式。 )

答案 1 :(得分:-1)

我猜,您需要使用spring ResourceUtils从spring boot应用程序的类路径中更改读取文件的方式,

File file = ResourceUtils.getFile("classpath:Brochure.pdf");
InputStream in = new FileInputStream(file);

我敢肯定,它将为您服务

答案 2 :(得分:-1)

我在项目中使用了以下代码。基本上,如果没有确切的路径,我要做的是扫描整个类路径以查找所需的文件。这是为了帮助我确保不需要将文件放在特定的路径中。

这是因为使用此行时遇到与您相同的错误。

getClass().getClassLoader().getResource("Brochure.pdf")

因此,我创建了两个函数,它们使用文件名,然后将jar中的类路径包括在内,然后递归搜索文件。

  private static File findConfigFile(String paths, String configFilename) {
    for (String p : paths.split(File.pathSeparator)) {
      File result = findConfigFile(new File(p), configFilename);
      if (result != null) {
        return result;
      }
    }
    return null;
  }

  private static File findConfigFile(File path,  String configFilename) {
    if (path.isDirectory()) {
      String[] subPaths = path.list();
      if (subPaths == null) {
        return null;
      }
      for (String sp : subPaths) {
        File subPath = new File(path.getAbsoluteFile() + "/" + sp);
        File result = findConfigFile(subPath, configFilename);
        if (result != null && result.getName().equalsIgnoreCase(configFilename)) {
          return result;
        }
      }
      return null;
    } else {
      File file = path;
      if (file.getName().equalsIgnoreCase(configFilename)) {
        return file;
      }
      return null;
    }
  }

这是我的代码示例:

import java.io.File;

public class FindResourcesRecursive {

    public File findConfigFile(String paths, String configFilename) {
        for (String p : paths.split(File.pathSeparator)) {
            File result = findConfigFile(new File(p), configFilename);
            if (result != null) {
                return result;
            }
        }
        return null;
    }

    private File findConfigFile(File path, String configFilename) {
        if (path.isDirectory()) {
            String[] subPaths = path.list();
            if (subPaths == null) {
                return null;
            }
            for (String sp : subPaths) {
                File subPath = new File(path.getAbsoluteFile() + "/" + sp);
                File result = findConfigFile(subPath, configFilename);
                if (result != null && result.getName().equalsIgnoreCase(configFilename)) {
                    return result;
                }
            }
            return null;
        } else {
            File file = path;
            if (file.getName().equalsIgnoreCase(configFilename)) {
                return file;
            }
            return null;
        }
    }

}

在这里,我有一个测试用例,在我的test / resources文件夹中有一个文件“ test.txt”。该文件的内容为:

A sample file

现在,这是我的测试用例:

import org.junit.Test;

import java.io.*;

import static org.junit.Assert.fail;

public class FindResourcesRecursiveTest {

    @Test
    public void testFindFile() {
        // Here in the test resources I have a file "test.txt"
        // Inside it is a string "A sample file"
        // My Unit Test will use the class FindResourcesRecursive to find the file and print out the results.
        File testFile = new FindResourcesRecursive().findConfigFile(
                System.getProperty("java.class.path"),
                "test.txt"
        );

        try (FileInputStream is = new FileInputStream(testFile)) {
            int i;
            while ((i = is.read()) != -1) {
                System.out.print((char) i);
            }
            System.out.println();
        } catch (IOException e) {
            fail();
        }

    }
}

现在,如果您运行此测试,它将打印出“示例文件”,并且测试将变为绿色。

现在,你还好吗?