Jason Stonebraker
Jason Stonebraker

Reputation: 809

Importing spring.ftl using Spring MVC, Sitemesh, Freemarker

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!

Upvotes: 6

Views: 10381

Answers (3)

Matthew Payne
Matthew Payne

Reputation: 3056

I like my spring.ftl included by default without having to add it manually within each view. In your configuration.

Define your freemarkerConfigurer as such.

   @Bean(name = "freemarkerConfig")
public FreeMarkerConfigurer freemarkerConfig() {
    FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
    configurer.setTemplateLoaderPath("/WEB-INF/views/");
    Map<String, Object> map = new HashMap<>();
    map.put("xml_escape", new XmlEscape());
    configurer.setFreemarkerVariables(map)
    def settings = new Properties()
    settings['auto_import']  =  'spring.ftl as spring, layout/application.ftl as l'
    configurer.setFreemarkerSettings(settings)
    println "returning freemarker config"
    return configurer;
}

Upvotes: 0

EliuX
EliuX

Reputation: 12685

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.

Upvotes: 4

Richard
Richard

Reputation: 1

<#import "spring.ftl" as spring/>

Without /

Upvotes: -3

Related Questions