Importing spring.ftl using Spring MVC, Sitemesh, Freemarker

Jason Stonebraker picture Jason Stonebraker · Dec 9, 2011 · Viewed 9.3k times · Source

How can I import the spring.ftl macros into a Freemarker template page using Spring MVC, Sitemesh, and Freemarker?

I've configured a Spring MVC app using Sitemesh and Freemarker based on Ted Young's configuration example. According to the Spring MVC/Freemarker integration reference, it is necessary to import the spring.ftl macros in order to bind the backing model to the view via <@spring.bind "command.name"/>. However, doing this:

<#import "/spring.ftl" as spring>
<@spring.bind "command.user"/>

Results in this exception:

org.springframework.web.util.NestedServletException: 
Request processing failed; nested exception is freemarker.
template.TemplateException: Error reading imported file spring.ftl

Others have experienced this issue, but I've yet to find a solution in google land. I also attempted to use this technique (zipping up spring.ftl, placing it in META-INF/lib, and adding the zip to the build path), but it didn't seem to work out.

Thanks!

Answer

EliuX picture EliuX · Jul 31, 2015

The problem is that spring dont know where to look after the spring.ftl file: This is my custom configuration for an MVC project using Boot

/**
 * Otras configuraciones de la aplicaciones web, incluyendo algunas definidas en
 * xml. Usar @ImportResource("classpath:/extra-config.xml") en caso de quererse
 * importar configuracion en xml
 */
@Configuration 
@PropertySource("classpath:application.properties")
public class WebAppConfig
{
    @Autowired
    private ServletContext context;

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer placeHolderConfigurer = new PropertySourcesPlaceholderConfigurer(); 
        return placeHolderConfigurer;
    }

   @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() throws IOException, TemplateException 
    {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer()
        {

            @Override
            protected void postProcessConfiguration(freemarker.template.Configuration config) throws IOException, TemplateException
            {
                WebappTemplateLoader WebAppTplLoader = new WebappTemplateLoader(context, "/WEB-INF/ftl");
                ClassTemplateLoader classTplLoader = new ClassTemplateLoader(context.getClassLoader(), "/templates");
                ClassTemplateLoader baseMvcTplLoader = new ClassTemplateLoader(FreeMarkerConfigurer.class, "");
                MultiTemplateLoader mtl = new MultiTemplateLoader(new TemplateLoader[]
                {
                    WebAppTplLoader,
                    classTplLoader,
                    baseMvcTplLoader
                });  
                config.setTemplateLoader(mtl);
            }
        };
        configurer.setDefaultEncoding("UTF-8"); 
        configurer.setPreferFileSystemAccess(false); 
        return configurer; 
    }

    @Bean
    public FreeMarkerViewResolver viewResolver()
    {
         FreeMarkerViewResolver viewResolver = new FreeMarkerViewResolver(); 
         viewResolver.setExposeSpringMacroHelpers(true);  
         viewResolver.setExposeRequestAttributes(true);
         viewResolver.setPrefix("");
         viewResolver.setSuffix(".ftl");
         viewResolver.setContentType("text/html;charset=UTF-8");
         return viewResolver;
    }
}

The first 2 loaders allow to load .ftl templates in war files from "/WEB-INF/ftl" and from regular jar files from src/resources/templates. If you want to use security tags in freemarker the escense are this two lines:

         viewResolver.setExposeSpringMacroHelpers(true);  
         viewResolver.setExposeRequestAttributes(true);

And the baseMvcTplLoader loader to get the spring.ftl from org.springframework.web.servlet.view.freemarker. I advice to explore ftl templates in some example project or documentation to have a clue of how spring.ftl works.

The configuration of the placeholder is not related to the freemarker configuration, yet its very useful for injecting values in variables from src/resources/application.properties by using the @Value annotation.

With this you can use all the spring power within freemarker templates.