DaFoot
DaFoot

Reputation: 1567

How do I add Freemarker support to a Spring MVC webapp? Dependency issue?

I'm trying to create a Spring MVC application using Freemarker and Java configuration.

I'm used to using JSPs, but thought I'd give Freemarker a spin in this project.

I've added Freemarker as a dependancy and the jar is being downloaded by Maven:

        <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.20</version>
    </dependency>

I'm trying to use 3.2.3.RELEASE version of Spring.

My MVC configuration, assembled from reading similar question:

@ComponentScan(basePackages="yhj.*")
@EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter{


@Bean
public ViewResolver viewResolver() {
    FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
    resolver.setCache(true);
    resolver.setPrefix("");
    resolver.setSuffix(".ftl");
    return resolver;

}

@Bean
public FreeMarkerConfigurer freemarkerConfig() {
    FreeMarkerConfigurer result = new FreeMarkerConfigurer();
    result.setTemplateLoaderPath("/WEB-INF/views/");
    return result;

}
}

When I try run this up I get a compilation error, my IDE is telling me the method 'setTemplateLoaderPath(String)' cannot be resolved.

So... does look like the right way of going about configuring Spring MVC with Freemarker? What dependency do I need to add to my POM if that is the issue?

Upvotes: 13

Views: 13906

Answers (4)

EliuX
EliuX

Reputation: 12625

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

John Deverall
John Deverall

Reputation: 6280

@Bean(name = "freeMarkerViewResolver")
    public FreeMarkerViewResolver getFreeMarkerViewResolver() { 
        FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
        resolver.setPrefix("/WEB-INF/views/json/");
        resolver.setSuffix(".json");
        resolver.setOrder(2);
        resolver.setContentType("application/json");
        resolver.setCache(true);
        return resolver;
    }

    @Bean(name = "freemarkerConfig")
    public FreeMarkerConfigurer getFreemarkerConfig() throws IOException, TemplateException { 
        FreeMarkerConfigurer result = new FreeMarkerConfigurer();
        result.setTemplateLoaderPaths("/"); // prevents FreeMarkerConfigurer from using its default path allowing setPrefix to work as expected
        return result;
    }

Upvotes: 5

Sofia Pahaoja
Sofia Pahaoja

Reputation: 2720

My solution for Spring Boot 1.0.2, Spring 4.0.3, and FreeMarker 2.3.20 was the following class:

@Configuration
public class MvcConfigurer extends WebMvcConfigurerAdapter {
  @Bean
  public ViewResolver viewResolver() {
    FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
    resolver.setCache(true);
    resolver.setPrefix("");
    resolver.setSuffix(".ftl");
    resolver.setContentType("text/html; charset=UTF-8");
    return resolver;
  }

  @Bean
  public FreeMarkerConfigurer freemarkerConfig() throws IOException, TemplateException {
    FreeMarkerConfigurationFactory factory = new FreeMarkerConfigurationFactory();
    factory.setTemplateLoaderPath("classpath:templates");
    factory.setDefaultEncoding("UTF-8");
    FreeMarkerConfigurer result = new FreeMarkerConfigurer();
    result.setConfiguration(factory.createConfiguration());
    return result;
  }
}

In addition you need the same pom.xml changes as in the question and DaFoot's own answer.

Upvotes: 14

DaFoot
DaFoot

Reputation: 1567

Well I've sorted the compilation issue, added a dependency to my pom...

    <dependency><!-- needed for freemarker FreeMarkerConfigurer stuff -->
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
        <version>${spring.version}</version>
    </dependency>

Upvotes: 12

Related Questions