在 Spring 中使用 Velocity 的 WebappResourceLoader [英] Using Velocity's WebappResourceLoader with Spring

查看:23
本文介绍了在 Spring 中使用 Velocity 的 WebappResourceLoader的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Velocity 创建一个由 Spring 的 JavaMailSender 类邮寄的电子邮件模板.我决定用来在我的 Web 应用程序中查找 Velocity 模板的资源加载器是 WebappResourceLoader,它位于 Velocity 工具 jar 中.

I'm trying to use Velocity to create an email template that is mailed by Spring's JavaMailSender class. The resource loader that I decided to use to find the Velocity template in my web app is WebappResourceLoader which is located in the Velocity tool jar.

但是,根据我使用 WebappResourceLoader 的方式,我会在 Web 应用程序启动时收到 NPE,或者找不到模板.

However, depending on how I use the WebappResourceLoader, I get either a NPE when the web app starts up or the template can't be found.

如果我在 Spring 应用程序上下文中为 Velocity 引擎指定 init 属性,我会得到 NPE.我的配置如下:

If I specify the init properties for the Velocity engine in my Spring application context I get the NPE. My configuration is as follows:

<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
  <property name="velocityProperties">
        <props>
        <prop key="resource.loader">webapp</prop>
        <prop key="webapp.resource.loader.class">org.apache.velocity.tools.view.WebappResourceLoader</prop>
        <prop key="webapp.resource.loader.path">/WEB-INF/velocity/</prop>
        </props>
   </property>
</bean>

我在应用程序启动时得到的堆栈跟踪是:

The stack trace I get when the app is starting up is:

java.lang.NullPointerException
at org.apache.velocity.tools.view.WebappResourceLoader.getResourceStream(WebappResourceLoader.java:145)
at org.apache.velocity.runtime.resource.loader.ResourceLoader.resourceExists(ResourceLoader.java:224)
at org.apache.velocity.runtime.resource.ResourceManagerImpl.getLoaderForResource(ResourceManagerImpl.java:641)
at org.apache.velocity.runtime.resource.ResourceManagerImpl.getLoaderNameForResource(ResourceManagerImpl.java:624)
at org.apache.velocity.runtime.RuntimeInstance.getLoaderNameForResource(RuntimeInstance.java:1464)
at org.apache.velocity.runtime.VelocimacroFactory.initVelocimacro(VelocimacroFactory.java:159)
at org.apache.velocity.runtime.RuntimeInstance.init(RuntimeInstance.java:261)
at org.apache.velocity.app.VelocityEngine.init(VelocityEngine.java:107)
at org.springframework.ui.velocity.VelocityEngineFactory.createVelocityEngine(VelocityEngineFactory.java:251)
at org.springframework.ui.velocity.VelocityEngineFactoryBean.afterPropertiesSet(VelocityEngineFactoryBean.java:57)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1460)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1398)

为了解决这个问题,我将我的应用程序上下文更改为如下:

To fix this I changed my application context to as below:

<bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean" />

然后在服务类中,就在将应用程序数据与模板(位于/WEB-INF/velocity 并命名为 regemail.vm)合并的代码之前,我添加了以下代码:

And then in the service class, right before the code to merge application data with the template (which is at /WEB-INF/velocity and named regemail.vm) I added the following code:

    velocityEngine.addProperty("resource.loader", "webapp");
    velocityEngine.addProperty("webapp.resource.loader.class", "org.apache.velocity.tools.view.WebappResourceLoader");
    velocityEngine.addProperty("webapp.resource.loader.path", "/WEB-INF/velocity/");
    velocityEngine.setApplicationAttribute("javax.servlet.ServletContext", "localhost:8080");

应用程序启动正常,但是当要发送电子邮件时,我收到以下错误:

The app starts fine but when the email is going to be sent, I get the following error:

