0

I got an existing SpringMVC+velocty project, and tried to upgrade it to SpringBoot+Velocity, as a dozens of velocty templates here.

First, everything works in my eclipse environment, and I can visit http://sxu-mvp-p.xxx-qa.com.cn:8888/login page.

However, when i built the jar using mvn clean package -Dconf=dev -Dmaven.test.skip=true and following exception was thrown

2018-09-22 14:42:43.652 [http-nio-8888-exec-3]  INFO com.xxx.monitor.controller.LoginController.login:58 - Hello world org.springframework.web.servlet.view.velocity.VelocityLayoutViewResolver@35390ee3
2018-09-22 14:42:43.654 [http-nio-8888-exec-3]  INFO com.xxx.monitor.controller.LoginController.login:61 - Receiver a login request: /login
2018-09-22 14:42:43.744 [http-nio-8888-exec-3] ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet].log:181 - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
        at org.springframework.web.servlet.view.velocity.VelocityToolboxView.createVelocityContext(VelocityToolboxView.java:113)
        at org.springframework.web.servlet.view.velocity.VelocityView.renderMergedTemplateModel(VelocityView.java:290)
        at org.springframework.web.servlet.view.AbstractTemplateView.renderMergedOutputModel(AbstractTemplateView.java:167)
        at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
        at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1286)
        at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1041)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:984)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:110)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at com.xxx.utils.web.HttpRequestMDCFilter.doFilter(HttpRequestMDCFilter.java:108)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
         .......

when visiting the login page.

Here are some of my configuration:

pom.xml
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>1.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-tools</artifactId>
            <version>2.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.struts</groupId>
                    <artifactId>*</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-velocity -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-velocity</artifactId>
            <version>1.4.7.RELEASE</version>
        </dependency>

//Spring-velocity.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
                           http://www.springframework.org/schema/mvc
                           http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-4.1.xsd"
       default-autowire="byName">

    <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
        <property name="resourceLoaderPath" value="/WEB-INF/vm"/>
        <property name="configLocation" value="classpath:velocity.properties"/>
    </bean>

    <bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    </bean>

    <bean id="exceptionResolver" class="com.xxx.monitor.ExceptionHandler"/>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityLayoutViewResolver">
        <property name="suffix" value=".vm"/>
        <property name="layoutUrl" value="/WEB-INF/vm/layout/default.vm"/>
        <!-- 使用springMacro、使用servlet的对象 -->
        <property name="exposeSpringMacroHelpers" value="true"/>
        <property name="exposeRequestAttributes" value="true"/>
         <property name="prefix" value="/WEB-INF/vm/" />
         <property name="viewClass" value="org.springframework.web.servlet.view.velocity.VelocityLayoutView" />
        <property name="exposeSessionAttributes" value="true"/>
        <property name="contentType" value="text/html;charset=UTF-8"/>
        <!-- spring的日期格式化 -->
        <property name="dateToolAttribute" value="dateTool"/>
        <property name="toolboxConfigLocation" value="/WEB-INF/velocity-tools.xml"/> 
        <property name="attributesMap">
            <map>
            </map>
        </property>
    </bean>

<!--     <bean id="velocityEngine"
        class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
    <property name="velocityProperties">
        <props>
            <prop key="resource.loader">file</prop>
            <prop key="file.resource.loader.class">
                org.apache.velocity.runtime.resource.loader.FileResourceLoader
            </prop>
            <prop key="file.resource.loader.path">WEB-INF/vm/</prop>
            <prop key="file.resource.loader.cache">false</prop>
        </props>
       </property>
</bean> -->
</beans>

  //velocity-tools.xml
   <toolbox>
    <tool>
        <key>stringUtils</key>
        <scope>application</scope>
        <class>org.apache.commons.lang.StringUtils</class>
    </tool>
    <tool>
        <key>dateFormatUtils</key>
        <scope>application</scope>
        <class>org.apache.commons.lang.time.DateFormatUtils</class>
    </tool>
    <tool>
        <key>escapeUtils</key>
        <scope>application</scope>
        <class>org.apache.commons.lang.StringEscapeUtils</class>
    </tool>
    <tool>
        <key>loginContextHolder</key>
        <scope>application</scope>
        <class>com.xxx.monitor.vo.LoginContextHolder</class>
    </tool>
</toolbox>

The directory hierarchy is shown BOOT-INFO/classes/ | spring-velocity.xml | velocity.properties | WEB-INF/ | velocity-tools.xml

NPE is thrown when servletContext.getResourceAsStream(toolboxFile) in ServletToolboxManager::getInstance(ServletContext servletContext, String toolboxFile).

Besides, controller is:

@Controller
@RequestMapping(value = "/")
public class LoginController extends BaseController{
   @RequestMapping(value = "/login", method = RequestMethod.GET)
    public ModelAndView login(HttpServletRequest request, HttpServletResponse response) {
        logger.info("Hello world {}", resolver.toString());
        // 展示login页面
        ModelAndView mav = new ModelAndView();
        logger.info("Receiver a login request: {} ", request.getRequestURI());
        LoginContextHolder.clear();
        mav.setViewName("login");
        return mav;
    }
}

It looks like something wrong in the configuration, and the toolboxConfigLocation is not used, or the path is wrongly configured. Can anyone help resolve it and explain why it works in eclipse? Thanks

shijie xu
  • 1,975
  • 21
  • 52
  • See https://stackoverflow.com/questions/48626714/spring5-0-1-velocityenginefactorybean – Ori Marko Sep 22 '18 at 09:03
  • Look like similar issue :http://forum.spring.io/forum/spring-projects/web/21884-exposing-velocity-generic-tool-results-in-nullpointer – soorapadman Sep 22 '18 at 12:21
  • This page is very old, but the exception is the same, and no solution is found there. I tried the ` "/WEB-INF/velocity-tools.xml" ` but issue is still there. – shijie xu Sep 22 '18 at 14:35

0 Answers0