freemarker入門 - 關於java代碼生成器

 freemarker入門 - 關於java代碼生成器   .

分類: JAVA編程  2014-02-11 16:44 1299人閱讀 評論(0) 收藏 舉報


http://blog.csdn.net/zxycode007/article/details/6211538



講代碼生成器之前先要說說模板,什麼叫模板呢,舉個例子吧,匯款單都見過吧,你不填寫的那些內容都屬於模板範疇

說到這應該明白了吧,模板就是把共性提取出來反覆使用,節約時間、工作量。。。。。

那跟代碼生成器有什麼關係呢,思考一下在編程語言中所有的語言是不是都用共性或者說規範,這些都是固定不變的,在具體點,軟件行業也是分主營業務 的,比如OA、CRM、ERP、SCM等等,那麼各個業務方向的軟件是不是也有其行業特點,這是不是也是固定的,那麼這就完了,這些獨特的地方是不是可以 提取出來作爲模板呢,不言而喻

言歸正傳,說到模板就不得不說現在主流的模板技術了,FreeMarker、Velocity(這個google在用),模板技術推崇一種模式:

輸出=模板+數據,所以運用到代碼生成器上也是一樣的道理,舉個簡單例子比如要生成一個javabean組件,就普通的pojo類,

那麼先分析一下生成這種類有什麼共性呢,關鍵字就不用說了,getter和setter方法都是get+屬性名uppercase首字母和set+ 屬性名uppercase首字母,還有“{}”、“;”、“()”等等這些都是不變的,那麼這些內容就可以作爲模板內容,包名、類名、屬性名這些是人爲要 取的,這些是變化的,故變的這部分就作爲數據,這樣就可以根據不同的‘數據’來生成不同的javabean

 


項目準備:先去down個freemarker.jar包,  http://freemarker.org/freemarkerdownload.html

上篇討論了代碼生成器的原理,輸出=模板+數據,那麼現在就生成一個Student.java文件做個簡單例子。

首先先寫出模板,先解決一個問題,上篇有講到屬性名首字母大寫的問題

由於freemarker中不支持將首字母大寫(屬性名中用到),那麼自己先寫一個自定義宏如下:


源碼 打印 ?
01. package  com; 
02.  
03. import  java.io.IOException; 
04. import  java.io.Writer; 
05. import  java.util.Map; 
06.  
07. import  freemarker.core.Environment; 
08. import  freemarker.template.TemplateDirectiveBody; 
09. import  freemarker.template.TemplateDirectiveModel; 
10. import  freemarker.template.TemplateException; 
11. import  freemarker.template.TemplateModel; 
12. import  freemarker.template.TemplateModelException; 
13.  
14. public   class  UpperFirstCharacter  implements  TemplateDirectiveModel { 
15.  
16.     public   void  execute(Environment env, 
17.             Map params, TemplateModel[] loopVars, 
18.             TemplateDirectiveBody body) 
19.             throws  TemplateException, IOException { 
20.         // Check if no parameters were given:  
21.         if  (!params.isEmpty()) { 
22.             throw   new  TemplateModelException( 
23.                     "This directive doesn't allow parameters." ); 
24.         } 
25.         if  (loopVars.length !=  0 ) { 
26.                 throw   new  TemplateModelException( 
27.                     "This directive doesn't allow loop variables." ); 
28.         } 
29.          
30.         // If there is non-empty nested content:  
31.         if  (body !=  null ) { 
32.             // Executes the nested body. Same as <#nested> in FTL, except  
33.             // that we use our own writer instead of the current output writer.  
34.             body.render(new  UpperCaseFilterWriter(env.getOut())); 
35.         } else  { 
36.             throw   new  RuntimeException( "missing body" ); 
37.         } 
38.     } 
39.      
40.     /** 
41.      * A {@link Writer} that transforms the character stream to upper case 
42.      * and forwards it to another {@link Writer}. 
43.      */   
44.     private   static   class  UpperCaseFilterWriter  extends  Writer { 
45.         
46.         private   final  Writer out; 
47.             
48.         UpperCaseFilterWriter (Writer out) { 
49.             this .out = out; 
50.         } 
51.  
52.         public   void  write( char [] cbuf,  int  off,  int  len) 
53.                 throws  IOException { 
54. //            char[] transformedCbuf = new char[len];  
55. //            for (int i = 0; i < len; i++) {  
56. //                transformedCbuf[i] = Character.toUpperCase(cbuf[i + off]);  
57. //            }  
58. //            out.write(transformedCbuf);  
59.             cbuf[0 ] = Character.toUpperCase(cbuf[ 0 ]); 
60.             out.write(String.valueOf(cbuf).trim());///把右邊空格去掉  
61.         } 
62.  
63.         public   void  flush()  throws  IOException { 
64.             out.flush(); 
65.         } 
66.  
67.         public   void  close()  throws  IOException { 
68.             out.close(); 
69.         } 
70.     } 
71.  
72. } 


