FreeMarker在JAVA中应用入门

来源:互联网 发布:撞库盗号软件 编辑:程序博客网 时间:2024/05/22 00:12
在项目中通常有生成XML文件发送到另一个系统的需求,简单的办法可以是用一个XML模板,通过Freemarker替换其中的'Mark'(${}),生成最终的XML文件.

下面记录了一下简单的示例步骤:

1,创建一个XML模板:

[html] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <people  xmlns:h="http://www.w3.org/TR/html4/">  
  3.     <person id="000001" age="20">  
  4.         <name>  
  5.             <family>${p.fname}</family>  
  6.             <given>${p.gname}</given>  
  7.         </name>  
  8.         <email>${p.email}</email>  
  9.         <link manager="${p.manager}" />       
  10.     </person>      
  11. </people>  

2,在JAVA中将mark用值替换掉:下面是JAVA代码

[java] view plaincopy
  1. package com.test.xml.freemarker;  
  2.   
  3. public class ValueObject {  
  4.     private String fname;  
  5.     private String gname;  
  6.     private String email;  
  7.     private String manager;  
  8.     public String getFname() {  
  9.         return fname;  
  10.     }  
  11.     public void setFname(String fname) {  
  12.         this.fname = fname;  
  13.     }  
  14.     public String getGname() {  
  15.         return gname;  
  16.     }  
  17.     public void setGname(String gname) {  
  18.         this.gname = gname;  
  19.     }  
  20.     public String getEmail() {  
  21.         return email;  
  22.     }  
  23.     public void setEmail(String email) {  
  24.         this.email = email;  
  25.     }  
  26.     public String getManager() {  
  27.         return manager;  
  28.     }  
  29.     public void setManager(String manager) {  
  30.         this.manager = manager;  
  31.     }      
  32. }  
  33. public class Test {  
  34.     Configuration freeMarkerCfg = new Configuration();  
  35.     Template template = null;  
  36.     public Test() {  
  37.         freeMarkerCfg.setClassForTemplateLoading(getClass(),"");  
  38.         freeMarkerCfg.setObjectWrapper(new DefaultObjectWrapper());  
  39.         try {  
  40.             template = freeMarkerCfg.getTemplate("test.xml");  
  41.         } catch (IOException e) {  
  42.             // TODO  
  43.             e.printStackTrace();  
  44.         }  
  45.     }  
  46.   
  47.     public void generateRequest(ValueObject obj) {  
  48.   
  49.         String reqFileName = "D:\\temp\\test.xml";  
  50.         try {  
  51.             Map<String, Object> parameters = new HashMap<String, Object>();  
  52.   
  53.             parameters.put("p", obj);  
  54.   
  55.             OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(reqFileName), "UTF-8");  
  56.             template.process(parameters, writer);  
  57.             writer.flush();  
  58.         } catch (IOException e) {  
  59.             e.printStackTrace();// TODO  
  60.         } catch (TemplateException e) {  
  61.             e.printStackTrace();// TODO  
  62.         }  
  63.   
  64.     }  
  65.     public static void main(String[] args) {  
  66.         ValueObject val = new ValueObject();  
  67.           
  68.         val.setFname("Yao");  
  69.         val.setGname("Yorker");  
  70.         val.setEmail("test@mail.com");  
  71.         val.setManager("manager");  
  72.           
  73.         new Test().generateRequest(val);  
  74.     }  
  75. }  

XML模板和class在package "com.test.xml.freemarker".

***在模板中通过${val}指定的值,如果在处理的时候val值为null,会出现下面的异常:

freemarker.core.InvalidReferenceException: Expression valis undefined on line 46, column 63 in test.ftl

FreeMarker这么做的本意是防止在传值的地方(Data Model)写入的参数,如想传入 parameters.put("abc", obj);,但是写成了parameters.put("abcd", obj);

但是有的时候,里面有的值不是必须有值的,可以通过${val!""}来绕过这个异常.${val!""}的意思是如果val为null,取值"".

***Freemarker对XML文件中特殊字符的处理:通过<#escape>

[html] view plaincopy
  1. <#escape x as x?xml>  
  2. <person id="000001" age="20">  
  3.     <name>  
  4.         <family>${p.fname}</family>  
  5.         <given>${p.gname}</given>  
  6.     </name>  
  7.     <email>${p.email}</email>  
  8.     <link manager="${p.manager}" />  
  9. </person>  
  10. </#escape>  

val.setManager("m&an<ager"); 传入的值就按照XML规范保存到XML文件 link manager="m&amp;an&lt;ager" />

***循环处理 <#list>

[html] view plaincopy
  1. <#list people as p>  
  2. <person id="000001" age="20">  
  3.     <name>  
  4.         <family>${p.fname}</family>  
  5.         <given>${p.gname}</given>  
  6.     </name>  
  7.     <email>${p.email}</email>  
  8.     <link manager="${p.manager}" />  
  9. </person>  
  10. </#list>  
  11.     List<ValueObject> pList = new ArrayList<ValueObject>();  
  12.     ValueObject val = null;  
  13.       
  14.     val = new ValueObject();          
  15.     val.setFname("Yao");  
  16.     val.setGname("Yorker");  
  17.     val.setEmail("test@mail.com");  
  18.     val.setManager("m&an<ager");          
  19.     pList.add(val);  
  20.       
  21.     val = new ValueObject();          
  22.     val.setFname("J");  
  23.     val.setGname("Jeremy");  
  24.     val.setEmail("test1@mail.com");  
  25.     val.setManager("m&an<ager");          
  26.     pList.add(val);  
  27.     parameters.put("people", pList);  

***分支处理<#if>,根据值对模板做不同的输出.

        <#if p.level == "L1">
        <l1tag>xxx</l1tag>
        </#if>

