首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >简单java代码生成器的开发教程(一),根据数据库表逆向工程生成实体类(附源码)

简单java代码生成器的开发教程(一),根据数据库表逆向工程生成实体类(附源码)

作者头像
全栈程序员站长
发布于 2022-08-30 11:30:28
发布于 2022-08-30 11:30:28
1.7K00
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

简单java代码生成器的开发流程(一),根据数据库表逆向工程生成实体类

以前开发过完整的快速开发平台,想分享里面的基本代码生成的开发流程,大概就两个重点,一代码生成引擎,二是编写模版

代码生成器的核心开发流程

  1. 如何连接数据库,获取数据库信息,以及根据数据库的表字段信息如何转换成java实体类型 1)获取数据库表信息 2)数据库表信息转java类型
  2. 配置必须的基本数据,根据模版语言编写代码模版,根据模版生成代码文件(我这里用freemarker模版语言) 1)配置数据库类型,帐号,密码,需要生成的表的基本信息 2)编写模版,根据配置的信息注入模版生成代码文件以及生成代码文件的路径

开发流程

根据数据库表信息转成java实体类

1. 获取数据库表的基本信息,核心代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   /** * 根据表名获取该表的所有字段信息 * @param tableName 表名称 * @return */
    public List<TableField> getTbfrFields(String tableName){ 
   
        List<TableField> tbColumns = new ArrayList();
        //与数据库的连接
        Connection conn = getConn();
        Statement stm = null;
        ResultSet rs = null;
        try { 
   
            stm = conn.createStatement();
            ResultSet rsKey = conn.getMetaData().getPrimaryKeys(null,null,tableName.toUpperCase());
            String keyName=null;
            while(rsKey.next()){ 
   
                keyName = rsKey.getString("COLUMN_NAME").toLowerCase();
                keyName = CommonUtils.getNoUnderlineStr(keyName);
            }
            rs = conn.getMetaData().getColumns(   null, getSchema(conn),tableName.toUpperCase(), "%");
            while(rs.next()){ 
   
                TableField tbfrField = new TableField();
                String fieldNm = rs.getString("COLUMN_NAME").toLowerCase();
                tbfrField.setName(fieldNm);//表字段名
                tbfrField.setPropertyName(CommonUtils.getNoUnderlineStr(fieldNm));//字段名
                tbfrField.setComment(rs.getString("REMARKS"));//字段注释
                tbfrField.setType(rs.getString("TYPE_NAME"));//字段类型
                tbfrField.setColumnType(this.getTypeConvert().processTypeConvert(tbfrField.getType()));

                if(keyName!=null && keyName.equals(tbfrField.getName())){ 
   
                    tbfrField.setKeyIdentityFlag(true);
                }else{ 
   
                    tbfrField.setKeyIdentityFlag(false);
                }

                tbColumns.add(tbfrField);
            }
            if(stm!=null){ 
   
                stm.close();
            }
            if(rs!=null){ 
   
                rs.close();
            }
        } catch (SQLException e) { 
   
            throw new RuntimeException("getColumnNames failure", e);
        } catch (Exception e) { 
   
            throw new RuntimeException("Exception rs failure", e);
        }
        return tbColumns;
    }
  1. 表字段类型转java数据类型,上面获取到表信息了,里面的this.getTypeConvert().processTypeConvert(tbfrField.getType())就是将数据库表类型转成java类型, 详细一点的可以参考下面这篇文章 总结java数据类型和mysql、oracle、pgsql数据类型对应关系https://blog.csdn.net/qq_21187515/article/details/91495237 核心代码如下
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public DbColumnType processTypeConvert(String fieldType) { 
   
        String t = fieldType.toLowerCase();
        if (!t.contains("char") && !t.contains("text")) { 
   
            if (t.contains("bigint")) { 
   
                return DbColumnType.LONG;
            } else if (t.contains("int")) { 
   
                return DbColumnType.INTEGER;
            } else if (!t.contains("date") && !t.contains("time") && !t.contains("year")) { 
   
                if (t.contains("text")) { 
   
                    return DbColumnType.STRING;
                } else if (t.contains("bit")) { 
   
                    return DbColumnType.BOOLEAN;
                } else if (t.contains("decimal")) { 
   
                    return DbColumnType.BIG_DECIMAL;
                } else if (t.contains("clob")) { 
   
                    return DbColumnType.CLOB;
                } else if (t.contains("blob")) { 
   
                    return DbColumnType.BLOB;
                } else if (t.contains("binary")) { 
   
                    return DbColumnType.BYTE_ARRAY;
                } else if (t.contains("float")) { 
   
                    return DbColumnType.FLOAT;
                } else if (t.contains("double")) { 
   
                    return DbColumnType.DOUBLE;
                } else { 
   
                    return !t.contains("json") && !t.contains("enum") ? DbColumnType.STRING : DbColumnType.STRING;
                }
            } else { 
   
                return DbColumnType.DATE;
            }
        } else { 
   
            return DbColumnType.STRING;
        }
    }

