Reputation: 4846
I am developing a web application using servlets in which i want to use Velocity
templates. For this purpose i have kept my templates under WEB-INF/templates
directory.
I have another plain Java class which generates code from this template and which requires to read this file.
My servlet calls method from this simple java class to get the generated code.
I tried to use the real path to read the template but i'm getting ResourceNotFoundException
every time i access the servlet.
Following is the code which i'm using in the sevlet
TemplateParser parser = new TemplateParser(getServletContext().getRealPath("/WEB-INF/templates/index.vm"));
String html = parser.parser();
out.println(html);
TemplateParser
is my simple java class.
I'm using it in a Netbeans
project and the path string generated is
C:\Users\Sushil Kumar\Documents\NetBeansProjects\ALTTC\build\web\WEB-INF\templates\index.vm
. This file exits at the given path but still getting the exception.
Stacktrace of the exception
org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'C:\Users\Sushil Kumar\Documents\NetBeansProjects\ALTTC\build\web\WEB-INF\templates\index.vm'
at org.apache.velocity.runtime.resource.ResourceManagerImpl.loadResource(ResourceManagerImpl.java:452)
at org.apache.velocity.runtime.resource.ResourceManagerImpl.getResource(ResourceManagerImpl.java:335)
at org.apache.velocity.runtime.RuntimeInstance.getTemplate(RuntimeInstance.java:1102)
at org.apache.velocity.runtime.RuntimeInstance.getTemplate(RuntimeInstance.java:1077)
at org.apache.velocity.app.VelocityEngine.getTemplate(VelocityEngine.java:528)
at me.uni.sushilkumar.alttc.TemplateParser.parser(TemplateParser.java:52)
at me.uni.sushilkumar.alttc.TemplateController.processRequest(TemplateController.java:38)
at me.uni.sushilkumar.alttc.TemplateController.doGet(TemplateController.java:57)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:393)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
EDIT as suggested by TheNewIdiot in the comments.
Properties p = new Properties();
p.setProperty("resource.loader", "file");
p.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
p.setProperty("file.resource.loader.path", path); <== path = getServletContext().getRealPath("/WEB-INF/templates")
p.setProperty("file.resource.loader.cache", "false");
p.setProperty("file.resource.loader.modificationCheckInterval", "0");
Upvotes: 0
Views: 2160
Reputation: 6647
Don't use FileResourceLoader
. Have a look at the documentation:
The simplest replacement for FileResourceLoader in a web application is actually a part of the VelocityTools project. It is the WebappResourceLoader. This ResourceLoader implementation is specifically designed to work just like the FileResourceLoader, but it is aware of the servlet context and allows you to configure resource paths relative to the servlet root, rather than the local file system.
If you are using the VelocityViewServlet, then it is automatically configured and ready to use the WebappResourceLoader. So if you want to change the configured path(s), you need only add a line like the following to your velocity.properties:
webapp.resource.loader.path=/WEB-INF/mytemplates/
If you need to set the WebappResourceLoader up on your own, then you can make your properties something like this:
resource.loader=webapp
webapp.resource.loader.class=org.apache.velocity.tools.view.WebappResourceLoader
webapp.resource.loader.path=/WEB-INF/mytemplates/
Or:
Properties props = new Properties();
props.setProperty("resource.loader", "webapp");
props.setProperty("webapp.resource.loader.class", "org.apache.velocity.tools.view.WebappResourceLoader");
props.setProperty("webapp.resource.loader.path", "/WEB-INF/mytemplates/");
VelocityEngine engine = new VelocityEngine(props);
You will also need to put the ServletContext into your VelocityEngine's application attributes before initializing that Engine. This is how the WebappResourceLoader knows how to find templates.
myVelocityEngine.setApplicationAttribute("javax.servlet.ServletContext", servletContext);
Upvotes: 4
Reputation: 3012
First of all you are not getting a FileNotFoundException
. As the stacktrace clearly says, you are getting a ResourceNotFoundException
, a velocity-specific exception telling that the resource (in your case the template) cannot be found.
Velocity uses objects of type ResourceLoaders
to load resources. IIRC, the deafult one is ClasspathResourceLoader
, that will look for resources in the classpath, and if the folder of your templates is not in the classpath you are out of luck. You can switch ResourceLoader and use a FileResourceLoader
instead, that will load stuff from the filesystem.
To change the ResourceLoader I would suggest to read the documentation as there are many ways to do that, that suit different scenarios. One way is the following:
Properties props = new Properties();
props.setProperty("resource.loader", "myapp");
props.setProperty("myapp.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
VelocityEngine engine = new VelocityEngine(props);
Upvotes: 1