March 24, 2009

Velocity and Spring Web MVC

The combination of Spring Web MVC with Velocity makes for easy view handling. One of the things that I'm confused about though is getting the configuration up an running. I've been very happy with this configuration so I thought I'd share it.

First part is to let the system know where to find Velocity templates. I store them all in a directory called velocity which is part of the web application.

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

Next up is letting Spring know that Velocity is the default View that will be used. This configures a few handy defaults that represent the common case response. That being is will be an XML response, the template name has no prefix and a .vm suffix, and we configure some custom tools to be available in the macros.

<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
    <property name="exposeSpringMacroHelpers">
        <value>true</value>
    </property>
    <property name="contentType">
        <value>text/xml</value>
    </property>
    <property name="prefix">
        <value></value>
    </property>
    <property name="suffix">
        <value>.vm</value>
    </property>
    <property name="toolboxConfigLocation">
        <value>/WEB-INF/toolbox.xml</value>
    </property>
</bean>

The toolbox configuration file defines some handy tools and in particular defaults the format that dates should be in when converted to a String. In this case the format is what ActionScript 3 expects, since this is the back end for a Flex project.

<toolbox>
    <tool>
        <key>esc</key>
        <scope>application</scope>
        <class>com.neophi.util.NullEscapeTool</class>
    </tool>
    <tool>
        <key>exceptionTool</key>
        <scope>application</scope>
        <class>com.neophi.util.ExceptionTool</class>
    </tool>
    <tool>
        <key>dateTool</key>
        <scope>application</scope>
        <class>org.apache.velocity.tools.generic.DateTool</class>
        <parameter name="format" value="EEE MMM dd HH:mm:ss 'UTC'Z yyyy"/>
    </tool>
</toolbox>

I've always felt like I'm missing some obvious configuration setting with Velocity that will make null values just show up as empty strings instead of being left as $model.attribute. Since I've not found that setting yet, the NullEscapeTool wraps the standard Velocity EscapeTool and sends back an empty string if the value was null.

@Override
public String xml(Object string) {
    String result = super.xml(string);
    if (result == null) {
        return "";
    }
    return result;
}

The ExceptionTool exposes one method stackTrace() that converts the stack trace associated with an exception to a string so that it can be included in the view. Not necessarily something you want to expose in a production environment, but very handy when debugging.

public String stackTrace(Exception exception) {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    PrintStream printStream = new PrintStream(byteArrayOutputStream);
    exception.printStackTrace(printStream);
    printStream.close();
    // Closing a ByteArrayOutputStream has no effect, so don't do it which avoids the need to try/catch the IOException
    return byteArrayOutputStream.toString();
}

Lastly if you want to have Velocity also handle certain exceptions that your web application may throw the exception resolver facility is great for handling that. In this case the exception value that ServerException refers to is a Velocity template that incorporates the ExceptionTool mentioned above.

<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="warnLogCategory">
        <value>com.neophi.exception</value>
    </property>
    <property name="defaultStatusCode">
        <value>200</value>
    </property>
    <property name="exceptionMappings">
        <props>
            <prop key="com.neophi.exception.ServerException">exception</prop>
        </props>
    </property>
</bean>


Tags: configuration java spring velocity