Использование Velocity WebappResourceLoader с Spring - PullRequest
3 голосов
/ 27 июня 2010

Я пытаюсь использовать Velocity для создания шаблона электронной почты, отправляемого классом SpringMail JavaMailSender.Загрузчик ресурсов, который я решил использовать, чтобы найти шаблон Velocity в моем веб-приложении, - это WebappResourceLoader, который находится в банке инструмента Velocity.

Однако, в зависимости от того, как я использую WebappResourceLoader, я получаю либо NPE при запуске веб-приложения, либо шаблон не может быть найден.

Если я указываю свойства init дляСкоростной движок в моем контексте приложения Spring я получаю NPE.Моя конфигурация выглядит следующим образом:

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

Трассировка стека, которую я получаю при запуске приложения:

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)

Чтобы исправить это, я изменил свой контекст приложения следующим образом:

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

И затем в классе обслуживания, прямо перед кодом для слияния данных приложения с шаблоном (который находится в / WEB-INF / speed и называется regemail.vm), я добавил следующий код:

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

Приложение запускается нормально, но когда письмо будет отправлено, я получаю следующую ошибку:

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 tools 2.0.Любая помощь высоко ценится.Спасибо!

Ответы [ 3 ]

1 голос
/ 19 ноября 2010

Если вы посмотрите документацию для VelocityEngineFactoryBean , вы заметите, что есть свойство 'resourceLoaderPath', которое вы можете установить. Учитывая вышеописанную конфигурацию, похоже, что вы разместили свои шаблоны Velocity в /WEB-INF/velocity/, поэтому используйте его в качестве значения для resourceLoaderPath и фабричного компонента, который должен нормально загружать ваши шаблоны.

1 голос
/ 17 февраля 2014

Три года спустя, но вот еще одно решение, которое не требует адаптации вашего Java-кода для передачи ServletContext в Velocity Engine.

Просто используйте VelocityConfigurer вместо VelocityEngineFactoryBean в вашем файле контекста Spring, например:

<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>
1 голос
/ 27 июня 2010

Вам необходимо передать объект ServletContext:

velocityEngine.setApplicationAttribute("javax.servlet.ServletContext", request.getSession().getServletContext());

Другой вариант будет использовать вместо ClasspathResourceLoader и поместить ваши шаблоны в classpath.

...