Java代码生成利器之rapid-generate应用五

本文我们将分析一下rapid-generate源码,看看其设计思路以及运行原理究竟是怎样的。

我们从Test类的main函数入口说起

public static void main(String[]args)throws Exception{
            GeneratorFacade g = new GeneratorFacade();
             //删除生成器的输出目录//
            g.deleteOutRootDir();

            //自动搜索数据库中的所有表并生成文件,template为模板的根目录
            g.generateByAllTable("template");

        }

GeneratorFacade 类从命名上就能看出,运用了门面设计模式,该类作为生成器功能的入口,统一组织管理各个模块以及功能。

g.generateByAllTable(“template”);这一句实际上是调用GeneratorFacade 内部类ProcessUtils的processByAllTable方法。

public void generateByAllTable(String templateRootDir) throws Exception {
            new ProcessUtils().processByAllTable(templateRootDir,false);
        }

进一步分析processByAllTable()方法

public void processByAllTable(String templateRootDir,boolean isDelete) throws Exception {
    //该方法通过读取数据库的metaData,获所有数据库表信息,并在内存中生成对应的Table对象。主要应用底层接口java.sql.DatabaseMetaData
                List<Table> tables = TableFactory.getInstance().getAllTables();
                List exceptions = new ArrayList();
                for(int i = 0; i < tables.size(); i++ ) {
                    try {
                        processByTable(getGenerator(templateRootDir),tables.get(i),isDelete);
                    }catch(GeneratorException ge) {
                        exceptions.addAll(ge.getExceptions());
                    }
                }
                PrintUtils.printExceptionsSumary("",getGenerator(templateRootDir).getOutRootDir(),exceptions);
            }

得到list之后,接下来遍历该集合,调用processByTable()方法

public void processByTable(Generator g, Table table,boolean isDelete) throws Exception {
    //生成GeneratorModel 对象,包含filePathModel和templateModel的两个Map集合,为下一步开始生成文件做准备
                GeneratorModel m = GeneratorModelUtils.newFromTable(table);
                PrintUtils.printBeginProcess(table.getSqlName()+" => "+table.getClassName(),isDelete);
                if(isDelete)
                    g.deleteBy(m.templateModel,m.filePathModel);
                else 
                    g.generateBy(m.templateModel,m.filePathModel);
            }     

读取templateModel和filePathModel两个Map集合作为generateBy函数的参数

/**
         * 生成文件
         * @param templateModel 生成器模板可以引用的变量
         * @param filePathModel 文件路径可以引用的变量
         * @throws Exception
         */
        public Generator generateBy(Map templateModel,Map filePathModel) throws Exception {
            processTemplateRootDirs(templateModel, filePathModel,false);
            return this;
        }

templateRootDirs是List集合,其中只有一个元素,[F:\2013-2014\Eclipse-J2EE\workspace\Rapid-Generator-Pro\template],该路径正是java项目中template目录所在路径

这里写图片描述

接着分析processTemplateRootDirs函数,由于list集合size位1,此处之循环1次,重点在scanTemplatesAndProcess函数。

private void processTemplateRootDirs(Map templateModel,Map filePathModel,boolean isDelete) throws Exception {
            if(StringHelper.isBlank(getOutRootDir())) throw new IllegalStateException("'outRootDir' property must be not null.");
            if(templateRootDirs.size() == 0) throw new IllegalStateException("'templateRootDirs' cannot empty");
            GeneratorException ge = new GeneratorException("generator occer error, Generator BeanInfo:"+BeanHelper.describe(this));
            for(int i = 0; i < this.templateRootDirs.size(); i++) {
                File templateRootDir = (File)templateRootDirs.get(i);
                List<Exception> exceptions = scanTemplatesAndProcess(templateRootDir,templateModel,filePathModel,isDelete);
                ge.addAll(exceptions); 
            }
            if(!ge.exceptions.isEmpty()) throw ge;
        }

scanTemplatesAndProcess函数接收template所在目录的路径以及templateModel和filePathModel两个Map参数

        private List<Exception> scanTemplatesAndProcess(File templateRootDir, Map templateModel,Map filePathModel,boolean isDelete) throws Exception {
            if(templateRootDir == null) throw new IllegalStateException("'templateRootDir' must be not null");
            GLogger.println("-------------------load template from templateRootDir = '"+templateRootDir.getAbsolutePath()+"' outRootDir:"+new File(outRootDir).getAbsolutePath());
            //获取模板根目录下所有要生成的文件模板路径
             List srcFiles = FileHelper.searchAllNotIgnoreFile(templateRootDir);

            List<Exception> exceptions = new ArrayList();
            for(int i = 0; i < srcFiles.size(); i++) {
                File srcFile = (File)srcFiles.get(i);
                try {
                    if(isDelete){
                        new TemplateProcessor().executeDelete(templateRootDir, templateModel,filePathModel, srcFile);
                    }else {
                        new TemplateProcessor().executeGenerate(templateRootDir, templateModel,filePathModel, srcFile);
                    }
                }catch(Exception e) {
                    if (ignoreTemplateGenerateException) {
                        GLogger.warn("iggnore generate error,template is:" + srcFile+" cause:"+e);
                        exceptions.add(e);
                    } else {
                        throw e;
                    }
                }
            }
            return exceptions;
        }

分析最终生成的核心代码,调用底层的freemarker,将模板转换为对应源码文件输出到指定目录下面。

    private void executeGenerate(File templateRootDir,Map templateModel, Map filePathModel ,File srcFile) throws SQLException, IOException,TemplateException {
                String templateFile = FileHelper.getRelativePath(templateRootDir, srcFile);
            //忽略目录,以及非模板的文件 if(GeneratorHelper.isIgnoreTemplateProcess(srcFile, templateFile,includes,excludes)) {
                    return;
                }

                if(isCopyBinaryFile && FileHelper.isBinaryFile(srcFile)) {
                    String outputFilepath = proceeForOutputFilepath(filePathModel, templateFile);
                    GLogger.println("[copy binary file by extention] from:"+srcFile+" => "+new File(getOutRootDir(),outputFilepath));
                    IOHelper.copyAndClose(new FileInputStream(srcFile), new FileOutputStream(new File(getOutRootDir(),outputFilepath)));
                    return;
                }

                String outputFilepath = null;
                try {
                    outputFilepath = proceeForOutputFilepath(filePathModel,templateFile);

                    initGeneratorControlProperties(srcFile);
                    processTemplateForGeneratorControl(templateModel, templateFile);

                    if(gg.isIgnoreOutput()) {
                        GLogger.println("[not generate] by gg.isIgnoreOutput()=true on template:"+templateFile);
                        return;
                    }

                    if(outputFilepath != null ) {
                        generateNewFileOrInsertIntoFile(templateFile,outputFilepath, templateModel);
                    }
                }catch(Exception e) {
                    throw new RuntimeException("generate oucur error,templateFile is:" + templateFile+" => "+ outputFilepath+" cause:"+e, e);
                }
            }

最后附上在分析时所打的断点

这里写图片描述

总结,原理其实很简单,就是用freemarker语法编写template模板文件,生成时读取数据库信息,动态的将freemarker语法标记替换掉,最终就得到了源码文件。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值