***对生成超大文件的测试:

[java] view plaincopy
  1. public void generateRequest(List<ValueObject> pList) {  
  2.     String reqFileName = "D:\\temp\\test.xml";  
  3.     try {  
  4.         Map<String, Object> parameters = new HashMap<String, Object>();  
  5.         parameters.put("people", pList);  
  6.         OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(reqFileName), "UTF-8");  
  7.         template.process(parameters, writer);  
  8.         writer.flush();  
  9.     } catch (IOException e) {  
  10.         e.printStackTrace();// TODO  
  11.     } catch (TemplateException e) {  
  12.         e.printStackTrace();// TODO  
  13.     }  
  14. }  
  15. public static void testLargeVolumn(){  
  16.     List<ValueObject> pList = new ArrayList<ValueObject>();  
  17.     ValueObject val = null;  
  18.       
  19.     for(int i=0;i<400000;i++){  
  20.         val = new ValueObject();          
  21.         val.setFname("Yao"+i);  
  22.         val.setGname("Yorker");  
  23.         val.setEmail("test@mail.com");  
  24.         val.setManager("m&an<ager");  
  25.         val.setLevel("L"+i);  
  26.         pList.add(val);  
  27.     }          
  28.     new Test().generateRequest(pList);  
  29. }  

一次性输出,本例在达到循环400000次的时候异常:java.lang.OutOfMemoryError: Java heap space

解决办法:分多次输出到最终的输出文件中.

1,将模板需要循环的部分单独做成一个模板.

先一次输出循环模板前面的部分,分多次输出循环部分,一次输出循环部分之后的部分.

示例如下,(这里由于循环之前部分和之后部分不涉及模板替换,直接用JAVA代码输出)

模板需要循环输出的部分:

[html] view plaincopy
  1. <#escape x as x?xml>  
  2. <#list people as p>  
  3. <person id="000001" age="20">  
  4.     <name>  
  5.         <family>${p.fname}</family>  
  6.         <given>${p.gname}</given>  
  7.     </name>  
  8.     <email>${p.email}</email>  
  9.     <link manager="${p.manager}" />  
  10.     <#if p.level == "L1">  
  11.     <l1tag>xxx</l1tag>  
  12.     </#if>  
  13. </person>  
  14. </#list>  
  15. </#escape>  

JAVA代码:

[java] view plaincopy
  1. public class LargeVolumnTest {  
  2.     Configuration freeMarkerCfg = new Configuration();  
  3.     Template template = null;  
  4.     public LargeVolumnTest() {  
  5.         freeMarkerCfg.setClassForTemplateLoading(getClass(),"");  
  6.         freeMarkerCfg.setObjectWrapper(new DefaultObjectWrapper());  
  7.         try {  
  8.             template = freeMarkerCfg.getTemplate("testL.xml");  
  9.         } catch (IOException e) {  
  10.             // TODO  
  11.             e.printStackTrace();  
  12.         }  
  13.     }  
  14.   
  15.     public void generateRequestHeader() {  
  16.         String reqFileName = "D:\\temp\\test.xml";  
  17.         try {  
  18.             OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(reqFileName), "UTF-8");  
  19.             writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");  
  20.             writer.write("<people  xmlns:h=\"http://www.w3.org/TR/html4/\">");  
  21.             writer.flush();  
  22.         } catch (IOException e) {  
  23.             e.printStackTrace();// TODO  
  24.         }   
  25.     }  
  26.     public void generateRequestTail() {  
  27.         String reqFileName = "D:\\temp\\test.xml";  
  28.         try {  
  29.             OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(reqFileName,true), "UTF-8");  
  30.             writer.write("</people>");              
  31.             writer.flush();  
  32.         } catch (IOException e) {  
  33.             e.printStackTrace();// TODO  
  34.         }   
  35.     }  
  36.       
  37.     public void generateRequest(List<ValueObject> pList) {  
  38.         String reqFileName = "D:\\temp\\test.xml";  
  39.         try {  
  40.             Map<String, Object> parameters = new HashMap<String, Object>();  
  41.             parameters.put("people", pList);  
  42.             OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(reqFileName,true), "UTF-8");  
  43.             template.process(parameters, writer);  
  44.             writer.flush();  
  45.         } catch (IOException e) {  
  46.             e.printStackTrace();// TODO  
  47.         } catch (TemplateException e) {  
  48.             e.printStackTrace();// TODO  
  49.         }  
  50.     }  
  51.   
  52.     public  void testLargeVolumn(){  
  53.         generateRequestHeader();  
  54.         List<ValueObject> pList = new ArrayList<ValueObject>();  
  55.         ValueObject val = null;  
  56.         int i=0;  
  57.         for(;i<500000;i++){  
  58.             val = new ValueObject();          
  59.             val.setFname("Yao"+i);  
  60.             val.setGname("Yorker");  
  61.             val.setEmail("test@mail.com");  
  62.             val.setManager("m&an<ager");  
  63.             val.setLevel("L"+i);  
  64.             pList.add(val);  
  65.             if(i%10000==0){  
  66.                 generateRequest(pList);  
  67.                 pList.clear();  
  68.             }  
  69.         }  
  70.         if(i%10000!=0){  
  71.             generateRequest(pList);  
  72.         }  
  73.         generateRequestTail();  
  74.     }  
  75.     public static void main(String[] args) {          
  76.         new LargeVolumnTest().testLargeVolumn();  
  77.     }  
  78. }  

注意在输出循环部分和结尾部分是通过追加到文件的方式:OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(reqFileName,true), "UTF-8");

最终生成的XML文档有90M,没有报异常.

这里有FreeMarker的中文manual :http://download.csdn.net/user/kkdelta

0 0