在一個大網站裏,有不少子域名,也就是有不少子系統,這些子系統由不一樣的團隊負責,對整個網站的風格的風格至少得要是一致的(最基本的頁頭、頁尾必須一致),這個時候得提供一份統一的頁頭、頁尾以及公共的JS、css等內容,但若是是直接給源代碼(ftl/js/css)的形式,對於後期的升級維護必然增長沒必要要的麻煩,必須得只有一個維護這個代碼。css
freemarker提供了遠程模板加載的功能,在各個業務方里就像使用本地的模板同樣使用遠程的統一的模板代碼。java
一、編寫自定義的模板加載器(繼續freemarker的接口或者抽象類)web
上圖中RemoteTemplateLoader是咱們實現的freemarker的URLTemplateLoader抽象類的遠程模板加載類。spring
代碼以下:apache
import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; import java.util.List; import org.apache.commons.lang3.StringUtils; import freemarker.cache.URLTemplateLoader; /** * 自定義遠程模板加載器,用來加載遠程機器上存放的模板文件.HTTP * * @author Administrator * */ public class RemoteTemplateLoader extends URLTemplateLoader { // 遠程模板文件的存儲路徑(目錄) private String remotePath; private List<String> includePaths; private String paths; public RemoteTemplateLoader(String remotePath) { if (remotePath == null) { throw new IllegalArgumentException("remotePath is null"); } this.remotePath = canonicalizePrefix(remotePath); if (this.remotePath.indexOf('/') == 0) { this.remotePath = this.remotePath.substring(this.remotePath.indexOf('/') + 1); } } @Override public Object findTemplateSource(String name) throws IOException { if(this.includePaths!=null&&this.includePaths.contains(name)){ return super.findTemplateSource(name); } return null; } @Override protected URL getURL(String name) { // name = name.replace("_zh", ""); String fullPath = this.remotePath + name; if ((this.remotePath.equals("/")) && (!isSchemeless(fullPath))) { return null; } URL url = null; try { url = new URL(fullPath); } catch (MalformedURLException e) { e.printStackTrace(); } return url; } private static boolean isSchemeless(String fullPath) { int i = 0; int ln = fullPath.length(); if ((i < ln) && (fullPath.charAt(i) == '/')) i++; while (i < ln) { char c = fullPath.charAt(i); if (c == '/') return true; if (c == ':') return false; i++; } return true; } public void setRemotePath(String remotePath) { this.remotePath = remotePath; } public void setPaths(String paths) { this.paths = paths; if (StringUtils.isNotEmpty(this.paths)) { String [] s = this.paths.split(";"); this.includePaths = Arrays.asList(s); } } }
二、在springMVC XML裏配置該RemoteTemplateLoaderless
<bean id="remoteTemplateLoader" class="com.xxx.RemoteTemplateLoader"> <constructor-arg name="remotePath" value="http://10.1.1.1/" /> <property name="paths" value="/test/a.ftl;/test/b.ftl" /> </bean> <bean id="remoteTemplateLoader2" class="com.xxx.RemoteTemplateLoader"> <constructor-arg name="remotePath" value="http://103.11.5.10/" /> <property name="paths" value="/test/a.ftl;/test/b.ftl" /> </bean> <util:list id="preTemplateLoaders" list-class="java.util.ArrayList" value-type="com.xxx.RemoteTemplateLoader"> <ref bean="remoteTemplateLoader" /> <ref bean="remoteTemplateLoader2" /> </util:list> <bean id="freeMarkerConfigurer" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <description>Required for Freemarker to work in web tier</description> <property name="configuration" ref="freemarkerConfiguration" /> </bean> <bean id="freemarkerConfiguration" class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean"> <description>Using the Config directly so we can use it outside the web tier</description> <property name="preferFileSystemAccess" value="true"/> <property name="postTemplateLoaders" ref="preTemplateLoaders" /> <!-- 模板加載路徑 --> <property name="templateLoaderPaths"> <list> <value>/WEB-INF/views</value> </list> </property> <property name="configLocation"> <value>classpath:conf/freemarker.properties</value> </property>
...................
</bean>
三、在本身的FTL文件中include該遠程模板ide
<#include "/test/a.ftl">
這個上面的url中是在RemoteTemplateLoader的XML的參數裏已經進行了配置,因此跟使用本地的ftl是同樣的。post