Java实现代码生成器案例

wen java案例 3

本文目录导读:

Java实现代码生成器案例

  1. 项目结构
  2. Maven依赖配置
  3. 数据模型类
  4. 数据库解析器
  5. 命名工具类
  6. 代码生成器核心
  7. 配置类
  8. Freemarker模板
  9. 启动类
  10. 高级特性扩展

我来提供一个完整的Java代码生成器实现案例,包含数据库表结构解析、模板渲染和代码生成功能。

项目结构

code-generator/
├── pom.xml
├── src/main/java/com/example/generator/
│   ├── GeneratorApplication.java
│   ├── config/
│   │   └── GeneratorConfig.java
│   ├── model/
│   │   ├── TableInfo.java
│   │   ├── ColumnInfo.java
│   │   └── GeneratorConfig.java
│   ├── parser/
│   │   └── DatabaseParser.java
│   ├── generator/
│   │   ├── CodeGenerator.java
│   │   └── TemplateEngine.java
│   └── utils/
│       └── NamingUtils.java
└── src/main/resources/
    ├── application.yml
    └── templates/
        ├── entity.ftl
        ├── mapper.ftl
        ├── service.ftl
        └── controller.ftl

Maven依赖配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>code-generator</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        <!-- MyBatis Plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>
        <!-- Freemarker模板引擎 -->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.32</version>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

数据模型类

// TableInfo.java
package com.example.generator.model;
import lombok.Data;
import java.util.List;
@Data
public class TableInfo {
    private String tableName;       // 表名
    private String entityName;      // 实体类名
    private String entityVariableName; // 实体变量名
    private String comment;         // 表注释
    private List<ColumnInfo> columns; // 列信息集合
}
// ColumnInfo.java
package com.example.generator.model;
import lombok.Data;
@Data
public class ColumnInfo {
    private String columnName;      // 列名
    private String dataType;        // JDBC类型
    private String columnComment;   // 列注释
    private boolean primaryKey;     // 是否主键
    private boolean autoIncrement;  // 是否自增
    private String javaProperty;    // Java属性名
    private String javaType;        // Java类型
    private String javaPackage;     // Java类型包名
    private boolean nullable;       // 是否可空
    private Integer columnSize;     // 列大小
    private Integer decimalDigits;  // 小数位数
}

数据库解析器

// DatabaseParser.java
package com.example.generator.parser;
import com.example.generator.model.ColumnInfo;
import com.example.generator.model.TableInfo;
import com.example.generator.utils.NamingUtils;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class DatabaseParser {
    private final String url;
    private final String username;
    private final String password;
    public DatabaseParser(String url, String username, String password) {
        this.url = url;
        this.username = username;
        this.password = password;
    }
    /**
     * 获取所有表信息
     */
    public List<TableInfo> getTables(String databaseName, String tablePrefix) throws SQLException {
        List<TableInfo> tables = new ArrayList<>();
        try (Connection conn = DriverManager.getConnection(url, username, password)) {
            DatabaseMetaData metaData = conn.getMetaData();
            // 获取表信息
            ResultSet rs = metaData.getTables(databaseName, null, tablePrefix + "%", 
                                              new String[]{"TABLE"});
            while (rs.next()) {
                String tableName = rs.getString("TABLE_NAME");
                String tableComment = rs.getString("REMARKS");
                TableInfo table = new TableInfo();
                table.setTableName(tableName);
                table.setComment(tableComment);
                table.setEntityName(NamingUtils.tableNameToClassName(tableName));
                table.setEntityVariableName(NamingUtils.tableNameToVariableName(tableName));
                // 获取列信息
                table.setColumns(getColumns(conn, databaseName, tableName));
                tables.add(table);
            }
        }
        return tables;
    }
    /**
     * 获取表的列信息
     */
    private List<ColumnInfo> getColumns(Connection conn, String databaseName, 
                                        String tableName) throws SQLException {
        List<ColumnInfo> columns = new ArrayList<>();
        DatabaseMetaData metaData = conn.getMetaData();
        // 获取主键信息
        ResultSet pkRs = metaData.getPrimaryKeys(databaseName, null, tableName);
        List<String> primaryKeys = new ArrayList<>();
        while (pkRs.next()) {
            primaryKeys.add(pkRs.getString("COLUMN_NAME"));
        }
        pkRs.close();
        // 获取列信息
        ResultSet rs = metaData.getColumns(databaseName, null, tableName, null);
        while (rs.next()) {
            ColumnInfo column = new ColumnInfo();
            column.setColumnName(rs.getString("COLUMN_NAME"));
            column.setDataType(rs.getString("TYPE_NAME"));
            column.setColumnComment(rs.getString("REMARKS"));
            column.setNullable(rs.getInt("NULLABLE") == DatabaseMetaData.columnNullable);
            column.setColumnSize(rs.getInt("COLUMN_SIZE"));
            column.setDecimalDigits(rs.getInt("DECIMAL_DIGITS"));
            column.setPrimaryKey(primaryKeys.contains(column.getColumnName()));
            column.setAutoIncrement("YES".equals(rs.getString("IS_AUTOINCREMENT")));
            // 转换为Java类型
            column.setJavaProperty(NamingUtils.columnNameToProperty(column.getColumnName()));
            SqlTypeConvertor.convert(column);
            columns.add(column);
        }
        rs.close();
        return columns;
    }
}
// SqlTypeConvertor.java - 类型转换器
package com.example.generator.parser;
import com.example.generator.model.ColumnInfo;
public class SqlTypeConvertor {
    public static void convert(ColumnInfo column) {
        String dataType = column.getDataType().toUpperCase();
        switch (dataType) {
            case "BIGINT":
            case "LONG":
                column.setJavaType("Long");
                column.setJavaPackage("java.lang");
                break;
            case "INT":
            case "INTEGER":
            case "MEDIUMINT":
                column.setJavaType("Integer");
                column.setJavaPackage("java.lang");
                break;
            case "SMALLINT":
            case "TINYINT":
                column.setJavaType("Integer");
                column.setJavaPackage("java.lang");
                break;
            case "VARCHAR":
            case "CHAR":
            case "TEXT":
            case "LONGTEXT":
            case "MEDIUMTEXT":
            case "TINYTEXT":
                column.setJavaType("String");
                column.setJavaPackage("java.lang");
                break;
            case "DATE":
            case "DATETIME":
            case "TIMESTAMP":
            case "TIME":
                column.setJavaType("Date");
                column.setJavaPackage("java.util");
                break;
            case "DECIMAL":
            case "NUMERIC":
                column.setJavaType("BigDecimal");
                column.setJavaPackage("java.math");
                break;
            case "DOUBLE":
            case "FLOAT":
                column.setJavaType("Double");
                column.setJavaPackage("java.lang");
                break;
            case "BOOLEAN":
            case "BIT":
                column.setJavaType("Boolean");
                column.setJavaPackage("java.lang");
                break;
            default:
                column.setJavaType("Object");
                column.setJavaPackage("java.lang");
                break;
        }
    }
}

