且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

写一个通用的代码生成器

更新时间:2022-06-03 08:19:19

       代码生成器对于JAVA码农来说并不陌生。在一些业务性比较强,但编码比较规范的项目中,往往会有大量的重复或者类似的代码要写。比如对表的增删改查,比如生成用于远程调用的客户端方法存根等等。面对这种情况,程序员通常的做法就是拿一个现成模块的代码copy过来再改改。于是,为了避免这种低效而容易出错的编码方式,诞生了各种各样的能跟据当前项目特证自动生成代码的代码生成器程序。这种程序的本质上就是将大量重复的复制修改工作用程序自动来做,以便自动产生适合自己项目的代码。

       然而,这种代码生成器往往都是针对某个单一的项目量身定做的,通用性并不强。而且生成器程序本身所用到的技术框架也各不相同。本文,将介绍本人的一个通用生成器框架,同时展示本人在这个框架上的一个基于Eclipse插件的实现。这个框架是将自动生成代码的逻辑进行一次抽象的设计,封装了自动生成代码底层的技术逻辑。使用这个框架,开发人员只需要跟据自己项目的业务特性,进行一些简单的配置,就可以达到自己生成代码的目地。

传统的代码生成器原理:

       在讲通用生成器之前,简单说说传统代码生成器的原理,大致上就是使用一些比如velocityfreemark之类的模板技术,写一些需要生成代码的文件模板,模板大部分的内容是代码文件可复用的那部分代码,而其中可能会有变会化的代码用比如“${}”之类的符号作为占位符。然后通过velocityfreemarkapi传递一些参数进去,让velocityfreemark帮我们跟据传入的参数自动替换掉模板中的占位符,这样就生成了我们想要的代码。

通用代码生成器原理:

       在传统的代码生成器的基础上,我抽像出三个概念:参数、模板、规则。这三个概念就是本框架的核心逻辑。以下分别介绍:

参数:

       在用模板生成代码之前,程序必须收集到足够的信息,作为填充模板文件中参数占位符的依据。比如在自动生成增删改查的代码生成器中,必须告诉生成器,生成的实体类将有哪些属性、每个属性的类型是什么等等。在用velocityfreemark的技术中,传入的参数是可以是任意的普通变量、集合对像、自定义对像等等。为了规范起见,本框架决定统一使用一个Map结构的对象作为参数。之所以选择Map这种数据结构,是为了更好的抽象出这些参数,做到写生成器程序的开发人员只需要通过简单的配置就可以定义出这些参数,而不需要跟据生成器具体的功能,去写一些业务相关的类。而且Map是可以多级嵌套的,也就是说一个Map中的Value值可以是另一个Map,这样做,可使得参数的层次感强,容易维护。

模板:

       通用生成器本质上还是基于velocityfreemark等某种模板技术,开发人员不可避免的要写一些模板程序文件。只不过,本框架封装了通过模板生成代码的具体的逻辑,用户只需要指定模板和参数并指定一些规则,程序将自动按照规则生成代码。下面介绍规则的概念:

规则:

       规则就是规定生成器按怎样的过程来生成想要的代码。比如,在一个自动生成增删改查的代码中,一般过程是先生成java实体类,再生成业务层的Service类、数据访问层Dao类,然后生成界面Jsp文件。这个过程,在传统的生成器中需要自己写代码来做这些事。我把它抽象成“规则”这个概念,就是想实现让程序员可以通过配置来自己制定这些规则,最后让程序自动去完成这些过程。

       总体上,通过个这个框架定制代码生成器的过程序分三步:参数定义、模板制做、规则制定。而通过这种方式生成具体代码的过程分两步:参数收集、将参数传入模板按照规则生成代码。我们可以写一个web界面或者eclipse插件来实现这些过程。

       CURD为例,下面展示本人用eclipse插件写的一个自动生成增删改查的生成器:

CURD生成器参数定义界面:

写一个通用的代码生成器

