This commit is contained in:
Wang 2025-10-09 15:05:59 +08:00
parent ce7a7e2c00
commit 09a9767992
3 changed files with 0 additions and 808 deletions

View File

@ -1,186 +0,0 @@
// 创建代码生成配置面板
private JPanel createGeneratorPanel() {
JPanel panel = new JPanel(new BorderLayout(10, 10));
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
// 标题
JLabel titleLabel = new JLabel("代码生成配置");
titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 18));
titleLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 20, 0));
panel.add(titleLabel, BorderLayout.NORTH);
// 主内容面板分为上下两部分
JPanel contentPanel = new JPanel(new BorderLayout(10, 10));
// 上部分配置选项
JPanel configPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 5, 5);
gbc.anchor = GridBagConstraints.WEST;
// 基础包名
JLabel basePackageLabel = new JLabel("基础包名:");
basePackageField = new JTextField();
basePackageField.setPreferredSize(new Dimension(300, 25));
// 是否启用Lombok
JLabel lombokLabel = new JLabel("启用Lombok:");
lombokCheckBox = new JCheckBox();
lombokCheckBox.setSelected(true);
// 父类实体
JLabel superEntityLabel = new JLabel("父类实体:");
superEntityField = new JTextField();
superEntityField.setPreferredSize(new Dimension(300, 25));
// 父类公共字段
JLabel superColumnsLabel = new JLabel("父类公共字段:");
superColumnsField = new JTextField();
superColumnsField.setPreferredSize(new Dimension(300, 25));
superColumnsField.setToolTipText("多个字段用逗号分隔id,createTime,updateTime");
// Vue2 生成选项
JLabel generateVue2Label = new JLabel("生成Vue2代码:");
generateVue2CheckBox = new JCheckBox();
generateVue2CheckBox.setSelected(true);
// Vue3 生成选项
JLabel generateVue3Label = new JLabel("生成Vue3代码:");
generateVue3CheckBox = new JCheckBox();
generateVue3CheckBox.setSelected(true);
// 保存配置按钮
JButton saveConfigBtn = new JButton("保存配置");
saveConfigBtn.addActionListener(e -> saveGeneratorConfig());
// 添加组件到配置面板
int row = 0;
gbc.gridx = 0;
gbc.gridy = row;
configPanel.add(basePackageLabel, gbc);
gbc.gridx = 1;
configPanel.add(basePackageField, gbc);
row++;
gbc.gridx = 0;
gbc.gridy = row;
configPanel.add(lombokLabel, gbc);
gbc.gridx = 1;
configPanel.add(lombokCheckBox, gbc);
row++;
gbc.gridx = 0;
gbc.gridy = row;
configPanel.add(superEntityLabel, gbc);
gbc.gridx = 1;
configPanel.add(superEntityField, gbc);
row++;
gbc.gridx = 0;
gbc.gridy = row;
configPanel.add(superColumnsLabel, gbc);
gbc.gridx = 1;
configPanel.add(superColumnsField, gbc);
row++;
gbc.gridx = 0;
gbc.gridy = row;
configPanel.add(generateVue2Label, gbc);
gbc.gridx = 1;
configPanel.add(generateVue2CheckBox, gbc);
row++;
gbc.gridx = 0;
gbc.gridy = row;
configPanel.add(generateVue3Label, gbc);
gbc.gridx = 1;
configPanel.add(generateVue3CheckBox, gbc);
row++;
gbc.gridx = 1;
gbc.gridy = row + 1;
gbc.anchor = GridBagConstraints.EAST;
configPanel.add(saveConfigBtn, gbc);
contentPanel.add(configPanel, BorderLayout.NORTH);
// 下部分表选择
JPanel tablePanel = new JPanel(new BorderLayout(10, 10));
// 过滤面板
JPanel filterPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
JLabel filterLabel = new JLabel("过滤:");
tableFilterField = new JTextField(20);
JButton filterBtn = new JButton("查询");
filterBtn.addActionListener(e -> filterTables());
filterPanel.add(filterLabel);
filterPanel.add(tableFilterField);
filterPanel.add(filterBtn);
tablePanel.add(filterPanel, BorderLayout.NORTH);
// 表列表
String[] columnNames = {"选择", "表名"};
tableModel = new DefaultTableModel(columnNames, 0) {
@Override
public Class<?> getColumnClass(int column) {
return column == 0 ? Boolean.class : String.class;
}
@Override
public boolean isCellEditable(int row, int column) {
return column == 0;
}
};
tableTable = new JTable(tableModel);
tableTable.getColumnModel().getColumn(0).setPreferredWidth(50);
tableTable.getColumnModel().getColumn(1).setPreferredWidth(300);
tableTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int column = tableTable.columnAtPoint(e.getPoint());
int row = tableTable.rowAtPoint(e.getPoint());
if (row != -1) {
if (column == 0) {
// 点击复选框列切换选中状态
Boolean checked = (Boolean) tableTable.getValueAt(row, 0);
tableTable.setValueAt(!checked, row, 0);
} else {
// 点击其他列也切换选中状态
Boolean checked = (Boolean) tableTable.getValueAt(row, 0);
tableTable.setValueAt(!checked, row, 0);
}
}
}
});
JScrollPane tableScrollPane = new JScrollPane(tableTable);
tablePanel.add(tableScrollPane, BorderLayout.CENTER);
contentPanel.add(tablePanel, BorderLayout.CENTER);
panel.add(contentPanel, BorderLayout.CENTER);
// 按钮面板
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
JButton backBtn = new JButton("返回");
JButton generateBtn = new JButton("生成代码");
backBtn.addActionListener(e -> {
CardLayout cl = (CardLayout) ((JPanel) getContentPane().getComponent(0)).getLayout();
cl.show((JPanel) getContentPane().getComponent(0), "dbPanel");
});
generateBtn.addActionListener(e -> generateCode());
buttonPanel.add(backBtn);
buttonPanel.add(generateBtn);
panel.add(buttonPanel, BorderLayout.SOUTH);
// 加载已保存的配置
loadGeneratorConfig();
return panel;
}