命名工具类

// NamingUtils.java
package com.example.generator.utils;
public class NamingUtils {
    /**
     * 表名转类名 (user_info -> UserInfo)
     */
    public static String tableNameToClassName(String tableName) {
        StringBuilder result = new StringBuilder();
        boolean upper = true;
        for (char c : tableName.toCharArray()) {
            if (c == '_' || c == '-') {
                upper = true;
            } else if (upper) {
                result.append(Character.toUpperCase(c));
                upper = false;
            } else {
                result.append(c);
            }
        }
        return result.toString();
    }
    /**
     * 表名转变量名 (user_info -> userInfo)
     */
    public static String tableNameToVariableName(String tableName) {
        String className = tableNameToClassName(tableName);
        if (className.isEmpty()) {
            return className;
        }
        return Character.toLowerCase(className.charAt(0)) + className.substring(1);
    }
    /**
     * 列名转属性名 (user_name -> userName)
     */
    public static String columnNameToProperty(String columnName) {
        StringBuilder result = new StringBuilder();
        boolean upper = false;
        for (char c : columnName.toCharArray()) {
            if (c == '_' || c == '-') {
                upper = true;
            } else if (upper) {
                result.append(Character.toUpperCase(c));
                upper = false;
            } else {
                result.append(c);
            }
        }
        return result.toString();
    }
    /**
     * 首字母大写
     */
    public static String capitalize(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        return Character.toUpperCase(str.charAt(0)) + str.substring(1);
    }
    /**
     * 首字母小写
     */
    public static String decapitalize(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }
        return Character.toLowerCase(str.charAt(0)) + str.substring(1);
    }
    /**
     * 将属性名转为下划线命名
     */
    public static String propertyToUnderscore(String property) {
        StringBuilder result = new StringBuilder();
        for (char c : property.toCharArray()) {
            if (Character.isUpperCase(c)) {
                if (result.length() > 0) {
                    result.append('_');
                }
                result.append(Character.toLowerCase(c));
            } else {
                result.append(c);
            }
        }
        return result.toString();
    }
}

代码生成器核心

