How to use velocity 1.7 with Spring
Solution 1
I had the same issue when using . I could have solved it in the following way:
@Configuration
public class ApplicationConfiguration {
@Bean
public VelocityEngine getVelocityEngine() throws VelocityException, IOException{
VelocityEngineFactory factory = new VelocityEngineFactory();
Properties props = new Properties();
props.put("resource.loader", "class");
props.put("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
factory.setVelocityProperties(props);
return factory.createVelocityEngine();
}
}
But instead - because I was using velocity templates for my views and had already declared a VelocityConfigurer, so I instead Autowired in my declaration of VelocityConfigurer and called getVelocityEngine() on that.
I did discover that, if it's being autowired into @Service-s or @Component-s and you've declared in a shared applicationContext.xml file, then the xml declaration had to be in that shared applicationContext.xml as well rather than the xxx-servlet.xml config.
I think this is because applicationContext.xml is shared amongst all servlets in the application, so it has to be fully processed before the xxx-servlet.xml files are.
Alternatively, you could enable spring bean factory debugging and see if it's having any issues instantiating it:
log4j.category.org.springframework.beans.factory=DEBUG
Solution 2
I think you cannot use @Autowired
with a static field. You can work around this with a non-static setter:
@Autowired
public void setVelocityEngine(VelocityEngine ve) {
EmailUtils.velocityEngine = ve;
}
or in another way but I would strongly recommend turning EmailUtils
into a non-static bean. Spring handles non-static components much better (no ugly hacks needed), it will be possible to swap implementations and your code will stick to DI philosphy.
Solution 3
This is my attempt, I initialize the "velocityEngine" bean manually via ClassPathXmlApplicationContext:
Spring application-context.xml
<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="velocityProperties">
<value>
resource.loader=class
class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
</value>
</property>
</bean>
This is my template_text.vm, put it in the classpath, same level as application-context.xml.
Dear $userName,
You have made the following request on $userTime.
#if( $isFileMissing )
Missing file(s) found in home directory:
#foreach( $missingFile in $missingFiles )
- $missingFile
#end
#end
Best regards,
This is the Java code:
public static void main(String[] args) throws Exception {
String[] springConfig = {"application-context.xml"};
org.springframework.context.ApplicationContext context = new org.springframework.context.support.ClassPathXmlApplicationContext(springConfig);
java.util.Map<String, Object> model = new java.util.HashMap<String, Object>();
model.put("userName", "John Low");
model.put("userTime", "2015-10-28 23:59:59");
model.put("isFileMissing", true);
model.put("missingFiles", new String[] {"line 1", "line 2", "line 3"});
String text = org.springframework.ui.velocity.VelocityEngineUtils.mergeTemplateIntoString((VelocityEngine)context.getBean("velocityEngine"), "/template_text.vm", "UTF-8", model);
System.out.println(text);
}
The output:
Dear John Low,
You have made the following request on 2015-10-28 23:59:59.
Missing file(s) found in home directory:
- file 1
- file AAA
- line 3
Best regards,
Solution 4
I had the same issue when I was upgrading our project to Java 11 + Spring Boot 2.1.8. I could have solved it in the following way:
@Configuration
public class AppConfig {
@Bean
public VelocityEngine velocityEngine() throws Exception {
Properties properties = new Properties();
properties.setProperty("input.encoding", "UTF-8");
properties.setProperty("output.encoding", "UTF-8");
properties.setProperty("resource.loader", "class");
properties.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
VelocityEngine velocityEngine = new VelocityEngine(properties);
return velocityEngine;
}
}
ashishjmeshram
Updated on September 16, 2020Comments
-
ashishjmeshram almost 4 years
I am using velocity 1.7 withe spring 3.1 framework for sending email. velocity is used for email templates.
Below is the configuration
<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean"> <property name="velocityProperties"> <props> <prop key="resource.loader">class</prop> <prop key="class.resource.loader.class"> org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader </prop> </props> </property> </bean>
and below is my code
@Component public class EmailUtils { @Autowired private static VelocityEngine velocityEngine; public static void sendMail(String subject, Map data, String template, String toName, String toAddress) { HtmlEmail email = new HtmlEmail(); try { email.setHostName(hostName); email.setSmtpPort(smtpPort); email.setSubject(subject); System.out.println(template +" template"); System.out.println(data +" data "); System.out.println(velocityEngine +" velocityEngine "); String message = VelocityEngineUtils.mergeTemplateIntoString( velocityEngine, template, data); System.out.println(message +" message message "); email.setMsg(message); email.addTo(toAddress, toName); email.setFrom(fromAddress, fromName); email.send(); } catch (EmailException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
When I run the application I get following error.
java.lang.NullPointerException at org.springframework.ui.velocity.VelocityEngineUtils.mergeTemplate(VelocityEngineUtils.java:58)
as the velocity engine is null.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd"> <bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean"> <property name="velocityProperties"> <props> <prop key="resource.loader">class</prop> <prop key="class.resource.loader.class"> org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader </prop> </props> </property> </bean>
Please help me. Is there any other configuration that I need to do?
-
ashishjmeshram over 12 yearshi Thanks for the answer. I removed static as you said. Now I am getting No matching bean of type [org.apache.velocity.app.VelocityEngine] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. while deploying the application. Please help.
-
mrembisz over 12 years
VelocityEngineFactoryBean
produces object of typeVelocityEngine
. How do you indicate context files to be loaded? -
mrembisz over 12 yearsIs your bean "velocityEngine" instantiated? You should see it listed if you enable INFO logging for "org.springframework".
-
ashishjmeshram over 12 yearsNo I dont see it in the list. But I can see EmailUtils in list.
-
mrembisz over 12 yearsAre you sure the file where it is defined is loaded at all? It should also be logged on INFO level. I see it as
INFO [XmlBeanDefinitionReader] Loading XML bean definitions from URL [file:/C:/Projects/my_project/springContext.xml]
-
ashishjmeshram over 12 yearsYes I can see this for my velocity.xml . Its getting loaded I think.
-
mrembisz over 12 yearsPlease post this entire log and code where you create spring context.