以前经常用freemarker,但是从来没有系统的学习过,最近有时间了,找到资料学习一下,官方文档下载地址:打开下载
freemarker会用并不难,本篇博客是分享freemarker和spring如何结合使用,代码全部是参考上家公司的经理的,前人栽树后人乘凉
以下两种方法,都是假设已经与springmvc整合完毕
自定义函数(普通)
1:实现TemplateMethodModelEx
package com.mall.web.template.method;
import com.fengyong.base.rely.ResultPoBean;
import com.product.po.user.base.BaseSysUserPo;
import com.product.service.user.UserService;
import freemarker.template.TemplateMethodModelEx;
import freemarker.template.TemplateModelException;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
* 描述:
*
* @author fengyong
* @date 2017/1/22.
*/
public class GetUserMethod implements TemplateMethodModelEx {
@Autowired
private UserService userService;
@Override
public Object exec(List arguments) throws TemplateModelException {
ResultPoBean<BaseSysUserPo> resultPoBean = userService.getSysUserPo(new Long(arguments.get(0).toString()));
return resultPoBean.getValue();
}
}
2:配置文件
<!--freemarker view config-->
<bean id="freeMarkerViewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="suffix" value=".ftl"/>
<property name="contentType" value="text/html; charset=UTF-8" />
<property name="exposeRequestAttributes" value="true" />
<property name="exposeSessionAttributes" value="false" />
<property name="exposeSpringMacroHelpers" value="true" />
</bean>
<bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/ftl"/>
<property name="freemarkerSettings">
<props>
<prop key="defaultEncoding">utf-8</prop>
<prop key="url_escaping_charset">utf-8</prop>
<prop key="template_update_delay">0</prop>
<prop key="locale">zh_CN</prop>
<prop key="number_format">0.######</prop>
<prop key="boolean_format">true,false</prop>
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
<prop key="date_format">yyyy-MM-dd</prop>
<prop key="time_format">HH:mm:ss</prop>
<prop key="whitespace_stripping">true</prop>
<prop key="auto_import">/app/auto_import.ftl as p</prop>
</props>
</property>
<property name="freemarkerVariables">
<map>
<!--一般地址的url-->
<entry key="base" value="#{servletContext.contextPath}"/>
<entry key="getUserMethod" value-ref="getUserMethod"/>
</map>
</property>
</bean>
<bean id="getUserMethod" class="com.mall.web.template.method.GetUserMethod"/>
3:ftl页面中使用
<#assign getUserMethod= getUserMethod("1")/>
${getUserMethod}
自定义函数(完美整合)
上面的方法是很多网上资料中都有得,但是有一定的缺点,如果有很多歌方法,那配置文件中的freemarkerVariables会无限增大,配置起来很麻烦,接下来,我会一步步解析。
1:首先看freemarkerVariables中定义的函数去了哪里
public void setFreemarkerVariables(Map<String, Object> variables) { this.freemarkerVariables = variables; }
2:查看freemarkerVariables去了哪里
public class FreeMarkerConfigurationFactory { protected final Log logger = LogFactory.getLog(this.getClass()); private Resource configLocation; private Properties freemarkerSettings; private Map<String, Object> freemarkerVariables;
3:在整个FreeMarkerConfigurationFactory里面,只有一处用到了freemarkerVariables。看下面代码
public Configuration createConfiguration() throws IOException, TemplateException { Configuration config = this.newConfiguration(); Properties props = new Properties(); if(this.configLocation != null) { if(this.logger.isInfoEnabled()) { this.logger.info("Loading FreeMarker configuration from " + this.configLocation); } PropertiesLoaderUtils.fillProperties(props, this.configLocation); } if(this.freemarkerSettings != null) { props.putAll(this.freemarkerSettings); } if(!props.isEmpty()) { config.setSettings(props); } if(!CollectionUtils.isEmpty(this.freemarkerVariables)) { config.setAllSharedVariables(new SimpleHash(this.freemarkerVariables, config.getObjectWrapper())); }
4:这时我们知道了自定义函数被放进了config,继续看这个方法
public void setAllSharedVariables(TemplateHashModelEx hash) throws TemplateModelException { TemplateModelIterator keys = hash.keys().iterator(); TemplateModelIterator values = hash.values().iterator(); while(keys.hasNext()) { setSharedVariable(((TemplateScalarModel)keys.next()).getAsString(), values.next()); } }
public void setSharedVariable(String name, TemplateModel tm) { Object replaced = sharedVariables.put(name, tm); if (replaced != null && rewrappableSharedVariables != null) { rewrappableSharedVariables.remove(name); } }
ok,现在看到了自定义函数都被放到了sharedVariables里面,那么我们只要获取config,调用setSharedVariable把自定义函数放进去,我们就可以不用无限配置了。
5:继续看config,从FreeMarkerConfigurationFactory的子FreeMarkerConfigurer(配置文件中出现过)可以看到config的去处
private Configuration configuration; private TaglibFactory taglibFactory; public FreeMarkerConfigurer() { } public void setConfiguration(Configuration configuration) { this.configuration = configuration; } public void setServletContext(ServletContext servletContext) { this.taglibFactory = new TaglibFactory(servletContext); } public void afterPropertiesSet() throws IOException, TemplateException { if(this.configuration == null) { this.configuration = this.createConfiguration(); } }
6:现在知道了config,也知道了如何往sharedVariables里面设置自定义函数,就可以开工了。
1:创建注解,用于标注自定义方法的类
package com.mall.web.template.method; import org.springframework.stereotype.Component; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by fengyong on 2017/1/22. */ @Target(value = ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Component public @interface FreemarkerComponent { String value() default ""; }
2:创建MdFreeMarkerConfigurer继承FreeMarkerConfigurer,并且ApplicationContextAware,实现ApplicationContextAware是为了获取ApplicationContext,并通过ApplicationContext获取注解和所注解的类
package com.mall.web.template.method; import freemarker.template.Configuration; import freemarker.template.TemplateException; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import java.io.IOException; import java.util.Map; /** * Created by fengyong on 2017/1/22. */ public class MdFreeMarkerConfigurer extends FreeMarkerConfigurer implements ApplicationContextAware { private ApplicationContext applicationContext; public void afterPropertiesSet() throws IOException, TemplateException { super.afterPropertiesSet(); Map<String, Object> map = applicationContext.getBeansWithAnnotation(FreemarkerComponent.class); Configuration configuration = this.getConfiguration(); for (String key : map.keySet()) { configuration.setSharedVariable(key, map.get(key)); } } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }解释一下afterPropertiesSet,这个方法是在实例化bean的时候调用。
3:写一个自定义方法
package com.mall.web.template.method; import com.fengyong.base.rely.ResultPoBean; import com.product.po.user.base.BaseSysUserPo; import com.product.service.user.UserService; import freemarker.template.TemplateMethodModelEx; import freemarker.template.TemplateModelException; import org.springframework.beans.factory.annotation.Autowired; import java.util.List; /** * 描述: * * @author fengyong * @date 2017/1/22. */ @FreemarkerComponent("getUserMethod") public class GetUserMethod implements TemplateMethodModelEx { @Autowired private UserService userService; @Override public Object exec(List arguments) throws TemplateModelException { ResultPoBean<BaseSysUserPo> resultPoBean = userService.getSysUserPo(new Long(arguments.get(0).toString())); return resultPoBean.getValue(); } }4:接下来需要修改<context:component-scan base-package="com.*" />,让spring可以扫描到所有的自定义方法类,这样ApplicationContext才可以获得这个注解和所注解的类,之后每次写自定义方法,都只需要加一个@FreemarkerComponent("****")就可以了,不需要再配置了。