// CodeGenerator.java
package com.example.generator.generator;
import com.example.generator.model.TableInfo;
import com.example.generator.parser.DatabaseParser;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CodeGenerator {
    private final DatabaseParser databaseParser;
    private final Configuration configuration;
    private final GeneratorConfig config;
    public CodeGenerator(GeneratorConfig config) {
        this.config = config;
        this.databaseParser = new DatabaseParser(config.getUrl(), 
                                                  config.getUsername(), 
                                                  config.getPassword());
        this.configuration = initFreeMarker();
    }
    /**
     * 初始化FreeMarker配置
     */
    private Configuration initFreeMarker() {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
        cfg.setClassLoaderForTemplateLoading(getClass().getClassLoader(), 
                                             "templates");
        cfg.setDefaultEncoding("UTF-8");
        return cfg;
    }
    /**
     * 生成所有代码
     */
    public void generateAll() throws SQLException, IOException, TemplateException {
        List<TableInfo> tables = databaseParser.getTables(config.getDatabaseName(), 
                                                          config.getTablePrefix());
        for (TableInfo table : tables) {
            generateEntity(table);
            generateMapper(table);
            generateService(table);
            generateController(table);
            System.out.println("生成成功: " + table.getEntityName());
        }
    }
    /**
     * 生成实体类
     */
    private void generateEntity(TableInfo table) throws IOException, TemplateException {
        Map<String, Object> data = new HashMap<>();
        data.put("table", table);
        data.put("packageName", config.getEntityPackage());
        data.put("imports", getImports(table));
        Template template = configuration.getTemplate("entity.ftl");
        renderTemplate(template, data, config.getEntityPath(), 
                       table.getEntityName() + ".java");
    }
    /**
     * 生成Mapper接口
     */
    private void generateMapper(TableInfo table) throws IOException, TemplateException {
        Map<String, Object> data = new HashMap<>();
        data.put("table", table);
        data.put("packageName", config.getMapperPackage());
        data.put("entityPackage", config.getEntityPackage());
        Template template = configuration.getTemplate("mapper.ftl");
        renderTemplate(template, data, config.getMapperPath(), 
                       table.getEntityName() + "Mapper.java");
    }
    /**
     * 生成Service
     */
    private void generateService(TableInfo table) throws IOException, TemplateException {
        Map<String, Object> data = new HashMap<>();
        data.put("table", table);
        data.put("packageName", config.getServicePackage());
        data.put("entityPackage", config.getEntityPackage());
        data.put("mapperPackage", config.getMapperPackage());
        Template template = configuration.getTemplate("service.ftl");
        renderTemplate(template, data, config.getServicePath(), 
                       table.getEntityName() + "Service.java");
    }
    /**
     * 生成Controller
     */
    private void generateController(TableInfo table) throws IOException, TemplateException {
        Map<String, Object> data = new HashMap<>();
        data.put("table", table);
        data.put("packageName", config.getControllerPackage());
        data.put("entityPackage", config.getEntityPackage());
        data.put("servicePackage", config.getServicePackage());
        Template template = configuration.getTemplate("controller.ftl");
        renderTemplate(template, data, config.getControllerPath(), 
                       table.getEntityName() + "Controller.java");
    }
    /**
     * 渲染模板并输出文件
     */
    private void renderTemplate(Template template, Map<String, Object> data, 
                                String outputPath, String fileName) 
            throws IOException, TemplateException {
        File dir = new File(outputPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File outputFile = new File(dir, fileName);
        try (FileWriter writer = new FileWriter(outputFile)) {
            template.process(data, writer);
        }
    }
    /**
     * 获取实体类需要的import
     */
    private String getImports(TableInfo table) {
        StringBuilder imports = new StringBuilder();
        for (ColumnInfo column : table.getColumns()) {
            if (!"java.lang".equals(column.getJavaPackage())) {
                imports.append("import ").append(column.getJavaPackage())
                       .append(".").append(column.getJavaType()).append(";\n");
            }
        }
        return imports.toString();
    }
}

配置类

// GeneratorConfig.java
package com.example.generator.generator;
import lombok.Data;
@Data
public class GeneratorConfig {
    // 数据库配置
    private String url;
    private String username;
    private String password;
    private String databaseName;
    private String tablePrefix;
    // 包名配置
    private String entityPackage;
    private String mapperPackage;
    private String servicePackage;
    private String controllerPackage;
    // 输出路径配置
    private String entityPath;
    private String mapperPath;
    private String servicePath;
    private String controllerPath;
}

Freemarker模板

<!-- entity.ftl -->
package ${packageName};
import lombok.Data;
import com.baomidou.mybatisplus.annotation.*;
${imports}
/**
 * ${table.comment!''}实体类
 */
@Data
@TableName("${table.tableName}")
public class ${table.entityName} {
<#list table.columns as column>
    <#if column.comment?? && column.comment?length gt 0>
    /**
     * ${column.comment}
     */
    </#if>
    <#if column.primaryKey>
    @TableId(value = "${column.columnName}", type = IdType.AUTO)
    <#else>
    @TableField("${column.columnName}")
    </#if>
    private ${column.javaType} ${column.javaProperty};
</#list>
}
<!-- mapper.ftl -->
package ${packageName};
import ${entityPackage}.${table.entityName};
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
 * ${table.comment!''}Mapper接口
 */
@Mapper
public interface ${table.entityName}Mapper extends BaseMapper<${table.entityName}> {
}
<!-- service.ftl -->
package ${packageName};
import ${entityPackage}.${table.entityName};
import ${mapperPackage}.${table.entityName}Mapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
 * ${table.comment!''}Service实现类
 */
@Service
public class ${table.entityName}Service extends ServiceImpl<${table.entityName}Mapper, ${table.entityName}> {
}
<!-- controller.ftl -->
package ${packageName};
import ${entityPackage}.${table.entityName};
import ${servicePackage}.${table.entityName}Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
 * ${table.comment!''}控制器
 */
@RestController
@RequestMapping("/api/${table.entityVariableName}")
public class ${table.entityName}Controller {
    @Autowired
    private ${table.entityName}Service ${table.entityVariableName}Service;
    /**
     * 获取列表
     */
    @GetMapping("/list")
    public List<${table.entityName}> list() {
        return ${table.entityVariableName}Service.list();
    }
    /**
     * 获取详情
     */
    @GetMapping("/{id}")
    public ${table.entityName} getById(@PathVariable Long id) {
        return ${table.entityVariableName}Service.getById(id);
    }
    /**
     * 新增
     */
    @PostMapping
    public boolean save(@RequestBody ${table.entityName} entity) {
        return ${table.entityVariableName}Service.save(entity);
    }
    /**
     * 更新
     */
    @PutMapping
    public boolean update(@RequestBody ${table.entityName} entity) {
        return ${table.entityVariableName}Service.updateById(entity);
    }
    /**
     * 删除
     */
    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable Long id) {
        return ${table.entityVariableName}Service.removeById(id);
    }
}

