I try to open and read an HTML file from within class path.
Please find the directory structure in screenshot below
Inside class SendEmail
class I want to read that verification.html
file.
When using the code below, it is throwing me a java.io.FileNotFoundException
exception here:
emailContent = readHTMLFile("../emailTemplate/EmailVerificationTemplate/verification.html");
The readHTMLFile
method looks like this:
public String readHTMLFile(String path) throws IOException {
String emailContent = "";
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
while ((emailContent = bufferedReader.readLine()) != null) {
stringBuilder.append(emailContent);
}
return stringBuilder.toString();
}
However, when I use an absolute path everything is working fine.
I am very new to Java world. Please help me to fix this.
verification.html
looks rather like a "class path resource" than a file... (A file is very environment dependent (eg thinking of its path/location), whereas a "CPR" we package & supply with our application & can refer to it with a known&fixed (absolute or relative) (class path) address.
Nor maven nor gradle (by default) "includes" anything else from src/main/java
than *.java
files. So please move the according files (including structure/packages) to src/main/resources
(or src/test/...
accordingly).
When the resource is finally in classpath, since spring:3.2.2, we can do that:
String emailBody = org.springframework.util.StreamUtils. copyToString( new org.springframework.core.io.ClassPathResource( "/full/package/of/emailTemplate/EmailVerificationTemplate/verification.html").getInputStream(), /* you must know(,): better. */ Charset;forName("UTF-8") );
(..also outside/before spring-boot-application.)
In spring context, the Resource
( Classpath
-, ServletContext
-, File
(,)-, URL
-, ...) can also be "injected", like:
@Value("classpath:/full/package/...")Resource verificationEmailBody
..instead of calling the constructor.
See also:
Resource
javadoc When you need to refer to verification.html
as a File
, then please ensure: It has a distinct (absolute (ok!) or relative (good luck!)) address (in all target environments)!
Your file is located inside the classpath . This is a special location within your source-code (here in package utils.emailTemplate.EmailVerificationTemplate
). So we call it a classpath resource or simply resource .
Usually those resources are destined to be published with your code, although they are actually not code.
In the Maven standard directory layout you would put them inside the special src/main/resources
folder, separated from code.
Resources are located relative from classpath using the classpath:
schema. Since they are part of the sources, package-tree you can also locate them relative to one of your classes.
From your SendEmail
class, the given template has relative path ../
. So you can instantiate it as Resource
building the URL using this.getClass().getResource(Stirng relativePath)
from within your SendEmail
class:
class SendEmail {
private final String relativePath = "../emailTemplate/EmailVerificationTemplate/verification.html";
// build the URL for the resource relative from within your class
public URL getVerificaitonEmailTemplateUrl() {
URL templateResourceUrl = this.getClass().getResource(relativePath);
return templateResourceUrl;
}
// load the resource
public InputStream getVerificaitonEmailTemplateStream() {
InputStream is = this.getClass().getResourceAsStream(relativePath);
return is;
}
}
Load a resource as input-stream getResourceAsStream(String name)
using the relative path from inside your class.
Alternative using Spring's special-purpose extension ClassPathResource
:
private final String relativePath = "../emailTemplate/EmailVerificationTemplate/verification.html";
public String loadContentAsFile() {
ClassPathResource resource = new ClassPathResource(relativePath);
File file resource.getFile();
String content = new String(Files.readAllBytes(file.toPath()));
return content;
}
public InputStream getContentAsStream() {
ClassPathResource resource = new ClassPathResource(relativePath);
InputStream is resource.getInputStream();
return is;
}
Attention: This reading from a file works only if your resource is inside the file system. Not if your resource is inside a JAR:
This implementation returns a File reference for the underlying class path resource, provided that it refers to a file in the file system.
A safer and more robust way to read from the ClassPathResource
is resource.getInputStream()
.
To fix your method, you could simply exchange the File
related parts to InputStream
:
public String readHTML(InputStream is) throws IOException {
String emailContent = "";
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
while ((emailContent = bufferedReader.readLine()) != null) {
stringBuilder.append(emailContent);
}
return stringBuilder.toString();
}
Or even simpler (see Baeldung's tutorial linked below):
String text = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8)) // choose the encoding to fit
.lines()
.collect(Collectors.joining("\n"));
Then re-use it to read from any stream (eg a File
, a Resource
, ClassPathResource
, even a URL
). For example:
public String loadTemplate(String relativeResourcePath) throws IOException {
InputStream inputStream = this.getClass().getResourceAsStream(relativeResourcePath)
String text = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
return text;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.