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

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

根据Navicate的数据库定义语句DDL生成实体类、Service层、Controller层和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.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

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

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

    /**
     * String
     */
    private static final String STRING_TYPE = "java.lang.String";

    /**
     * 空字符串,主要用于生成实体类代码时调整格式用
     */
    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<>();

    /**
     * package路径
     */
    private static String packagePath = "xxx";

    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");
        // 二进制类型(二进制对应是否正确待确定)
        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);
        generateXmlMapper(tableInfo);
        generateMapper(tableInfo);
        generateService(tableInfo);
        generateServiceImpl(tableInfo);
        generateController(tableInfo);
    }

    /**
     * 生成MyBatis的XML文件
     *
     * @param tableInfo 表信息
     */
    private static void generateXmlMapper(TableInfo tableInfo) {
        List<String> xml = new ArrayList<>();
        xml.add("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        xml.add("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">");
        xml.add(String.format("<mapper namespace=\"%s.mapper.%s\">", packagePath, tableInfo.getMapperName()));
        xml.addAll(generateInsert(tableInfo));
        xml.addAll(generateBatchInsert(tableInfo));
        xml.addAll(generateUpdate(tableInfo));
        xml.addAll(generateDelete(tableInfo));
        xml.addAll(generateGet(tableInfo));
        xml.addAll(generateCount(tableInfo));
        xml.addAll(generateList(tableInfo));
        xml.addAll(generateResultMap(tableInfo));
        xml.add("</mapper>");
        printCode(xml, tableInfo.getMapperName() + " XML");
    }

    /**
     * 生成MyBatis的resultMap代码
     *
     * @param tableInfo 表信息
     * @return
     */
    private static List<String> generateResultMap(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("    <resultMap id=\"%sResultMap\" type=\"%s.entity.%s\">",
                caseFirstLetterToLower(tableInfo.getVariableNamePrefix()), packagePath, tableInfo.getEntityName()));
        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>");
        return codes;
    }

    /**
     * 生成MyBatis的list代码
     *
     * @param tableInfo 表信息
     * @return
     */
    private static List<String> generateList(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("    <select id=\"list\" resultType=\"%s.entity.%s\">", packagePath,
                tableInfo.getEntityName()));
        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>");
        for (int index = 0; index < properties.size(); index++) {
            Property property = properties.get(index);
            codes.add(String.format("            <if test=\"param.%s != null\">", property.getProperty()));
            if (STRING_TYPE.equals(property.getJavaType())) {
                codes.add(String.format("                AND `%s` like CONCAT(\"%%\", #{param.%s}, \"%%\")",
                        property.getColumn(),
                        property.getProperty()));
            } else {
                codes.add(String.format("                AND `%s` = #{param.%s}", property.getColumn(), property.getProperty()));
            }
            codes.add(String.format("            </if>"));
        }
        codes.add("        </where>");
        codes.add("        LIMIT #{pageStart}, #{pageSize}");
        codes.add("    </select>");
        codes.add(SPACE);
        return codes;
    }

    /**
     * 生成MyBatis的Count代码
     *
     * @param tableInfo 表信息
     * @return
     */
    private static List<String> generateCount(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add("    <select id=\"count\" resultType=\"java.lang.Long\">");
        codes.add(String.format("        SELECT COUNT(*) FROM `%s`", tableInfo.getJdbcTableName()));
        List<Property> properties = tableInfo.getProperties();
        codes.add("        <where>");
        for (int index = 0; index < properties.size(); index++) {
            Property property = properties.get(index);
            codes.add(String.format("            <if test=\"param.%s != null\">", property.getProperty()));
            if (STRING_TYPE.equals(property.getJavaType())) {
                codes.add(String.format("                AND `%s` like CONCAT(\"%%\", #{param.%s}, \"%%\")",
                        property.getColumn(),
                        property.getProperty()));
            } else {
                codes.add(String.format("                AND `%s` = #{param.%s}", property.getColumn(), property.getProperty()));
            }
            codes.add(String.format("            </if>"));
        }
        codes.add("        </where>");
        codes.add("    </select>");
        codes.add(SPACE);
        return codes;
    }

    /**
     * 生成MyBatis的get代码
     *
     * @param tableInfo 表信息
     * @return
     */
    private static List<String> generateGet(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("    <select id=\"get\" resultType=\"%s.entity.%s\">", packagePath,
                tableInfo.getEntityName()));
        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>");
        for (int index = 0; index < properties.size(); index++) {
            Property property = properties.get(index);
            codes.add(String.format("            <if test=\"param.%s != null\">", property.getProperty()));
            if (STRING_TYPE.equals(property.getJavaType())) {
                codes.add(String.format("                AND `%s` like CONCAT(\"%%\", #{param.%s}, \"%%\")",
                        property.getColumn(),
                        property.getProperty()));
            } else {
                codes.add(String.format("                AND `%s` = #{param.%s}", property.getColumn(), property.getProperty()));
            }
            codes.add(String.format("            </if>"));
        }
        codes.add("        </where>");
        codes.add("        LIMIT 1");
        codes.add("    </select>");
        codes.add(SPACE);
        return codes;
    }

    /**
     * 生成MyBatis的delete代码
     *
     * @param tableInfo 表信息
     * @return
     */
    private static List<String> generateDelete(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("    <delete id=\"delete\" parameterType=\"%s.entity.%s\">",
                packagePath, tableInfo.getEntityName()));
        codes.add(String.format("        DELETE FROM `%s`", tableInfo.getJdbcTableName()));
        codes.add("        WHERE `id` = #{id} <!--todo modify condition>-->");
        codes.add("    </delete>");
        codes.add(SPACE);
        return codes;
    }

    /**
     * 生成MyBatis的update代码
     *
     * @param tableInfo 表信息
     * @return
     */
    private static List<String> generateUpdate(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("    <update id=\"update\" parameterType=\"%s.entity.%s\">",
                packagePath, tableInfo.getEntityName()));
        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>");
        codes.add(SPACE);
        return codes;
    }

    /**
     * 生成MyBatis的batchInsert代码
     *
     * @param tableInfo 表信息
     * @return
     */
    private static List<String> generateBatchInsert(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("    <insert id=\"batchInsert\" parameterType=\"%s.entity.%s\">",
                packagePath, tableInfo.getEntityName()));
        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>");
        codes.add(SPACE);
        return codes;
    }

    /**
     * 生成MyBatis的insert代码
     *
     * @param tableInfo 表信息
     * @return
     */
    private static List<String> generateInsert(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("    <insert id=\"insert\" parameterType=\"%s.entity.%s\">",
                packagePath, tableInfo.getEntityName()));
        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 (");
        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("    </insert>");
        codes.add(SPACE);
        return codes;
    }

    /**
     * 生成java实体类代码
     *
     * @param tableInfo 表信息
     */
    private static void generateEntity(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("package %s.entity;", packagePath));
        codes.add(SPACE);
        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.getEntityName()));
        Set<String> imported = new HashSet<>();
        for (Property property : tableInfo.getProperties()) {
            String javaType = property.getJavaType();
            if (!javaType.startsWith(DEFAULT_IMPORT) && !imported.contains(javaType)) {
                codes.add(2, String.format("import %s;", javaType));
                imported.add(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 (!imported.isEmpty()) {
            codes.add(imported.size() + 2, SPACE);
        }
        if (SPACE.equals(codes.get(codes.size() - 1))) {
            codes.remove(codes.size() - 1);
        }
        codes.add("}");
        printCode(codes, tableInfo.getEntityName());
    }

    /**
     * 生成Controller代码
     *
     * @param tableInfo 表信息
     */
    private static void generateController(TableInfo tableInfo) {
        String serviceVar = caseFirstLetterToLower(tableInfo.getServiceName());
        List<String> codes = new ArrayList<>();
        codes.add(String.format("package %s.controller;", packagePath));
        codes.add(SPACE);
        codes.add(String.format("import %s.entity.%s;", packagePath, tableInfo.getEntityName()));
        codes.add(String.format("import %s.service.%s;", packagePath, tableInfo.getServiceName()));
        codes.add("import org.springframework.beans.factory.annotation.Autowired;");
        codes.add("import org.springframework.web.bind.annotation.GetMapping;");
        codes.add("import org.springframework.web.bind.annotation.PostMapping;");
        codes.add("import org.springframework.web.bind.annotation.RequestBody;");
        codes.add("import org.springframework.web.bind.annotation.RequestMapping;");
        codes.add("import org.springframework.web.bind.annotation.RequestParam;");
        codes.add("import org.springframework.web.bind.annotation.RestController;");
        codes.add(SPACE);
        codes.add("import java.util.List;");
        codes.add(SPACE);
        codes.add(String.format("/**" + LINE_SEPARATOR +
                " * %s" + LINE_SEPARATOR +
                " *" + LINE_SEPARATOR +
                " * @author auto" + LINE_SEPARATOR +
                " * @since %s" + LINE_SEPARATOR +
                " */", tableInfo.getControllerName(), FORMATTER.format(LocalDateTime.now())));
        codes.add("@RestController");
        codes.add(String.format("@RequestMapping(\"/%s\")", tableInfo.getJdbcTableName()));
        codes.add(String.format("public class %s {", tableInfo.getControllerName()));
        codes.add("    @Autowired");
        codes.add(String.format("    private %s %s;", tableInfo.getServiceName(), serviceVar));

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 保存单条数据" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param body 数据" + LINE_SEPARATOR +
                "     */");
        codes.add("    @PostMapping(\"/save\")");
        codes.add(String.format("    public void save(@RequestBody %s body) {", tableInfo.getEntityName()));
        codes.add(String.format("        %s.save(body);", serviceVar));
        codes.add("    }");

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 批量保存数据" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param list 多条数据" + LINE_SEPARATOR +
                "     */");
        codes.add("    @PostMapping(\"/batchSave\")");
        codes.add(String.format("    public void batchSave(@RequestBody List<%s> list) {", tableInfo.getEntityName()));
        codes.add(String.format("        %s.batchSave(list);", serviceVar));
        codes.add("    }");

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 更新数据" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param body 单条数据" + LINE_SEPARATOR +
                "     */");
        codes.add("    @PostMapping(\"/update\")");
        codes.add(String.format("    public void update(@RequestBody %s body) {", tableInfo.getEntityName()));
        codes.add(String.format("        %s.update(body);", serviceVar));
        codes.add("    }");

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 根据id删除数据" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param id id" + LINE_SEPARATOR +
                "     */");
        codes.add("    @GetMapping(\"/delete\")");
        codes.add("    public void delete(@RequestParam(value = \"id\") Integer id) {");
        codes.add(String.format("        %s.delete(id);", serviceVar));
        codes.add("    }");

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 单条查询" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param params 查询参数" + LINE_SEPARATOR +
                "     * @return 查询结果" + LINE_SEPARATOR +
                "     */");
        codes.add("    @GetMapping(\"/get\")");
        codes.add(String.format("    public %s get(%s params) {", tableInfo.getEntityName(), tableInfo.getEntityName()));
        codes.add(String.format("        return %s.get(params);", serviceVar));
        codes.add("    }");

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 批量查询" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param params    查询参数" + LINE_SEPARATOR +
                "     * @param pageIndex 页码" + LINE_SEPARATOR +
                "     * @param pageSize  页面大小" + LINE_SEPARATOR +
                "     * @return 查询结果" + LINE_SEPARATOR +
                "     */");
        codes.add("    @GetMapping(\"/list\")");
        codes.add(String.format("    public List<%s> list(%s params,", tableInfo.getEntityName(),
                tableInfo.getEntityName()));
        String formatSpace = generateFormatSpace(codes.get(codes.size() - 1));
        codes.add(formatSpace.concat("@RequestParam(required = false, name = \"pageIndex\", defaultValue = \"1\") Integer pageIndex,"));
        codes.add(formatSpace.concat("@RequestParam(required = false, name = \"pageSize\", defaultValue = \"10\") Integer pageSize) {"));
        codes.add(String.format("        return %s.list(params, pageIndex, pageSize);", serviceVar));
        codes.add("    }");

        codes.add("}");
        printCode(codes, tableInfo.getControllerName());
    }

    /**
     * 生成对应的格式化空格
     *
     * @param methodCode 方法定义代码
     * @return 格式化空格
     */
    private static String generateFormatSpace(String methodCode) {
        int indexOf = methodCode.indexOf("(");
        if (indexOf == -1) {
            return SPACE;
        }
        StringBuilder sb = new StringBuilder();
        while (indexOf-- >= 0) {
            sb.append(" ");
        }
        return sb.toString();
    }

    /**
     * 生成ServiceImpl代码
     *
     * @param tableInfo 表信息
     */
    private static void generateServiceImpl(TableInfo tableInfo) {
        String mapperVar = caseFirstLetterToLower(tableInfo.getMapperName());
        List<String> codes = new ArrayList<>();
        codes.add(String.format("package %s.service.impl;", packagePath));
        codes.add(SPACE);
        codes.add(String.format("import %s.entity.%s;", packagePath, tableInfo.getEntityName()));
        codes.add(String.format("import %s.mapper.%s;", packagePath, tableInfo.getMapperName()));
        codes.add(String.format("import %s.service.%s;", packagePath, tableInfo.getServiceName()));
        codes.add("import org.springframework.beans.factory.annotation.Autowired;");
        codes.add("import org.springframework.stereotype.Service;");
        codes.add(SPACE);
        codes.add("import java.util.List;");
        codes.add(SPACE);
        codes.add(String.format("/**" + LINE_SEPARATOR +
                " * %s" + LINE_SEPARATOR +
                " *" + LINE_SEPARATOR +
                " * @author auto" + LINE_SEPARATOR +
                " * @since %s" + LINE_SEPARATOR +
                " */", tableInfo.getServiceImplName(), FORMATTER.format(LocalDateTime.now())));
        codes.add("@Service");
        codes.add(String.format("public class %s implements %s {", tableInfo.getServiceImplName(), tableInfo.getServiceName()));
        codes.add("    @Autowired");
        codes.add(String.format("    private %s %s;", tableInfo.getMapperName(), mapperVar));

        codes.add(SPACE);
        codes.add("    @Override");
        codes.add(String.format("    public void save(%s item) {" + LINE_SEPARATOR +
                "        %s.insert(item);" + LINE_SEPARATOR +
                "    }", tableInfo.getEntityName(), mapperVar));

        codes.add(SPACE);
        codes.add("    @Override");
        codes.add(String.format("    public void batchSave(List<%s> list) {" + LINE_SEPARATOR +
                "        %s.batchInsert(list);" + LINE_SEPARATOR +
                "    }", tableInfo.getEntityName(), mapperVar));

        codes.add(SPACE);
        codes.add("    @Override");
        codes.add(String.format("    public void update(%s item) {" + LINE_SEPARATOR +
                "        %s.update(item);" + LINE_SEPARATOR +
                "    }", tableInfo.getEntityName(), mapperVar));

        codes.add(SPACE);
        codes.add("    @Override");
        codes.add(String.format("    public void delete(Integer id) {" + LINE_SEPARATOR +
                "        %s.delete(id);" + LINE_SEPARATOR +
                "    }", mapperVar));

        codes.add(SPACE);
        codes.add("    @Override");
        codes.add(String.format("    public %s get(%s param) {" + LINE_SEPARATOR +
                "        return %s.get(param);" + LINE_SEPARATOR +
                "    }", tableInfo.getEntityName(), tableInfo.getEntityName(), mapperVar));

        codes.add(SPACE);
        codes.add("    @Override");
        codes.add(String.format("    public List<%s> list(%s param, Integer pageIndex, Integer pageSize) {" + LINE_SEPARATOR +
                "        return %s.list(param, (pageIndex - 1) * pageSize, pageSize);" + LINE_SEPARATOR +
                "    }", tableInfo.getEntityName(), tableInfo.getEntityName(), mapperVar));

        codes.add("}");
        printCode(codes, tableInfo.getServiceImplName());
    }

    /**
     * 生成Service代码
     *
     * @param tableInfo 表信息
     */
    private static void generateService(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("package %s.service;", packagePath));
        codes.add(SPACE);
        codes.add(String.format("import %s.entity.%s;", packagePath, tableInfo.getEntityName()));
        codes.add(SPACE);
        codes.add("import java.util.List;");
        codes.add(SPACE);
        codes.add(String.format("/**" + LINE_SEPARATOR +
                " * %s" + LINE_SEPARATOR +
                " *" + LINE_SEPARATOR +
                " * @author auto" + LINE_SEPARATOR +
                " * @since %s" + LINE_SEPARATOR +
                " */", tableInfo.getServiceName(), FORMATTER.format(LocalDateTime.now())));
        codes.add(String.format("public interface %s {", tableInfo.getServiceName()));

        codes.add("    /**" + LINE_SEPARATOR +
                "     * 保存单条数据" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param item 数据" + LINE_SEPARATOR +
                "     */");
        codes.add(String.format("    void save(%s item);", tableInfo.getEntityName()));

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 批量保存数据" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param list 多条数据" + LINE_SEPARATOR +
                "     */");
        codes.add(String.format("    void batchSave(List<%s> list);", tableInfo.getEntityName()));

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 更新数据" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param item 单条数据" + LINE_SEPARATOR +
                "     */");
        codes.add(String.format("    void update(%s item);", tableInfo.getEntityName()));

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 根据id删除数据" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param id id" + LINE_SEPARATOR +
                "     */");
        codes.add(String.format("    void delete(Integer id);"));

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 单条查询" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param param 查询参数" + LINE_SEPARATOR +
                "     * @return 查询结果" + LINE_SEPARATOR +
                "     */");
        codes.add(String.format("    %s get(%s param);", tableInfo.getEntityName(), tableInfo.getEntityName()));

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 批量查询" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param param     查询参数" + LINE_SEPARATOR +
                "     * @param pageIndex 页码" + LINE_SEPARATOR +
                "     * @param pageSize  页面大小" + LINE_SEPARATOR +
                "     * @return 查询结果" + LINE_SEPARATOR +
                "     */");
        codes.add(String.format("    List<%s> list(%s param, Integer pageIndex, Integer pageSize);",
                tableInfo.getEntityName(), tableInfo.getEntityName()));

        codes.add("}");
        printCode(codes, tableInfo.getServiceName());
    }

    /**
     * 生成Mapper代码
     *
     * @param tableInfo 表信息
     */
    private static void generateMapper(TableInfo tableInfo) {
        List<String> codes = new ArrayList<>();
        codes.add(String.format("package %s.mapper;", packagePath));
        codes.add(SPACE);
        codes.add(String.format("import %s.entity.%s;", packagePath, tableInfo.getEntityName()));
        codes.add("import org.apache.ibatis.annotations.Mapper;");
        codes.add("import org.apache.ibatis.annotations.Param;");
        codes.add(SPACE);
        codes.add("import java.util.List;");
        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("@Mapper");
        codes.add(String.format("public interface %s {", tableInfo.getMapperName()));

        codes.add("    /**" + LINE_SEPARATOR +
                "     * 保存单条数据" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param item 数据" + LINE_SEPARATOR +
                "     */");
        codes.add(String.format("    void insert(@Param(\"item\") %s item);", tableInfo.getEntityName()));

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 批量保存数据" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param list 多条数据" + LINE_SEPARATOR +
                "     */");
        codes.add(String.format("    void batchInsert(@Param(\"list\") List<%s> list);", tableInfo.getEntityName()));

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 更新数据" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param item 单条数据" + LINE_SEPARATOR +
                "     */");
        codes.add(String.format("    void update(@Param(\"item\") %s item);", tableInfo.getEntityName()));

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 根据id删除数据" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param id id" + LINE_SEPARATOR +
                "     */");
        codes.add(String.format("    void delete(@Param(\"id\") Integer id);"));

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 单条查询" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param param 查询参数" + LINE_SEPARATOR +
                "     * @return 查询结果" + LINE_SEPARATOR +
                "     */");
        codes.add(String.format("    %s get(@Param(\"param\") %s param);", tableInfo.getEntityName(), tableInfo.getEntityName()));

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 查询记录总数" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param param 查询参数" + LINE_SEPARATOR +
                "     * @return 查询结果" + LINE_SEPARATOR +
                "     */");
        codes.add(String.format("    Long count(@Param(\"param\") %s param);", tableInfo.getEntityName()));

        codes.add(SPACE);
        codes.add("    /**" + LINE_SEPARATOR +
                "     * 批量查询" + LINE_SEPARATOR +
                "     *" + LINE_SEPARATOR +
                "     * @param param     查询参数" + LINE_SEPARATOR +
                "     * @param pageStart 当前页面起始索引" + LINE_SEPARATOR +
                "     * @param pageSize  页面大小" + LINE_SEPARATOR +
                "     * @return 查询结果" + LINE_SEPARATOR +
                "     */");
        codes.add(String.format("    List<%s> list(@Param(\"param\") %s param, @Param(\"pageStart\") " +
                "Integer pageStart, @Param(\"pageSize\") Integer pageSize);", tableInfo.getEntityName(), tableInfo.getEntityName()));

        codes.add("}");
        printCode(codes, tableInfo.getMapperName());
    }

    /**
     * 打印生成的代码
     *
     * @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")) {
                setClassName(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 setClassName(TableInfo tableInfo, String line) {
        int start = line.indexOf("`") + 1;
        String jdbcTableName = line.substring(start, line.indexOf("`", start));
        String camel = underLineToCamel(jdbcTableName);
        String classNamePrefix = caseFirstLetterToUpper(camel);
        tableInfo.setJdbcTableName(jdbcTableName);
        tableInfo.setVariableNamePrefix(classNamePrefix);
        tableInfo.setEntityName(classNamePrefix + "Entity");
        tableInfo.setMapperName(classNamePrefix + "Mapper");
        tableInfo.setServiceName(classNamePrefix + "Service");
        tableInfo.setServiceImplName(classNamePrefix + "ServiceImpl");
        tableInfo.setControllerName(classNamePrefix + "Controller");
    }

    /**
     * 下划线转小驼峰
     *
     * @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.toUpperCase(Locale.ROOT);
        }
        char letter = word.charAt(0);
        if (letter <= 'Z') {
            return word;
        }
        char upperLetter = (char) (letter - ('a' - 'A'));
        return upperLetter + word.substring(1);
    }

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

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

        /**
         * 变量名前缀(表名转小驼峰)
         */
        private String variableNamePrefix;

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

        /**
         * mapper类类名
         */
        private String mapperName;

        /**
         * service类类名
         */
        private String serviceName;

        /**
         * service实现类类类名
         */
        private String serviceImplName;

        /**
         * controller类类名
         */
        private String controllerName;

        /**
         * 类属性(表字段)集合
         */
        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 `person_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` varchar(255) COMMENT '证件照',\n" +
                "  PRIMARY KEY (`id`)\n" +
                ") ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;";
        packagePath = "com.example.study";
        generateCode(ddl);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值