根据数据库定义语句DDL生成实体类和Mybatis增删改查代码

这段代码展示了如何根据数据库定义语句(DDL)生成Java实体类以及Mybatis的增、删、改、查(CRUD)操作代码。通过解析DDL,创建了数据库字段与Java类型、JDBC类型的映射,并提供了生成实体类、ResultMap、SELECT、DELETE、UPDATE和INSERT的方法。
摘要由CSDN通过智能技术生成

根据Navicate的数据库定义语句DDL生成实体类和Mybatis增删改查代码输出到控制台。


代码如下:

import lombok.Getter;
import lombok.Setter;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

/**
 * 根据数据库定义语句DDL生成实体类和Mybatis增删改查代码
 *
 * @author java_t_t
 * @since 2023-04-22
 */
public class UseDDLGenerateCode {
    /**
     * 换行符
     */
    private static final String LINE_SEPARATOR = "\n";

    /**
     * java默认import为:import java.lang.*
     */
    private static final String DEFAULT_IMPORT = "java.lang.";

    /**
     * 空字符串,主要用于生成实体类代码时调整格式用
     */
    private static final String SPACE = "";

    /**
     * 年月日格式化器
     */
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    /**
     * jdbc类型与java数据类型的映射
     */
    private static final Map<String, String> JDBC_JAVA_TYPE_MAP = new HashMap<>();
    /**
     * MySQL数据类型与jdbc数据类型的映射
     */
    private static final Map<String, String> DB_JDBC_TYPE_MAP = new HashMap<>();

    static {
        // ====================jdbc与java type映射====================
        // 数值类型
        JDBC_JAVA_TYPE_MAP.put("TINYINT", "java.lang.Integer");
        JDBC_JAVA_TYPE_MAP.put("SMALLINT", "java.lang.Integer");
        JDBC_JAVA_TYPE_MAP.put("MEDIUMINT", "java.lang.Integer");
        JDBC_JAVA_TYPE_MAP.put("INT", "java.lang.Integer");
        JDBC_JAVA_TYPE_MAP.put("INTEGER", "java.lang.Integer");
        JDBC_JAVA_TYPE_MAP.put("BIGINT", "java.lang.Long");
        JDBC_JAVA_TYPE_MAP.put("FLOAT", "java.lang.Float");
        JDBC_JAVA_TYPE_MAP.put("DOUBLE", "java.lang.Double");
        JDBC_JAVA_TYPE_MAP.put("DECIMAL", "java.math.BigDecimal");
        // 字符串类型
        JDBC_JAVA_TYPE_MAP.put("CHAR", "java.lang.String");
        JDBC_JAVA_TYPE_MAP.put("VARCHAR", "java.lang.String");
        JDBC_JAVA_TYPE_MAP.put("TINYTEXT", "java.lang.String");
        JDBC_JAVA_TYPE_MAP.put("TEXT", "java.lang.String");
        JDBC_JAVA_TYPE_MAP.put("MEDIUMTEXT", "java.lang.String");
        JDBC_JAVA_TYPE_MAP.put("LONGTEXT", "java.lang.String");
        JDBC_JAVA_TYPE_MAP.put("ENUM", "java.lang.String");
        JDBC_JAVA_TYPE_MAP.put("SET", "java.lang.String");
        // 时间类型
        JDBC_JAVA_TYPE_MAP.put("YEAR", "java.time.Year");
        JDBC_JAVA_TYPE_MAP.put("DATE", "java.time.LocalDate");
        JDBC_JAVA_TYPE_MAP.put("TIME", "java.time.LocalTime");
        JDBC_JAVA_TYPE_MAP.put("DATETIME", "java.time.LocalDateTime");
        JDBC_JAVA_TYPE_MAP.put("TIMESTAMP", "java.time.LocalDateTime");
        // 二进制类型(二进制不知道该使用什么类型去接收,下面代码注释掉,仅作为MySQL数据类型的参考)
        /*JDBC_JAVA_TYPE_MAP.put("BIT", "java.lang.Byte[]");
        JDBC_JAVA_TYPE_MAP.put("BINARY", "java.lang.Byte[]");
        JDBC_JAVA_TYPE_MAP.put("VARBINARY", "java.lang.Byte[]");
        JDBC_JAVA_TYPE_MAP.put("TINYBLOB", "java.lang.Byte[]");
        JDBC_JAVA_TYPE_MAP.put("BLOB", "java.lang.Byte[]");
        JDBC_JAVA_TYPE_MAP.put("MEDIUMBLOB", "java.lang.Byte[]");
        JDBC_JAVA_TYPE_MAP.put("LONGBLOB", "java.lang.Byte[]");*/

        // ====================数据库字段类型与jdbc type映射====================
        // 数值类型
        DB_JDBC_TYPE_MAP.put("tinyint", "TINYINT");
        DB_JDBC_TYPE_MAP.put("smallint", "SMALLINT");
        DB_JDBC_TYPE_MAP.put("mediumint", "INTEGER");
        DB_JDBC_TYPE_MAP.put("int", "INTEGER");
        DB_JDBC_TYPE_MAP.put("integer", "INTEGER");
        DB_JDBC_TYPE_MAP.put("bigint", "BIGINT");
        DB_JDBC_TYPE_MAP.put("float", "FLOAT");
        DB_JDBC_TYPE_MAP.put("double", "DOUBLE");
        DB_JDBC_TYPE_MAP.put("decimal", "DECIMAL");
        // 字符串类型
        DB_JDBC_TYPE_MAP.put("char", "CHAR");
        DB_JDBC_TYPE_MAP.put("varchar", "VARCHAR");
        DB_JDBC_TYPE_MAP.put("tinytext", "VARCHAR");
        DB_JDBC_TYPE_MAP.put("text", "VARCHAR");
        DB_JDBC_TYPE_MAP.put("mediumtext", "VARCHAR");
        DB_JDBC_TYPE_MAP.put("longtext", "VARCHAR");
        DB_JDBC_TYPE_MAP.put("enum", "VARCHAR");
        DB_JDBC_TYPE_MAP.put("set", "VARCHAR");
        // 时间类型
        DB_JDBC_TYPE_MAP.put("year", "DATE");
        DB_JDBC_TYPE_MAP.put("date", "DATE");
        DB_JDBC_TYPE_MAP.put("time", "TIME");
        DB_JDBC_TYPE_MAP.put("datetime", "TIMESTAMP");
        DB_JDBC_TYPE_MAP.put("timestamp", "TIMESTAMP");
        // 二进制类型
        DB_JDBC_TYPE_MAP.put("bit", "BIT");
        DB_JDBC_TYPE_MAP.put("binary", "BINARY");
        DB_JDBC_TYPE_MAP.put("varbinary", "VARBINARY");
        DB_JDBC_TYPE_MAP.put("tinyblob", "BLOB");
        DB_JDBC_TYPE_MAP.put("blob", "BLOB");
        DB_JDBC_TYPE_MAP.put("mediumblob", "BLOB");
        DB_JDBC_TYPE_MAP.put("longblob", "BLOB");
    }