[Java] view plaincopy

01. package com; 
02.  
03. import java.io.IOException; 
04. import java.io.Writer; 
05. import java.util.Map; 
06.  
07. import freemarker.core.Environment; 
08. import freemarker.template.TemplateDirectiveBody; 
09. import freemarker.template.TemplateDirectiveModel; 
10. import freemarker.template.TemplateException; 
11. import freemarker.template.TemplateModel; 
12. import freemarker.template.TemplateModelException; 
13.  
14. public class UpperFirstCharacter implements TemplateDirectiveModel { 
15.  
16.     public void execute(Environment env, 
17.             Map params, TemplateModel[] loopVars, 
18.             TemplateDirectiveBody body) 
19.             throws TemplateException, IOException { 
20.         // Check if no parameters were given: 
21.         if (!params.isEmpty()) { 
22.             throw new TemplateModelException( 
23.                     "This directive doesn't allow parameters."); 
24.         } 
25.         if (loopVars.length != 0) { 
26.                 throw new TemplateModelException( 
27.                     "This directive doesn't allow loop variables."); 
28.         } 
29.          
30.         // If there is non-empty nested content: 
31.         if (body != null) { 
32.             // Executes the nested body. Same as <#nested> in FTL, except 
33.             // that we use our own writer instead of the current output writer. 
34.             body.render(new UpperCaseFilterWriter(env.getOut())); 
35.         } else { 
36.             throw new RuntimeException("missing body"); 
37.         } 
38.     } 
39.      
40.     /**
41.      * A {@link Writer} that transforms the character stream to upper case
42.      * and forwards it to another {@link Writer}.
43.      */  
44.     private static class UpperCaseFilterWriter extends Writer { 
45.         
46.         private final Writer out; 
47.             
48.         UpperCaseFilterWriter (Writer out) { 
49.             this.out = out; 
50.         } 
51.  
52.         public void write(char[] cbuf, int off, int len) 
53.                 throws IOException { 
54. //            char[] transformedCbuf = new char[len]; 
55. //            for (int i = 0; i < len; i++) { 
56. //                transformedCbuf[i] = Character.toUpperCase(cbuf[i + off]); 
57. //            } 
58. //            out.write(transformedCbuf); 
59.             cbuf[0] = Character.toUpperCase(cbuf[0]); 
60.             out.write(String.valueOf(cbuf).trim());///把右邊空格去掉 
61.         } 
62.  
63.         public void flush() throws IOException { 
64.             out.flush(); 
65.         } 
66.  
67.         public void close() throws IOException { 
68.             out.close(); 
69.         } 
70.     } 
71.  
72. } 

 

下面呢就可以編寫模板了,代碼如下:


源碼 打印 ?
01. package  ${ package }; 
02.  
03. //這個地方可以事先定義好需要的類  
04. import  java.util.Date; 
05.  
06. import  java.io.Serializable; 
07.  
08. public   class  ${className}  implements  Serializable{ 
09. <#list properties as pro> 
10.     private  ${pro.proType} ${pro.proName}; 
11. </#list> 
12.      
13. <#list properties as pro> 
14.     public   void  set< @upperFC >${pro.proName}</ @upperFC >(${pro.proType} ${pro.proName}){ 
15.         this .${pro.proName}=${pro.proName}; 
16.     } 
17.      
18.     public  ${pro.proType} get< @upperFC >${pro.proName}</ @upperFC >(){ 
19.         return   this .${pro.proName}; 
20.     } 
21.      
22. </#list> 
23. } 


[Java] view plaincopy

01. package ${package}; 
02.  
03. //這個地方可以事先定義好需要的類 
04. import java.util.Date; 
05.  
06. import java.io.Serializable; 
07.  
08. public class ${className} implements Serializable{ 
09. <#list properties as pro> 
10.     private ${pro.proType} ${pro.proName}; 
11. </#list> 
12.      
13. <#list properties as pro> 
14.     public void set<@upperFC>${pro.proName}</@upperFC>(${pro.proType} ${pro.proName}){ 
15.         this.${pro.proName}=${pro.proName}; 
16.     } 
17.      
18.     public ${pro.proType} get<@upperFC>${pro.proName}</@upperFC>(){ 
19.         return this.${pro.proName}; 
20.     } 
21.      
22. </#list> 
23. } 

模板文件取名爲javabean.html,在com包下

下面編寫測試類:


