如何根据Mapper的Class反向生成SQL文件创建数据库表

news2025/1/20 14:50:30

微信公众号:大数据高性能计算

在这里插入图片描述

问题:已经根据数据库表生成了一堆的Mapper Class,但是当另一个新同学复制项目的时候没有SQL建表文件,导致无法创建数据库,那么这时候我们就需要通过反射以及注解相关的解析自动去生成数据库表文件。

看一下我们的工程的Mapper:
在这里插入图片描述
可以看到我们已经有大量的数据库实体对象了
针对每一个实体对象,我们看下通用的结构:

在这里插入图片描述
我们可以看到这个实体Class里面有所有的属性字段,也有表名的注解,自增主键的注解,所有借助反射以及注解我们可以拿到我们想要的信息。 同时这里的属性字段都是驼峰命名的,所以还需要一个操作类将驼峰字段转为下划线字段命名,比如userId 转成 user_id,之后就是Java数据类型与数据库数据类型的基础映射。主要的几个Class类如下:
CamelToSnake: 用于做转换成下划线命名的

public class CamelToSnake {
    public static void main(String[] args) {
        String camelCase = "myVariableName";
        String snakeCase = camelToSnake(camelCase);
        System.out.println(snakeCase);
    }

    public static String camelToSnake(String camelCase) {
        StringBuilder snakeCase = new StringBuilder();
        for (int i = 0; i < camelCase.length(); i++) {
            char currentChar = camelCase.charAt(i);
            if (Character.isUpperCase(currentChar) && i > 0) {
                snakeCase.append('_');
            }
            snakeCase.append(Character.toLowerCase(currentChar));
        }
        return snakeCase.toString();
    }
}

PackageScanner: 扫描我们的实体类所在的对象的路径,拿到所有Class对象,供后面解析所用、


