如何在Spring中使用Velocity 1.7

6
我将使用velocity 1.7与spring 3.1框架发送电子邮件,其中velocity用于电子邮件模板。
以下是配置:
<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>

以下是我的代码:
 @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();
        }
    }
}

当我运行应用程序时,出现以下错误。
java.lang.NullPointerException
at org.springframework.ui.velocity.VelocityEngineUtils.mergeTemplate(VelocityEngineUtils.java:58)

由于速度引擎为空。

<?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>

请帮我看看,还需要做其他配置吗?


1
你是否已经正确配置了Spring以使用XML配置和注解配置? - ndeverge
你传递了什么模板?我怀疑那里可能有问题。 - JasonG
Ashish,你看到nico_ekito关于注释配置的评论了吗?你的XML中有<context:annotation-config />吗?在你的示例XML配置片段中没有它。 - Rup
4个回答

9
当我使用时,我遇到了同样的问题。我可以通过以下方式解决它:
@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();      
    }
}

但是,由于我在视图中使用了 velocity 模板并已经声明了 VelocityConfigurer,所以我在声明VelocityConfigurer时使用了 Autowired 并调用了 getVelocityEngine()。
我发现,如果它被自动装配到@Service或@Component中,并且您已经在共享的applicationContext.xml文件中声明了bean,则 xml 声明也必须在该共享的applicationContext.xml中,而不是 xxx-servlet.xml 配置文件中。
我认为这是因为 applicationContext.xml 在应用程序中的所有 servlet 之间共享,因此必须在处理 xxx-servlet.xml 文件之前完全处理。
或者,您可以启用 spring bean 工厂调试,并查看它是否有任何实例化问题:
log4j.category.org.springframework.beans.factory=DEBUG

5

我认为您不能使用@Autowired注解来修饰静态字段。但是您可以通过非静态setter方法解决此问题:

@Autowired
public void setVelocityEngine(VelocityEngine ve) {
  EmailUtils.velocityEngine = ve;
}

或者另一种方式是,但我强烈建议将EmailUtils转换为非静态bean。Spring更好地处理非静态组件(无需丑陋的黑客),可以交换实现,并且您的代码将遵循DI哲学。


谢谢你的回答。我按照你说的去掉了static关键字。但是在部署应用程序时,出现了“找不到类型为[org.apache.velocity.app.VelocityEngine]的匹配bean”的错误,期望至少有一个bean符合此依赖项的自动装配候选项。请帮忙解决。 - ajm
VelocityEngineFactoryBean 会生成类型为 VelocityEngine 的对象。您如何指示要加载的上下文文件? - mrembisz
你的bean "velocityEngine" 是否已经实例化?如果你为 "org.springframework" 启用了 INFO 日志记录,你应该能看到它被列出。 - mrembisz
不,我在列表中没有看到它。但是我可以在列表中看到EmailUtils。 - ajm
你确定定义它的文件被加载了吗?它应该在INFO级别下记录日志。我看到它是这样的:INFO [XmlBeanDefinitionReader] Loading XML bean definitions from URL [file:/C:/Projects/my_project/springContext.xml] - mrembisz
显示剩余2条评论

2

当我将我们的项目升级到Java 11 + Spring Boot 2.1.8时,遇到了同样的问题。我可以通过以下方式解决它:

@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;
    }
}

1
这是我的尝试,我通过ClassPathXmlApplicationContext手动初始化"velocityEngine" bean:
Spring应用程序-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>

这是我的template_text.vm,将其放在类路径中,与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,

这是Java代码:

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);
}

输出:

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,

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接