FreeMarker 应用笔记(1)

前不久项目中遇到一个问题:要求生成静态页面。

于是想到了velocity和FreeMarker。。。。

这是两个JAVA模板引擎,作为当前流行的几大MVC框架的有益补充,受到了开源框架Spring的支持。

下面总结一下初步FreeMarker应用。

1。要和Spring结合,首先要在Spring的Context中注册org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer的一个实例。

<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
      <property name="templateLoaderPath" value="/template/"/>
    </bean>


2。编写模板:

比如,编写一个生成SQL脚本的模板。


<#if genreList?exists>
<#list genreList as commongenre>
INSERT INTO test1.tb_commongenre (vc2genrename) VALUES ('${commongenre?js_string}');
</#list>
</#if>
<#if cataList?exists>
<#list cataList as vc2catagorytagname>
INSERT INTO test1.tb_catagorytags (vc2catagorytagname) VALUES ('${vc2catagorytagname?js_string}');
</#list>
</#if>
<#if stdgenList?exists>
<#list stdgenList as vc2stdgenrename>
INSERT INTO test1.tb_stdgenre (vc2stdgenrename) VALUES ('${vc2stdgenrename?js_string}');
</#list>
</#if>



3:编写代码来生成最终的脚本。

public class MusicSqlGenerator {
    ApplicationContext ctx = new ClassPathXmlApplicationContext(
        new String[] {"applicationContext.xml"});
    private String tablename;

    private String basePath = "/home/x-spirit";

    public void genSql() throws Exception{
        FreeMarkerConfigurer freemarkerConfig = (FreeMarkerConfigurer)ctx.getBean("freemarkerConfig");
        Template tpl =freemarkerConfig.getConfiguration().getTemplate("newSQLTemplate.sql");
        Map map = new HashMap();
        
        map.put("stdgenList",readToList(new ArrayList<String>(), "tb_stdgenre",true,-1,-1));
        String context = FreeMarkerTemplateUtils
                         .processTemplateIntoString(tpl, map);


        PrintWriter pw = new PrintWriter(new FileOutputStream("c:/target.sql"));
        pw.println(context);
        pw.flush();
        pw.close();
    }
    public String[] readToList(List<String> list,String tablename,boolean all,int start,int limit)throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(basePath+File.separator+tablename), "UTF-8"));
        String s = null;
        int i = 0;
        int j = 0;
        while((s=br.readLine())!=null){
            if(all){
                list.add(s);
            }else{
                if(++i>=start){
                    if(++j<=limit){
                        list.add(s);
                    }
                }
            }
            
        }
        String[] arr = list.toArray(new String[list.size()]);
        return arr;
    }
    public static void main(String args[]){
        try {
            new MusicSqlGenerator().genSql();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
        
}


结果,当tb_stdgenre文件中包含将近100MB的数据时,程序出现堆内存泄露。。。因为这100MB的数据要在一个String对象里面存储实在是太多了。。。


于是研究了Spring的源代码和FreeMarker的源代码,对程序做了如下改进:

首先继承Spring里面的FreeMarkerTemplateUtils。这个类里面是把StringWriter传进去,最后返回一个String。。。这就是罪魁祸首阿。。那我直接把用于磁盘I/O的PrintWriter传进去好了,这样至少不会瞬间在内存里堆积大量的数据。

public class FreeMarkerTemplateUtils extends org.springframework.ui.freemarker.FreeMarkerTemplateUtils{

        public static void processTemplateIntoFile(Template template, Object model,String filepath)
			throws IOException, TemplateException {
                PrintWriter pw = new PrintWriter(new FileOutputStream(filepath));
		template.process(model, pw);
	}
}


注意这段代码后面不需要对pw对象做flush()和close()。因为FreeMarker里面已经做过了。不相信的读者请自己去看源码。

接下来对原来的程序进行改造:
public class MusicSqlGenerator {
    ApplicationContext ctx = new ClassPathXmlApplicationContext(
        new String[] {"applicationContext.xml"});
    private String tablename;

    private String basePath = "/home/x-spirit";

    public void genSql() throws Exception{
        FreeMarkerConfigurer freemarkerConfig = (FreeMarkerConfigurer)ctx.getBean("freemarkerConfig");
        Template tpl =freemarkerConfig.getConfiguration().getTemplate("newSQLTemplate.sql");
        Map map = new HashMap();
        
        map.put("stdgenList",readToList(new ArrayList<String>(), "tb_stdgenre",true,-1,-1));
        FreeMarkerTemplateUtils
                         .processTemplateIntoFile(tpl, map,"/home/x-spirit/results/musicStyle.sql");


       
    }
    public String[] readToList(List<String> list,String tablename,boolean all,int start,int limit)throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(basePath+File.separator+tablename), "UTF-8"));
        String s = null;
        int i = 0;
        int j = 0;
        while((s=br.readLine())!=null){
            if(all){
                list.add(s);
            }else{
                if(++i>=start){
                    if(++j<=limit){
                        list.add(s);
                    }
                }
            }
            
        }
        String[] arr = list.toArray(new String[list.size()]);
        return arr;
    }
    public static void main(String args[]){
        try {
            new MusicSqlGenerator().genSql();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
        
}



好了。先写到这里。。。

总之,感觉Spring对FreeMarker的支持其实还不是特别的好,就是简单封装了一下。不过至少也为我们使用提供了参照范例。感谢Juergen Hoeller的启发。

你可能感兴趣的:(spring,sql,freemarker,框架,velocity)