439
foo.java
View File

@ -1,439 +0,0 @@
public class BackendCodeGenerator {
// 生成后端代码
public static void generateBackendCode(String url, String username, String password, List<String> tables, Map<String, Map<String,Object>> columns) {
GeneratorConfig generatorConfig = ConfigUtil.getGeneratorConfigAsObject();
String basePackage = generatorConfig.getBasePackage();
String superEntityClass = generatorConfig.getSuperEntityClass();
String[] superEntityColumns = generatorConfig.getSuperEntityColumns();
// 解析包名获取作者和模块名
String author = System.getProperty("user.name");
String moduleName = basePackage.substring(basePackage.lastIndexOf(".") + 1);
// 生成路径
String projectPath = System.getProperty("user.dir");
String outputDir = projectPath + "/generated-code/backend/src/main/java";
FastAutoGenerator.create(url, username, password)
// 全局配置
.globalConfig(builder -> {
builder.author(author) // 设置作者
.enableSwagger() // 开启Swagger模式
.outputDir(outputDir) // 指定输出目录
.dateType(DateType.ONLY_DATE); // 时间策略
})
// 包配置
.packageConfig(builder -> {
builder.parent(basePackage) // 父包名
.moduleName(moduleName) // 父包模块名
// 模块名为seer
// 实体类包名为entity
.entity("entity")
// 服务层包名为service
.service("service")
// 服务实现类包名为service.impl
.serviceImpl("service.impl")
// Mapper接口包名为mapper
.mapper("mapper")
// Mapper XML文件包名为mapper.xml
.xml("mapper.xml")
// 构建包配置
.pathInfo(Collections.singletonMap(OutputFile.xml,
projectPath + "/generated-code/backend/src/main/resources/mapper"));
})
// 策略配置
.strategyConfig(builder -> {
builder.addInclude(tables) // 设置需要生成的表名
.addTablePrefix("t_", "sys_") // 设置过滤表前缀
// Entity策略配置
.entityBuilder()
.enableLombok() // 开启Lombok
.superClass(superEntityClass) // 设置父类
.addSuperEntityColumns(superEntityColumns) // 父类公共字段
.enableTableFieldAnnotation() // 开启字段注解
// Service策略配置
.serviceBuilder()
.formatServiceFileName("I%sService")
.formatServiceImplFileName("%sServiceImpl")
// Mapper策略配置
.mapperBuilder()
.superClass(BaseMapper.class) // 设置父类
.enableMapperAnnotation() // 开启@Mapper注解
.formatMapperFileName("%sMapper")
.formatXmlFileName("%sMapper");
builder.entityBuilder()
// 实体类继承自BaseEntity类
.superClass(BaseEntity.class)
// 启用Lombok注解
.enableLombok()
// 启用表字段注解
.enableTableFieldAnnotation()
// 逻辑删除字段名为deleted
.logicDeleteColumnName("deleted")
// 添加父类实体的共有字段
.addSuperEntityColumns("id", "created_by", "created_time", "updated_by", "updated_time")
// 添加表字段填充策略
.addTableFills(new Column("create_time", FieldFill.INSERT))
// 添加属性填充策略
.addTableFills(new Property("update_time", FieldFill.INSERT_UPDATE))
// 主键类型为AUTO
.idType(IdType.AUTO)
// 设置生成文件名格式为%sEntity
.formatFileName("%sEntity")
// 构建实体类配置
.build();
})
// 使用Freemarker引擎模板
.templateEngine(new FreemarkerTemplateEngine())
.execute();
// 生成自定义Controller
generateControllers(basePackage, moduleName, tables);
// 生成请求和响应类
generateRequestAndResponseClasses(basePackage, tables,columns);
}
// 生成符合RESTful规范的Controller
private static void generateControllers(String basePackage, String moduleName, List<String> tables) {
try {
// 初始化FreeMarker配置
Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
cfg.setClassForTemplateLoading(BackendCodeGenerator.class, "/templates/backend");
cfg.setDefaultEncoding("UTF-8");
// 获取模板
Template template = cfg.getTemplate("custom-controller.java.ftl");
// 生成路径
String projectPath = System.getProperty("user.dir");
String outputDir = projectPath + "/generated-code/backend/src/main/java/" +
basePackage.replace(".", "/") + "/" + moduleName + "/controller/";
// 创建目录
File dir = new File(outputDir);
if (!dir.exists()) {
dir.mkdirs();
}
// 为每个表生成Controller
for (String table : tables) {
// 处理表名转换为类名
String className = tableToClassName(table);
String varName = className.substring(0, 1).toLowerCase() + className.substring(1);
// 准备数据模型
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("basePackage", basePackage);
dataModel.put("moduleName", moduleName);
dataModel.put("className", className);
dataModel.put("varName", varName);
dataModel.put("author", System.getProperty("user.name"));
dataModel.put("date", new Date());
// 生成文件
String fileName = outputDir + className + "Controller.java";
try (Writer out = new FileWriter(new File(fileName))) {
template.process(dataModel, out);
}
}
} catch (IOException | TemplateException e) {
log.info("生成Controller文件失败" + e.getMessage(),e);
}
}
/**
* 生成所有请求和响应类
*/
public static void generateRequestAndResponseClasses(String basePackage, List<String> tables, Map<String, Map<String,Object>> columns) {
List<String> commonColumns = Arrays.asList("deleted","createTime","updateTime","createBy","updateBy");
Map<String, Map<String,Object>> columnMaps = columns.entrySet().stream().filter(entry -> !commonColumns.contains(entry.getKey())).collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));
// 生成响应类
generateResponseClasses(basePackage, tables,columnMaps);
// 生成查询请求类
generateQueryRequestClasses(basePackage, tables,columnMaps);
// 生成通用请求类
generateRequestClasses(basePackage, tables,columnMaps);
// 生成PageRequest基类
generatePageRequestClass(basePackage, tables,columnMaps);
}
/**
* 生成统一响应类
*/
public static void generateResponseClasses(String basePackage, List<String> tables, Map<String, Map<String,Object>> tableColumnsInfo) {
generateClassFiles(basePackage, tables, tableColumnsInfo, "admin-response.java.ftl", "Response", "/controller/response/");
}
/**
* 生成查询请求类
*/
public static void generateQueryRequestClasses(String basePackage, List<String> tables, Map<String, Map<String,Object>> tableColumnsInfo) {
generateClassFiles(basePackage, tables, tableColumnsInfo, "admin-query-admin-request.java.ftl", "QueryRequest", "/controller/request/");
}
/**
* 生成通用请求类
*/
public static void generateRequestClasses(String basePackage, List<String> tables, Map<String, Map<String,Object>> tableColumnsInfo) {
generateClassFiles(basePackage, tables, tableColumnsInfo, "admin-request.java.ftl", "Request", "/controller/request/");
}
/**
* 通用类文件生成方法
*/
private static void generateClassFiles(String basePackage, List<String> tables, Map<String, Map<String,Object>> tableColumnsInfo,
String templateName, String suffix, String outputPath) {
try {
// 初始化FreeMarker配置
Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
cfg.setClassForTemplateLoading(BackendCodeGenerator.class, "/templates/backend");
cfg.setDefaultEncoding("UTF-8");
// 获取模板
Template template = cfg.getTemplate(templateName);
// 生成路径
String projectPath = System.getProperty("user.dir");
String outputDir = projectPath + "/generated-code/backend/src/main/java/" +
basePackage.replace(".", "/") + outputPath;
// 创建目录
File dir = new File(outputDir);
if (!dir.exists()) {
dir.mkdirs();
}
// 为每个表生成类文件
for (String table : tables) {
// 处理表名转换为类名
String className = tableToClassName(table);
// 获取表的列信息
Map<String, Object> tableInfo = tableColumnsInfo.get(table);
List<ColumnInfo> columns = new ArrayList<>();
boolean hasDateField = false;
boolean hasBigDecimalField = false;
if (tableInfo != null) {
columns = processColumns(tableInfo);
hasDateField = hasFieldType(columns, "Date");
hasBigDecimalField = hasFieldType(columns, "BigDecimal");
}
// 准备数据模型
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("basePackage", basePackage);
dataModel.put("className", className);
dataModel.put("columns", columns);
dataModel.put("hasDateField", hasDateField);
dataModel.put("hasBigDecimalField", hasBigDecimalField);
// 生成文件
String fileName = outputDir + className + suffix + ".java";
try (Writer out = new FileWriter(new File(fileName))) {
template.process(dataModel, out);
}
}
} catch (IOException | TemplateException e) {
log.error("生成" + suffix + "类文件失败:" + e.getMessage(), e);
}
}
/**
* 生成PageRequest基类
*/
public static void generatePageRequestClass(String basePackage, List<String> tables, Map<String, Map<String,Object>> columns) {
try {
// 初始化FreeMarker配置
Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
cfg.setClassForTemplateLoading(BackendCodeGenerator.class, "/templates/backend");
cfg.setDefaultEncoding("UTF-8");
Template pageRequestTemplate = cfg.getTemplate("admin-pageRequest.java.ftl");
// 生成路径
String projectPath = System.getProperty("user.dir");
String outputDir = projectPath + "/generated-code/backend/src/main/java/" +
basePackage.replace(".", "/") + "/controller/request/";
// 创建目录
File dir = new File(outputDir);
if (!dir.exists()) {
dir.mkdirs();
}
// 为每个表生成Controller
for (String table : tables) {
// 处理表名转换为类名
String className = tableToClassName(table);
String varName = className.substring(0, 1).toLowerCase() + className.substring(1);
// 准备数据模型
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("basePackage", basePackage);
dataModel.put("className", className);
dataModel.put("varName", varName);
dataModel.put("author", System.getProperty("user.name"));
dataModel.put("date", new Date());
// 生成文件
String fileName = outputDir + className + "Controller.java";
try (Writer out = new FileWriter(new File(fileName))) {
pageRequestTemplate.process(dataModel, out);
}
}
} catch (IOException | TemplateException e) {
log.error("生成PageRequest基类文件失败" + e.getMessage(), e);
}
}
// 表名转类名下划线转驼峰
private static String tableToClassName(String tableName) {
// 去除表前缀
if (tableName.startsWith("t_")) {
tableName = tableName.substring(2);
}
// 下划线转驼峰
StringBuilder sb = new StringBuilder();
boolean nextUpperCase = false;
for (char c : tableName.toCharArray()) {
if (c == '_') {
nextUpperCase = true;
} else {
if (nextUpperCase) {
sb.append(Character.toUpperCase(c));
nextUpperCase = false;
} else {
sb.append(c);
}
}
}
// 首字母大写
if (sb.length() > 0) {
sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
}
return sb.toString();
}
/**
* 处理列信息转换为Java属性
*/
private static List<ColumnInfo> processColumns(Map<String, Object> tableInfo) {
List<ColumnInfo> columnInfos = new ArrayList<>();
@SuppressWarnings("unchecked")
List<Map<String, Object>> columns = (List<Map<String, Object>>) tableInfo.get("columns");
if (columns != null) {
for (Map<String, Object> column : columns) {
ColumnInfo info = new ColumnInfo();
String columnName = (String) column.get("columnName");
String dataType = (String) column.get("dataType");
String columnComment = (String) column.get("columnComment");
String isNullable = (String) column.get("isNullable");
String columnKey = (String) column.get("columnKey");
info.setColumnName(columnName);
info.setPropertyName(columnToProperty(columnName));
info.setJavaType(mapDataTypeToJavaType(dataType));
info.setDataType(dataType);
info.setComment(columnComment != null ? columnComment : "");
info.setNullable("YES".equalsIgnoreCase(isNullable));
info.setPrimaryKey("PRI".equalsIgnoreCase(columnKey));
columnInfos.add(info);
}
}
return columnInfos;
}
/**
* 将数据库列名转换为Java属性名下划线转驼峰
*/
private static String columnToProperty(String columnName) {
if (columnName == null || columnName.isEmpty()) {
return columnName;
}
StringBuilder result = new StringBuilder();
boolean nextUpperCase = false;
for (char c : columnName.toCharArray()) {
if (c == '_') {
nextUpperCase = true;
} else {
if (nextUpperCase) {
result.append(Character.toUpperCase(c));
nextUpperCase = false;
} else {
result.append(Character.toLowerCase(c));
}
}
}
return result.toString();
}
/**
* 将数据库类型映射为Java类型
*/
private static String mapDataTypeToJavaType(String dataType) {
if (dataType == null) {
return "String";
}
dataType = dataType.toLowerCase();
switch (dataType) {
case "tinyint":
case "smallint":
case "mediumint":
case "int":
return "Integer";
case "bigint":
return "Long";
case "float":
case "double":
return "Double";
case "decimal":
case "numeric":
return "BigDecimal";
case "date":
case "datetime":
case "timestamp":
return "Date";
case "bit":
return "Boolean";
default:
return "String";
}
}
/**
* 检查是否有特定类型的字段
*/
private static boolean hasFieldType(List<ColumnInfo> columns, String javaType) {
if (columns == null || columns.isEmpty()) {
return false;
}
for (ColumnInfo column : columns) {
if (javaType.equals(column.getJavaType())) {
return true;
}
}
return false;
}
}