启动类

// Main.java
package com.example.generator;
import com.example.generator.generator.CodeGenerator;
import com.example.generator.generator.GeneratorConfig;
public class Main {
    public static void main(String[] args) {
        // 创建配置
        GeneratorConfig config = new GeneratorConfig();
        // 数据库配置
        config.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8");
        config.setUsername("root");
        config.setPassword("123456");
        config.setDatabaseName("test");
        config.setTablePrefix("sys_");
        // 包名配置
        config.setEntityPackage("com.example.demo.entity");
        config.setMapperPackage("com.example.demo.mapper");
        config.setServicePackage("com.example.demo.service");
        config.setControllerPackage("com.example.demo.controller");
        // 输出路径配置
        String basePath = System.getProperty("user.dir") + "/src/main/java/com/example/demo";
        config.setEntityPath(basePath + "/entity");
        config.setMapperPath(basePath + "/mapper");
        config.setServicePath(basePath + "/service");
        config.setControllerPath(basePath + "/controller");
        try {
            // 执行代码生成
            CodeGenerator generator = new CodeGenerator(config);
            generator.generateAll();
            System.out.println("代码生成完成!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

高级特性扩展

// 支持自定义模板
public void generateCustomCode(TableInfo table, String templateName, 
                               String outputPath, Map<String, Object> extraData) 
        throws IOException, TemplateException {
    Map<String, Object> data = new HashMap<>();
    data.put("table", table);
    data.putAll(extraData);
    Template template = configuration.getTemplate(templateName);
    renderTemplate(template, data, outputPath, 
                   table.getEntityName() + "Custom.java");
}
// 支持批量生成SQL脚本
public List<String> generateCreateTableSQL(TableInfo table) {
    List<String> sqls = new ArrayList<>();
    StringBuilder sql = new StringBuilder();
    sql.append("CREATE TABLE ").append(table.getTableName()).append(" (");
    for (ColumnInfo column : table.getColumns()) {
        sql.append("\n  ").append(column.getColumnName()).append(" ")
           .append(column.getDataType());
        if (!column.isNullable()) {
            sql.append(" NOT NULL");
        }
        if (column.isAutoIncrement()) {
            sql.append(" AUTO_INCREMENT");
        }
        sql.append(",");
    }
    // 添加主键
    sql.append("\n  PRIMARY KEY (");
    table.getColumns().stream()
         .filter(ColumnInfo::isPrimaryKey)
         .forEach(c -> sql.append(c.getColumnName()).append(","));
    sql.deleteCharAt(sql.length() - 1);
    sql.append(")");
    sql.append("\n)");
    sqls.add(sql.toString());
    return sqls;
}

这个代码生成器案例包含了完整的数据库表结构解析、类型转换、模板渲染和代码生成功能,支持生成实体类、Mapper、Service和Controller等常用代码,使用时只需要修改配置信息即可快速生成项目基础代码,大大提高开发效率。

抱歉,评论功能暂时关闭!