用freemarker模版语言进行编写的模版

  1. 生成文件之前获取配置信息存到Map变量,之后注入模版生成代码文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public Map<String, Object> execute() { 
   


        Map data = new HashMap();
        data.put("entityPackage", globalConfig.getEntityPackage());//实体的包名
        //移除表前缀,表名之间的下划线,得到实体类型
        String entity = CommonUtils.getNoUnderlineStr(CommonUtils.removePrefix(tableInfo.getName().toLowerCase(),globalConfig.getPrefix()));
        data.put("entity", entity);//实体名称
        data.put("author", globalConfig.getAuthor());//创建作者
        data.put("date",  CommonUtils.getFormatTime("yyyy-MM-dd", new Date() ));//创建时间
        data.put("table", tableInfo);//表信息
// for (TableField field:tableInfo.getFields()) { 
   
// if(field.isKeyIdentityFlag()){//获取主键字段信息
// data.put("tbKey", field.getName());
// data.put("tbKeyType", field.getColumnType());
// break;
// }
// }
        return data;
    }
  1. 编写生成实体的模版,模板在resources/template目录下,可以根据需要自行修改
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package ${ 
   entityPackage};

import ${ 
   entityPackage}.${ 
   entity};
import java.io.Serializable;

/** * 描述: ${table.comment} * author: ${author} * date: ${date} */
@TableName("${table.name}")
public class ${ 
   entity} implements Serializable { 
   


    private static final long serialVersionUID = 1L;
<#-- 循环属性名称 -->
<#list table.fields as field>
<#if field.comment??>
    /** * ${field.comment} */
</#if>
<#if field.keyIdentityFlag>
    @TableId(value="${field.name}", type= IdType.AUTO)
</#if>
    private ${ 
   field.propertyType} ${ 
   field.propertyName};

</#list>
<#-- 循环set/get方法 -->
<#list table.fields as field>
<#if field.propertyType == "Boolean">
<#assign getprefix="is"/>
<#else>
<#assign getprefix="get"/>
</#if>
    public ${ 
   field.propertyType} ${ 
   getprefix}${ 
   field.capitalName}() { 
   
	return ${ 
   field.propertyName};
    }

    public void set${ 
   field.propertyName?cap_first}(${ 
   field.propertyType} ${ 
   field.propertyName}) { 
   
        this.${ 
   field.propertyName} = ${ 
   field.propertyName};
    }
</#list>
}
  1. 得到代码生成的文件路径
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** * 获取代码生成的文件路径 * @param type * @param entityName * @return */
  public String getCodePath(String type, String entityName)
  { 
   
    StringBuilder path = new StringBuilder();
    if (StringUtils.isNotBlank(type)) { 
   
      String codeType = Enum.valueOf(CodeType.class, type).toString();

      //开头,项目路径
      if(StringUtils.isEmpty(this.globalConfig.getOutputDir())){ 
   
        String projectPath = getProjectPath();//没有设置outputDir的话默认用当前项目resources/code路径下
        path.append(projectPath+"src/main/resources/code");//项目名
      }else{ 
   
        path.append(this.globalConfig.getOutputDir());//项目名
      }
      path.append("/");
      if("entity".equals(codeType)){ 
   
        //包名 package.path
        path.append(globalConfig.getEntityPackage());
        path.append("/");
        //文件名
        path.append(StringUtils.capitalize(entityName));
        //后缀
        path.append(".java");
      }else { 
   
        //其他类型文件生成
      }

    } else { 
   
      throw new IllegalArgumentException("type is null");
    }
    return path.toString();
  }
  1. 把配置数据注入模版,生成代码文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  /** * 把配置数据注入模版,生成代码文件 * @param templateFileName * @param type * @param data * @throws TemplateException * @throws IOException */
  public void generateFile(String templateFileName, String type, Map data) throws TemplateException,IOException
  { 
   

      String entityName = data.get("entity").toString();
      String fileNamePath = getCodePath(type, entityName);//获取生成的文件路径
      System.out.println("fileNamePath:"+fileNamePath);
      String fileDir = StringUtils.substringBeforeLast(fileNamePath, "/");
      Template template = getConfiguration().getTemplate(templateFileName);//获取模版信息
      FileUtils.forceMkdir(new File(fileDir + "/"));
      Writer out = new OutputStreamWriter(
        new FileOutputStream(fileNamePath), globalConfig.getSystem_encoding());//生成的文件编码
      template.process(data, out);//结合模版生成代码文件
      out.close();
  }

