springMVC加载远程freemarker模板文件
在一个大网站里,有很多子域名,也就是有很多子系统,这些子系统由不同的团队负责,对整个网站的风格的风格至少得要是一致的(最基本的页头、页尾必须一致),这个时候得提供一份统一的页头、页尾以及公共的JS、css等内容,但如果是直接给源代码(ftl/js/css)的形式,对于后期的升级维护必然增加不必要的麻烦,必须得只有一个维护这个代码。
freemarker提供了远程模板加载的功能,在各个业务方里就像使用本地的模板一样使用远程的统一的模板代码。
1、编写自定义的模板加载器(继续freemarker的接口或者抽象类)
上图中RemoteTemplateLoader是我们实现的freemarker的URLTemplateLoader抽象类的远程模板加载类。
代码如下:
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); } } }
2、在springMVC XML里配置该RemoteTemplateLoader
<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>
3、在自己的FTL文件中include该远程模板
<#include "/test/a.ftl">
这个上面的url中是在RemoteTemplateLoader的XML的参数里已经进行了配置,所以跟使用本地的ftl是一样的。