代码生成工具原理解析

本贴最后更新于 4259 天前,其中的信息可能已经时移世易

现在网上有很多开源的代码生成工具,如jeecg框架,其实现的主要功能就是根据数据库表能自动生成前后和后台的代码,帮助开发人员生成一些重复性的、统一的代码,然后开发人员再在生成的代码的基础上做一些个性化的修改,这样就可以加快开发的进程。

根据以上分析,我们可以把代码生成分为2个步骤:
1、读取数据库表信息,主要包括表名、字段名称、字段类型、主键、外键等。技术:java.sql.DatabaseMetaData
2、编写模板文件,根据模板文件和读出的数据库表数据生成相应的代码。技术:freemarker

代码示例:

package db;

import java.io.File;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.apache.commons.io.FileUtils;

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;

public class CodeGenerator {

/** * 代码工厂实例 * @param args */ public static void main(String[] args) { String dataBase = "hibernate"; // 数据库名 String username = "root"; // 数据库用户名 String password = "root"; // 数据库密码 String tableName = "my_user_role"; // 表名 String pack = "com.wj.model"; // 包名 try { // 获取数据 Collection<Map<String, String>> properties = readData(dataBase, username, password, tableName); Configuration cfg = new Configuration(); cfg.setDirectoryForTemplateLoading(new File("template")); cfg.setObjectWrapper(new DefaultObjectWrapper()); //获取模板文件 Template template = cfg.getTemplate("model.ftl"); Map<String, Object> map = new HashMap<String, Object>(); map.put("class", getClassName(tableName)); map.put("pack", pack); map.put("properties", properties); // 生成输出到控制台 Writer out = new OutputStreamWriter(System.out); template.process(map, out); out.flush(); //生成输出到文件 String root = genPackStr("src",pack); File fileDir = new File(root); // 创建文件夹,不存在则创建 FileUtils.forceMkdir(fileDir); // 指定生成输出的文件 File output = new File(fileDir + "/"+getClassName(tableName)+".java"); Writer writer = new FileWriter(output); template.process(map, writer); writer.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 读取表数据 * @param dataBase 数据库名 * @param tableName 表名 * @return */ public static Collection<Map<String, String>> readData(String dataBase, String username, String password, String tableName){ Collection<Map<String, String>> properties = new HashSet<Map<String, String>>(); Connection conn = null; ResultSet rs = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/"+dataBase+"?useUnicode=true&characterEncoding=UTF-8",username, password); DatabaseMetaData dbmd = conn.getMetaData(); rs = dbmd.getColumns(null, null, tableName, null); while (rs.next()) { Map<String, String> map = new HashMap<String, String>(); map.put("fieldName", genFieldName(rs.getString("COLUMN_NAME"))); map.put("fieldType", genFieldType(rs.getString("TYPE_NAME"))); properties.add(map); } } catch (Exception e) { e.printStackTrace(); }finally{ try { if(conn != null){ conn.close(); } if(rs != null){ rs.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return properties; } /** * 根据包名获取对应的路径名 * @param root 根路径 * @param pack 包名 * @return */ public static String genPackStr(String root,String pack){ String result = root; String [] dirs = pack.split("\\."); for(String dir : dirs){ result += "/"+dir; } return result; } /** * 根据表面获取类名 * @param tableName 表名 * @return */ public static String getClassName(String tableName){ String result = ""; String lowerFeild = tableName.toLowerCase(); String[] fields = lowerFeild.split("_"); if (fields.length > 1) { for(int i=0;i<fields.length;i++){ result += fields[i].substring(0,1).toUpperCase() + fields[i].substring(1, fields[i].length()); } } return result; } /** * 根据表字段名获取java中的字段名 * @param field 字段名 * @return */ public static String genFieldName(String field) { String result = ""; String lowerFeild = field.toLowerCase(); String[] fields = lowerFeild.split("_"); result += fields[0]; if (fields.length > 1) { for(int i=1;i<fields.length;i++){ result += fields[i].substring(0,1).toUpperCase() + fields[i].substring(1, fields[i].length()); } } return result; } /** * 根据表字段的类型生成对应的java的属性类型 * @param type 字段类型 * @return */ public static String genFieldType(String type){ String result = "String"; if(type.toLowerCase().equals("varchar")){ result = "String"; }else if(type.toLowerCase().equals("int")){ result = "int"; } return result; }

}

效果图,可以看出我们根据数据库中的my_user_role表,自动生成了MyUserRole.java实体类

实例下载地址:http://download.csdn.net/detail/tianma630/5534811

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 大疆创新

    深圳市大疆创新科技有限公司(DJI-Innovations,简称 DJI),成立于 2006 年,是全球领先的无人飞行器控制系统及无人机解决方案的研发和生产商,客户遍布全球 100 多个国家。通过持续的创新,大疆致力于为无人机工业、行业用户以及专业航拍应用提供性能最强、体验最佳的革命性智能飞控产品和解决方案。