设置全局的配置 、数据库配置,执行generateToFile()方法生成代码文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
   public static void main(String[] args)
    { 
   
        GlobalConfig globalConfig = new GlobalConfig();//全局配置
        globalConfig.setTableNames(new String[]{ 
   "pre_score","pre_student"});//需要生成的实体
        globalConfig.setPrefix(new String[]{ 
   "ali_"});//生成的实体移除前缀
        globalConfig.setOutputDir("D://code/");//文件输出路径,不配置的话默认输出当前项目的resources/code目录下
        DataSourceConfig dsc = new DataSourceConfig();//数据库配置
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUrl("jdbc:mysql://192.168.33.203:3306/test?useUnicode=true&amp;characterEncoding=UTF-8&amp;&useSSL=false");
        dsc.setUsername("root");
        dsc.setPassword("root");
        CodeGenerate codeGenerate = new CodeGenerate(globalConfig,dsc);
        //生成代码
        codeGenerate.generateToFile();
    }

执行完codeGenerate.generateToFile()后可以看到已经把表pre_score、pre_student生成了实体类代码文件

生成的Sorce.java文件内容:

代码生成器源码:https://gitee.com/zhangxinlin/code-generate

简单java代码生成器的开发教程(二),生成springboot+mybatis-plus的增删查改的基本代码(开发利器,附源码)

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/144884.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年5月1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
剑指Offer LeetCode 面试题18. 删除链表的节点
输入: head = [4,5,1,9], val = 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 示例 2:
手撕代码八百里
2020/07/28
3450
剑指 Offer 面试题 18. 删除链表的节点
今天分享的题目来源于 LeetCode 上的剑指 Offer 系列 面试题18. 删除链表的节点,又是一道简简单单的送分题,基本上看一遍都能掌握。
五分钟学算法
2020/07/16
3480
LeetCode-面试题18-删除链表的节点
没有O(1)的时间复杂度要求,顺序查找,头结点是查找值直接返回,如果不是则继续找,指针指向查找数的前一个位置,如果没有找完了都没有找到,循环依然是要跳出的,此时res.next==null,就不需要对链表进行修改,所以只有!=null的时候才有删除操作
benym
2022/07/14
2000
剑指offer | 面试题15:删除链表的节点
题目描述: 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。
千羽
2021/12/29
2100
剑指offer | 面试题15:删除链表的节点
动画:删除链表的节点
大家好,我是帅吴,欢迎来到 图解剑指 Offer 结构化专栏,在这个专栏里我将和大家一起学习如何用结构化的思维来思考、解题、写代码,希望能帮助你即使在面试的时候紧张也能做对。
五分钟学算法
2021/05/31
1.3K0
腾讯面试官:删除链表的节点,怎么删?
大家好,我是吴师兄,不啰嗦,直接开始今天的算法学习,冲冲冲。 一、题目描述 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。 返回删除后的链表的头节点。 示例 1: 输入: head = [4,5,1,9], val = 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 示例 2: 输入: head = [4,5,1,9], val = 1 输出: [4,5,9] 解释: 给定你链表中值为 1 的第
五分钟学算法
2021/10/26
5320
[路飞]_leetcode-剑指 Offer 18-删除链表的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。 返回删除后的链表的头节点。 注意: 此题对比原题有改动 示例 1: 输入: head = [4,5,1,9], val = 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 复制代码 示例 2: 输入: head = [4,5,1,9], val = 1 输出: [4,5,9] 解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该
玖柒的小窝
2021/12/08
1860
剑指Offer - 面试题18. 删除链表的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。 返回删除后的链表的头节点。
Michael阿明
2020/07/13
2990
剑指 Offer 18. 删除链表的节点
对于链表的删除 我们需要知道删除链表的节点只能在要删除节点的前一个节点做删除操作,如果在要删除的节点本身做操作是无法进行删除的,明确了这一点很容易就可以做出这道题;
暴躁的程序猿
2022/03/24
1680
leetcode链表之删除链表的节点
序 本文主要记录一下leetcode链表之删除链表的节点 OIP (45).jpeg 题目 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。 ​ 返回删除后的链表的头节点。 ​ 注意:此题对比原题有改动 ​ 示例 1: ​ 输入: head = [4,5,1,9], val = 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. ​ 示例 2: ​ 输入: head = [4,5,1,9], val
code4it
2020/09/12
6110
leetcode链表之删除链表的节点
【算法题解】 Day26 双指针
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。
sidiot
2023/08/31
1890
【算法题解】 Day26 双指针
剑指Offer题解 - Day23
链表的题目,首先考虑使用双指针来解决。根据题目描述,保证了链表中节点互不相同,因此遍历节点,当遇到指定值时,进行删除处理。同时暂存链表的头部节点,方便最后返回。
chuckQu
2022/08/19
1270
LeetCode17|删除链表的节点
1,问题简述 给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。 返回删除后的链表的头节点。 注意:此题对比原题有改动 2,示例 输入: head = [4,5,1,9], val = 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 3,题解思路 使用哨兵节点和HashSet集合进行操作。 4,题解程序 import java.util.HashSet; import java.util.Linke
码农王同学
2020/08/12
4440
LeetCode17|删除链表的节点
剑指offer - 删除链表节点 - JavaScript
题目描述:给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。
心谭博客
2020/04/21
9140
【剑指Offer】18. 删除链表的节点
NowCode 题目描述 返回删除后的链表的头节点。 输入: head = [4,5,1,9], val = 5 输出: [4,1,9] 解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9. 解题思路 /** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode
瑞新
2020/12/07
2350
精选 TOP 面试题 001 | LeetCode 237. 删除链表中的节点
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
江不知
2019/12/12
3840
精选 TOP 面试题 001 | LeetCode 237. 删除链表中的节点
Swift 删除链表中的节点 - LeetCode
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
韦弦zhy
2018/12/19
1.5K4
leecode刷题(20)-- 删除链表中的节点
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
希希里之海
2019/03/08
7000
leecode刷题(20)-- 删除链表中的节点
删除链表中的节点
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点。传入函数的唯一参数为 要被删除的节点 。
_kyle
2020/12/18
2.9K0
LeetCode 237. 删除链表中的节点
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
Michael阿明
2022/11/26
5070
LeetCode 237. 删除链表中的节点
推荐阅读
相关推荐
剑指Offer LeetCode 面试题18. 删除链表的节点
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验