在实际的项目开发中,有很大一部分的时间都在做一些重复的工作,比如与数据库表对应的实体类的编写,普遍使用的dao、service的基本增删改查操作等等,因此,编写一个代码自动生成工具可以大大的提高工作效率,虽然一些框架和开发工具都附带有代码生成的功能,但是比较单一,一般只能生成表对应的实体类,网上下载的又很难通用,因为每个项目的架构都不太一样,无法满足我们的需求。
本文介绍的是在实际项目的开发过程中衍生出来的,并且在使用中的一款代码生成工具,旨在抛砖引玉,使之稍作修改或借鉴里面的一些设计就能写出完全符合自己需求的代码生成软件。
说到代码生成,对新手来说可能觉得很深奥,其实它的原理十分简单,无非就是字符串的替换以及文件的创建。为了操作方便,本文使用velocity这个强大的模板引擎,不知道velocity的,请点这里Velocity用户指南中文版。
说说我们的代码生成工具要实现的一些基本功能:
- 基于配置文件,所有的信息都在这里指定,包括数据库链接,自定义转换等。这里采用xml配置文件的方式。
- 可以定义常量,比如定义生成的目录,代码的作者名字等供后面使用,好处是修改配置时只需要修改这个常量即可。
- 支持配置自定义的转换,比如生成实体类时将数据库的clob映射为byte[],timestamp、datetime等统一映射为Date。
- 配置文件可以嵌套,类似一些框架的include标签。
- 生成任务自由定义,例如model、dao、service,可以指定生成文件的前缀后缀包名等(xxxDao,xxxService的格式)。
- 根据表生成时,可以指定任务具体生成哪些文件,方便不需要生成一些文件时可以不用删除配置好的任务信息。
- 支持数据库的扩展,更换数据库只需简单实现特有的信息查询就可进行生成。目前有mysql、oracle的实现。
- 可以自由生成model、mapper、dao、service、action、controller、jsp等各类文件,理论上只要配置好代码模板都可以生成。
- 支持实现插件扩展。(该功能开发完成之后发现比较鸡肋,因为velocity的强大操作都可以在模板中完成,实现自定义的生成类和实现插件也差不多,但是不影响设计的思想)。
- 支持实现自定义的生成类,进行一些特殊的生成。
简单介绍完了,下面来看一下配置文件的定义,所有的生成信息都是从配置文件中获取的,一切也就从配置文件开始:
<?xml version="1.0" encoding="UTF-8"?> <config> <!--<jdbc name="dialect" value="oracle"/>--> <!--<jdbc name="driverClassName" value="oracle.jdbc.OracleDriver"/>--> <!--<jdbc name="url" value="jdbc:oracle:thin:@localhost:1522/test"/>--> <!--<jdbc name="username" value="test"/>--> <!--<jdbc name="password" value="test"/>--> <jdbc name="dialect" value="mysql"/> <jdbc name="driverClassName" value="com.mysql.jdbc.Driver"/> <jdbc name="url" value="jdbc:mysql://localhost:3306/youke?useUnicode=true&characterEncoding=utf-8"/> <jdbc name="username" value="root"/> <jdbc name="password" value=""/> <constant name="encoding" value="UTF-8"/> <constant name="templateDir" value="template"/> <constant name="targetDir" value="D:/mryk/mincoder"/> <constant name="creator" value="liyd"/> <convert dbType="number" jdbcType="BIGINT" javaType="java.lang.Long"/> <convert dbType="VARCHAR2" jdbcType="VARCHAR" javaType="java.lang.String"/> <convert dbType="SYS.XMLTYPE" jdbcType="LONGVARCHAR" javaType="java.lang.String"/> <convert dbType="timestamp" jdbcType="TIMESTAMP" javaType="java.util.Date"/> <convert dbType="datetime" jdbcType="TIMESTAMP" javaType="java.util.Date"/> <convert dbType="BLOB" jdbcType="BLOB" javaType="java.lang.Byte[]"/> <include file="tableConfig.xml"/> </config>
以上是一个总的配置文件信息,一些常规的不会经常被改动的信息被定义在这里,各标签的作用相信一看就能明白:
jdbc标签,指定了数据库的jdbc连接信息。
constant标签,定义了一些常量。
convert标签,自定义的一些转换,将指定的数据库类型转换为指定的Java类型。
include 标签,嵌套插入了一个表的配置文件,具体表的生成信息定义在这里面。
以下是tableConfig.xml文件的配置信息:
<?xml version="1.0" encoding="UTF-8"?> <config> <constant name="modelDir" value="mryk-core-model"/> <constant name="daoDir" value="mryk-core-dao"/> <constant name="serviceDir" value="youke-service"/> <constant name="mapperDir" value="mryk-core-mapper"/> <constant name="managerDir" value="mryk-core-manager"/> <constant name="basePackage" value="com.meiriyouke.core"/> <table name="USER" desc="用户"> <tasks> <task name="model"/> <task name="modelVo"/> <task name="dao"/> <task name="daoImpl"/> <task name="service"/> <task name="serviceImpl"/> </tasks> </table> <tasks> <task name="model" class="com.meiriyouke.easycode.generator.DefaultCodeGenerator"> <property name="template" value="template/model.vm"/> <property name="beginFix" value=""/> <property name="endFix" value=""/> <property name="suffix" value=".java"/> <property name="moduledir" value="${modelDir}"/> <property name="srcdir" value="src/main/java"/> <property name="package" value="${basePackage}.base.model"/> </task> <task name="modelVo" class="com.meiriyouke.easycode.generator.DefaultCodeGenerator"> <property name="template" value="template/modelVo.vm"/> <property name="beginFix" value=""/> <property name="endFix" value="Vo"/> <property name="suffix" value=".java"/> <property name="moduledir" value="${modelDir}"/> <property name="srcdir" value="src/main/java"/> <property name="package" value="${basePackage}.base.vo"/> </task> ...... </tasks> </config>
constant标签,同样是常量定义,这里定义了几个模块的路径,因为我的项目是maven的多模块结构,如下图:
table标签,指定对哪张表进行代码生成,tasks子标签指定了具体要进行代码生成的任务。
task标签,定义了各生成任务的配置信息。其中:
- name属性指明任务的名称,后面获取任务的生成类文件需要依赖此名称。
- class属性指明使用哪个类进生代码的生成。
- template指定使用的模板。
- beginFix指定生成的文件统一以什么开头。
- endFix指定生成的文件统一以什么结尾。
- suffix生成文件的后缀。
- moduledir模块路径。
- srcdir源码文件夹。
- package包路径。
好了,到这里我们的配置文件已经定义完成了。因为只作代码生成用,所以就没有编写xsd的校验文件,接下来就是解析了。