本文目录导读:

我来提供一个完整的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等常用代码,使用时只需要修改配置信息即可快速生成项目基础代码,大大提高开发效率。