View File

@ -1,183 +0,0 @@
<template>
<div class="app-container">
<div class="filter-container">
<el-input v-model="searchParams.keyword" placeholder="请输入关键词" style="width: 200px;" class="filter-item" @keyup.enter="handleQuery" />
<el-button type="primary" icon="Search" @click="handleQuery" class="filter-item">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery" class="filter-item">重置</el-button>
<el-button type="primary" icon="Plus" @click="handleAdd" class="filter-item">新增</el-button>
</div>
<el-table
v-loading="listLoading"
:data="list"
border
fit
highlight-current-row
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="ID" prop="id" width="80" align="center" />
<!-- 根据实际字段动态生成表格列 -->
<#if columns?? && columns.columns??>
<#list columns.columns as column>
<#assign columnName = column.columnName>
<#assign propertyName = column.propertyName>
<el-table-column label="${column.comment!columnName}" prop="${propertyName}" />
</#list>
</#if>
<el-table-column label="操作" width="200" align="center">
<template #default="scope">
<el-button size="small" type="text" @click="handleView(scope.row)">查看</el-button>
<el-button size="small" type="text" @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="small" type="text" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
:current-page="pagination.currentPage"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
<!-- 新增/编辑弹窗 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="500px">
<${entityName}Form ref="formRef" :data="formData" />
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { get${entityName}List, delete${entityName} } from '@/api/${lowerEntityName}'
import ${entityName}Form from './${entityName}Form.vue'
import { ElMessage, ElConfirm } from 'element-plus'
// 列表数据
const list = ref([])
const listLoading = ref(false)
// 搜索参数
const searchParams = ref({
keyword: ''
})
// 分页参数
const pagination = ref({
currentPage: 1,
pageSize: 10,
total: 0
})
// 弹窗相关
const dialogVisible = ref(false)
const dialogTitle = ref('')
const formData = ref({})
const formRef = ref(null)
// 页面加载时查询数据
onMounted(() => {
handleQuery()
})
// 查询数据
const handleQuery = () => {
listLoading.value = true
get${entityName}List({
pageNum: pagination.value.currentPage,
pageSize: pagination.value.pageSize,
...searchParams.value
}).then(response => {
list.value = response.data.records
pagination.value.total = response.data.total
listLoading.value = false
}).catch(() => {
listLoading.value = false
})
}
// 重置查询
const resetQuery = () => {
searchParams.value = {
keyword: ''
}
pagination.value.currentPage = 1
handleQuery()
}
// 分页大小变化
const handleSizeChange = (val) => {
pagination.value.pageSize = val
handleQuery()
}
// 当前页变化
const handleCurrentChange = (val) => {
pagination.value.currentPage = val
handleQuery()
}
// 新增
const handleAdd = () => {
dialogTitle.value = '新增${entityName}'
formData.value = {}
dialogVisible.value = true
}
// 编辑
const handleEdit = (row) => {
dialogTitle.value = '编辑${entityName}'
formData.value = { ...row }
dialogVisible.value = true
}
// 查看
const handleView = (row) => {
dialogTitle.value = '查看${entityName}'
formData.value = { ...row }
dialogVisible.value = true
}
// 删除
const handleDelete = (row) => {
ElConfirm('确定要删除这条记录吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
delete${entityName}(row.id).then(() => {
ElMessage.success('删除成功')
handleQuery()
})
})
}
// 提交表单
const handleSubmit = () => {
formRef.value.validate(valid => {
if (valid) {
// 调用保存方法,实际项目中需要根据新增/编辑调用不同接口
ElMessage.success('保存成功')
dialogVisible.value = false
handleQuery()
}
})
}
</script>
<style scoped>
.filter-container {
padding: 10px 0;
}
.filter-item {
margin-right: 10px;
}
</style>