SEVERE: Servlet.service() for servlet default threw exception
org.apache.velocity.exception.ResourceNotFoundException: Unable to find resource 'regmail.vm'
at org.apache.velocity.runtime.resource.ResourceManagerImpl.loadResource(ResourceManagerImpl.java:483)
at org.apache.velocity.runtime.resource.ResourceManagerImpl.getResource(ResourceManagerImpl.java:354)
at org.apache.velocity.runtime.RuntimeInstance.getTemplate(RuntimeInstance.java:1400)
at org.apache.velocity.app.VelocityEngine.mergeTemplate(VelocityEngine.java:370)
at org.apache.velocity.app.VelocityEngine.mergeTemplate(VelocityEngine.java:345)
at org.springframework.ui.velocity.VelocityEngineUtils.mergeTemplate(VelocityEngineUtils.java:58)
at org.springframework.ui.velocity.VelocityEngineUtils.mergeTemplateIntoString(VelocityEngineUtils.java:122)
at com.mywebapp.web.service.RegistrationServiceImpl$1.prepare(RegistrationServiceImpl.java:60)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:353)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:345)
at com.mywebapp.web.service.RegistrationServiceImpl.sendRegEmail(RegistrationServiceImpl.java:65)
at com.mywebapp.web.controller.SignUpController.onSubmit(SignUpController.java:97)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

我使用的是 Velocity 1.6.4 版和 Velocity 工具 2.0.非常感谢任何帮助.谢谢!

I'm using Velocity version 1.6.4 and Velocity tools 2.0. Any help much appreciated. Thanks!

推荐答案

三年后,但这里有另一种解决方案,它不需要调整您的 Java 代码以将 ServletContext 传递给 Velocity Engine.

Three years later, but here's another solution that does not require to adapt your Java code to pass the ServletContext to Velocity Engine.

在您的 Spring Context 文件中简单地使用 VelocityConfigurer 而不是 VelocityEngineFactoryBean,如下所示:

Simply use VelocityConfigurer instead of VelocityEngineFactoryBean in your Spring Context file like this:

<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
    <property name="velocityPropertiesMap">
        <map>
            <entry key="runtime.log.invalid.reference"><value>true</value></entry>
            <entry key="runtime.log.logsystem.class"><value>org.apache.velocity.runtime.log.Log4JLogChute</value></entry>
            <entry key="runtime.log.logsystem.log4j.logger"><value>velocity</value></entry>
            <entry key="input.encoding"><value>UTF-8</value></entry>
            <entry key="output.encoding"><value>UTF-8</value></entry>
            <entry key="directive.include.output.errormsg.start"><value></value></entry>
            <entry key="directive.parse.max.depth"><value>10</value></entry>
            <entry key="directive.set.null.allowed"><value>true</value></entry>
            <entry key="velocimacro.library.autoreload"><value>true</value></entry>
            <entry key="velocimacro.permissions.allow.inline"><value>true</value></entry>
            <entry key="velocimacro.permissions.allow.inline.to.replace.global"><value>false</value></entry>
            <entry key="velocimacro.permissions.allow.inline.local.scope"><value>false</value></entry>
            <entry key="velocimacro.context.localscope"><value>false</value></entry>
            <entry key="runtime.interpolate.string.literals"><value>true</value></entry>
            <entry key="resource.manager.class"><value>org.apache.velocity.runtime.resource.ResourceManagerImpl</value></entry>
            <entry key="resource.manager.cache.class"><value>org.apache.velocity.runtime.resource.ResourceCacheImpl</value></entry>
            <entry key="resource.loader"><value>webapp, class, ds</value></entry>
            <entry key="class.resource.loader.description"><value>Velocity Classpath Resource Loader</value></entry>
            <entry key="class.resource.loader.class"><value>org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader</value></entry>
            <entry key="webapp.resource.loader.class"><value>org.apache.velocity.tools.view.WebappResourceLoader</value></entry>
            <entry key="webapp.resource.loader.path"><value>/WEB-INF/views/</value></entry>
            <entry key="webapp.resource.loader.cache"><value>false</value></entry>
            <entry key="webapp.resource.loader.modificationCheckInterval"><value>2</value></entry>
            <entry key="ds.resource.loader.instance"><ref bean="templateLoader"/></entry>
            <entry key="ds.resource.loader.resource.table"><value>templates</value></entry>
            <entry key="ds.resource.loader.resource.keycolumn"><value>code</value></entry>
            <entry key="ds.resource.loader.resource.templatecolumn"><value>content</value></entry>
            <entry key="ds.resource.loader.resource.timestampcolumn"><value>updated</value></entry>
            <entry key="ds.resource.loader.cache"><value>false</value></entry>
        </map>
    </property>
</bean>

<bean id="templateLoader" 
    class="org.apache.velocity.runtime.resource.loader.DataSourceResourceLoader">
    <property name="dataSource" ref="yourDataSource"></property>
</bean>

这篇关于在 Spring 中使用 Velocity 的 WebappResourceLoader的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