赞
踩
最近做项目写了一个代码生成器,现在就分享出来给大家,顺便说一下代码生成器是什么东西!
代码生成器顾名思义就是一个生成代码的软件。为了节省成本,在日常的企业开发中,代码生成器使用比较普遍。
代码生成器的原理就是: 根据模板+ 数据生成不同文件 。比如以下的两段代码。
1.ItripHotelOrderMapper 文件
2.ItripHotelOrderMapper 文件
在上述 ItripHotelOrderMapper 和 ItripHotelOrderMapper 文件中,我们注意到,两个文件的代码很相似。除了高亮部分不一致以外,其它的代码均一致。因此,我们可以设想,我们能不能编写模板生成这样的 Mapper 类。高亮部分使用占位符来进行代替,具体内容根据具体数据进行置换
了解了代码生成器的概念和原理,接下来我开始着手编写属于自己的代码生成器。我将代码生成器的分为三部分:
➢ 模板:生成文件的模板文件。
➢ 数据:生成文件所需要的关键数据。
➢ 合成机制:使用数据置换模板中的占位符,生成新的文件的机制。
表的vo类:
- /**
- * 表Vo
- */
- public class TableVo {
- private String className;//帕斯卡风格的类名
- private String camelName;//骆驼风格的类名
- private String tableName;//下划线风格的表名
- private List<ColumnVo> columns = new ArrayList<ColumnVo>();//列集合
- }
列的vo类:
- /**
- * 列Vo类
- */
- public class ColumnVo {
- private String dbName;//数据库列名
- private String javaName;//java属性名
-
- private String dbType;//数据库列类型
- private String javaType;//java属性类型
-
- private String comm;//注释
- private String upperCaseColumnName;//转成帕斯卡之后的名称
- }
转换Java格式名称的工具类:
- /**
- * 转换java格式名称的工具类
- */
- public class JavaNameUtil {
- /**
- * 下划线风格的命名转换为java骆驼命名法或帕斯卡命名法的名称
- * @param underscoreName
- * @param isPascal true:帕斯卡,false:骆驼
- * @return
- */
- public static String translate(String underscoreName, boolean isPascal) {
- StringBuilder result = new StringBuilder();
- if(underscoreName != null && underscoreName.length() > 0) {
- boolean flag = false;
- //首字母特殊处理,转换成帕斯卡命名法或骆驼命名法的名称
- char firstChar = underscoreName.charAt(0);
- if(isPascal) {
- result.append(Character.toUpperCase(firstChar));
- } else {
- result.append(firstChar);
- }
- //第二个之后的所有字符
- for(int i = 1; i < underscoreName.length(); i++) {
- char ch = underscoreName.charAt(i);
- //如果这个字符为下划线,下个字符需要大写处理
- if('_' == ch) {
- flag = true;
- } else {
- if(flag) {
- result.append(Character.toUpperCase(ch));
- flag = false;
- } else {
- result.append(ch);
- }
- }
- }
- }
- return result.toString();
- }
-
- /**
- * 将下划线风格的命名直接转换为骆驼命名法的名称
- * @param str
- * @return
- */
- public static String toCamel(String str) {
- return translate(str, false);
- }
-
- /**
- * 将下划线风格的命名直接转换为帕斯卡命名法的名称
- * @param str
- * @return
- */
- public static String toPascal(String str) {
- return translate(str, true);
- }
-
- /**
- * 将数据库类型转换成java类型
- * @param dbType
- * @return
- */
- public static String dbTypeToJavaType(String dbType) {
- String javaType = null;
- switch (dbType) {
- case "VARCHAR": javaType = "String";break;
- case "BIGINT": javaType = "Long";break;
- case "INT": javaType = "Integer";break;
- case "DATETIME":javaType = "Date";break;
- default: javaType = "String";break;
- }
- return javaType;
- }

负责连接数据库、获取表、列的元信息:
- /**
- * 负责连接数据库、获取表、列的元信息
- */
- public class MetadataUtil {
- private static Connection conn;//连接
- private static DatabaseMetaData meta;//数据库员信息
- //静态代码加载数据库驱动
- static {
- try {
- Class.forName("com.mysql.jdbc.Driver");
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- System.out.println("数据库连接失败");
- }
- }
-
- //打开连接,获取数据库元信息
- public static void openConnection() {
- try {
- if(conn == null || conn.isClosed()) {
- conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/数据库名?useUnicode=true",
- "账号",
- "密码");
- meta = conn.getMetaData();//获取数据库的元数据对象
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- //关闭连接
- public static void closeConnection() {
- try {
- if(conn != null || !conn.isClosed()) {
- conn.isClosed();
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- //获取所有表名称
- public static String[] getTableNames() {
- openConnection();
- ResultSet rs = null;
- List<String> nameList = new ArrayList<String>();
-
- try {
- rs = meta.getTables(null, null, null, new String[] {"TABLE"});
- while (rs.next()) {
- String tName = rs.getString("TABLE_NAME");
- nameList.add(tName);
- }
- } catch (SQLException e) {
- e.printStackTrace();
- } finally {
- closeConnection();
- }
-
- return (String [])nameList.toArray(new String [] {});
- }
-
- //获取某个表的列信息
- public static List<String []> getTableColumnsInfo(String tableName) throws SQLException {
- openConnection();
-
- ResultSet rs = meta.getColumns(null, "%", tableName, "%");
- List<String[]> columnInfoList = new ArrayList<String[]>();
- while (rs.next()) {
- String[] colInfo = new String[3];
- colInfo[0] = rs.getString("COLUMN_NAME");
- colInfo[1] = rs.getString("REMARKS");
- colInfo[2] = rs.getString("TYPE_NAME");
- columnInfoList.add(colInfo);
- }
-
- closeConnection();
-
- return columnInfoList;
- }

代码生成器类:
- **
- * 代码生成器
- */
- public class CodeGenerator {
- protected Configuration cfg;//Freemarker配置对象
- protected Map valueMap;//要填充到模板的数据
- protected Template template;//ftl模板对象
- protected String savePath;//保存代码的路径
- protected List<TableVo> tableList;//表信息对象集合
- protected String fileNameSuffix;//生成的文件名后缀
-
- public CodeGenerator(String ftl) throws Exception {
- cfg = new Configuration();//Freemarker配置对象
- cfg.setClassForTemplateLoading(this.getClass(), "/templates");//设置加载ftl模板的路径
- template = cfg.getTemplate(ftl);//加载模板文件
-
- valueMap = new HashMap();
- parseMetadata();
- }
-
- //获取所有的表信息、列信息,并且转换为对象
- public void parseMetadata() throws Exception {
- tableList = new ArrayList<TableVo>();
-
- //获取所有表名
- String [] tableNameArr = MetadataUtil.getTableNames();
- for (String tName : tableNameArr) {
- TableVo table= new TableVo();//表对象
- //下划线转帕斯卡命名
- table.setClassName(JavaNameUtil.toPascal(tName));
- table.setTableName(tName);
- table.setCamelName(JavaNameUtil.toCamel(tName));
- //调用工具类,获取列信息
- List<String []> colInfoList = MetadataUtil.getTableColumnsInfo(tName);
- for(String[] colInfo : colInfoList) {
- String colName = colInfo[0];//列名
- String comment = colInfo[1];//列注释
- String colType = colInfo[2];//列类型
- ColumnVo column = new ColumnVo();
- column.setDbName(colName);
- column.setDbType(colType);
- column.setComm(comment);
- column.setJavaName(JavaNameUtil.toCamel(colName));
- column.setJavaType(JavaNameUtil.dbTypeToJavaType(colType));
- //列名转帕斯卡命名法,用户生成get和set方法命名
- column.setUpperCaseColumnName(JavaNameUtil.toPascal(colName));
- //将列信息加入表对象的列信息列表中
- table.getColumns().add(column);
- }
- //加入表集合
- tableList.add(table);
- }
- MetadataUtil.closeConnection();//关闭数据库连接
- System.out.println("构建元数据成功!\n\n");
- }
-
- //抽象生成代码的方法,各子类实现
- public void generateCode() throws Exception {
- System.out.println("--------------开始生成" + template.getName() + "代码生成器开始生成代码");
- OutputStreamWriter writer = null;
- for(TableVo table : tableList) {
- valueMap.put("table", table);
- try {
- //生成的每个代码文件,拼接文件名,创建文件写入器
- writer = new FileWriter(savePath + "/" + table.getClassName() + fileNameSuffix);
- //Freemarker合成数据和模板,输出到代码文件
- this.template.process(valueMap, writer);
- //清空写入器缓冲
- writer.flush();
- } catch (TemplateException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- try {
- writer.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- System.out.println("根据" + template.getName() + "模板生成代码成功");
- }

代码生成器入口类main方法:
- public class App {
- public static void main(String [] args) throws Exception {
- String myProjectPkg = "cn.itrip";
- //实体类生成器
- CodeGenerator pojoGenerator = new CodeGenerator("pojo.ftl");//设置所用的模板
- pojoGenerator.setSavePath("url");//设置生成代码保存的位置
- pojoGenerator.setFileNameSuffix(".java");//设置文件后缀名
- pojoGenerator.setPackage(myProjectPkg);//项目包名
- //mapper接口生成器
- CodeGenerator mapperGenerator = new CodeGenerator("mapper.ftl");//设置所用的模板
- mapperGenerator.setSavePath("url");//设置生成代码保存的位置
- mapperGenerator.setFileNameSuffix("Mapper.java");//设置文件后缀名
- mapperGenerator.setPackage(myProjectPkg);//项目包名
- //mapper映射文件生成器
- CodeGenerator sqlGenerator = new CodeGenerator("sql.ftl");//设置所用的模板
- sqlGenerator.setSavePath("url");//设置生成代码保存的位置
- sqlGenerator.setFileNameSuffix("Mapper.xml");//设置文件后缀名
- sqlGenerator.setPackage(myProjectPkg);//项目包名
- try {
- //调用代码生成器
- pojoGenerator.generateCode();
- mapperGenerator.generateCode();
- sqlGenerator.generateCode();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }

最后在写3个模板文件(pojo、mapper、sql.ftl)然后运行一下App类就可以自动生成代码了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。