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. } 


一. 生成器模板路径可以引用相关变量 如 ${basepackage}/${className}.java,根据该变量生成输出文件 二. 自动搜索某个目录所有模板文件,无需配置 三.代码生成器模板可以引用的相关变量 1. g.generateByTable("table_name") 方法可以引用的变量 table : cn.org.rapid_framework.generator.provider.db.table.model.Table 2. g.generateByClass(UserInfo.class) 方法可以引用的变量 clazz : cn.org.rapid_framework.generator.provider.java.model.JavaClass 3. g.generateBySql("select * from user_info where pwd=:pwd") 方法可以引用的变量 sql : cn.org.rapid_framework.generator.provider.db.sql.model.Sql 4.公共变量 env : 系统环境变量 System.getProperties() : 直接引用,没有前缀 generator.properties 文件中的所有属性,直接引用,没有前缀 gg : 模板控制变量, cn.org.rapid_framework.generator.GeneratorControl 四.每个模板有gg变量可以控制自身的自定义配置 (每一个模板都会创建新的gg实例) 如是否生成,是否覆盖目标文件,甚至是生成其它文件 ${gg.setIgnoreOutput(true)}: 如果为true则不生成输出文件 ${gg.generateFile(outputFile,content)} 在模板中生成其它文件 ${gg.getProperty(key,defaultValue)}: 得到proproty,如果没有找到,则返回默认值 ${gg.getInputProperty(key)}: 会弹出一个输入框,提示用户输入值 具体参考: http://code.google.com/p/rapid-framework/wiki/rapid_generator_gg 五.支持生成(gen)及删除操作(del),即生成的代码也可以很方便的删除 六. 自动删除模板扩展名: .ftl,.vm 举例: 如你有一个模板 SqlMap.xml.ftl 将变为 SqlMap.xml 所以你要生成ftl扩展名的文件,应该将文件名从 list.ftl => list.ftl.ftl 七. 模板自动include所有父目录的:macro.include文件,可以存放公共的macro 示例: 如你的模板为 com/project/UserDao.java, 将自动include: com/project/macro.include, com/macro.include, macro.include 八. generator.xml (或者generator.properties)配置文件 1.类似ant可以变量引用,引用环境变量使用${env.JAVA_HOME}, 引用System.getProperties()直接引用 2.自动替换generator.properties中的句号(.)为反斜杠,设置key为key+"_dir"后缀 示例: pkg=com.company => pkg_dir=com/company 九.自动拷贝二进制文件至输出目录 如模板目录下的 zip,rar,doc文件将会自动拷贝至输出目录,不会破坏文件格式 (通过扩展名自动识别) 十. 数据库表配置,用于自定义生成器模板引用的table变量,配置文件必须存放在classpath: generator_config/table/table_name.xml (该文件生成器可以生成,自己再自定义修改) <!-- <数据库列名 columnAlias="列的别名" javaType="自定义javaType" unique="是否唯一性约束" nullable="是否可以为空" pk="是否主键,在表没有主键的情况下,可以指定一个代理主键" updatable="是否可以更新" insertab
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值