图:CURD生成器参数定义

       上图是CURD生成器的参数定义,从上图中,可以看到,CURD生成器的参数主要有“实体名称”、“对应表名”、“属性定义”等等。而且从上图的左则可以看到,这些参数是分级的树状结构。这样做,在本生成器生成代码的“参数收集”的过程中,会把参数按照这个树状结构,收集到一个多级嵌套的Map对象中,作为模板的传入参数。

       上图中间,是对每个参数的具体属性定义,比如参数代码、数据类型、默认值等等。其中最重要的是参数代码,在同一级所有参数中,参数代码不能重复,在生成代码的参数收集过种中,它被处理成参数Map中的key(因为参数分级,可按照层级关系生成含点号“.”的Key)。比如上图中“实体名称(entityName)”这个参数,它是“实体基本信息(entityWizardPage)”这个参数的下级参数,那么它在Map对像中的key就是“entityWizardPage.entityName”。这样做,是方便传入velocity模板中(本插件用的是velocity模板技术)。

       上图的右则,是维护这些参数定义的一些操作按钮,可以增加参数、修改参数等等(程序员全完不需要懂得Eclipse插件,只要使用这个插件就可以定义出这些参数)。

CURD生成器规则定义界面:

写一个通用的代码生成器

图:CURD生成器规则定义


       上图是CURD生成器的参数定义,从上图右则可以看到,此生成器定义了如下规则:生成实体类、生成Action类、生成Service类、生成Dao类、生成Jsp文件。在用这个生成器生成增删改查的代码时,程序将自动按照这个流程生成实体类、Action类和Service类等等。上图中间是对每个规则的具体定义,比如生成实体类的模板在哪里,生成的实体类最终在哪个输出目录里,这个规则是否被禁用,触发条件是什么等等。上图右则的按钮就是制定规则的一些操作,比如增加一个规则、修改一个现有的规则等等。

CURD生成器模板制作:

       在定义CURD生成器的参数和规则的生同时,可以制定生成相关代码的模板。本人通过Eclipse插件实现了一个VM模板文档编辑器,如下图所示:

写一个通用的代码生成器

图:CURD生成器模板


       上图就是CURD模板文件编写界面,本框架所有生成器的模板文件都是vm格式,Eclispe插件会自动使用本插件定制的一个编辑器打开。界面如上图所示,图中中间就是模板文件内容的编辑界面,图中用蓝色标出的高亮的代码部分就是用“${}”符号括起来的参数占位符,而且占位符内容就是前文“参数定义”一节的树状参数定义,这里按照层级关系用点号表达出来,这种表达方式也正是典型的velocity语法,能被velocity模板引擎直接识别。为了方便书写,我写了一个Eclipse自定义视图,列出当前生成器定义的所有参数,如上图右则所示。

CURD生成器参数收集:

       在用这个生成器生成CURD界面时,需要开发人员录入事先定义的参数信息,CURD参数收集界面的属性定义界面如下:

写一个通用的代码生成器

:CURD生成器“实体属性”参数收集


       上图就是CURD生成器生成实体时的实体类属性定义界面,通过右边的“添加”、“编辑”等按钮可以添加或修改实体类中的属性。值得一提的是,上图这个界面并不是一成不变的,而是开发人员通过前文的“参数定义”一节自己配置出来的,开发人员就算不懂Eclipse插件开发,也可以跟据自己的需要,配置一些这类似的界面。

       以上就是本人按照本文介绍的代码生成器框架的原理写的一个自动生成代码的插件,并展示了一个生成CURD代码的配置过程。大家如果使用这个插件,也可以自己配置一些适合自己项目的生成器。而无需了解velocity模板引擎,更无需了解Eclipse插件开发,只要跟据自己项目的业务需求,定义参数、编写模板、制定规则后,就可以定制出适合自己eclipse插件形式的代码生成器了。

       目前这个插件,还在不断的测试和完善之中,等做好后发布出来给大家用用。如果想关注更多信息,了解最新动态,可以扫码关注我的个人公众号:

写一个通用的代码生成器