import com.baomidou.mybatisplus.annotation.TableName;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class PackageScanner {
    public static void main(String[] args) {
        String packageName = "com.fuint.repository.model"; // 替换成您要扫描的包名
        List<Class<?>> classes = scanPackage(packageName);

        for (Class<?> clazz : classes) {
            System.out.println(clazz.getName());
            // 使用 getAnnotation 方法来获取 @TableName 注解
            TableName tableNameAnnotation = clazz.getAnnotation(TableName.class);

            if (tableNameAnnotation != null) {
                String tableName = tableNameAnnotation.value();
                System.out.println("Table Name: " + tableName);
            } else {
                System.out.println("@TableName annotation not found.");
            }
        }
    }

    public static List<Class<?>> scanPackage(String packageName) {
        List<Class<?>> classes = new ArrayList<>();
        String packagePath = packageName.replace('.', '/');
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        URL packageURL = classLoader.getResource(packagePath);

        if (packageURL != null) {
            File packageDir = new File(packageURL.getFile());
            if (packageDir.isDirectory()) {
                File[] files = packageDir.listFiles();
                if (files != null) {
                    for (File file : files) {
                        if (file.isFile() && file.getName().endsWith(".class")) {
                            String className = packageName + "." + file.getName().replace(".class", "");
                            try {
                                Class<?> clazz = Class.forName(className);
                                classes.add(clazz);
                            } catch (ClassNotFoundException e) {
                                // 处理异常
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
        return classes;
    }
}


最后就是实体转化成SQL的全文件解析:


import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Entity2Sql {


    public static void main(String[] args) {

        List<Class<?>> classes = PackageScanner.scanPackage("com.fuint.repository.model");
        for (Class<?> entityClass : classes) {

            TableName tableNameAnnotation = entityClass.getAnnotation(TableName.class);
            String tableName = null;
            if (tableNameAnnotation != null) {
                tableName = tableNameAnnotation.value();
                //System.out.println("Table Name: " + tableName);
            } else {
                throw new RuntimeException("@TableName annotation not found.");
            }

            StringBuilder sql = new StringBuilder();

            sql.append("DROP TABLE IF EXISTS" ).append(" `").append(tableName).append("`;\n");

            sql.append("CREATE TABLE ").append(tableName).append(" (\n");

            Field[] fields = entityClass.getDeclaredFields();

            String primaryKeyFieldName = "";
            for (Field field : fields) {

                /*ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
                if (annotation == null) {
                    continue;
                }*/
                if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
                    continue;
                }

                TableId tableIdAnnotation = field.getAnnotation(TableId.class);
                IdType type = null;
                String value = null;
                if (tableIdAnnotation != null) {
                    type = tableIdAnnotation.type();
                    value = tableIdAnnotation.value();
                }
                String fieldCamel2Snake = CamelToSnake.camelToSnake(field.getName());
                String fieldType = field.getType().getSimpleName();

                // 根据字段类型转换为数据库对应的数据类型
                String dbType = convertToDbType(fieldType);

                // 添加字段和数据类型到SQL语句中
                if (type != null && type == IdType.AUTO) {
                    primaryKeyFieldName = value;
                    sql.append("\t").append(fieldCamel2Snake).append(" ").append(dbType).append(" NOT NULL AUTO_INCREMENT COMMENT '自增ID'").append(",\n");

                } else {
                    sql.append("\t").append(fieldCamel2Snake).append(" ").append(dbType).append(",\n");
                }
            }

            // 使用 getAnnotation 方法来获取 @ApiModel 注解
            ApiModel apiModelAnnotation = entityClass.getAnnotation(ApiModel.class);
            String description = null;
            if (apiModelAnnotation != null) {
                description = apiModelAnnotation.description();
                //System.out.println("Description: " + description);
            } else {
                throw new RuntimeException("@ApiModel annotation not found.");
            }
            // 添加主键约束
            sql.append("\tPRIMARY KEY (" + primaryKeyFieldName + ")\n");
            if (description != null) {

                sql.append(")ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED COMMENT='" + description + "';");
            } else {
                sql.append(")ENGINE=InnoDB DEFAULT CHARSET=utf8;");
            }


            System.out.println(sql.toString());
        }
    }

    private static String convertToDbType(String fieldType) {
        Map<String, String> typeMap = new HashMap<>();
        typeMap.put("boolean", "BOOLEAN");
        typeMap.put("byte", "TINYINT");
        typeMap.put("short", "SMALLINT");
        typeMap.put("int", "INT");
        typeMap.put("long", "BIGINT");
        typeMap.put("float", "FLOAT");
        typeMap.put("double", "DOUBLE");
        typeMap.put("char", "CHAR(1)");
        typeMap.put("String", "VARCHAR(255)");
        typeMap.put("Date", "DATETIME");

        typeMap.put("Boolean", "BOOLEAN");
        typeMap.put("Byte", "TINYINT");
        typeMap.put("Short", "SMALLINT");
        typeMap.put("Integer", "INT");
        typeMap.put("Long", "BIGINT");
        typeMap.put("Float", "FLOAT");
        typeMap.put("Double", "DOUBLE");
        typeMap.put("Character", "CHAR(1)");

        // 可以继续添加其他类型的映射关系

        String dbType = typeMap.get(fieldType);

        if (dbType == null) {
            dbType = "VARCHAR(255)";
        }

        return dbType;
    }

}

最后我们看看我们生成的结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1095465.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Springboot-MyBatisPlue入门

一 创建项目&#xff0c;选择spring boot 初始化&#xff0c;配置相关信息 第五步创建实体类 二 快速开发实体类的jar包--lombok <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12<…

openGauss学习笔记-100 openGauss 数据库管理-管理数据库安全-客户端接入之用SSL进行安全的TCP/IP连接

文章目录 openGauss学习笔记-100 openGauss 数据库管理-管理数据库安全-客户端接入之用SSL进行安全的TCP/IP连接100.1 背景信息100.2 前提条件100.3 注意事项100.4 操作步骤100.5 相关参考 openGauss学习笔记-100 openGauss 数据库管理-管理数据库安全-客户端接入之用SSL进行安…

Vue-3.4Vuex

Vuex概述 是什么&#xff1a; vuex是一个vue的状态管理工具&#xff0c;状态就是数据。 Vuex是一个插件&#xff0c;可以帮我们管理vue通用的数据&#xff08;多组件共享的数据&#xff09; 例如&#xff1a;购物车数据、个人信息数据 场景&#xff1a; 1&#xff09;某个…

暴力递归转动态规划(十)

题目 给定一个二维数组matrix[][]&#xff0c;一个人必须从左上角出发&#xff0c;最终到达右下角&#xff0c;沿途只可以向下或者向右走&#xff0c;沿途的数字都累加就是距离累加和。返回最小距离累加和。 这道题中会采用压缩数组的算法来进行优化 暴力递归 暴力递归方法的整…

OpenCV学习笔记-环境搭建

文章目录 概述下载安装Visual Studio 2022下载安装OpenCVVisual Studio 配置配置包含路径配置库路径配置链接器配置环境变量Path路径 测试C测试Python 测试 概述 OpenCV&#xff08;Open source computer vision&#xff09;是一个跨平台的计算机视觉和机器学习开源库&#xf…

C语言char与short取反以及符号判断问题

这个问题主要是在从对一个变量进行符号判断引出&#xff0c;有一种判断方法是#define ISUNSIGNED(Value) (Value >0 && ~Value >0) 主要是通过将符号位取反然后将变量与0进行比较。传入int与unsigned int结果正确&#xff0c;但是当传入unsigned char 与unsign…

差分进化算法,依旧强势

文章目录 前言DE算法DE代码DE再思考相关阅读 前言 过去两个月&#xff0c;一直在学习线性和整数规划。 今天开始&#xff0c;要回到智能优化算法了。用“回”这个字&#xff0c;主要是因为智能优化算法其实是我的老朋友了&#xff0c;毕竟在读博的大部分时间里&#xff0c;我…

论文阅读:Offboard 3D Object Detection from Point Cloud Sequences

目录 概要 Motivation 整体架构流程 技术细节 3D Auto Labeling Pipeline The static object auto labeling model The dynamic object auto labeling model 小结 论文地址&#xff1a;[2103.05073] Offboard 3D Object Detection from Point Cloud Sequences (arxiv.o…

基于springboot+vue的前后端分离房屋租赁信息网站

项目介绍 在网络高速发展的时代&#xff0c;众多的软件被开发出来&#xff0c;给用户带来了很大的选择余地&#xff0c;而且人们越来越追求更个性的需求。在这种时代背景下&#xff0c;房东只能以用户为导向&#xff0c;所以开发租房网站是必须的。 系统采用了Java技术&#x…

爬虫 | 【实践】Best Computer Science Scientists数据爬取

文章目录 &#x1f4da;数据需求&#x1f4da;数据爬取&#x1f407;排行榜页数据爬取&#x1f407;获取详情页&#x1f407;目标信息提取 &#x1f4da;完整代码与结果 &#x1f4da;数据需求 姓名&#xff0c;国家&#xff0c;学校 最有名研究领域 目前研究领域 共同作…

16 | 如何自定义 HandlerMethodArgumentResolvers

上一讲我们介绍了 SpringDataWebConfiguration 类的用法&#xff0c;那么这次我们来看一下这个类是如何被加载的&#xff0c;PageableHandlerMethodArgumentResolver 和 SortHandlerMethodArgumentResolver 又是如何生效的&#xff0c;以及如何定义自己的 HandlerMethodArgumen…

c语言练习89:链表的使用

链表的使用 虽然有这么多的链表的结构&#xff0c;但是我们实际中最常⽤还是两种结构&#xff1a; 单链表 和 双向带头循环链表 1. ⽆头单向⾮循环链表&#xff1a;结构简单&#xff0c;⼀般不会单独⽤来存数据。实际中更多是作为其他数据结 构的⼦结构&#xff0c;如哈希桶、…

数据结构与算法—单链表

目录 一、链表 1、链表的概念及结构 2、分类 二、实现单向链表 1、声明链表结构体 2、输出 3、头插&尾插 4、头删尾删 5、查找 6、指定位置插入 7、删除指定节点 8、删除指定节点的后一个节点 9、单链表的销毁 完整版 LList.h LList.c text.c 一、链表 …

Go错误处理方式真的不好吗?

平时经常上一些网络平台阅读一些技术讨论的话题&#xff0c;对Go语言方面也有些浅浅的关注&#xff0c;正如标题所问&#xff0c;Go语言错误处理可以说算是网络上开发中对Go语言吐槽最多的点之一&#xff0c;那么&#xff0c;Go错误处理真的很不堪吗&#xff1f; 对此我认为&a…

CANoe制作网关实现CAN(FD)报文故障注入(报文长度/timeout/信号错误/E2E)1

CANoe制作网关实现CAN报文故障注入&#xff08;报文长度/timeout/信号错误/E2E&#xff09; 文章目录 CANoe制作网关实现CAN报文故障注入&#xff08;报文长度/timeout/信号错误/E2E&#xff09;1.基本介绍和实现功能 1.基本介绍和实现功能 下面是一个完整的CAN/CANFD总线&…

【Wifi】Wifi架构介绍

Wifi架构介绍 本文基于Android介绍其Wifi架构。Wifi是许多操作系统提供的重要功能之一&#xff0c;特别是越来越多的车载系统wifi是其必备功能。为啥wifi是必备功能&#xff1f; 一方面是传统的上网&#xff08;现在有些车载使用DCM模块管理网络&#xff09;&#xff0c;另一方…

项目管理软件中注释功能的作用是什么?

在项目管理软件中&#xff0c;注释功能允许您对任务、文件夹和项目进行详细的标注。这一功能不仅便于团队成员之间的沟通与协作&#xff0c;还能提高项目管理的效率。通过在项目中添加评论&#xff0c;您可以及时了解项目的最新动态&#xff0c;提出疑问并寻求解决方案。此外&a…

【大模型应用开发教程】01_大模型简介

C1 大模型简介 一. 什么是LLM&#xff08;大语言模型&#xff09;&#xff1f;1. 发展历程2. 大语言模型的概念LLM的应用和影响 二、大模型的能力和特点1. 大模型的能力1.1 涌现能力&#xff08;emergent abilities&#xff09;1.2 作为基座模型支持多元应用的能力1.3 支持对话…

AN基础工具——填色工具

【AN基础工具——填色工具】 基本使用方法填色补充给色块周围画上线 变色动画渐变变色的蜥蜴 本篇内容&#xff1a;填色动画制作 重点内容&#xff1a;填色工具 工 具&#xff1a;Adobe Animate 2022 基本使用方法 填色补充 之前说图形要封闭才能填色&#xff0c;实际情况是有…

ESP8266 Node Mcu开发板连接WIFI并上报数据到MQTT服务器——物联网应用开发

一、前言 本文主要介绍关于ESP8266 Node Mcu开发板如何连接WIFI并将本地采集的数据上传到MQTT服务器中。 大家调试可以使用MQTTBox 二、WIFI连接 首先&#xff0c;导入WIFI连接所需的头文件&#xff0c;引入所需库。 #include <ESP8266WiFi.h> 声明字符串常量&#xff0…