有人可以指出我在这里做错了什么。
我有一个小型天气应用,可以生成并发送HTML电子邮件。使用下面的代码,当我从Eclipse运行它时,一切正常。我的电子邮件已生成,它可以访问我的图片资源,并通过附带的附件发送电子邮件。
但是,当我通过运行 mvn install 构建可执行jar并使用 java -jar NameOfMyJar.jar 运行jar时,我得到 java.io.FileNotFound 我的图片资源的例外情况。
我知道我必须对我访问图像资源的方式做错了,我只是不明白为什么它没有打包时工作正常,但每当炸弹时都会爆炸我将它打包成一个罐子。
非常感谢任何建议。
我的项目布局
我如何访问我的图片资源
//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
答案 0 :(得分:8)
其他人使用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,并且可以以相同的方式访问。我会修复文件结构以遵循这个约定。
注意: 的Constructed(正如Bill Shannon所说,这是不正确的)。正如他在下面的评论中提到的那样MimeBodyPart
,来自InputStream
“您也可以使用”
附加数据mbp.setDataHandler(new DataHandler(new ByteArrayDataSource(
this.getClass().getResourceAsStream("/Cloudy_Day.png", "image/png"))));
答案 1 :(得分:2)
您无法将JAR文件中的资源作为文件访问,只能将其作为InputStream读取:getResourceAsStream()
。
由于MimeBodyPart没有用于InputStream的attach()
方法,最简单的方法应该是读取资源并将其写入临时文件,然后附加这些文件。
答案 2 :(得分:1)
试试这个
new MimeBodyPart().attachFile(new File(this.getClass().getClassLoader().getResource("resources/Cloudy_Day.png").toURI());
答案 3 :(得分:0)
我不知道这是否会帮助任何人。但是,我有一个与OP类似的情况,我通过使用递归函数在类路径中找到文件来解决了这种情况。这样的想法是,当另一个开发人员决定将资源移动到另一个文件夹/路径时。只要名称仍然相同,仍会找到它。
例如,在我的工作中,我们通常将资源放在罐子外面,然后将所述资源路径添加到我们的类路径中,因此这里的资源类路径会根据其所在位置而有所不同。
这是我的代码开始工作的地方,无论文件放在何处,只要它在类路径中就可以找到。
这是我的代码示例:
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();
}
}
}
现在,如果您运行此测试,它将打印出“示例文件”,并且测试将变为绿色。