源碼 打印 ?
01. package  com; 
02.  
03. import  java.io.File; 
04. import  java.io.FileOutputStream; 
05. import  java.io.IOException; 
06. import  java.io.OutputStreamWriter; 
07. import  java.util.ArrayList; 
08. import  java.util.HashMap; 
09. import  java.util.List; 
10. import  java.util.Map; 
11.  
12. import  freemarker.template.Configuration; 
13. import  freemarker.template.Template; 
14. import  freemarker.template.TemplateException; 
15.  
16. public   class  Test { 
17.  
18.     /** 
19.      * @param args 
20.      */  
21.     public   static   void  main(String[] args) { 
22.         //System.out.println(System.getProperty("user.dir")+"============");  
23.         Configuration cfg = new  Configuration(); 
24.         try  { 
25.             cfg.setClassForTemplateLoading(Test.class ,  "/com" ); //指定模板所在的classpath目錄  
26.             cfg.setSharedVariable("upperFC" ,  new  UpperFirstCharacter()); //添加一個"宏"共享變量用來將屬性名首字母大寫  
27.             Template t = cfg.getTemplate("javabean.html" ); //指定模板  
28.             FileOutputStream fos = new  FileOutputStream( new  File( "d:/Student.java")); //java文件的生成目錄  
29.              
30.             //模擬數據源  
31.             Map data = new  HashMap(); 
32.             data.put("package" ,  "edu" ); //包名  
33.             data.put("className" ,  "Student" ); 
34.              
35.             List pros = new  ArrayList(); 
36.             Map pro_1 = new  HashMap(); 
37.             pro_1.put("proType" , String. class .getSimpleName()); 
38.             pro_1.put("proName" ,  "name" ); 
39.             pros.add(pro_1); 
40.              
41.             Map pro_2 = new  HashMap(); 
42.             pro_2.put("proType" , String. class .getSimpleName()); 
43.             pro_2.put("proName" ,  "sex" ); 
44.             pros.add(pro_2); 
45.              
46.             Map pro_3 = new  HashMap(); 
47.             pro_3.put("proType" , Integer. class .getSimpleName()); 
48.             pro_3.put("proName" ,  "age" ); 
49.             pros.add(pro_3); 
50.              
51.             data.put("properties" , pros); 
52.             t.process(data, new  OutputStreamWriter(fos, "utf-8" )); //  
53.             fos.flush(); 
54.             fos.close(); 
55.         } catch  (IOException e) { 
56.             e.printStackTrace(); 
57.         } catch  (TemplateException e) { 
58.             e.printStackTrace(); 
59.         } 
60.     } 
61.  
62. } 


[Java] view plaincopy

01. package com; 
02.  
03. import java.io.File; 
04. import java.io.FileOutputStream; 
05. import java.io.IOException; 
06. import java.io.OutputStreamWriter; 
07. import java.util.ArrayList; 
08. import java.util.HashMap; 
09. import java.util.List; 
10. import java.util.Map; 
11.  
12. import freemarker.template.Configuration; 
13. import freemarker.template.Template; 
14. import freemarker.template.TemplateException; 
15.  
16. public class Test { 
17.  
18.     /**
19.      * @param args
20.      */ 
21.     public static void main(String[] args) { 
22.         //System.out.println(System.getProperty("user.dir")+"============"); 
23.         Configuration cfg = new Configuration(); 
24.         try { 
25.             cfg.setClassForTemplateLoading(Test.class, "/com");//指定模板所在的classpath目錄 
26.             cfg.setSharedVariable("upperFC", new UpperFirstCharacter());//添加一個"宏"共享變量用來將屬性名首字母大寫 
27.             Template t = cfg.getTemplate("javabean.html");//指定模板 
28.             FileOutputStream fos = new FileOutputStream(new File("d:/Student.java"));//java文件的生成目錄 
29.              
30.             //模擬數據源 
31.             Map data = new HashMap(); 
32.             data.put("package", "edu");//包名 
33.             data.put("className", "Student"); 
34.              
35.             List pros = new ArrayList(); 
36.             Map pro_1 = new HashMap(); 
37.             pro_1.put("proType", String.class.getSimpleName()); 
38.             pro_1.put("proName", "name"); 
39.             pros.add(pro_1); 
40.              
41.             Map pro_2 = new HashMap(); 
42.             pro_2.put("proType", String.class.getSimpleName()); 
43.             pro_2.put("proName", "sex"); 
44.             pros.add(pro_2); 
45.              
46.             Map pro_3 = new HashMap(); 
47.             pro_3.put("proType", Integer.class.getSimpleName()); 
48.             pro_3.put("proName", "age"); 
49.             pros.add(pro_3); 
50.              
51.             data.put("properties", pros); 
52.             t.process(data, new OutputStreamWriter(fos,"utf-8"));// 
53.             fos.flush(); 
54.             fos.close(); 
55.         } catch (IOException e) { 
56.             e.printStackTrace(); 
57.         } catch (TemplateException e) { 
58.             e.printStackTrace(); 
59.         } 
60.     } 
61.  
62. } 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章