    /**
     * 根据数据库定义语句DDL生成实体类和Mybatis增删改查代码
     *
     * @param ddl DDL语句(DDL从navicate复制出来,其它手写的格式不一定支持)
     * @return 解析后的表信息
     */
    public static void generateCode(String ddl) {
        TableInfo tableInfo = parseDDL(ddl);
        generateEntity(tableInfo);
        generateInsert(tableInfo);
        generateUpdate(tableInfo);
        generateDelete(tableInfo);
        generateSelect(tableInfo);
        generateResultMap(tableInfo);
    }

    /**
     * 生成Mybatis的resultMap代码
     *
     * @param tableInfo 表信息
     */
    private static void generateResultMap(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("    <resultMap id=\"%sResultMap\" type=\"xxx.%s\">",
                tableInfo.getJavaTableName(), tableInfo.getJavaTableName()));
        List<Property> properties = tableInfo.getProperties();
        for (int index = 0; index < properties.size(); index++) {
            Property property = properties.get(index);
            codes.add(String.format("        <result column=\"%s\" property=\"%s\" jdbcType=\"%s\" javaType=\"%s\"/>",
                    property.getColumn(), property.getProperty(), property.getJdbcType(), property.getJavaType()));
        }
        codes.add("    </resultMap>");
        printCode(codes, "ResultMap");
    }

    /**
     * 生成Mybatis的select代码
     *
     * @param tableInfo 表信息
     */
    private static void generateSelect(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("    <select id=\"select\" resultType=\"xxx.%s\">", tableInfo.getJavaTableName()));
        codes.add("        SELECT");
        List<Property> properties = tableInfo.getProperties();
        for (int index = 0; index < properties.size(); index++) {
            Property property = properties.get(index);
            if (index < properties.size() - 1) {
                codes.add(String.format("            `%s` as `%s`,", property.getColumn(), property.getProperty()));
            } else {
                codes.add(String.format("            `%s` as `%s`", property.getColumn(), property.getProperty()));
            }
        }
        codes.add(String.format("        FROM `%s`", tableInfo.getJdbcTableName()));
        codes.add("        WHERE <!--todo add condition>-->");
        codes.add("    </select>");
        printCode(codes, "Select");
    }

    /**
     * 生成Mybatis的delete代码
     *
     * @param tableInfo 表信息
     */
    private static void generateDelete(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("    <delete id=\"delete\" parameterType=\"xxx.%s\">", tableInfo.getJavaTableName()));
        codes.add(String.format("        DELETE FROM `%s`", tableInfo.getJdbcTableName()));
        codes.add("        WHERE <!--todo add condition>-->");
        codes.add("    </delete>");
        printCode(codes, "Delete");
    }

    /**
     * 生成Mybatis的update代码
     *
     * @param tableInfo 表信息
     */
    private static void generateUpdate(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("    <update id=\"update\" parameterType=\"xxx.%s\">", tableInfo.getJavaTableName()));
        codes.add(String.format("        UPDATE `%s` SET", tableInfo.getJdbcTableName()));
        List<Property> properties = tableInfo.getProperties();
        for (int index = 0; index < properties.size(); index++) {
            Property property = properties.get(index);
            if (index < properties.size() - 1) {
                codes.add(String.format("        `%s` = #{item.%s},", property.getColumn(), property.getProperty()));
            } else {
                codes.add(String.format("        `%s` = #{item.%s}", property.getColumn(), property.getProperty()));
            }
        }
        codes.add("        WHERE <!--todo add condition>-->");
        codes.add("    </update>");
        printCode(codes, "Update");
    }

    /**
     * 生成Mybatis的insert代码
     *
     * @param tableInfo 表信息
     */
    private static void generateInsert(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("    <insert id=\"insert\" parameterType=\"xxx.%s\">", tableInfo.getJavaTableName()));
        codes.add(String.format("        INSERT INTO `%s`(", tableInfo.getJdbcTableName()));
        List<Property> properties = tableInfo.getProperties();
        for (int index = 0; index < properties.size(); index++) {
            Property property = properties.get(index);
            if (index < properties.size() - 1) {
                codes.add(String.format("        `%s`,", property.getColumn()));
            } else {
                codes.add(String.format("        `%s`", property.getColumn()));
            }
        }
        codes.add("        ) VALUES");
        codes.add("        <foreach collection=\"list\" open=\"(\" separator=\"),(\" close=\")\" item=\"item\">");
        for (int index = 0; index < properties.size(); index++) {
            Property property = properties.get(index);
            if (index < properties.size() - 1) {
                codes.add(String.format("            #{item.%s},", property.getProperty()));
            } else {
                codes.add(String.format("            #{item.%s}", property.getProperty()));
            }
        }
        codes.add("        </foreach>");
        codes.add("    </insert>");
        printCode(codes, "Insert");
    }

    /**
     * 生成java实体类代码
     *
     * @param tableInfo 表信息
     */
    private static void generateEntity(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add("import lombok.Getter;");
        codes.add("import lombok.Setter;");
        codes.add(SPACE);
        codes.add(String.format("/**" + LINE_SEPARATOR +
                " * %s" + LINE_SEPARATOR +
                " *" + LINE_SEPARATOR +
                " * @author auto" + LINE_SEPARATOR +
                " * @since %s" + LINE_SEPARATOR +
                " */", tableInfo.getJdbcTableName(), FORMATTER.format(LocalDateTime.now())));
        codes.add("@Setter");
        codes.add("@Getter");
        codes.add(String.format("public class %s {", tableInfo.getJavaTableName()));
        for (Property property : tableInfo.getProperties()) {
            String javaType = property.getJavaType();
            if (!javaType.startsWith(DEFAULT_IMPORT)) {
                codes.add(0, String.format("import %s;", javaType));
            }
            javaType = javaType.substring(javaType.lastIndexOf(".") + 1);
            String comment = (property.getComment() == null || property.getComment().isEmpty())
                    ? property.getColumn() : property.getComment();
            String field = String.format("    /**" + LINE_SEPARATOR +
                    "     * %s" + LINE_SEPARATOR +
                    "     */" + LINE_SEPARATOR +
                    "    private %s %s;", comment, javaType, property.getProperty());
            codes.add(field);
            codes.add(SPACE);
        }
        if (SPACE.equals(codes.get(codes.size() - 1))) {
            codes.remove(codes.size() - 1);
        }
        codes.add("}");
        printCode(codes, "Entity Code");
    }

    /**
     * 打印生成的代码
     *
     * @param codes 代码
     * @param type  生成代码类型
     */
    private static void printCode(List<String> codes, String type) {
        System.out.println("====================" + type + "====================");
        System.out.println(String.join(LINE_SEPARATOR, codes));
    }

    /**
     * 解析数据库定义语句DDL
     *
     * @param ddl DDL语句(DDL从navicate复制出来,其它手写的格式不一定支持)
     * @return 解析后的表信息
     */
    private static TableInfo parseDDL(String ddl) {
        TableInfo tableInfo = new TableInfo();
        List<Property> properties = new ArrayList<>();
        String[] lines = ddl.split(LINE_SEPARATOR);
        for (String line : lines) {
            if (line == null || line.trim().isEmpty()) {
                continue;
            }
            line = line.trim().toLowerCase(Locale.ROOT);
            if (line.contains("create table")) {
                setTableName(tableInfo, line);
            } else {
                Property property = parseProperty(line);
                if (property == null) {
                    continue;
                }
                properties.add(property);
            }
        }
        tableInfo.setProperties(properties);
        return tableInfo;
    }

    /**
     * 解析表字段(类属性)
     *
     * @param line 表字段
     * @return 类属性(表字段)信息
     */
    private static Property parseProperty(String line) {
        if (!line.startsWith("`")) {
            return null;
        }
        String[] split = line.split(" ");
        Property property = new Property();
        for (int index = 0; index < split.length; index++) {
            String str = split[index];
            if (index == 0) {
                String column = str.substring(1, str.length() - 1);
                property.setColumn(column);
                property.setProperty(underLineToCamel(column));
                continue;
            }
            if (index == 1) {
                int endIndex = str.indexOf("(");
                String dbType = endIndex < 0 ? str : str.substring(0, endIndex);
                property.setDbType(dbType);
                property.setJdbcType(DB_JDBC_TYPE_MAP.getOrDefault(dbType, "UNKNOW"));
                property.setJavaType(JDBC_JAVA_TYPE_MAP.getOrDefault(property.getJdbcType(), "UNKNOW"));
                continue;
            }
            if ("comment".equals(str) && ++index < split.length) {
                String comment = split[index];
                comment = comment.substring(1, comment.length() - 2).trim();
                property.setComment(comment);
            }
        }
        return property;
    }

    /**
     * 设置表名信息,包括数据库表名和对应的实体类类名
     *
     * @param tableInfo 表信息
     * @param line      建表语句的CREATE TABLE所在行
     */
    private static void setTableName(TableInfo tableInfo, String line) {
        int start = line.indexOf("`") + 1;
        String jdbcTableName = line.substring(start, line.indexOf("`", start));
        String camel = underLineToCamel(jdbcTableName);
        String javaTableName = caseFirstLetterToUpper(camel) + "Entity";
        tableInfo.setJdbcTableName(jdbcTableName);
        tableInfo.setJavaTableName(javaTableName);
    }

    /**
     * 下划线转小驼峰
     *
     * @param underLine 下划线风格的变量名
     * @return 小驼峰风格的变量名
     */
    private static String underLineToCamel(String underLine) {
        StringBuilder camel = new StringBuilder();
        String[] words = underLine.split("_");
        for (int index = 0; index < words.length; index++) {
            String word = words[index];
            if (word.isEmpty()) {
                continue;
            }
            camel.append(index == 0 ? word : caseFirstLetterToUpper(word));
        }
        return camel.toString();
    }

    /**
     * 首字母转大写
     *
     * @param word 单词
     * @return 首字母转大写的单词
     */
    private static String caseFirstLetterToUpper(String word) {
        if (word.isEmpty() || word.length() == 1) {
            return word.toLowerCase(Locale.ROOT);
        }
        char letter = word.charAt(0);
        char upperLetter = (char) (letter - ('a' - 'A'));
        return upperLetter + word.substring(1);
    }

    /**
     * 表信息
     */
    @Getter
    @Setter
    static class TableInfo {
        /**
         * 数据库表名
         */
        private String jdbcTableName;

        /**
         * 实体类类名
         */
        private String javaTableName;

        /**
         * 类属性(表字段)集合
         */
        private List<Property> properties;
    }

    /**
     * 类属性(表字段)
     */
    @Getter
    @Setter
    static class Property {
        /**
         * 表字段名
         */
        private String column;

        /**
         * 类属性名
         */
        private String property;

        /**
         * 数据库表字段类型
         */
        private String dbType;

        /**
         * jdbc类型
         */
        private String jdbcType;

        /**
         * 类属性数据类型
         */
        private String javaType;

        /**
         * 说明信息
         */
        private String comment;
    }

    public static void main(String[] args) {
        String ddl = "CREATE TABLE `student_info` (\n" +
                "  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',\n" +
                "  `name` varchar(255) NOT NULL COMMENT 'name''\"''',\n" +
                "  `sex` tinyint(1) NOT NULL COMMENT '性`别',\n" +
                "  `address` varchar(255) NOT NULL COMMENT '地址',\n" +
                "  `birthday` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '生日',\n" +
                "  `find_type` int(11) DEFAULT NULL COMMENT '测试下划线命名法',\n" +
                "  `picture` blob COMMENT '证件照',\n" +
                "  PRIMARY KEY (`id`)\n" +
                ") ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;";
        generateCode(ddl);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值