001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.view.freemarker; 018 019import java.io.IOException; 020import java.util.List; 021 022import javax.servlet.ServletContext; 023 024import freemarker.cache.ClassTemplateLoader; 025import freemarker.cache.TemplateLoader; 026import freemarker.ext.jsp.TaglibFactory; 027import freemarker.template.Configuration; 028import freemarker.template.TemplateException; 029 030import org.springframework.beans.factory.InitializingBean; 031import org.springframework.context.ResourceLoaderAware; 032import org.springframework.lang.Nullable; 033import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory; 034import org.springframework.util.Assert; 035import org.springframework.web.context.ServletContextAware; 036 037/** 038 * JavaBean to configure FreeMarker for web usage, via the "configLocation" 039 * and/or "freemarkerSettings" and/or "templateLoaderPath" properties. 040 * The simplest way to use this class is to specify just a "templateLoaderPath"; 041 * you do not need any further configuration then. 042 * 043 * <pre class="code"> 044 * <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> 045 * <property name="templateLoaderPath"><value>/WEB-INF/freemarker/</value></property> 046 * </bean></pre> 047 * 048 * This bean must be included in the application context of any application 049 * using Spring's FreeMarkerView for web MVC. It exists purely to configure FreeMarker. 050 * It is not meant to be referenced by application components but just internally 051 * by FreeMarkerView. Implements FreeMarkerConfig to be found by FreeMarkerView without 052 * depending on the bean name of the configurer. Each DispatcherServlet can define its 053 * own FreeMarkerConfigurer if desired. 054 * 055 * <p>Note that you can also refer to a preconfigured FreeMarker Configuration 056 * instance, for example one set up by FreeMarkerConfigurationFactoryBean, via 057 * the "configuration" property. This allows to share a FreeMarker Configuration 058 * for web and email usage, for example. 059 * 060 * <p>This configurer registers a template loader for this package, allowing to 061 * reference the "spring.ftl" macro library contained in this package: 062 * 063 * <pre class="code"> 064 * <#import "/spring.ftl" as spring/> 065 * <@spring.bind "person.age"/> 066 * age is ${spring.status.value}</pre> 067 * 068 * Note: Spring's FreeMarker support requires FreeMarker 2.3 or higher. 069 * 070 * @author Darren Davison 071 * @author Rob Harrop 072 * @since 03.03.2004 073 * @see #setConfigLocation 074 * @see #setFreemarkerSettings 075 * @see #setTemplateLoaderPath 076 * @see #setConfiguration 077 * @see org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean 078 * @see FreeMarkerView 079 */ 080public class FreeMarkerConfigurer extends FreeMarkerConfigurationFactory 081 implements FreeMarkerConfig, InitializingBean, ResourceLoaderAware, ServletContextAware { 082 083 @Nullable 084 private Configuration configuration; 085 086 @Nullable 087 private TaglibFactory taglibFactory; 088 089 090 /** 091 * Set a preconfigured Configuration to use for the FreeMarker web config, e.g. a 092 * shared one for web and email usage, set up via FreeMarkerConfigurationFactoryBean. 093 * If this is not set, FreeMarkerConfigurationFactory's properties (inherited by 094 * this class) have to be specified. 095 * @see org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean 096 */ 097 public void setConfiguration(Configuration configuration) { 098 this.configuration = configuration; 099 } 100 101 /** 102 * Initialize the {@link TaglibFactory} for the given ServletContext. 103 */ 104 @Override 105 public void setServletContext(ServletContext servletContext) { 106 this.taglibFactory = new TaglibFactory(servletContext); 107 } 108 109 110 /** 111 * Initialize FreeMarkerConfigurationFactory's Configuration 112 * if not overridden by a preconfigured FreeMarker Configuration. 113 * <p>Sets up a ClassTemplateLoader to use for loading Spring macros. 114 * @see #createConfiguration 115 * @see #setConfiguration 116 */ 117 @Override 118 public void afterPropertiesSet() throws IOException, TemplateException { 119 if (this.configuration == null) { 120 this.configuration = createConfiguration(); 121 } 122 } 123 124 /** 125 * This implementation registers an additional ClassTemplateLoader 126 * for the Spring-provided macros, added to the end of the list. 127 */ 128 @Override 129 protected void postProcessTemplateLoaders(List<TemplateLoader> templateLoaders) { 130 templateLoaders.add(new ClassTemplateLoader(FreeMarkerConfigurer.class, "")); 131 } 132 133 134 /** 135 * Return the Configuration object wrapped by this bean. 136 */ 137 @Override 138 public Configuration getConfiguration() { 139 Assert.state(this.configuration != null, "No Configuration available"); 140 return this.configuration; 141 } 142 143 /** 144 * Return the TaglibFactory object wrapped by this bean. 145 */ 146 @Override 147 public TaglibFactory getTaglibFactory() { 148 Assert.state(this.taglibFactory != null, "No TaglibFactory available"); 149 return this.taglibFactory; 150 } 151 152}