关于java代码生成器

    技术2022-05-20  57

    讲代码生成器之前先要说说模板,什么叫模板呢,举个例子吧,汇款单都见过吧,你不填写的那些内容都属于模板范畴

    说到这应该明白了吧,模板就是把共性提取出来反复使用,节约时间、工作量。。。。。

    那跟代码生成器有什么关系呢,思考一下在编程语言中所有的语言是不是都用共性或者说规范,这些都是固定不变的,在具体点,软件行业也是分主营业务 的,比如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中不支持将首字母大写(属性名中用到),那么自己先写一个自定义宏如下:

    源码 打印 ? package  com;      import  java.io.IOException;   import  java.io.Writer;   import  java.util.Map;      import  freemarker.core.Environment;   import  freemarker.template.TemplateDirectiveBody;   import  freemarker.template.TemplateDirectiveModel;   import  freemarker.template.TemplateException;   import  freemarker.template.TemplateModel;   import  freemarker.template.TemplateModelException;      public   class  UpperFirstCharacter  implements  TemplateDirectiveModel {          public   void  execute(Environment env,               Map params, TemplateModel[] loopVars,               TemplateDirectiveBody body)               throws  TemplateException, IOException {           // Check if no parameters were given:            if  (!params.isEmpty()) {               throw   new  TemplateModelException(                       "This directive doesn't allow parameters." );           }           if  (loopVars.length !=  0 ) {                   throw   new  TemplateModelException(                       "This directive doesn't allow loop variables." );           }                      // If there is non-empty nested content:            if  (body !=  null ) {               // Executes the nested body. Same as <#nested> in FTL, except                // that we use our own writer instead of the current output writer.                body.render(new  UpperCaseFilterWriter(env.getOut()));           } else  {               throw   new  RuntimeException( "missing body" );           }       }              /**        * A {@link Writer} that transforms the character stream to upper case        * and forwards it to another {@link Writer}.        */         private   static   class  UpperCaseFilterWriter  extends  Writer {                     private   final  Writer out;                         UpperCaseFilterWriter (Writer out) {               this .out = out;           }              public   void  write( char [] cbuf,  int  off,  int  len)                   throws  IOException {   //            char[] transformedCbuf = new char[len];    //            for (int i = 0; i < len; i++) {    //                transformedCbuf[i] = Character.toUpperCase(cbuf[i + off]);    //            }    //            out.write(transformedCbuf);                cbuf[0 ] = Character.toUpperCase(cbuf[ 0 ]);               out.write(String.valueOf(cbuf).trim());///把右边空格去掉            }              public   void  flush()  throws  IOException {               out.flush();           }              public   void  close()  throws  IOException {               out.close();           }       }      }   package com; import java.io.IOException; import java.io.Writer; import java.util.Map; import freemarker.core.Environment; import freemarker.template.TemplateDirectiveBody; import freemarker.template.TemplateDirectiveModel; import freemarker.template.TemplateException; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; public class UpperFirstCharacter implements TemplateDirectiveModel { public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException { // Check if no parameters were given: if (!params.isEmpty()) { throw new TemplateModelException( "This directive doesn't allow parameters."); } if (loopVars.length != 0) { throw new TemplateModelException( "This directive doesn't allow loop variables."); } // If there is non-empty nested content: if (body != null) { // Executes the nested body. Same as <#nested> in FTL, except // that we use our own writer instead of the current output writer. body.render(new UpperCaseFilterWriter(env.getOut())); } else { throw new RuntimeException("missing body"); } } /** * A {@link Writer} that transforms the character stream to upper case * and forwards it to another {@link Writer}. */ private static class UpperCaseFilterWriter extends Writer { private final Writer out; UpperCaseFilterWriter (Writer out) { this.out = out; } public void write(char[] cbuf, int off, int len) throws IOException { // char[] transformedCbuf = new char[len]; // for (int i = 0; i < len; i++) { // transformedCbuf[i] = Character.toUpperCase(cbuf[i + off]); // } // out.write(transformedCbuf); cbuf[0] = Character.toUpperCase(cbuf[0]); out.write(String.valueOf(cbuf).trim());///把右边空格去掉 } public void flush() throws IOException { out.flush(); } public void close() throws IOException { out.close(); } } }

     

    下面呢就可以编写模板了,代码如下:

    源码 打印 ? package  ${ package };      //这个地方可以事先定义好需要的类    import  java.util.Date;      import  java.io.Serializable;      public   class  ${className}  implements  Serializable{   <#list properties as pro>       private  ${pro.proType} ${pro.proName};   </#list>          <#list properties as pro>       public   void  set< @upperFC >${pro.proName}</ @upperFC >(${pro.proType} ${pro.proName}){           this .${pro.proName}=${pro.proName};       }              public  ${pro.proType} get< @upperFC >${pro.proName}</ @upperFC >(){           return   this .${pro.proName};       }          </#list>   }   package ${package}; //这个地方可以事先定义好需要的类 import java.util.Date; import java.io.Serializable; public class ${className} implements Serializable{ <#list properties as pro> private ${pro.proType} ${pro.proName}; </#list> <#list properties as pro> public void set<@upperFC>${pro.proName}</@upperFC>(${pro.proType} ${pro.proName}){ this.${pro.proName}=${pro.proName}; } public ${pro.proType} get<@upperFC>${pro.proName}</@upperFC>(){ return this.${pro.proName}; } </#list> }

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

    下面编写测试类:

    源码 打印 ? package  com;      import  java.io.File;   import  java.io.FileOutputStream;   import  java.io.IOException;   import  java.io.OutputStreamWriter;   import  java.util.ArrayList;   import  java.util.HashMap;   import  java.util.List;   import  java.util.Map;      import  freemarker.template.Configuration;   import  freemarker.template.Template;   import  freemarker.template.TemplateException;      public   class  Test {          /**        * @param args        */        public   static   void  main(String[] args) {           //System.out.println(System.getProperty("user.dir")+"============");            Configuration cfg = new  Configuration();           try  {               cfg.setClassForTemplateLoading(Test.class"/com" ); //指定模板所在的classpath目录                cfg.setSharedVariable("upperFC"new  UpperFirstCharacter()); //添加一个"宏"共享变量用来将属性名首字母大写                Template t = cfg.getTemplate("javabean.html" ); //指定模板                FileOutputStream fos = new  FileOutputStream( new  File( "d:/Student.java" )); //java文件的生成目录                               //模拟数据源                Map data = new  HashMap();               data.put("package""edu" ); //包名                data.put("className""Student" );                              List pros = new  ArrayList();               Map pro_1 = new  HashMap();               pro_1.put("proType" , String. class .getSimpleName());               pro_1.put("proName""name" );               pros.add(pro_1);                              Map pro_2 = new  HashMap();               pro_2.put("proType" , String. class .getSimpleName());               pro_2.put("proName""sex" );               pros.add(pro_2);                              Map pro_3 = new  HashMap();               pro_3.put("proType" , Integer. class .getSimpleName());               pro_3.put("proName""age" );               pros.add(pro_3);                              data.put("properties" , pros);               t.process(data, new  OutputStreamWriter(fos, "utf-8" )); //                fos.flush();               fos.close();           } catch  (IOException e) {               e.printStackTrace();           } catch  (TemplateException e) {               e.printStackTrace();           }       }      }   package com; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; public class Test { /** * @param args */ public static void main(String[] args) { //System.out.println(System.getProperty("user.dir")+"============"); Configuration cfg = new Configuration(); try { cfg.setClassForTemplateLoading(Test.class, "/com");//指定模板所在的classpath目录 cfg.setSharedVariable("upperFC", new UpperFirstCharacter());//添加一个"宏"共享变量用来将属性名首字母大写 Template t = cfg.getTemplate("javabean.html");//指定模板 FileOutputStream fos = new FileOutputStream(new File("d:/Student.java"));//java文件的生成目录 //模拟数据源 Map data = new HashMap(); data.put("package", "edu");//包名 data.put("className", "Student"); List pros = new ArrayList(); Map pro_1 = new HashMap(); pro_1.put("proType", String.class.getSimpleName()); pro_1.put("proName", "name"); pros.add(pro_1); Map pro_2 = new HashMap(); pro_2.put("proType", String.class.getSimpleName()); pro_2.put("proName", "sex"); pros.add(pro_2); Map pro_3 = new HashMap(); pro_3.put("proType", Integer.class.getSimpleName()); pro_3.put("proName", "age"); pros.add(pro_3); data.put("properties", pros); t.process(data, new OutputStreamWriter(fos,"utf-8"));// fos.flush(); fos.close(); } catch (IOException e) { e.printStackTrace(); } catch (TemplateException e) { e.printStackTrace(); } } }

     

    运行一下测试类,在D盘可以找到一个Student.java的文件,打开看看对不对


    最新回复(0)