package com.xxx.xxxx.utils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.cqcloud.platform.entity.SysPaymentInfo;

import cn.hutool.core.lang.Console;
import io.swagger.v3.oas.annotations.media.Schema;

/**
 * 根据实体创建表sql语句
 * @author weimeilayer@gmail.com ✨
 * @date 💓💕 2024年8月6日 🐬🐇 💓💕
 */
public class SqlGenerator {

    public static String createTableSql(Class<?> clazz) {
        // 检查类是否包含 @TableName 注解
        if (!clazz.isAnnotationPresent(TableName.class)) {
            throw new IllegalArgumentException("The class must be annotated with @TableName");
        }

        // 初始化 StringBuilder 来构建 SQL 语句
        StringBuilder sql = new StringBuilder();
        TableName tableNameAnnotation = clazz.getAnnotation(TableName.class);
        String tableName = tableNameAnnotation.value();

        // 获取类级别的 @Schema 注解
        Schema classSchema = clazz.getAnnotation(Schema.class);
        String tableComment = (classSchema != null) ? classSchema.description() : clazz.getSimpleName();

        // 构建 SQL 语句的初始部分
        sql.append("drop table if exists ").append(tableName).append(" cascade;\n");
        sql.append("create table ").append(tableName).append(" (\n");

        // 获取类的所有字段
        Field[] fields = clazz.getDeclaredFields();
        String primaryKey = null;
        Map<String, String> columnComments = new HashMap<>();

        // 遍历每个字段
        for (Field field : fields) {
            // 跳过 serialVersionUID 字段
            if (field.getName().equals("serialVersionUID")) {
                continue;
            }

            // 跳过被 @TableField 注解并且 exist 属性为 false 的字段
            if (field.isAnnotationPresent(TableField.class) && field.getAnnotation(TableField.class).exist() == false) {
                continue;
            }

            // 初始化列名和列类型
            String columnName;
            String columnType = null;

            // 检查字段是否被 @TableId 注解
            if (field.isAnnotationPresent(TableId.class)) {
                TableId tableId = field.getAnnotation(TableId.class);
                columnName = tableId.value();
                if (tableId.type() == IdType.ASSIGN_ID) {
                    primaryKey = columnName;
                }
            } else {
                TableField tableField = field.getAnnotation(TableField.class);
                columnName = (tableField != null && !tableField.value().isEmpty()) ? tableField.value() : field.getName();
            }

            // 将列名从驼峰命名转换为下划线命名
            columnName = convertToUnderscore(columnName);

            // 根据字段类型设置列类型
            Class<?> fieldType = field.getType();
            if (fieldType == String.class) {
                columnType = "varchar(255)";
            } else if (fieldType == int.class || fieldType == Integer.class) {
                columnType = "integer";
            } else if (fieldType == long.class || fieldType == Long.class) {
                columnType = "bigint";
            } else if (fieldType == double.class || fieldType == Double.class) {
                columnType = "double precision";
            } else if (fieldType == BigDecimal.class) {
                columnType = "numeric(19, 2)";
            } else if (fieldType == boolean.class || fieldType == Boolean.class) {
                columnType = "boolean";
            } else if (fieldType == LocalDateTime.class) {
                columnType = "timestamp";
            }

            // 处理 @Schema 注解以获取列注释
            if (field.isAnnotationPresent(Schema.class)) {
                Schema schema = field.getAnnotation(Schema.class);
                columnComments.put(columnName, schema.description());
            }

            // 构建列定义部分的 SQL 语句
            sql.append("    ").append(columnName).append(" ").append(columnType);

            // 如果字段被 @TableId 注解,设置为主键
            if (field.isAnnotationPresent(TableId.class)) {
                sql.append(" primary key");
            }

            // 处理 @TableField 注解以设置默认值
            if (field.isAnnotationPresent(TableField.class)) {
                TableField tableField = field.getAnnotation(TableField.class);
                if (tableField.fill() == FieldFill.INSERT || tableField.fill() == FieldFill.UPDATE) {
                    sql.append(" default current_timestamp");
                }
            }

            // 添加列定义的结尾部分
            sql.append(",\n");
        }

        // 删除最后一个逗号并完成 SQL 语句
        sql.setLength(sql.length() - 2); // Remove the last comma
        sql.append("\n);\n");

        // 添加表和列的注释
        sql.append("comment on table \"public\".\"").append(tableName).append("\" IS '").append(tableComment).append("';\n");

        if (!columnComments.isEmpty()) {
            columnComments.forEach((columnName, comment) -> {
                sql.append("comment on column ").append(tableName).append(".").append(columnName)
                        .append(" IS '").append(comment).append("';\n");
            });
        }

        // 打印 SQL 语句
        Console.log(sql);
        return sql.toString();
    }

    // 辅助方法:将驼峰命名转换为下划线命名
    private static String convertToUnderscore(String camelCase) {
        StringBuilder result = new StringBuilder();
        for (char c : camelCase.toCharArray()) {
            if (Character.isUpperCase(c)) {
                result.append('_').append(Character.toLowerCase(c));
            } else {
                result.append(c);
            }
        }
        return result.toString();
    }

    // 执行调用方法
    public static void main(String[] args) {
        createTableSql(SysPaymentInfo.class);
    }
}

运行结果
Springboot 3.0.0基于swagger3.0的根据实体类建表SQL语句(postgresql系类数据库)-LMLPHP
实体案例
Springboot 3.0.0基于swagger3.0的根据实体类建表SQL语句(postgresql系类数据库)-LMLPHP

08-07 07:09