    2 引用 • 14 回帖 • 4 关注
  • OnlyOffice
    4 引用 • 22 关注
  • Mac

    Mac 是苹果公司自 1984 年起以“Macintosh”开始开发的个人消费型计算机,如:iMac、Mac mini、Macbook Air、Macbook Pro、Macbook、Mac Pro 等计算机。

    168 引用 • 597 回帖
  • Caddy

    Caddy 是一款默认自动启用 HTTPS 的 HTTP/2 Web 服务器。

    12 引用 • 54 回帖 • 178 关注
  • 招聘

    哪里都缺人,哪里都不缺人。

    188 引用 • 1057 回帖 • 1 关注
  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    200 引用 • 120 回帖 • 1 关注
  • RYMCU

    RYMCU 致力于打造一个即严谨又活泼、专业又不失有趣,为数百万人服务的开源嵌入式知识学习交流平台。

    4 引用 • 6 回帖 • 57 关注
  • jQuery

    jQuery 是一套跨浏览器的 JavaScript 库,强化 HTML 与 JavaScript 之间的操作。由 John Resig 在 2006 年 1 月的 BarCamp NYC 上释出第一个版本。全球约有 28% 的网站使用 jQuery,是非常受欢迎的 JavaScript 库。

    63 引用 • 134 回帖 • 733 关注
  • Sandbox

    如果帖子标签含有 Sandbox ,则该帖子会被视为“测试帖”,主要用于测试社区功能,排查 bug 等,该标签下内容不定期进行清理。

    435 引用 • 1250 回帖 • 593 关注
  • TGIF

    Thank God It's Friday! 感谢老天,总算到星期五啦!

    290 引用 • 4494 回帖 • 654 关注
  • API

    应用程序编程接口(Application Programming Interface)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

    79 引用 • 431 回帖
  • 以太坊

    以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约、开源的底层系统。以太坊是一个平台和一种编程语言 Solidity,使开发人员能够建立和发布下一代去中心化应用。 以太坊可以用来编程、分散、担保和交易任何事物:投票、域名、金融交易所、众筹、公司管理、合同和知识产权等等。

    34 引用 • 367 回帖
  • 叶归
    8 引用 • 38 回帖 • 18 关注
  • SendCloud

    SendCloud 由搜狐武汉研发中心孵化的项目,是致力于为开发者提供高质量的触发邮件服务的云端邮件发送平台,为开发者提供便利的 API 接口来调用服务,让邮件准确迅速到达用户收件箱并获得强大的追踪数据。

    2 引用 • 8 回帖 • 500 关注
  • CodeMirror
    2 引用 • 17 回帖 • 162 关注
  • Tomcat

    Tomcat 最早是由 Sun Microsystems 开发的一个 Servlet 容器,在 1999 年被捐献给 ASF(Apache Software Foundation),隶属于 Jakarta 项目,现在已经独立为一个顶级项目。Tomcat 主要实现了 JavaEE 中的 Servlet、JSP 规范,同时也提供 HTTP 服务,是市场上非常流行的 Java Web 容器。

    162 引用 • 529 回帖 • 2 关注
  • Sphinx

    Sphinx 是一个基于 SQL 的全文检索引擎,可以结合 MySQL、PostgreSQL 做全文搜索,它可以提供比数据库本身更专业的搜索功能,使得应用程序更容易实现专业化的全文检索。

    1 引用 • 223 关注
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    76 引用 • 258 回帖 • 629 关注
  • Hprose

    Hprose 是一款先进的轻量级、跨语言、跨平台、无侵入式、高性能动态远程对象调用引擎库。它不仅简单易用,而且功能强大。你无需专门学习,只需看上几眼,就能用它轻松构建分布式应用系统。

    9 引用 • 17 回帖 • 636 关注
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    175 引用 • 3854 回帖
  • 深度学习

    深度学习(Deep Learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。

    54 引用 • 44 回帖 • 1 关注
  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    557 引用 • 675 回帖
  • 安装

    你若安好,便是晴天。

    132 引用 • 1184 回帖 • 2 关注
  • SQLServer

    SQL Server 是由 [微软] 开发和推广的关系数据库管理系统(DBMS),它最初是由 微软、Sybase 和 Ashton-Tate 三家公司共同开发的,并于 1988 年推出了第一个 OS/2 版本。

    21 引用 • 31 回帖 • 2 关注
  • ActiveMQ

    ActiveMQ 是 Apache 旗下的一款开源消息总线系统,它完整实现了 JMS 规范,是一个企业级的消息中间件。

    19 引用 • 13 回帖 • 678 关注
  • 域名

    域名(Domain Name),简称域名、网域,是由一串用点分隔的名字组成的 Internet 上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位(有时也指地理位置)。

    43 引用 • 208 回帖
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3201 引用 • 8216 回帖 • 1 关注