有人可以指出我在这里做错了什么。
我有一个小天气应用程序,生成并发送HTML电子邮件。使用下面的代码,当我从Eclipse运行它时,一切正常。我的电子邮件生成后,它可以访问我的图像资源,并发送包含附件的电子邮件。
但是,当我通过运行mvn install构建可执行jar并使用java -jar NameOfMyJar.jar运行jar时,我的图像资源获得了java.io.FileNotFound异常。
我知道我必须对我如何访问我的图像资源做错了,我只是不明白为什么它在没有打包的情况下工作正常,但每当我将它打包到jar中时都会爆炸。
任何建议都非常感谢。
我的项目布局
我如何访问我的图像资源
//Setup the ATTACHMENTS
MimeBodyPart attachmentsPart = new MimeBodyPart();
try {
attachmentsPart.attachFile("resources/Cloudy_Day.png");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
StackTrace
Exception in thread "main" java.lang.RuntimeException: javax.mail.MessagingException: IOException while sending message;
nested exception is:
java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
at Utilities.SendEmailUsingGmailSMTP.SendTheEmail(SendEmailUsingGmailSMTP.java:139)
at Utilities.SendEmailUsingGmailSMTP.SendWeatherEmail(SendEmailUsingGmailSMTP.java:66)
at Weather.Main.start(Main.java:43)
at Weather.Main.main(Main.java:23)
Caused by: javax.mail.MessagingException: IOException while sending message;
nested exception is:
java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1167)
at javax.mail.Transport.send0(Transport.java:195)
at javax.mail.Transport.send(Transport.java:124)
at Utilities.SendEmailUsingGmailSMTP.SendTheEmail(SendEmailUsingGmailSMTP.java:134)
... 3 more
Caused by: java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:146)
at javax.activation.FileDataSource.getInputStream(FileDataSource.java:97)
at javax.activation.DataHandler.writeTo(DataHandler.java:305)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1485)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:865)
at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:462)
at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:103)
at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:889)
at javax.activation.DataHandler.writeTo(DataHandler.java:317)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1485)
at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1773)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1119)
... 6 more
其他人使用getResourceAsStream
是正确的,但路径有点棘手。你在resources
文件夹中看到小包装图标?这表示resource
文件夹中的所有文件都将放入类路径的根目录中。就像src/main/java
中的所有包都放在根目录中一样。所以你会从路径中取出resources
InputStream is = getClass().getResourceAsStream("/Cloudy_Day.png");
抛开:Maven有一个文件结构约定。类路径资源通常放入src/main/resources
。如果你在resources
中创建一个src/main
目录,那么Eclipse应该会自动拾取它,并为你应该在项目浏览器中看到的路径src/main/resource
创建一个小包图标。这些文件也将转到root,并且可以以相同的方式访问。我会修复文件结构以遵循此约定。
注意:一个MimeBodyPart
,可以是来自Constructed的InputStream
(正如Bill Shannon所说,这是不正确的)。如下面的评论中所述
“你也可以使用”附加数据“
mbp.setDataHandler(new DataHandler(new ByteArrayDataSource(
this.getClass().getResourceAsStream("/Cloudy_Day.png", "image/png"))));
您不能将JAR文件中的资源作为File访问,只能将它们作为InputStream读取:getResourceAsStream()
。
由于MimeBodyPart没有用于InputStream的attach()
方法,最简单的方法应该是读取资源并将其写入临时文件,然后附加这些文件。
试试这个
new MimeBodyPart().attachFile(new File(this.getClass().getClassLoader().getResource("resources/Cloudy_Day.png").toURI());
我不知道这是否会对任何人有所帮助。但是,我有一个与OP类似的情况,我通过使用递归函数在类路径中查找文件来解决这个问题。这个想法是这样的,当另一个开发人员决定将资源移动到另一个文件夹/路径时。只要名称仍然相同,它仍然会被发现。
例如,在我的工作中,我们通常将我们的资源放在jar之外,然后我们将所述资源路径添加到我们的类路径中,因此这里资源的类路径将根据它所在的位置而不同。
这就是我的代码开始工作的地方,无论文件放在何处,只要它在类路径中就可以找到。
以下是我的代码实例:
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();
}
}
}
现在,如果您运行此测试,它将打印出“示例文件”,测试将为绿色。