代码生成设计
1. 概述
ZsAdmin 提供强大的代码生成功能,支持一键生成前后端 CRUD 代码,包括实体类、Mapper、Service、Controller、前端页面等,大幅提高开发效率。本文档将详细介绍后端代码生成的设计与实现。
2. 技术选型
| 技术 | 版本 | 用途 |
|---|---|---|
| Velocity | 2.x | 模板引擎 |
| MyBatis Plus | 3.5.x | ORM 框架 |
| Spring Boot | 3.x | 后端框架 |
| Vue 3 | 3.x | 前端框架 |
| Arco Design Vue | 2.x | UI 组件库 |
3. 代码生成架构
3.1 核心组件
- CodeGenerator:代码生成器主类
- TemplateEngine:模板引擎
- VelocityTemplateEngine:Velocity 模板引擎实现
- GeneratorConfig:生成配置
- TableInfo:表信息
- ColumnInfo:列信息
3.2 架构图
mermaid
graph TD
A[用户操作] --> B[CodeGeneratorController]
B --> C[CodeGeneratorService]
C --> D[DatabaseService]
D --> E[获取表信息]
E --> F[TableInfo]
F --> G[获取列信息]
G --> H[ColumnInfo]
C --> I[TemplateEngine]
I --> J[VelocityTemplateEngine]
J --> K{生成类型}
K --> |实体类| L[Entity Template]
K --> |Mapper| M[Mapper Template]
K --> |Service| N[Service Template]
K --> |Controller| O[Controller Template]
K --> |前端页面| P[Vue Template]
L --> Q[生成 Java 代码]
M --> Q
N --> Q
O --> Q
P --> R[生成 Vue 代码]
Q --> S[输出到指定目录]
R --> S4. 核心实现
4.1 代码生成器配置
java
@Data
public class GeneratorConfig {
/**
* 数据库表名
*/
private String tableName;
/**
* 包名
*/
private String packageName;
/**
* 模块名
*/
private String moduleName;
/**
* 作者
*/
private String author;
/**
* 生成类型:单表、树表、主子表
*/
private String generateType;
/**
* 是否生成前端代码
*/
private Boolean generateFrontend;
/**
* 是否生成 Swagger 文档
*/
private Boolean generateSwagger;
/**
* 生成路径
*/
private String outputPath;
}4.2 代码生成器主类
java
@Component
public class CodeGenerator {
@Autowired
private DatabaseService databaseService;
@Autowired
private VelocityTemplateEngine velocityTemplateEngine;
public void generate(GeneratorConfig config) {
// 获取表信息
TableInfo tableInfo = databaseService.getTableInfo(config.getTableName());
// 获取列信息
List<ColumnInfo> columnInfos = databaseService.getColumnInfos(config.getTableName());
// 构建数据模型
Map<String, Object> dataModel = buildDataModel(config, tableInfo, columnInfos);
// 生成代码
generateCode(dataModel, config);
}
private Map<String, Object> buildDataModel(GeneratorConfig config, TableInfo tableInfo, List<ColumnInfo> columnInfos) {
// 构建数据模型
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("config", config);
dataModel.put("tableInfo", tableInfo);
dataModel.put("columnInfos", columnInfos);
dataModel.put("now", new Date());
return dataModel;
}
private void generateCode(Map<String, Object> dataModel, GeneratorConfig config) {
// 生成实体类
velocityTemplateEngine.generate("entity.java.vm", dataModel, config.getOutputPath() + "/entity/");
// 生成 Mapper
velocityTemplateEngine.generate("mapper.java.vm", dataModel, config.getOutputPath() + "/mapper/");
// 生成 Service
velocityTemplateEngine.generate("service.java.vm", dataModel, config.getOutputPath() + "/service/");
// 生成 Controller
velocityTemplateEngine.generate("controller.java.vm", dataModel, config.getOutputPath() + "/controller/");
// 生成前端代码
if (config.getGenerateFrontend()) {
generateFrontendCode(dataModel, config);
}
}
private void generateFrontendCode(Map<String, Object> dataModel, GeneratorConfig config) {
// 生成 Vue 页面
velocityTemplateEngine.generate("vue/index.vue.vm", dataModel, config.getOutputPath() + "/vue/");
// 生成 API 调用
velocityTemplateEngine.generate("vue/api.js.vm", dataModel, config.getOutputPath() + "/vue/");
// 生成路由配置
velocityTemplateEngine.generate("vue/router.js.vm", dataModel, config.getOutputPath() + "/vue/");
}
}4.3 数据库服务
java
@Service
public class DatabaseService {
@Autowired
private JdbcTemplate jdbcTemplate;
public TableInfo getTableInfo(String tableName) {
// 查询表信息
String sql = "SELECT TABLE_NAME, TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = ? AND TABLE_SCHEMA = DATABASE()";
return jdbcTemplate.queryForObject(sql, new Object[]{tableName}, (rs, rowNum) -> {
TableInfo tableInfo = new TableInfo();
tableInfo.setTableName(rs.getString("TABLE_NAME"));
tableInfo.setTableComment(rs.getString("TABLE_COMMENT"));
return tableInfo;
});
}
public List<ColumnInfo> getColumnInfos(String tableName) {
// 查询列信息
String sql = "SELECT COLUMN_NAME, COLUMN_TYPE, DATA_TYPE, COLUMN_COMMENT, IS_NULLABLE, COLUMN_KEY, COLUMN_DEFAULT " +
"FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND TABLE_SCHEMA = DATABASE()";
return jdbcTemplate.query(sql, new Object[]{tableName}, (rs, rowNum) -> {
ColumnInfo columnInfo = new ColumnInfo();
columnInfo.setColumnName(rs.getString("COLUMN_NAME"));
columnInfo.setColumnType(rs.getString("COLUMN_TYPE"));
columnInfo.setDataType(rs.getString("DATA_TYPE"));
columnInfo.setColumnComment(rs.getString("COLUMN_COMMENT"));
columnInfo.setIsNullable(rs.getString("IS_NULLABLE"));
columnInfo.setColumnKey(rs.getString("COLUMN_KEY"));
columnInfo.setColumnDefault(rs.getString("COLUMN_DEFAULT"));
return columnInfo;
});
}
}5. 代码生成功能
5.1 生成类型
- 单表:生成单表 CRUD 代码
- 树表:生成树表 CRUD 代码,支持树形结构
- 主子表:生成主子表 CRUD 代码,支持主子表关联
5.2 生成内容
后端代码
- 实体类:包含字段、getter/setter、toString 等
- Mapper 接口:包含基本的 CRUD 方法
- Mapper XML:包含 SQL 语句
- Service 接口:包含业务逻辑接口
- Service 实现:包含业务逻辑实现
- Controller:包含 RESTful API
- Swagger 文档:自动生成 API 文档
前端代码
- Vue 页面:包含列表、表单、详情等页面
- API 调用:包含与后端交互的 API
- 路由配置:包含路由定义
- 组件:包含自定义组件
5.3 配置选项
- 包名配置
- 模块名配置
- 作者配置
- 生成类型选择
- 前端代码生成开关
- Swagger 文档生成开关
- 生成路径配置
6. 最佳实践
6.1 数据库设计规范
- 表名使用下划线命名,如
sys_user - 字段名使用下划线命名,如
user_name - 每个表必须有
id主键 - 包含
create_by、create_time、update_by、update_time字段 - 表和字段必须有注释
6.2 代码生成规范
- 生成的代码应符合项目的代码规范
- 生成的代码应包含适当的注释
- 生成的代码应易于维护和扩展
- 生成的代码应遵循 SOLID 原则
6.3 使用建议
- 先设计数据库表,再生成代码
- 生成代码后,根据业务需求进行调整
- 不要直接修改生成的代码,应通过继承或扩展的方式进行修改
- 定期更新模板,适应项目的代码规范变化
7. 扩展功能
7.1 自定义模板
- 支持自定义 Velocity 模板
- 支持根据项目需求调整模板
- 支持模板版本管理
7.2 批量生成
- 支持批量生成多张表的代码
- 支持生成整个模块的代码
- 支持生成整个项目的代码
7.3 集成开发工具
- 支持 IDEA 插件
- 支持 VS Code 插件
- 支持 Eclipse 插件
8. 性能优化
- 缓存表信息,避免重复查询数据库
- 异步生成代码,提高用户体验
- 支持增量生成,只生成修改的代码
- 模板预编译,提高生成速度