init
This commit is contained in:
parent
421de0b7e6
commit
548cf48701
5
.idea/.gitignore
generated
vendored
Normal file
5
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Environment-dependent path to Maven home directory
|
||||
/mavenHomeManager.xml
|
||||
6
.idea/ApifoxUploaderProjectSetting.xml
generated
Normal file
6
.idea/ApifoxUploaderProjectSetting.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ApifoxUploaderProjectSetting">
|
||||
<option name="apiAccessToken" value="APS-7Em7CF8xpPJXB0iKgPeqbBDJufFaINiLgi" />
|
||||
</component>
|
||||
</project>
|
||||
15
.idea/compiler.xml
generated
Normal file
15
.idea/compiler.xml
generated
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<option name="BUILD_PROCESS_HEAP_SIZE" value="1024" />
|
||||
<annotationProcessing>
|
||||
<profile name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<module name="complete-multi-db-connection-code-generator" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
<bytecodeTargetLevel target="8" />
|
||||
</component>
|
||||
</project>
|
||||
7
.idea/encodings.xml
generated
Normal file
7
.idea/encodings.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
20
.idea/jarRepositories.xml
generated
Normal file
20
.idea/jarRepositories.xml
generated
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://maven.aliyun.com/repository/public" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
12
.idea/misc.xml
generated
Normal file
12
.idea/misc.xml
generated
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
186
MainFrame.java
Normal file
186
MainFrame.java
Normal file
@ -0,0 +1,186 @@
|
||||
// 创建代码生成配置面板
|
||||
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;
|
||||
}
|
||||
6
codegenerator.properties
Normal file
6
codegenerator.properties
Normal file
@ -0,0 +1,6 @@
|
||||
#Tue Sep 16 18:49:22 CST 2025
|
||||
db.password=Zs139768
|
||||
db.connName=MySQL
|
||||
db.url=jdbc\:mysql\://192.168.0.45\:3306/seer_teach?useSSL\=false&serverTimezone\=Asia/Shanghai&useUnicode\=true&characterEncoding\=UTF-8&connectTimeout\=10000&socketTimeout\=60000
|
||||
db.type=mysql
|
||||
db.username=root
|
||||
439
foo.java
Normal file
439
foo.java
Normal file
@ -0,0 +1,439 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
183
list.vue.ftl
Normal file
183
list.vue.ftl
Normal file
@ -0,0 +1,183 @@
|
||||
<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>
|
||||
99
pom.xml
Normal file
99
pom.xml
Normal file
@ -0,0 +1,99 @@
|
||||
<?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>
|
||||
|
||||
<groupId>com.codegenerator</groupId>
|
||||
<artifactId>complete-multi-db-connection-code-generator</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<mybatis-plus.version>3.5.13</mybatis-plus.version>
|
||||
<freemarker.version>2.3.31</freemarker.version>
|
||||
<mysql.version>8.0.28</mysql.version>
|
||||
<lombok.version>1.18.24</lombok.version>
|
||||
<hutool.version>5.8.16</hutool.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- MyBatis-Plus -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-generator</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据库驱动 -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${mysql.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- FreeMarker -->
|
||||
<dependency>
|
||||
<groupId>org.freemarker</groupId>
|
||||
<artifactId>freemarker</artifactId>
|
||||
<version>${freemarker.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Hutool工具类 -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>2.7.15</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.codegenerator.Main</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
16
src/main/java/com/codegenerator/Main.java
Normal file
16
src/main/java/com/codegenerator/Main.java
Normal file
@ -0,0 +1,16 @@
|
||||
package com.codegenerator;
|
||||
|
||||
import com.codegenerator.ui.MainFrame;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 在EDT线程中启动Swing应用
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
MainFrame frame = new MainFrame();
|
||||
frame.setVisible(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.codegenerator.config;
|
||||
|
||||
public class DbConnectionConfig {
|
||||
private String name;
|
||||
private String dbType;
|
||||
private String url;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDbType() {
|
||||
return dbType;
|
||||
}
|
||||
|
||||
public void setDbType(String dbType) {
|
||||
this.dbType = dbType;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
90
src/main/java/com/codegenerator/config/GeneratorConfig.java
Normal file
90
src/main/java/com/codegenerator/config/GeneratorConfig.java
Normal file
@ -0,0 +1,90 @@
|
||||
package com.codegenerator.config;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class GeneratorConfig {
|
||||
// 数据库连接列表
|
||||
private List<DbConnectionConfig> dbConnections = new ArrayList<>();
|
||||
// 当前选中的连接索引
|
||||
private int selectedDbConnectionIndex = 0;
|
||||
|
||||
// 基础配置
|
||||
private String basePackage = "com.example";
|
||||
private boolean lombokEnabled = true;
|
||||
private boolean useLombok;
|
||||
private boolean generateVue2 = true;
|
||||
private boolean generateVue3 = true;
|
||||
private String superEntityClass = "";
|
||||
private String[] superEntityColumns = {"id", "create_time", "update_time"};
|
||||
private String backendOutputDir = "${user.dir}/src/main/java";
|
||||
private String vue2OutputDir = "${user.dir}/src/main/vue2";
|
||||
private String vue3OutputDir = "${user.dir}/src/main/vue3";
|
||||
private String customTemplateDir = "";
|
||||
|
||||
// 字段类型映射
|
||||
private Map<String, String> fieldTypeMappings = new HashMap<String, String>() {{ put("int", "Integer");
|
||||
put("bigint", "Long");
|
||||
put("varchar", "String");
|
||||
put("datetime", "LocalDateTime");
|
||||
put("date", "LocalDate");
|
||||
put("double", "Double");
|
||||
put("float", "Float");
|
||||
put("tinyint", "Boolean");
|
||||
}};
|
||||
|
||||
public GeneratorConfig() {
|
||||
initDefaultConnections();
|
||||
}
|
||||
|
||||
// 初始化默认连接
|
||||
public void initDefaultConnections() {
|
||||
if (dbConnections.isEmpty()) {
|
||||
// 添加默认MySQL连接
|
||||
DbConnectionConfig mysqlConn = new DbConnectionConfig();
|
||||
setFieldValue(mysqlConn, "name", "本地MySQL");
|
||||
setFieldValue(mysqlConn, "dbType", "mysql");
|
||||
setFieldValue(mysqlConn, "url", "jdbc:mysql://192.168.0.45:3306/seer_teach?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&connectTimeout=10000&socketTimeout=60000");
|
||||
setFieldValue(mysqlConn, "username", "root");
|
||||
setFieldValue(mysqlConn, "password", "Zs139768");
|
||||
dbConnections.add(mysqlConn);
|
||||
|
||||
// 添加默认PostgreSQL连接
|
||||
DbConnectionConfig pgConn = new DbConnectionConfig();
|
||||
setFieldValue(pgConn, "name", "本地PostgreSQL");
|
||||
setFieldValue(pgConn, "dbType", "postgresql");
|
||||
setFieldValue(pgConn, "url", "jdbc:postgresql://localhost:5432/test");
|
||||
setFieldValue(pgConn, "username", "postgres");
|
||||
setFieldValue(pgConn, "password", "postgres");
|
||||
dbConnections.add(pgConn);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前选中的连接
|
||||
public DbConnectionConfig getSelectedDbConnection() {
|
||||
if (dbConnections.isEmpty()) {
|
||||
initDefaultConnections();
|
||||
}
|
||||
|
||||
if (selectedDbConnectionIndex < 0 || selectedDbConnectionIndex >= dbConnections.size()) {
|
||||
selectedDbConnectionIndex = 0;
|
||||
}
|
||||
|
||||
return dbConnections.get(selectedDbConnectionIndex);
|
||||
}
|
||||
|
||||
// 临时的辅助方法,绕过Lombok注解处理器问题
|
||||
private <T> void setFieldValue(Object obj, String fieldName, T value) {
|
||||
try {
|
||||
java.lang.reflect.Field field = obj.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
field.set(obj, value);
|
||||
} catch (Exception e) {
|
||||
// 忽略异常
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/main/java/com/codegenerator/database/ColumnInfo.java
Normal file
24
src/main/java/com/codegenerator/database/ColumnInfo.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.codegenerator.database;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ColumnInfo {
|
||||
private String columnName; // 列名
|
||||
private String propertyName; // Java属性名
|
||||
private String dataType; // 数据库数据类型
|
||||
private String javaType; // Java类型
|
||||
private String comment; // 列注释
|
||||
private boolean nullable; // 是否可为空
|
||||
private boolean primaryKey; // 是否为主键
|
||||
private int columnSize; // 列大小
|
||||
private int decimalDigits; // 小数位数
|
||||
private int dataTypeCode;
|
||||
public ColumnInfo() {}
|
||||
|
||||
public ColumnInfo(String columnName, String propertyName, String javaType) {
|
||||
this.columnName = columnName;
|
||||
this.propertyName = propertyName;
|
||||
this.javaType = javaType;
|
||||
}
|
||||
}
|
||||
259
src/main/java/com/codegenerator/database/DatabaseConnector.java
Normal file
259
src/main/java/com/codegenerator/database/DatabaseConnector.java
Normal file
@ -0,0 +1,259 @@
|
||||
package com.codegenerator.database;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DatabaseConnector {
|
||||
|
||||
// 根据数据库类型加载对应的驱动
|
||||
private static void loadDriver(String dbType) throws ClassNotFoundException {
|
||||
switch (dbType.toLowerCase()) {
|
||||
case "mysql":
|
||||
Class.forName("com.mysql.cj.jdbc.Driver");
|
||||
break;
|
||||
case "postgresql":
|
||||
Class.forName("org.postgresql.Driver");
|
||||
break;
|
||||
case "oracle":
|
||||
Class.forName("oracle.jdbc.driver.OracleDriver");
|
||||
break;
|
||||
case "sqlserver":
|
||||
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("不支持的数据库类型: " + dbType);
|
||||
}
|
||||
}
|
||||
|
||||
// 连接数据库并获取表信息
|
||||
public static List<TableInfo> connectAndGetTables(String url, String username, String password, String dbType) throws Exception {
|
||||
loadDriver(dbType);
|
||||
|
||||
List<TableInfo> tables = new ArrayList<>();
|
||||
|
||||
try (Connection conn = DriverManager.getConnection(url, username, password)) {
|
||||
DatabaseMetaData metaData = conn.getMetaData();
|
||||
|
||||
// 根据数据库类型获取表信息
|
||||
String[] types = {"TABLE"};
|
||||
ResultSet rs;
|
||||
|
||||
switch (dbType.toLowerCase()) {
|
||||
case "mysql":
|
||||
case "postgresql":
|
||||
case "sqlserver":
|
||||
rs = metaData.getTables(null, null, "%", types);
|
||||
break;
|
||||
case "oracle":
|
||||
// Oracle通常使用大写表名
|
||||
rs = metaData.getTables(null, username.toUpperCase(), "%", types);
|
||||
break;
|
||||
default:
|
||||
rs = metaData.getTables(null, null, "%", types);
|
||||
}
|
||||
|
||||
while (rs.next()) {
|
||||
TableInfo table = new TableInfo();
|
||||
table.setName(rs.getString("TABLE_NAME"));
|
||||
table.setComment(rs.getString("REMARKS"));
|
||||
|
||||
// 获取表的列信息
|
||||
List<ColumnInfo> columns = getTableColumns(metaData, table.getName(), dbType, username);
|
||||
table.setColumns(columns);
|
||||
|
||||
tables.add(table);
|
||||
}
|
||||
}
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
// 获取表的列信息
|
||||
private static List<ColumnInfo> getTableColumns(DatabaseMetaData metaData, String tableName, String dbType, String username) throws SQLException {
|
||||
List<ColumnInfo> columns = new ArrayList<>();
|
||||
|
||||
ResultSet rs;
|
||||
switch (dbType.toLowerCase()) {
|
||||
case "oracle":
|
||||
// Oracle需要指定用户名( schema )
|
||||
rs = metaData.getColumns(null, username.toUpperCase(), tableName, "%");
|
||||
break;
|
||||
default:
|
||||
rs = metaData.getColumns(null, null, tableName, "%");
|
||||
}
|
||||
|
||||
while (rs.next()) {
|
||||
ColumnInfo column = new ColumnInfo();
|
||||
column.setColumnName(rs.getString("COLUMN_NAME"));
|
||||
column.setDataType(rs.getString("TYPE_NAME"));
|
||||
column.setComment(rs.getString("REMARKS"));
|
||||
column.setNullable(rs.getInt("NULLABLE") == 1);
|
||||
column.setPrimaryKey(false); // 主键信息需要通过其他方式获取
|
||||
|
||||
// 获取列的其他信息
|
||||
column.setColumnSize(rs.getInt("COLUMN_SIZE"));
|
||||
column.setDecimalDigits(rs.getInt("DECIMAL_DIGITS"));
|
||||
column.setDataTypeCode(rs.getInt("DATA_TYPE"));
|
||||
|
||||
// 设置Java类型映射
|
||||
column.setJavaType(mapDataTypeToJavaType(rs.getString("TYPE_NAME"), rs.getInt("DATA_TYPE")));
|
||||
|
||||
// 设置属性名(下划线转驼峰)
|
||||
column.setPropertyName(columnToProperty(column.getColumnName()));
|
||||
|
||||
columns.add(column);
|
||||
}
|
||||
|
||||
// 获取主键信息
|
||||
setPrimaryKeys(metaData, tableName, username, dbType, columns);
|
||||
|
||||
return columns;
|
||||
}
|
||||
|
||||
// 获取表的主键信息
|
||||
private static void setPrimaryKeys(DatabaseMetaData metaData, String tableName, String username, String dbType, List<ColumnInfo> columns) throws SQLException {
|
||||
ResultSet rs;
|
||||
switch (dbType.toLowerCase()) {
|
||||
case "oracle":
|
||||
rs = metaData.getPrimaryKeys(null, username.toUpperCase(), tableName);
|
||||
break;
|
||||
default:
|
||||
rs = metaData.getPrimaryKeys(null, null, tableName);
|
||||
}
|
||||
|
||||
while (rs.next()) {
|
||||
String pkColumnName = rs.getString("COLUMN_NAME");
|
||||
// 标记主键列
|
||||
for (ColumnInfo column : columns) {
|
||||
if (pkColumnName.equals(column.getColumnName())) {
|
||||
column.setPrimaryKey(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 将数据库列名转换为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 dataTypeName, int dataTypeCode) {
|
||||
if (dataTypeName == null) {
|
||||
return "String";
|
||||
}
|
||||
|
||||
String lowerDataType = dataTypeName.toLowerCase();
|
||||
|
||||
switch (lowerDataType) {
|
||||
case "tinyint":
|
||||
return "Byte";
|
||||
case "smallint":
|
||||
return "Short";
|
||||
case "integer":
|
||||
case "int":
|
||||
return "Integer";
|
||||
case "bigint":
|
||||
return "Long";
|
||||
case "float":
|
||||
return "Float";
|
||||
case "double":
|
||||
return "Double";
|
||||
case "decimal":
|
||||
case "numeric":
|
||||
return "BigDecimal";
|
||||
case "bit":
|
||||
return "Boolean";
|
||||
case "boolean":
|
||||
return "Boolean";
|
||||
case "date":
|
||||
case "time":
|
||||
case "timestamp":
|
||||
case "datetime":
|
||||
return "Date";
|
||||
case "char":
|
||||
case "varchar":
|
||||
case "text":
|
||||
case "longvarchar":
|
||||
case "nchar":
|
||||
case "nvarchar":
|
||||
case "longnvarchar":
|
||||
return "String";
|
||||
case "binary":
|
||||
case "varbinary":
|
||||
case "longvarbinary":
|
||||
return "byte[]";
|
||||
default:
|
||||
// 根据SQL类型代码判断
|
||||
switch (dataTypeCode) {
|
||||
case Types.TINYINT:
|
||||
return "Byte";
|
||||
case Types.SMALLINT:
|
||||
return "Short";
|
||||
case Types.INTEGER:
|
||||
return "Integer";
|
||||
case Types.BIGINT:
|
||||
return "Long";
|
||||
case Types.FLOAT:
|
||||
return "Float";
|
||||
case Types.DOUBLE:
|
||||
return "Double";
|
||||
case Types.DECIMAL:
|
||||
case Types.NUMERIC:
|
||||
return "BigDecimal";
|
||||
case Types.BIT:
|
||||
case Types.BOOLEAN:
|
||||
return "Boolean";
|
||||
case Types.DATE:
|
||||
case Types.TIME:
|
||||
case Types.TIMESTAMP:
|
||||
return "Date";
|
||||
case Types.CHAR:
|
||||
case Types.VARCHAR:
|
||||
case Types.LONGVARCHAR:
|
||||
case Types.NCHAR:
|
||||
case Types.NVARCHAR:
|
||||
case Types.LONGNVARCHAR:
|
||||
return "String";
|
||||
case Types.BINARY:
|
||||
case Types.VARBINARY:
|
||||
case Types.LONGVARBINARY:
|
||||
return "byte[]";
|
||||
default:
|
||||
return "String";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 测试数据库连接
|
||||
public static boolean testConnection(String url, String username, String password, String dbType) throws Exception {
|
||||
loadDriver(dbType);
|
||||
|
||||
try (Connection conn = DriverManager.getConnection(url, username, password)) {
|
||||
return conn.isValid(5); // 5秒超时
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/main/java/com/codegenerator/database/TableInfo.java
Normal file
33
src/main/java/com/codegenerator/database/TableInfo.java
Normal file
@ -0,0 +1,33 @@
|
||||
package com.codegenerator.database;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TableInfo {
|
||||
private String name;
|
||||
private String comment;
|
||||
private List<ColumnInfo> columns;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public void setComment(String comment) {
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public List<ColumnInfo> getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public void setColumns(List<ColumnInfo> columns) {
|
||||
this.columns = columns;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,353 @@
|
||||
package com.codegenerator.generator;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
|
||||
import com.baomidou.mybatisplus.generator.config.OutputFile;
|
||||
import com.baomidou.mybatisplus.generator.config.rules.DateType;
|
||||
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
|
||||
import com.baomidou.mybatisplus.generator.fill.Column;
|
||||
import com.baomidou.mybatisplus.generator.fill.Property;
|
||||
import com.codegenerator.config.GeneratorConfig;
|
||||
import com.codegenerator.database.ColumnInfo;
|
||||
import com.codegenerator.util.ConfigUtil;
|
||||
import com.seer.teach.common.entity.BaseEntity;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.Template;
|
||||
import freemarker.template.TemplateException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
public class BackendCodeGenerator {
|
||||
// 生成后端代码
|
||||
public static void generateBackendCode(String url, String username, String password, List<String> tables,String moduleName, 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 projectPath = System.getProperty("user.dir");
|
||||
String outputDir = projectPath + "/generated-code/backend/src/main/java";
|
||||
|
||||
FastAutoGenerator.create(url, username, password)
|
||||
// 全局配置
|
||||
.globalConfig(builder -> {
|
||||
builder.author(author)
|
||||
.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();
|
||||
|
||||
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()));
|
||||
String path = System.getProperty("user.dir") + "/generated-code/backend/src/main/java/" + basePackage.replace(".", "/") + "/" + moduleName ;
|
||||
|
||||
generate( moduleName, basePackage,tables,columnMaps, path);
|
||||
}
|
||||
|
||||
private static void generate(String moduleName,String basePackage, List<String> tables, Map<String, Map<String,Object>> columnMaps,String path) {
|
||||
generateClass(moduleName,basePackage, tables,columnMaps,"admin-service.java.ftl",path + "/service/","Service","Admin");
|
||||
|
||||
generateClass(moduleName,basePackage, tables,columnMaps,"admin-convert.java.ftl",path + "/convert/","Convert","Admin");
|
||||
|
||||
// 生成自定义Controller
|
||||
generateClass(moduleName,basePackage, tables,columnMaps,"admin-custom-controller.java.ftl",path + "/controller/","Controller","Admin");
|
||||
|
||||
// 生成响应类
|
||||
generateClass(moduleName,basePackage, tables,columnMaps,"admin-response.java.ftl",path + "/controller/response/","Resp","Admin");
|
||||
|
||||
// 生成创建和更新的请求类
|
||||
generateClass(moduleName,basePackage, tables,columnMaps,"admin-request.java.ftl",path + "/controller/request/","Req","Admin");
|
||||
|
||||
// 生成查询请求类
|
||||
generateClass(moduleName,basePackage, tables,columnMaps,"admin-query-request.java.ftl",path + "/controller/request/","QueryReq","Admin");
|
||||
|
||||
// 生成PageRequest基类
|
||||
generateClass(moduleName,basePackage, tables,columnMaps,"admin-pageRequest.java.ftl",path + "/controller/request/","PageReq","Admin");
|
||||
}
|
||||
|
||||
private static void generateClass(String moduleName,String basePackage, List<String> tables, Map<String, Map<String,Object>> tableColumnsInfo,String templateName, String path,String suffix,String prefix){
|
||||
try {
|
||||
// 初始化FreeMarker配置
|
||||
Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
|
||||
cfg.setClassForTemplateLoading(BackendCodeGenerator.class, "/templates/backend/" + prefix.toLowerCase());
|
||||
cfg.setDefaultEncoding("UTF-8");
|
||||
|
||||
Template pageRequestTemplate = cfg.getTemplate(templateName);
|
||||
// 创建目录
|
||||
File dir = new File(path);
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
// 为每个表生成通用请求类
|
||||
for (String table : tables) {
|
||||
// 处理表名,转换为类名
|
||||
String className = tableToClassName(table);
|
||||
String varName = tableToValName(className);
|
||||
// 获取表的列信息
|
||||
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("varName", varName);
|
||||
dataModel.put("prefix", prefix);
|
||||
dataModel.put("suffix", suffix);
|
||||
dataModel.put("moduleName", moduleName);
|
||||
dataModel.put("columns", columns);
|
||||
dataModel.put("hasDateField", hasDateField);
|
||||
dataModel.put("hasBigDecimalField", hasBigDecimalField);
|
||||
dataModel.put("author", System.getProperty("user.name"));
|
||||
dataModel.put("date", new Date());
|
||||
// 生成文件
|
||||
String fileName = path + prefix + className + suffix + ".java";
|
||||
try (Writer out = new FileWriter(new File(fileName))) {
|
||||
pageRequestTemplate.process(dataModel, out);
|
||||
}
|
||||
}
|
||||
} catch (IOException | TemplateException e) {
|
||||
log.error("生成文件失败:" + 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();
|
||||
}
|
||||
|
||||
private static String tableToValName(String tableName) {
|
||||
return tableName.substring(0,1).toLowerCase() + tableName.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理列信息,转换为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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,342 @@
|
||||
package com.codegenerator.generator;
|
||||
|
||||
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.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class FrontendCodeGenerator {
|
||||
|
||||
// 生成Vue2代码
|
||||
public static void generateVue2Code(List<String> tables,Map<String, Map<String,Object>> columns) {
|
||||
generateVueCode(tables, "vue2",columns);
|
||||
}
|
||||
|
||||
// 生成Vue3代码
|
||||
public static void generateVue3Code(List<String> tables,Map<String, Map<String,Object>> columns) {
|
||||
generateVueCode(tables, "vue3",columns);
|
||||
}
|
||||
|
||||
// 生成request.js文件
|
||||
private static void generateRequestFile(Template requestTemplate, String utilsOutputDir) throws IOException, TemplateException {
|
||||
// 创建utils目录
|
||||
File utilsDir = new File(utilsOutputDir);
|
||||
if (!utilsDir.exists()) {
|
||||
utilsDir.mkdirs();
|
||||
}
|
||||
|
||||
// 准备数据模型(这里不需要特别的数据模型)
|
||||
Map<String, Object> dataModel = new HashMap<>();
|
||||
dataModel.put("token", "");
|
||||
// 生成request.js文件
|
||||
String requestFileName = utilsOutputDir + "request.js";
|
||||
try (Writer requestOut = new FileWriter(new File(requestFileName))) {
|
||||
requestTemplate.process(dataModel, requestOut);
|
||||
}
|
||||
}
|
||||
|
||||
// 生成Vue代码
|
||||
private static void generateVueCode(List<String> tables, String version,Map<String, Map<String,Object>> columns) {
|
||||
try {
|
||||
// 初始化FreeMarker配置
|
||||
Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
|
||||
cfg.setClassForTemplateLoading(FrontendCodeGenerator.class, "/templates/frontend");
|
||||
cfg.setDefaultEncoding("UTF-8");
|
||||
|
||||
// 获取模板
|
||||
Template listTemplate = cfg.getTemplate(version + "/list.vue.ftl");
|
||||
Template formTemplate = cfg.getTemplate(version + "/form.vue.ftl");
|
||||
Template requestTemplate = cfg.getTemplate("api/api.js.ftl");
|
||||
|
||||
// 生成路径
|
||||
String projectPath = System.getProperty("user.dir");
|
||||
String baseOutputDir = projectPath + "/generated-code/frontend/" + version + "/src/views/";
|
||||
String apiOutputDir = projectPath + "/generated-code/frontend/" + version + "/src/api/";
|
||||
String utilsOutputDir = projectPath + "/generated-code/frontend/" + version + "/src/utils/";
|
||||
|
||||
// 生成request.js工具文件
|
||||
generateRequestFile(requestTemplate, utilsOutputDir);
|
||||
|
||||
// 为每个表生成Vue组件
|
||||
for (String table : tables) {
|
||||
// 处理表名,转换为类名和路径
|
||||
String className = tableToClassName(table);
|
||||
String varName = className.substring(0, 1).toLowerCase() + className.substring(1);
|
||||
String outputDir = baseOutputDir + varName + "/";
|
||||
|
||||
// 创建目录
|
||||
File dir = new File(outputDir);
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
// 准备数据模型
|
||||
Map<String, Object> dataModel = new HashMap<>();
|
||||
dataModel.put("entityName", className);
|
||||
dataModel.put("lowerEntityName", varName);
|
||||
dataModel.put("className", className);
|
||||
dataModel.put("varName", varName);
|
||||
dataModel.put("tableName", table);
|
||||
dataModel.put("version", version);
|
||||
|
||||
// 添加列信息到数据模型
|
||||
if (columns.containsKey(table)) {
|
||||
dataModel.put("columns", columns.get(table));
|
||||
}
|
||||
|
||||
// 生成列表组件
|
||||
String listFileName = outputDir + "List.vue";
|
||||
Writer listOut = new FileWriter(new File(listFileName));
|
||||
listTemplate.process(dataModel, listOut);
|
||||
listOut.close();
|
||||
|
||||
// 生成表单组件
|
||||
String formFileName = outputDir + "Form.vue";
|
||||
Writer formOut = new FileWriter(new File(formFileName));
|
||||
formTemplate.process(dataModel, formOut);
|
||||
formOut.close();
|
||||
|
||||
// 生成API请求文件
|
||||
generateApiFile(dataModel, apiOutputDir, varName);
|
||||
}
|
||||
} catch (IOException | TemplateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// 生成API请求文件
|
||||
private static void generateApiFile(Map<String, Object> dataModel, String apiOutputDir, String varName) throws IOException {
|
||||
// 创建API目录
|
||||
File apiDir = new File(apiOutputDir);
|
||||
if (!apiDir.exists()) {
|
||||
apiDir.mkdirs();
|
||||
}
|
||||
|
||||
// 准备API文件内容
|
||||
String className = (String) dataModel.get("className");
|
||||
StringBuilder content = new StringBuilder();
|
||||
|
||||
// 导入请求库
|
||||
content.append("import request from '@/utils/request'\n\n");
|
||||
|
||||
// 生成API方法
|
||||
content.append("// 获取分页数据\nexport const get").append(className).append("Page = (params) => {\n");
|
||||
content.append(" return request({\n");
|
||||
content.append(" url: '/api/").append(varName).append("/page',\n");
|
||||
content.append(" method: 'get',\n");
|
||||
content.append(" params\n");
|
||||
content.append(" })\n}");
|
||||
content.append("\n\n");
|
||||
|
||||
content.append("// 通过ID获取详情\nexport const get").append(className).append(" = (id) => {\n");
|
||||
content.append(" return request({\n");
|
||||
content.append(" url: '/api/").append(varName).append("/' + id,\n");
|
||||
content.append(" method: 'get'\n");
|
||||
content.append(" })\n}");
|
||||
content.append("\n\n");
|
||||
|
||||
content.append("// 新增\nexport const save").append(className).append(" = (data) => {\n");
|
||||
content.append(" return request({\n");
|
||||
content.append(" url: '/api/").append(varName).append("',\n");
|
||||
content.append(" method: 'post',\n");
|
||||
content.append(" data\n");
|
||||
content.append(" })\n}");
|
||||
content.append("\n\n");
|
||||
|
||||
content.append("// 更新\nexport const update").append(className).append(" = (data) => {\n");
|
||||
content.append(" return request({\n");
|
||||
content.append(" url: '/api/").append(varName).append("',\n");
|
||||
content.append(" method: 'put',\n");
|
||||
content.append(" data\n");
|
||||
content.append(" })\n}");
|
||||
content.append("\n\n");
|
||||
|
||||
content.append("// 删除\nexport const delete").append(className).append(" = (id) => {\n");
|
||||
content.append(" return request({\n");
|
||||
content.append(" url: '/api/").append(varName).append("/' + id,\n");
|
||||
content.append(" method: 'delete'\n");
|
||||
content.append(" })\n}");
|
||||
|
||||
// 写入文件
|
||||
String apiFileName = apiOutputDir + varName + ".js";
|
||||
try (FileWriter apiOut = new FileWriter(new File(apiFileName))) {
|
||||
apiOut.write(content.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// 表名转类名(下划线转驼峰)
|
||||
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();
|
||||
}
|
||||
|
||||
// 测试生成的代码
|
||||
public static Map<String, Object> testGeneratedCode() {
|
||||
Map<String, Object> testResult = new HashMap<>();
|
||||
List<String> successFiles = new ArrayList<>();
|
||||
List<String> errorFiles = new ArrayList<>();
|
||||
boolean isSuccess = true;
|
||||
|
||||
try {
|
||||
String projectPath = System.getProperty("user.dir");
|
||||
|
||||
// 检查后端代码
|
||||
testResult.put("backendTest", checkBackendCode(projectPath, successFiles, errorFiles));
|
||||
|
||||
// 检查Vue2前端代码
|
||||
testResult.put("vue2Test", checkFrontendCode(projectPath, "vue2", successFiles, errorFiles));
|
||||
|
||||
// 检查Vue3前端代码
|
||||
testResult.put("vue3Test", checkFrontendCode(projectPath, "vue3", successFiles, errorFiles));
|
||||
|
||||
// 综合结果
|
||||
if (!errorFiles.isEmpty()) {
|
||||
isSuccess = false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errorFiles.add("测试过程中发生异常: " + e.getMessage());
|
||||
isSuccess = false;
|
||||
}
|
||||
|
||||
testResult.put("success", isSuccess);
|
||||
testResult.put("successFiles", successFiles);
|
||||
testResult.put("errorFiles", errorFiles);
|
||||
return testResult;
|
||||
}
|
||||
|
||||
// 检查后端代码
|
||||
private static boolean checkBackendCode(String projectPath, List<String> successFiles, List<String> errorFiles) {
|
||||
boolean isSuccess = true;
|
||||
String backendDirPath = projectPath + "/generated-code/backend";
|
||||
File backendDir = new File(backendDirPath);
|
||||
|
||||
if (!backendDir.exists() || backendDir.listFiles() == null || backendDir.listFiles().length == 0) {
|
||||
errorFiles.add("后端代码目录不存在或为空: " + backendDirPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查Controller文件是否符合RESTful规范
|
||||
File controllerDir = new File(backendDirPath + "/src/main/java/com/example/controller");
|
||||
if (controllerDir.exists() && controllerDir.isDirectory()) {
|
||||
File[] controllerFiles = controllerDir.listFiles((dir, name) -> name.endsWith("Controller.java"));
|
||||
if (controllerFiles != null && controllerFiles.length > 0) {
|
||||
for (File file : controllerFiles) {
|
||||
try {
|
||||
String content = new String(java.nio.file.Files.readAllBytes(file.toPath()));
|
||||
// 检查是否包含RESTful注解
|
||||
if (content.contains("@RestController") && content.contains("@RequestMapping") &&
|
||||
content.contains("@GetMapping") && content.contains("@PostMapping") &&
|
||||
content.contains("@PutMapping") && content.contains("@DeleteMapping")) {
|
||||
successFiles.add("后端Controller文件符合RESTful规范: " + file.getName());
|
||||
} else {
|
||||
errorFiles.add("后端Controller文件不符合RESTful规范: " + file.getName());
|
||||
isSuccess = false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
errorFiles.add("读取Controller文件失败: " + file.getName() + ", 错误: " + e.getMessage());
|
||||
isSuccess = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
// 检查前端代码
|
||||
private static boolean checkFrontendCode(String projectPath, String version, List<String> successFiles, List<String> errorFiles) {
|
||||
boolean isSuccess = true;
|
||||
String frontendDirPath = projectPath + "/generated-code/frontend/" + version;
|
||||
File frontendDir = new File(frontendDirPath);
|
||||
|
||||
if (!frontendDir.exists() || frontendDir.listFiles() == null || frontendDir.listFiles().length == 0) {
|
||||
errorFiles.add(version + "前端代码目录不存在或为空: " + frontendDirPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查Vue组件文件
|
||||
File viewsDir = new File(frontendDirPath + "/src/views");
|
||||
if (viewsDir.exists() && viewsDir.isDirectory()) {
|
||||
File[] viewDirs = viewsDir.listFiles(File::isDirectory);
|
||||
if (viewDirs != null && viewDirs.length > 0) {
|
||||
for (File dir : viewDirs) {
|
||||
File listVueFile = new File(dir, "List.vue");
|
||||
File formVueFile = new File(dir, "Form.vue");
|
||||
|
||||
if (listVueFile.exists()) {
|
||||
successFiles.add(version + "列表组件文件存在: " + listVueFile.getPath());
|
||||
} else {
|
||||
errorFiles.add(version + "列表组件文件不存在: " + listVueFile.getPath());
|
||||
isSuccess = false;
|
||||
}
|
||||
|
||||
if (formVueFile.exists()) {
|
||||
successFiles.add(version + "表单组件文件存在: " + formVueFile.getPath());
|
||||
} else {
|
||||
errorFiles.add(version + "表单组件文件不存在: " + formVueFile.getPath());
|
||||
isSuccess = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查API文件
|
||||
File apiDir = new File(frontendDirPath + "/src/api");
|
||||
if (apiDir.exists() && apiDir.isDirectory()) {
|
||||
File[] apiFiles = apiDir.listFiles((dir, name) -> name.endsWith(".js"));
|
||||
if (apiFiles != null && apiFiles.length > 0) {
|
||||
for (File file : apiFiles) {
|
||||
successFiles.add(version + "API文件存在: " + file.getName());
|
||||
}
|
||||
} else {
|
||||
errorFiles.add(version + "API文件不存在: " + apiDir.getPath());
|
||||
isSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查request.js工具文件
|
||||
File utilsDir = new File(frontendDirPath + "/src/utils");
|
||||
File requestFile = new File(utilsDir, "request.js");
|
||||
if (requestFile.exists()) {
|
||||
successFiles.add(version + "请求工具文件存在: " + requestFile.getPath());
|
||||
} else {
|
||||
errorFiles.add(version + "请求工具文件不存在: " + requestFile.getPath());
|
||||
isSuccess = false;
|
||||
}
|
||||
|
||||
return isSuccess;
|
||||
}
|
||||
}
|
||||
143
src/main/java/com/codegenerator/ui/DbConnectionEditorDialog.java
Normal file
143
src/main/java/com/codegenerator/ui/DbConnectionEditorDialog.java
Normal file
@ -0,0 +1,143 @@
|
||||
package com.codegenerator.ui;
|
||||
|
||||
import com.codegenerator.config.DbConnectionConfig;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
|
||||
public class DbConnectionEditorDialog extends JDialog {
|
||||
private DbConnectionConfig connection;
|
||||
private JTextField nameField;
|
||||
private JComboBox<String> dbTypeCombo;
|
||||
private JTextField urlField;
|
||||
private JTextField usernameField;
|
||||
private JPasswordField passwordField;
|
||||
|
||||
public DbConnectionEditorDialog(Dialog parent, DbConnectionConfig conn) {
|
||||
super(parent, conn == null ? "新增数据库连接" : "编辑数据库连接", true);
|
||||
this.connection = conn != null ? conn : new DbConnectionConfig();
|
||||
|
||||
initUI();
|
||||
if (conn != null) {
|
||||
loadConnectionData();
|
||||
}
|
||||
|
||||
setSize(500, 300);
|
||||
setLocationRelativeTo(parent);
|
||||
}
|
||||
|
||||
private void initUI() {
|
||||
JPanel mainPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
gbc.insets = new Insets(5, 5, 5, 5);
|
||||
gbc.anchor = GridBagConstraints.WEST;
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
|
||||
int row = 0;
|
||||
|
||||
// 连接名称
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = row++;
|
||||
mainPanel.add(new JLabel("连接名称:"), gbc);
|
||||
gbc.gridx = 1;
|
||||
nameField = new JTextField(25);
|
||||
mainPanel.add(nameField, gbc);
|
||||
|
||||
// 数据库类型
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = row++;
|
||||
mainPanel.add(new JLabel("数据库类型:"), gbc);
|
||||
gbc.gridx = 1;
|
||||
dbTypeCombo = new JComboBox<>(new String[]{"mysql", "postgresql", "oracle", "sqlserver"});
|
||||
mainPanel.add(dbTypeCombo, gbc);
|
||||
|
||||
// URL
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = row++;
|
||||
mainPanel.add(new JLabel("连接URL:"), gbc);
|
||||
gbc.gridx = 1;
|
||||
urlField = new JTextField(25);
|
||||
mainPanel.add(urlField, gbc);
|
||||
|
||||
// 用户名
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = row++;
|
||||
mainPanel.add(new JLabel("用户名:"), gbc);
|
||||
gbc.gridx = 1;
|
||||
usernameField = new JTextField(25);
|
||||
mainPanel.add(usernameField, gbc);
|
||||
|
||||
// 密码
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = row++;
|
||||
mainPanel.add(new JLabel("密码:"), gbc);
|
||||
gbc.gridx = 1;
|
||||
passwordField = new JPasswordField(25);
|
||||
mainPanel.add(passwordField, gbc);
|
||||
|
||||
// 按钮
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = row++;
|
||||
gbc.gridwidth = 2;
|
||||
gbc.anchor = GridBagConstraints.CENTER;
|
||||
|
||||
JPanel buttonPanel = new JPanel();
|
||||
JButton saveButton = new JButton("保存");
|
||||
saveButton.addActionListener(this::saveConnection);
|
||||
|
||||
JButton cancelButton = new JButton("取消");
|
||||
cancelButton.addActionListener(e -> dispose());
|
||||
|
||||
buttonPanel.add(saveButton);
|
||||
buttonPanel.add(cancelButton);
|
||||
mainPanel.add(buttonPanel, gbc);
|
||||
|
||||
add(mainPanel);
|
||||
}
|
||||
|
||||
private void loadConnectionData() {
|
||||
nameField.setText(connection.getName());
|
||||
dbTypeCombo.setSelectedItem(connection.getDbType());
|
||||
urlField.setText(connection.getUrl());
|
||||
usernameField.setText(connection.getUsername());
|
||||
passwordField.setText(connection.getPassword());
|
||||
}
|
||||
|
||||
private void saveConnection(ActionEvent e) {
|
||||
String name = nameField.getText().trim();
|
||||
String dbType = (String) dbTypeCombo.getSelectedItem();
|
||||
String url = urlField.getText().trim();
|
||||
String username = usernameField.getText().trim();
|
||||
String password = new String(passwordField.getPassword());
|
||||
|
||||
// 简单验证
|
||||
if (name.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(this, "请输入连接名称");
|
||||
return;
|
||||
}
|
||||
|
||||
if (url.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(this, "请输入连接URL");
|
||||
return;
|
||||
}
|
||||
|
||||
if (username.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(this, "请输入用户名");
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存数据
|
||||
connection.setName(name);
|
||||
connection.setDbType(dbType);
|
||||
connection.setUrl(url);
|
||||
connection.setUsername(username);
|
||||
connection.setPassword(password);
|
||||
|
||||
dispose();
|
||||
}
|
||||
|
||||
public DbConnectionConfig getConnection() {
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,331 @@
|
||||
package com.codegenerator.ui;
|
||||
|
||||
import com.codegenerator.config.DbConnectionConfig;
|
||||
import com.codegenerator.config.GeneratorConfig;
|
||||
import com.codegenerator.util.ConfigUtil;
|
||||
import com.codegenerator.util.DatabaseUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.List;
|
||||
|
||||
public class DbConnectionManagerDialog extends JDialog {
|
||||
private JTable table;
|
||||
private DefaultTableModel tableModel;
|
||||
private List<DbConnectionConfig> connections;
|
||||
private GeneratorConfig config;
|
||||
private MainFrame parentFrame;
|
||||
|
||||
public DbConnectionManagerDialog(MainFrame parent, GeneratorConfig config) {
|
||||
super(parent, "数据库连接管理", true);
|
||||
this.parentFrame = parent;
|
||||
// 加载已保存的配置,如果没有则使用传入的配置
|
||||
this.config = ConfigUtil.loadDbConnections();
|
||||
this.connections = config.getDbConnections();
|
||||
initUI();
|
||||
}
|
||||
|
||||
private void initUI() {
|
||||
setSize(600, 400);
|
||||
setLocationRelativeTo(getParent());
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
// 创建表格模型
|
||||
tableModel = new DefaultTableModel(new String[] {"连接名称", "数据库类型", "连接URL", "用户名"}, 0) {
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int column) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
table = new JTable(tableModel);
|
||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
table.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
int selectedRow = table.getSelectedRow();
|
||||
if (selectedRow >= 0) {
|
||||
editConnection(selectedRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 创建主面板
|
||||
JPanel mainPanel = new JPanel(new BorderLayout());
|
||||
mainPanel.add(new JScrollPane(table), BorderLayout.CENTER);
|
||||
|
||||
// 创建按钮面板
|
||||
JPanel buttonPanel = new JPanel();
|
||||
JButton addButton = new JButton("添加");
|
||||
JButton editButton = new JButton("编辑");
|
||||
JButton deleteButton = new JButton("删除");
|
||||
JButton testButton = new JButton("测试连接");
|
||||
JButton selectButton = new JButton("选择");
|
||||
|
||||
addButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
addConnection();
|
||||
// 保存配置
|
||||
ConfigUtil.saveDbConnections(connections, getSelectedDbConnectionIndex(config));
|
||||
}
|
||||
});
|
||||
|
||||
editButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int selectedRow = table.getSelectedRow();
|
||||
if (selectedRow >= 0) {
|
||||
editConnection(selectedRow);
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(DbConnectionManagerDialog.this, "请先选择一个连接");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
deleteButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int selectedRow = table.getSelectedRow();
|
||||
deleteConnection(selectedRow);
|
||||
// 保存配置
|
||||
ConfigUtil.saveDbConnections(connections, getSelectedDbConnectionIndex(config));
|
||||
}
|
||||
});
|
||||
|
||||
testButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int selectedRow = table.getSelectedRow();
|
||||
testConnection(selectedRow);
|
||||
}
|
||||
});
|
||||
|
||||
selectButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int selectedRow = table.getSelectedRow();
|
||||
if (selectedRow >= 0) {
|
||||
setSelectedDbConnectionIndex(config, selectedRow);
|
||||
// 保存配置
|
||||
ConfigUtil.saveDbConnections(connections, selectedRow);
|
||||
// 更新MainFrame的UI
|
||||
DbConnectionConfig selectedConn = connections.get(selectedRow);
|
||||
// 将选中的连接信息设置到MainFrame的UI中
|
||||
try {
|
||||
java.lang.reflect.Field field = parentFrame.getClass().getDeclaredField("connNameField");
|
||||
field.setAccessible(true);
|
||||
JTextField connNameField = (JTextField) field.get(parentFrame);
|
||||
connNameField.setText(getConnectionName(selectedConn));
|
||||
|
||||
field = parentFrame.getClass().getDeclaredField("dbTypeCombo");
|
||||
field.setAccessible(true);
|
||||
JComboBox<String> dbTypeCombo = (JComboBox<String>) field.get(parentFrame);
|
||||
dbTypeCombo.setSelectedItem(getConnectionDbType(selectedConn));
|
||||
|
||||
field = parentFrame.getClass().getDeclaredField("urlField");
|
||||
field.setAccessible(true);
|
||||
JTextField urlField = (JTextField) field.get(parentFrame);
|
||||
urlField.setText(getConnectionUrl(selectedConn));
|
||||
|
||||
field = parentFrame.getClass().getDeclaredField("usernameField");
|
||||
field.setAccessible(true);
|
||||
JTextField usernameField = (JTextField) field.get(parentFrame);
|
||||
usernameField.setText(getConnectionUsername(selectedConn));
|
||||
|
||||
field = parentFrame.getClass().getDeclaredField("passwordField");
|
||||
field.setAccessible(true);
|
||||
JPasswordField passwordField = (JPasswordField) field.get(parentFrame);
|
||||
passwordField.setText(getConnectionPassword(selectedConn));
|
||||
|
||||
// 也保存单连接配置,以便兼容旧的代码
|
||||
ConfigUtil.saveDbConfig(
|
||||
getConnectionName(selectedConn),
|
||||
getConnectionDbType(selectedConn),
|
||||
getConnectionUrl(selectedConn),
|
||||
getConnectionUsername(selectedConn),
|
||||
getConnectionPassword(selectedConn)
|
||||
);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
dispose();
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(DbConnectionManagerDialog.this, "请先选择一个连接");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
buttonPanel.add(addButton);
|
||||
buttonPanel.add(editButton);
|
||||
buttonPanel.add(deleteButton);
|
||||
buttonPanel.add(testButton);
|
||||
buttonPanel.add(selectButton);
|
||||
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
|
||||
|
||||
add(mainPanel);
|
||||
loadConnections();
|
||||
}
|
||||
|
||||
private void loadConnections() {
|
||||
// 清空表格
|
||||
tableModel.setRowCount(0);
|
||||
|
||||
// 添加连接到表格
|
||||
for (DbConnectionConfig conn : connections) {
|
||||
tableModel.addRow(new Object[] {
|
||||
getConnectionName(conn),
|
||||
getConnectionDbType(conn),
|
||||
getConnectionUrl(conn),
|
||||
getConnectionUsername(conn)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void addConnection() {
|
||||
DbConnectionEditorDialog dialog = new DbConnectionEditorDialog(this, new DbConnectionConfig());
|
||||
dialog.setVisible(true);
|
||||
loadConnections();
|
||||
}
|
||||
|
||||
private void editConnection(int selectedRow) {
|
||||
if (selectedRow >= 0 && selectedRow < connections.size()) {
|
||||
DbConnectionEditorDialog dialog = new DbConnectionEditorDialog(
|
||||
this, connections.get(selectedRow));
|
||||
dialog.setVisible(true);
|
||||
loadConnections();
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(this, "请先选择一个连接");
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteConnection(int selectedRow) {
|
||||
if (selectedRow >= 0 && selectedRow < connections.size()) {
|
||||
// 不能删除最后一个连接
|
||||
if (connections.size() <= 1) {
|
||||
JOptionPane.showMessageDialog(this, "至少保留一个数据库连接");
|
||||
return;
|
||||
}
|
||||
|
||||
int confirm = JOptionPane.showConfirmDialog(this,
|
||||
"确定要删除选中的连接吗?", "确认删除", JOptionPane.YES_NO_OPTION);
|
||||
|
||||
if (confirm == JOptionPane.YES_OPTION) {
|
||||
connections.remove(selectedRow);
|
||||
// 如果删除的是当前选中的连接,自动切换到第一个
|
||||
if (selectedRow == getSelectedDbConnectionIndex(config)) {
|
||||
setSelectedDbConnectionIndex(config, 0);
|
||||
parentFrame.updateConnectionUI();
|
||||
}
|
||||
loadConnections();
|
||||
}
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(this, "请先选择一个连接");
|
||||
}
|
||||
}
|
||||
|
||||
private void testConnection(int selectedRow) {
|
||||
if (selectedRow >= 0 && selectedRow < connections.size()) {
|
||||
DbConnectionConfig conn = connections.get(selectedRow);
|
||||
try {
|
||||
// 测试连接的代码
|
||||
if (DatabaseUtil.testConnection(
|
||||
getConnectionUrl(conn),
|
||||
getConnectionUsername(conn),
|
||||
getConnectionPassword(conn))) {
|
||||
JOptionPane.showMessageDialog(this, "连接测试成功!");
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(this, "连接测试失败!");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
JOptionPane.showMessageDialog(this, "连接测试失败: " + ex.getMessage(),
|
||||
"错误", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(this, "请先选择一个连接");
|
||||
}
|
||||
}
|
||||
|
||||
// 临时的辅助方法,绕过Lombok注解处理器问题
|
||||
private String getConnectionName(DbConnectionConfig conn) {
|
||||
try {
|
||||
java.lang.reflect.Field field = conn.getClass().getDeclaredField("name");
|
||||
field.setAccessible(true);
|
||||
return (String) field.get(conn);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private String getConnectionDbType(DbConnectionConfig conn) {
|
||||
try {
|
||||
java.lang.reflect.Field field = conn.getClass().getDeclaredField("dbType");
|
||||
field.setAccessible(true);
|
||||
return (String) field.get(conn);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
return "mysql";
|
||||
}
|
||||
}
|
||||
|
||||
private String getConnectionUrl(DbConnectionConfig conn) {
|
||||
try {
|
||||
java.lang.reflect.Field field = conn.getClass().getDeclaredField("url");
|
||||
field.setAccessible(true);
|
||||
return (String) field.get(conn);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private String getConnectionUsername(DbConnectionConfig conn) {
|
||||
try {
|
||||
java.lang.reflect.Field field = conn.getClass().getDeclaredField("username");
|
||||
field.setAccessible(true);
|
||||
return (String) field.get(conn);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private String getConnectionPassword(DbConnectionConfig conn) {
|
||||
try {
|
||||
java.lang.reflect.Field field = conn.getClass().getDeclaredField("password");
|
||||
field.setAccessible(true);
|
||||
return (String) field.get(conn);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private int getSelectedDbConnectionIndex(GeneratorConfig config) {
|
||||
try {
|
||||
java.lang.reflect.Field field = config.getClass().getDeclaredField("selectedDbConnectionIndex");
|
||||
field.setAccessible(true);
|
||||
return field.getInt(config);
|
||||
} catch (Exception e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void setSelectedDbConnectionIndex(GeneratorConfig config, int index) {
|
||||
try {
|
||||
java.lang.reflect.Field field = config.getClass().getDeclaredField("selectedDbConnectionIndex");
|
||||
field.setAccessible(true);
|
||||
field.setInt(config, index);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void addConnection(DbConnectionConfig conn) {
|
||||
connections.add(conn);
|
||||
}
|
||||
}
|
||||
587
src/main/java/com/codegenerator/ui/MainFrame.java
Normal file
587
src/main/java/com/codegenerator/ui/MainFrame.java
Normal file
@ -0,0 +1,587 @@
|
||||
package com.codegenerator.ui;
|
||||
|
||||
import com.codegenerator.generator.BackendCodeGenerator;
|
||||
import com.codegenerator.generator.FrontendCodeGenerator;
|
||||
import com.codegenerator.util.CodeTestUtil;
|
||||
import com.codegenerator.util.ConfigUtil;
|
||||
import com.codegenerator.util.DatabaseUtil;
|
||||
import com.codegenerator.config.GeneratorConfig;
|
||||
import com.codegenerator.config.DbConnectionConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
public class MainFrame extends JFrame {
|
||||
// 数据库连接相关组件
|
||||
private JComboBox<String> dbTypeCombo;
|
||||
private JTextField connNameField;
|
||||
private JTextField urlField;
|
||||
private JTextField usernameField;
|
||||
private JPasswordField passwordField;
|
||||
|
||||
// 代码生成配置相关组件
|
||||
private JTextField basePackageField;
|
||||
private JCheckBox lombokCheckBox;
|
||||
private JTextField superEntityField;
|
||||
private JTextField superColumnsField;
|
||||
private JTextField moduleNameField;
|
||||
// 表选择相关组件
|
||||
private JTextField tableFilterField;
|
||||
private JTable tableTable;
|
||||
private DefaultTableModel tableModel;
|
||||
private List<String> allTables;
|
||||
private Map<String, Map<String,Object>> columnInfoMap;
|
||||
private JCheckBox generateVue2CheckBox;
|
||||
private JCheckBox generateVue3CheckBox;
|
||||
|
||||
public MainFrame() {
|
||||
initUI();
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
private void initUI() {
|
||||
setTitle("代码生成器");
|
||||
setSize(900, 700);
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setLocationRelativeTo(null);
|
||||
|
||||
// 创建主面板,使用卡片布局
|
||||
JPanel mainPanel = new JPanel(new CardLayout());
|
||||
|
||||
// 1. 数据库连接面板
|
||||
JPanel dbPanel = createDbPanel();
|
||||
// 2. 代码生成配置面板
|
||||
JPanel generatorPanel = createGeneratorPanel();
|
||||
|
||||
mainPanel.add(dbPanel, "dbPanel");
|
||||
mainPanel.add(generatorPanel, "generatorPanel");
|
||||
|
||||
add(mainPanel);
|
||||
|
||||
// 显示数据库连接面板
|
||||
((CardLayout) mainPanel.getLayout()).show(mainPanel, "dbPanel");
|
||||
}
|
||||
|
||||
// 创建数据库连接面板
|
||||
private JPanel createDbPanel() {
|
||||
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 formPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
gbc.insets = new Insets(5, 5, 5, 5);
|
||||
gbc.anchor = GridBagConstraints.WEST;
|
||||
|
||||
// 数据库类型
|
||||
JLabel dbTypeLabel = new JLabel("数据库类型:");
|
||||
dbTypeCombo = new JComboBox<>(new String[]{"mysql"});
|
||||
dbTypeCombo.setPreferredSize(new Dimension(300, 25));
|
||||
|
||||
// 连接名
|
||||
JLabel connNameLabel = new JLabel("连接名称:");
|
||||
connNameField = new JTextField();
|
||||
connNameField.setPreferredSize(new Dimension(300, 25));
|
||||
connNameField.setText("dev");
|
||||
|
||||
// URL
|
||||
JLabel urlLabel = new JLabel("连接URL:");
|
||||
urlField = new JTextField();
|
||||
urlField.setPreferredSize(new Dimension(300, 25));
|
||||
urlField.setText("jdbc:mysql://192.168.0.45:3306/seer_teach?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&connectTimeout=10000&socketTimeout=60000");
|
||||
// 用户名
|
||||
JLabel usernameLabel = new JLabel("用户名:");
|
||||
usernameField = new JTextField();
|
||||
usernameField.setPreferredSize(new Dimension(300, 25));
|
||||
usernameField.setText("root");
|
||||
// 密码
|
||||
JLabel passwordLabel = new JLabel("密码:");
|
||||
passwordField = new JPasswordField();
|
||||
passwordField.setPreferredSize(new Dimension(300, 25));
|
||||
passwordField.setText("Zs139768");
|
||||
|
||||
// 添加组件到表单
|
||||
int row = 0;
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = row;
|
||||
formPanel.add(dbTypeLabel, gbc);
|
||||
gbc.gridx = 1;
|
||||
formPanel.add(dbTypeCombo, gbc);
|
||||
|
||||
row++;
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = row;
|
||||
formPanel.add(connNameLabel, gbc);
|
||||
gbc.gridx = 1;
|
||||
formPanel.add(connNameField, gbc);
|
||||
|
||||
row++;
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = row;
|
||||
formPanel.add(urlLabel, gbc);
|
||||
gbc.gridx = 1;
|
||||
formPanel.add(urlField, gbc);
|
||||
|
||||
row++;
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = row;
|
||||
formPanel.add(usernameLabel, gbc);
|
||||
gbc.gridx = 1;
|
||||
formPanel.add(usernameField, gbc);
|
||||
|
||||
row++;
|
||||
gbc.gridx = 0;
|
||||
gbc.gridy = row;
|
||||
formPanel.add(passwordLabel, gbc);
|
||||
gbc.gridx = 1;
|
||||
formPanel.add(passwordField, gbc);
|
||||
|
||||
// 滚动面板包裹表单
|
||||
JScrollPane scrollPane = new JScrollPane(formPanel);
|
||||
panel.add(scrollPane, BorderLayout.CENTER);
|
||||
|
||||
// 按钮面板
|
||||
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
||||
JButton testBtn = new JButton("测试连接");
|
||||
JButton connectBtn = new JButton("连接");
|
||||
JButton manageBtn = new JButton("管理连接");
|
||||
|
||||
testBtn.addActionListener(e -> {
|
||||
String connName = connNameField.getText();
|
||||
String dbType = (String) dbTypeCombo.getSelectedItem();
|
||||
String url = urlField.getText();
|
||||
String username = usernameField.getText();
|
||||
String password = new String(passwordField.getPassword());
|
||||
|
||||
if (url.isEmpty() || username.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(this, "请填写必要的连接信息!", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DatabaseUtil.testConnection(url, username, password)) {
|
||||
// 如果连接名称为空,使用默认名称
|
||||
if (connName.isEmpty()) {
|
||||
connName = "数据库连接_" + System.currentTimeMillis();
|
||||
connNameField.setText(connName);
|
||||
}
|
||||
|
||||
// 保存配置
|
||||
ConfigUtil.saveDbConfig(connName, dbType, url, username, password);
|
||||
JOptionPane.showMessageDialog(this, "连接成功!配置已保存。");
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(this, "连接失败,请检查配置!", "错误", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
});
|
||||
|
||||
connectBtn.addActionListener(e -> {
|
||||
String connName = connNameField.getText();
|
||||
String dbType = (String) dbTypeCombo.getSelectedItem();
|
||||
String url = urlField.getText();
|
||||
String username = usernameField.getText();
|
||||
String password = new String(passwordField.getPassword());
|
||||
|
||||
if (connName.isEmpty() || url.isEmpty() || username.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(this, "请填写必要的连接信息!", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DatabaseUtil.testConnection(url, username, password)) {
|
||||
// 保存配置
|
||||
ConfigUtil.saveDbConfig(connName, dbType, url, username, password);
|
||||
|
||||
// 切换到代码生成配置面板
|
||||
CardLayout cl = (CardLayout) ((JPanel) getContentPane().getComponent(0)).getLayout();
|
||||
cl.show((JPanel) getContentPane().getComponent(0), "generatorPanel");
|
||||
|
||||
// 加载表列表
|
||||
loadTables(url, username, password);
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(this, "连接失败,请检查配置!", "错误", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
});
|
||||
|
||||
manageBtn.addActionListener(e -> {
|
||||
GeneratorConfig generatorConfig = new GeneratorConfig();
|
||||
DbConnectionManagerDialog dialog = new DbConnectionManagerDialog(MainFrame.this, generatorConfig);
|
||||
dialog.setVisible(true);
|
||||
});
|
||||
|
||||
buttonPanel.add(testBtn);
|
||||
buttonPanel.add(connectBtn);
|
||||
buttonPanel.add(manageBtn);
|
||||
panel.add(buttonPanel, BorderLayout.SOUTH);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
// 创建代码生成配置面板
|
||||
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);
|
||||
|
||||
JLabel moduleNameLabel = new JLabel("模块名:");
|
||||
moduleNameField = new JTextField();
|
||||
moduleNameField.setPreferredSize(new Dimension(300, 25));
|
||||
moduleNameField.setToolTipText("模块名,用于生成代码的包名");
|
||||
|
||||
// 保存配置按钮
|
||||
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 = 0;
|
||||
gbc.gridy = row;
|
||||
configPanel.add(moduleNameLabel, gbc);
|
||||
gbc.gridx = 1;
|
||||
configPanel.add(moduleNameField, 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;
|
||||
}
|
||||
|
||||
// 加载配置
|
||||
private void loadConfig() {
|
||||
try {
|
||||
// 先尝试从多连接配置加载
|
||||
GeneratorConfig dbConfig = ConfigUtil.loadDbConnections();
|
||||
if (!dbConfig.getDbConnections().isEmpty()) {
|
||||
DbConnectionConfig selectedConn = dbConfig.getSelectedDbConnection();
|
||||
if (selectedConn != null) {
|
||||
connNameField.setText(selectedConn.getName());
|
||||
dbTypeCombo.setSelectedItem(selectedConn.getDbType());
|
||||
urlField.setText(selectedConn.getUrl());
|
||||
usernameField.setText(selectedConn.getUsername());
|
||||
passwordField.setText(selectedConn.getPassword());
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to load db config", e);
|
||||
}
|
||||
|
||||
// 如果多连接配置加载失败,则使用旧的单连接配置
|
||||
Map<String, String> dbConfig = ConfigUtil.getDbConfig();
|
||||
connNameField.setText(dbConfig.get("connName"));
|
||||
dbTypeCombo.setSelectedItem(dbConfig.get("dbType"));
|
||||
urlField.setText(dbConfig.get("url"));
|
||||
usernameField.setText(dbConfig.get("username"));
|
||||
passwordField.setText(dbConfig.get("password"));
|
||||
|
||||
// 加载生成器配置
|
||||
loadGeneratorConfig();
|
||||
}
|
||||
|
||||
// 加载生成器配置
|
||||
private void loadGeneratorConfig() {
|
||||
GeneratorConfig generatorConfig = ConfigUtil.getGeneratorConfigAsObject();
|
||||
basePackageField.setText(generatorConfig.getBasePackage());
|
||||
lombokCheckBox.setSelected(generatorConfig.isUseLombok());
|
||||
superEntityField.setText(generatorConfig.getSuperEntityClass());
|
||||
String[] superColumns = generatorConfig.getSuperEntityColumns();
|
||||
if (superColumns != null && superColumns.length > 0) {
|
||||
superColumnsField.setText(String.join(",", superColumns));
|
||||
}
|
||||
generateVue2CheckBox.setSelected(generatorConfig.isGenerateVue2());
|
||||
generateVue3CheckBox.setSelected(generatorConfig.isGenerateVue3());
|
||||
}
|
||||
|
||||
// 保存生成器配置
|
||||
private void saveGeneratorConfig() {
|
||||
String basePackage = basePackageField.getText();
|
||||
boolean useLombok = lombokCheckBox.isSelected();
|
||||
String superEntityClass = superEntityField.getText();
|
||||
String[] superEntityColumns = superColumnsField.getText().split(",");
|
||||
boolean generateVue2 = generateVue2CheckBox.isSelected();
|
||||
boolean generateVue3 = generateVue3CheckBox.isSelected();
|
||||
if (basePackage.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(this, "请填写基础包名!", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigUtil.saveGeneratorConfig(basePackage, useLombok, superEntityClass, superEntityColumns, generateVue2, generateVue3);
|
||||
JOptionPane.showMessageDialog(this, "配置保存成功!");
|
||||
}
|
||||
|
||||
// 加载数据库表
|
||||
private void loadTables(String url, String username, String password) {
|
||||
// 清空表格
|
||||
tableModel.setRowCount(0);
|
||||
|
||||
// 获取所有表
|
||||
allTables = DatabaseUtil.getTables(url, username, password);
|
||||
|
||||
columnInfoMap = DatabaseUtil.getTableColumns(url, username, password, allTables);
|
||||
|
||||
// 添加到表格
|
||||
for (String table : allTables) {
|
||||
tableModel.addRow(new Object[]{false, table});
|
||||
}
|
||||
}
|
||||
|
||||
// 过滤表
|
||||
private void filterTables() {
|
||||
String filter = tableFilterField.getText().trim().toLowerCase();
|
||||
|
||||
// 清空表格
|
||||
tableModel.setRowCount(0);
|
||||
|
||||
// 添加符合条件的表
|
||||
for (String table : allTables) {
|
||||
if (filter.isEmpty() || table.toLowerCase().contains(filter)) {
|
||||
tableModel.addRow(new Object[]{false, table});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 生成代码
|
||||
private void generateCode() {
|
||||
// 获取选中的表
|
||||
List<String> selectedTables = getSelectedTables();
|
||||
if (selectedTables.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(this, "请至少选择一个表", "提示", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取数据库连接信息
|
||||
String url = urlField.getText();
|
||||
String username = usernameField.getText();
|
||||
String password = new String(passwordField.getPassword());
|
||||
String moduleName = moduleNameField.getText();
|
||||
String basePackage = basePackageField.getText();
|
||||
|
||||
// 设置默认值
|
||||
if (moduleName == null || moduleName.trim().isEmpty()) {
|
||||
moduleName = "seer";
|
||||
}
|
||||
|
||||
if (basePackage == null || basePackage.trim().isEmpty()) {
|
||||
basePackage = "com.example";
|
||||
}
|
||||
|
||||
// 获取表的列信息
|
||||
Map<String, Map<String, Object>> tableColumns = DatabaseUtil.getTableColumns(url, username, password, selectedTables);
|
||||
|
||||
// 生成后端代码
|
||||
BackendCodeGenerator.generateBackendCode(url, username, password, selectedTables, moduleName, tableColumns);
|
||||
|
||||
// 生成前端Vue2代码
|
||||
if (generateVue2CheckBox.isSelected()) {
|
||||
FrontendCodeGenerator.generateVue2Code(selectedTables, tableColumns);
|
||||
}
|
||||
|
||||
// 生成前端Vue3代码
|
||||
if (generateVue3CheckBox.isSelected()) {
|
||||
FrontendCodeGenerator.generateVue3Code(selectedTables, tableColumns);
|
||||
}
|
||||
|
||||
JOptionPane.showMessageDialog(this, "代码生成完成", "提示", JOptionPane.INFORMATION_MESSAGE);
|
||||
} catch (Exception ex) {
|
||||
JOptionPane.showMessageDialog(this, "代码生成失败: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// 获取选中的表
|
||||
private List<String> getSelectedTables() {
|
||||
return java.util.stream.IntStream.range(0, tableModel.getRowCount())
|
||||
.filter(i -> (Boolean) tableModel.getValueAt(i, 0))
|
||||
.mapToObj(i -> (String) tableModel.getValueAt(i, 1))
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
}
|
||||
|
||||
// 更新连接UI(在数据库连接配置变更时调用)
|
||||
public void updateConnectionUI() {
|
||||
// 重新加载配置
|
||||
loadConfig();
|
||||
}
|
||||
}
|
||||
151
src/main/java/com/codegenerator/util/CodeTestUtil.java
Normal file
151
src/main/java/com/codegenerator/util/CodeTestUtil.java
Normal file
@ -0,0 +1,151 @@
|
||||
package com.codegenerator.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class CodeTestUtil {
|
||||
|
||||
// 测试生成的代码
|
||||
public static Map<String, Object> testGeneratedCode(boolean generateVue2,boolean generateVue3) {
|
||||
Map<String, Object> testResult = new HashMap<>();
|
||||
List<String> successFiles = new ArrayList<>();
|
||||
List<String> errorFiles = new ArrayList<>();
|
||||
boolean isSuccess = true;
|
||||
|
||||
try {
|
||||
String projectPath = System.getProperty("user.dir");
|
||||
|
||||
// 检查后端代码
|
||||
testResult.put("backendTest", checkBackendCode(projectPath, successFiles, errorFiles));
|
||||
|
||||
if (generateVue2){
|
||||
// 检查Vue2前端代码
|
||||
testResult.put("vue2Test", checkFrontendCode(projectPath, "vue2", successFiles, errorFiles));
|
||||
}
|
||||
if (generateVue3) {
|
||||
// 检查Vue3前端代码
|
||||
testResult.put("vue3Test", checkFrontendCode(projectPath, "vue3", successFiles, errorFiles));
|
||||
}
|
||||
// 综合结果
|
||||
if (!errorFiles.isEmpty()) {
|
||||
isSuccess = false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
errorFiles.add("测试过程中发生异常: " + e.getMessage());
|
||||
isSuccess = false;
|
||||
}
|
||||
|
||||
testResult.put("success", isSuccess);
|
||||
testResult.put("successFiles", successFiles);
|
||||
testResult.put("errorFiles", errorFiles);
|
||||
return testResult;
|
||||
}
|
||||
|
||||
// 检查后端代码
|
||||
private static boolean checkBackendCode(String projectPath, List<String> successFiles, List<String> errorFiles) {
|
||||
boolean isSuccess = true;
|
||||
String backendDirPath = projectPath + "/generated-code/backend";
|
||||
File backendDir = new File(backendDirPath);
|
||||
|
||||
if (!backendDir.exists() || backendDir.listFiles() == null || backendDir.listFiles().length == 0) {
|
||||
errorFiles.add("后端代码目录不存在或为空: " + backendDirPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查Controller文件是否符合RESTful规范
|
||||
File controllerDir = new File(backendDirPath + "/src/main/java/com/example/controller");
|
||||
if (controllerDir.exists() && controllerDir.isDirectory()) {
|
||||
File[] controllerFiles = controllerDir.listFiles((dir, name) -> name.endsWith("Controller.java"));
|
||||
if (controllerFiles != null && controllerFiles.length > 0) {
|
||||
for (File file : controllerFiles) {
|
||||
try {
|
||||
String content = new String(java.nio.file.Files.readAllBytes(file.toPath()));
|
||||
// 检查是否包含RESTful注解
|
||||
if (content.contains("@RestController") && content.contains("@RequestMapping") &&
|
||||
content.contains("@GetMapping") && content.contains("@PostMapping") &&
|
||||
content.contains("@PutMapping") && content.contains("@DeleteMapping")) {
|
||||
successFiles.add("后端Controller文件符合RESTful规范: " + file.getName());
|
||||
} else {
|
||||
errorFiles.add("后端Controller文件不符合RESTful规范: " + file.getName());
|
||||
isSuccess = false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
errorFiles.add("读取Controller文件失败: " + file.getName() + ", 错误: " + e.getMessage());
|
||||
isSuccess = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
// 检查前端代码
|
||||
private static boolean checkFrontendCode(String projectPath, String version, List<String> successFiles, List<String> errorFiles) {
|
||||
boolean isSuccess = true;
|
||||
String frontendDirPath = projectPath + "/generated-code/frontend/" + version;
|
||||
File frontendDir = new File(frontendDirPath);
|
||||
|
||||
if (!frontendDir.exists() || frontendDir.listFiles() == null || frontendDir.listFiles().length == 0) {
|
||||
errorFiles.add(version + "前端代码目录不存在或为空: " + frontendDirPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查Vue组件文件
|
||||
File viewsDir = new File(frontendDirPath + "/src/views");
|
||||
if (viewsDir.exists() && viewsDir.isDirectory()) {
|
||||
File[] viewDirs = viewsDir.listFiles(File::isDirectory);
|
||||
if (viewDirs != null && viewDirs.length > 0) {
|
||||
for (File dir : viewDirs) {
|
||||
File listVueFile = new File(dir, "List.vue");
|
||||
File formVueFile = new File(dir, "Form.vue");
|
||||
|
||||
if (listVueFile.exists()) {
|
||||
successFiles.add(version + "列表组件文件存在: " + listVueFile.getPath());
|
||||
} else {
|
||||
errorFiles.add(version + "列表组件文件不存在: " + listVueFile.getPath());
|
||||
isSuccess = false;
|
||||
}
|
||||
|
||||
if (formVueFile.exists()) {
|
||||
successFiles.add(version + "表单组件文件存在: " + formVueFile.getPath());
|
||||
} else {
|
||||
errorFiles.add(version + "表单组件文件不存在: " + formVueFile.getPath());
|
||||
isSuccess = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查API文件
|
||||
File apiDir = new File(frontendDirPath + "/src/api");
|
||||
if (apiDir.exists() && apiDir.isDirectory()) {
|
||||
File[] apiFiles = apiDir.listFiles((dir, name) -> name.endsWith(".js"));
|
||||
if (apiFiles != null && apiFiles.length > 0) {
|
||||
for (File file : apiFiles) {
|
||||
successFiles.add(version + "API文件存在: " + file.getName());
|
||||
}
|
||||
} else {
|
||||
errorFiles.add(version + "API文件不存在: " + apiDir.getPath());
|
||||
isSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查request.js工具文件
|
||||
File utilsDir = new File(frontendDirPath + "/src/utils");
|
||||
File requestFile = new File(utilsDir, "request.js");
|
||||
if (requestFile.exists()) {
|
||||
successFiles.add(version + "请求工具文件存在: " + requestFile.getPath());
|
||||
} else {
|
||||
errorFiles.add(version + "请求工具文件不存在: " + requestFile.getPath());
|
||||
isSuccess = false;
|
||||
}
|
||||
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
}
|
||||
161
src/main/java/com/codegenerator/util/ConfigUtil.java
Normal file
161
src/main/java/com/codegenerator/util/ConfigUtil.java
Normal file
@ -0,0 +1,161 @@
|
||||
package com.codegenerator.util;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.setting.dialect.Props;
|
||||
import com.codegenerator.config.DbConnectionConfig;
|
||||
import com.codegenerator.config.GeneratorConfig;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ConfigUtil {
|
||||
private static final String CONFIG_FILE = "codegenerator.properties";
|
||||
private static Props props;
|
||||
|
||||
static {
|
||||
init();
|
||||
}
|
||||
|
||||
private static void init() {
|
||||
File file = new File(CONFIG_FILE);
|
||||
if (!file.exists()) {
|
||||
FileUtil.touch(file);
|
||||
}
|
||||
props = new Props(file);
|
||||
}
|
||||
|
||||
// 保存数据库连接配置
|
||||
public static void saveDbConfig(String connName, String dbType, String url, String username, String password) {
|
||||
props.setProperty("db.connName", connName);
|
||||
props.setProperty("db.type", dbType);
|
||||
props.setProperty("db.url", url);
|
||||
props.setProperty("db.username", username);
|
||||
props.setProperty("db.password", password);
|
||||
props.store(CONFIG_FILE);
|
||||
}
|
||||
|
||||
// 保存多个数据库连接配置
|
||||
public static void saveDbConnections(List<DbConnectionConfig> connections, int selectedIndex) {
|
||||
// 清除旧的连接配置
|
||||
for (int i = 0; i < 100; i++) { // 最大100个连接
|
||||
String prefix = "db.connections." + i + ".";
|
||||
if (!props.containsKey(prefix + "name")) {
|
||||
break;
|
||||
}
|
||||
props.remove(prefix + "name");
|
||||
props.remove(prefix + "dbType");
|
||||
props.remove(prefix + "url");
|
||||
props.remove(prefix + "username");
|
||||
props.remove(prefix + "password");
|
||||
}
|
||||
|
||||
// 保存新的连接配置
|
||||
for (int i = 0; i < connections.size(); i++) {
|
||||
DbConnectionConfig conn = connections.get(i);
|
||||
String prefix = "db.connections." + i + ".";
|
||||
props.setProperty(prefix + "name", conn.getName());
|
||||
props.setProperty(prefix + "dbType", conn.getDbType());
|
||||
props.setProperty(prefix + "url", conn.getUrl());
|
||||
props.setProperty(prefix + "username", conn.getUsername());
|
||||
props.setProperty(prefix + "password", conn.getPassword());
|
||||
}
|
||||
|
||||
// 保存当前选中的连接索引
|
||||
props.setProperty("db.selectedIndex", String.valueOf(selectedIndex));
|
||||
props.store(CONFIG_FILE);
|
||||
}
|
||||
|
||||
// 加载多个数据库连接配置
|
||||
public static GeneratorConfig loadDbConnections() {
|
||||
GeneratorConfig config = new GeneratorConfig();
|
||||
config.setDbConnections(new ArrayList<>());
|
||||
|
||||
// 加载连接列表
|
||||
for (int i = 0; i < 100; i++) { // 最大100个连接
|
||||
String prefix = "db.connections." + i + ".";
|
||||
if (!props.containsKey(prefix + "name")) {
|
||||
break;
|
||||
}
|
||||
|
||||
DbConnectionConfig conn = new DbConnectionConfig();
|
||||
conn.setName(props.getStr(prefix + "name", ""));
|
||||
conn.setDbType(props.getStr(prefix + "dbType", "mysql"));
|
||||
conn.setUrl(props.getStr(prefix + "url", ""));
|
||||
conn.setUsername(props.getStr(prefix + "username", ""));
|
||||
conn.setPassword(props.getStr(prefix + "password", ""));
|
||||
|
||||
config.getDbConnections().add(conn);
|
||||
}
|
||||
|
||||
// 加载选中的连接索引
|
||||
int selectedIndex = props.getInt("db.selectedIndex", 0);
|
||||
config.setSelectedDbConnectionIndex(selectedIndex);
|
||||
|
||||
// 如果没有连接,初始化默认连接
|
||||
if (config.getDbConnections().isEmpty()) {
|
||||
config.initDefaultConnections();
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
// 获取数据库连接配置
|
||||
public static Map<String, String> getDbConfig() {
|
||||
Map<String, String> config = new HashMap<>();
|
||||
config.put("connName", props.getStr("db.connName", ""));
|
||||
config.put("dbType", props.getStr("db.type", "mysql"));
|
||||
config.put("url", props.getStr("db.url", ""));
|
||||
config.put("username", props.getStr("db.username", ""));
|
||||
config.put("password", props.getStr("db.password", ""));
|
||||
return config;
|
||||
}
|
||||
|
||||
// 保存代码生成配置
|
||||
public static void saveGeneratorConfig(String basePackage, boolean useLombok,
|
||||
String superEntityClass, String[] superEntityColumns,boolean generateVue2,boolean generateVue3) {
|
||||
props.setProperty("codegenerator.basePackage", basePackage);
|
||||
props.setProperty("codegenerator.useLombok", String.valueOf(useLombok));
|
||||
props.setProperty("codegenerator.superEntityClass", superEntityClass);
|
||||
props.setProperty("codegenerator.superEntityColumns", StrUtil.join(",", superEntityColumns));
|
||||
props.setProperty("codegenerator.generateVue2", generateVue2);
|
||||
props.setProperty("codegenerator.generateVue3", generateVue3);
|
||||
props.store(CONFIG_FILE);
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
saveGeneratorConfig("com.seer.teach", true, "com.seer.teach.common.BaseEntity", new String[]{"id", "createTime", "updateTime"},true,true);
|
||||
System.out.println(getGeneratorConfig());
|
||||
}
|
||||
|
||||
// 获取代码生成配置 - 返回配置对象
|
||||
public static GeneratorConfig getGeneratorConfigAsObject() {
|
||||
GeneratorConfig config = new GeneratorConfig();
|
||||
Map<String, Object> generatorConfig = getGeneratorConfig();
|
||||
|
||||
config.setBasePackage((String) generatorConfig.get("basePackage"));
|
||||
config.setUseLombok((Boolean) generatorConfig.get("useLombok"));
|
||||
config.setSuperEntityClass((String) generatorConfig.get("superEntityClass"));
|
||||
config.setSuperEntityColumns((String[]) generatorConfig.get("superEntityColumns"));
|
||||
config.setGenerateVue2((Boolean) generatorConfig.get("generateVue2"));
|
||||
config.setGenerateVue3((Boolean) generatorConfig.get("generateVue3"));
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
// 获取代码生成配置
|
||||
public static Map<String, Object> getGeneratorConfig() {
|
||||
Map<String, Object> config = new HashMap<>();
|
||||
config.put("basePackage", props.getStr("codegenerator.basePackage", "com.seer.teach"));
|
||||
config.put("useLombok", props.getBool("codegenerator.useLombok", true));
|
||||
config.put("superEntityClass", props.getStr("codegenerator.superEntityClass", "com.seer.teach.common.BaseEntity"));
|
||||
config.put("superEntityColumns", props.getStr("codegenerator.superEntityColumns", "id,createTime,updateTime").split(","));
|
||||
config.put("generateVue3", props.getBool("codegenerator.generateVue3", true));
|
||||
config.put("generateVue2", props.getBool("codegenerator.generateVue2", true));
|
||||
return config;
|
||||
}
|
||||
}
|
||||
195
src/main/java/com/codegenerator/util/DatabaseUtil.java
Normal file
195
src/main/java/com/codegenerator/util/DatabaseUtil.java
Normal file
@ -0,0 +1,195 @@
|
||||
package com.codegenerator.util;
|
||||
|
||||
import com.mysql.cj.jdbc.Driver;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DatabaseUtil {
|
||||
private static Connection connection;
|
||||
|
||||
// 测试数据库连接
|
||||
public static boolean testConnection(String url, String username, String password) {
|
||||
try {
|
||||
Class.forName(Driver.class.getName());
|
||||
connection = java.sql.DriverManager.getConnection(url, username, password);
|
||||
return connection.isValid(3000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取数据库连接
|
||||
public static Connection getConnection(String url, String username, String password) throws SQLException, ClassNotFoundException {
|
||||
Class.forName(Driver.class.getName());
|
||||
return java.sql.DriverManager.getConnection(url, username, password);
|
||||
}
|
||||
|
||||
// 获取所有非系统表
|
||||
public static List<String> getTables(String url, String username, String password) {
|
||||
List<String> tables = new ArrayList<>();
|
||||
Connection conn = null;
|
||||
Statement stmt = null;
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
conn = getConnection(url, username, password);
|
||||
// MySQL查询非系统表
|
||||
String sql = "SELECT table_name FROM information_schema.tables " +
|
||||
"WHERE table_schema = (SELECT database()) " +
|
||||
"AND table_type = 'BASE TABLE' " +
|
||||
"AND table_name NOT LIKE 'sys_%' " +
|
||||
"AND table_name NOT LIKE 'information_schema_%' " +
|
||||
"AND table_name NOT LIKE 'mysql_%' " +
|
||||
"AND table_name NOT LIKE 'performance_schema_%'";
|
||||
|
||||
// 使用传统JDBC方法执行查询
|
||||
stmt = conn.createStatement();
|
||||
rs = stmt.executeQuery(sql);
|
||||
|
||||
// 处理结果集
|
||||
while (rs.next()) {
|
||||
tables.add(rs.getString("table_name"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
// 关闭资源
|
||||
if (rs != null) {
|
||||
try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }
|
||||
}
|
||||
if (stmt != null) {
|
||||
try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); }
|
||||
}
|
||||
if (conn != null) {
|
||||
try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }
|
||||
}
|
||||
}
|
||||
return tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取表的列信息
|
||||
* @param url 数据库连接URL
|
||||
* @param username 用户名
|
||||
* @param password 密码
|
||||
* @param tableNames 表名列表
|
||||
* @return 表的列信息
|
||||
*/
|
||||
public static Map<String, Map<String, Object>> getTableColumns(String url, String username, String password, List<String> tableNames) {
|
||||
Map<String, Map<String, Object>> tableColumnsInfo = new HashMap<>();
|
||||
|
||||
// 创建表名列表的SQL字符串
|
||||
StringBuilder tableNamesList = new StringBuilder();
|
||||
for (int i = 0; i < tableNames.size(); i++) {
|
||||
if (i > 0) {
|
||||
tableNamesList.append(",");
|
||||
}
|
||||
tableNamesList.append("'").append(tableNames.get(i)).append("'");
|
||||
}
|
||||
|
||||
Connection conn = null;
|
||||
Statement stmt = null;
|
||||
ResultSet rs = null;
|
||||
|
||||
try {
|
||||
conn = getConnection(url, username, password);
|
||||
|
||||
// 一次性查询所有表的列信息
|
||||
String sql = "SELECT " +
|
||||
"TABLE_NAME, " +
|
||||
"COLUMN_NAME, " +
|
||||
"DATA_TYPE, " +
|
||||
"IS_NULLABLE, " +
|
||||
"COLUMN_DEFAULT, " +
|
||||
"COLUMN_COMMENT, " +
|
||||
"ORDINAL_POSITION, " +
|
||||
"CHARACTER_MAXIMUM_LENGTH, " +
|
||||
"NUMERIC_PRECISION, " +
|
||||
"NUMERIC_SCALE, " +
|
||||
"COLUMN_KEY " +
|
||||
"FROM information_schema.COLUMNS " +
|
||||
"WHERE TABLE_SCHEMA = (SELECT DATABASE()) " +
|
||||
"AND TABLE_NAME IN (" + tableNamesList.toString() + ") " +
|
||||
"ORDER BY TABLE_NAME, ORDINAL_POSITION";
|
||||
|
||||
stmt = conn.createStatement();
|
||||
rs = stmt.executeQuery(sql);
|
||||
|
||||
// 按表名分组处理结果
|
||||
String currentTable = null;
|
||||
Map<String, Object> currentTableInfo = null;
|
||||
List<Map<String, Object>> currentColumns = null;
|
||||
|
||||
while (rs.next()) {
|
||||
String tableName = rs.getString("TABLE_NAME");
|
||||
|
||||
// 如果是新表,初始化表信息
|
||||
if (!tableName.equals(currentTable)) {
|
||||
if (currentTable != null) {
|
||||
// 保存上一个表的信息
|
||||
currentTableInfo.put("columns", currentColumns);
|
||||
tableColumnsInfo.put(currentTable, currentTableInfo);
|
||||
}
|
||||
|
||||
// 初始化新表的信息
|
||||
currentTable = tableName;
|
||||
currentTableInfo = new HashMap<>();
|
||||
currentColumns = new ArrayList<>();
|
||||
}
|
||||
|
||||
// 添加列信息
|
||||
Map<String, Object> column = new HashMap<>();
|
||||
column.put("columnName", rs.getString("COLUMN_NAME"));
|
||||
column.put("dataType", rs.getString("DATA_TYPE"));
|
||||
column.put("isNullable", rs.getString("IS_NULLABLE"));
|
||||
column.put("columnDefault", rs.getString("COLUMN_DEFAULT"));
|
||||
column.put("columnComment", rs.getString("COLUMN_COMMENT"));
|
||||
column.put("ordinalPosition", rs.getInt("ORDINAL_POSITION"));
|
||||
column.put("characterMaximumLength", rs.getObject("CHARACTER_MAXIMUM_LENGTH"));
|
||||
column.put("numericPrecision", rs.getObject("NUMERIC_PRECISION"));
|
||||
column.put("numericScale", rs.getObject("NUMERIC_SCALE"));
|
||||
column.put("columnKey", rs.getString("COLUMN_KEY"));
|
||||
|
||||
currentColumns.add(column);
|
||||
}
|
||||
|
||||
// 保存最后一个表的信息
|
||||
if (currentTable != null) {
|
||||
currentTableInfo.put("columns", currentColumns);
|
||||
tableColumnsInfo.put(currentTable, currentTableInfo);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
// 关闭资源
|
||||
if (rs != null) {
|
||||
try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }
|
||||
}
|
||||
if (stmt != null) {
|
||||
try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); }
|
||||
}
|
||||
if (conn != null) {
|
||||
try { conn.close(); } catch (SQLException e) { e.printStackTrace(); }
|
||||
}
|
||||
}
|
||||
|
||||
return tableColumnsInfo;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
package com.seer.teach.common.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import lombok.ToString;
import java.time.LocalDateTime;
/**
* @Author: Captain
* @Autograph: 安稳
* @Description:
* @Date: 2023-07-20 16:44:26
*/
@Data
@ToString
public class BaseEntity {
/**
* 主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 是否删除,0-正常,1-删除
*/
@TableField("deleted")
@TableLogic
private Integer deleted=0;
/**
* 更新时间
*/
@TableField(value = "update_time", fill = FieldFill.UPDATE)
private LocalDateTime updateTime;
/**
* 创建人
*/
@TableField(value = "create_by", fill = FieldFill.INSERT)
private String createBy;
/**
* 创建时间
*/
@TableField(value = "create_time", fill = FieldFill.INSERT)
private LocalDateTime createTime;
/**
* 修改人
*/
@TableField(value = "update_by", fill = FieldFill.UPDATE)
private String updateBy;
/**
* 租户ID
*/
@TableField(value = "tenant_id")
private String tenantId;
}
|
||||
@ -0,0 +1,21 @@
|
||||
package ${basePackage}.${moduleName}.convert;
|
||||
|
||||
import ${basePackage}.${moduleName}.admin.controller.request.${className}Req;
|
||||
import ${basePackage}.${moduleName}.admin.controller.response.${className}Resp;
|
||||
import ${basePackage}.${moduleName}.entity.${className}Entity;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface ${prefix}${className}Convert {
|
||||
|
||||
${prefix}${className}Convert INSTANCE = Mappers.getMapper(${prefix}${className}Convert.class);
|
||||
|
||||
${prefix}${className}Resp entityToResponse(${className}Entity ${varName}Entity);
|
||||
|
||||
List<${prefix}${className}Resp> entityListToResponseList(List<${className}Entity> ${varName}EntityList);
|
||||
|
||||
${className}Entity reqToEntity(${prefix}${className}Req ${varName}Request);
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
|
||||
package ${basePackage}.controller;
|
||||
|
||||
import com.seer.teach.common.PageListBean;
|
||||
import com.seer.teach.common.ResultBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import ${basePackage}.${moduleName}.admin.controller.request.Admin${className}Req;
|
||||
import ${basePackage}.${moduleName}.admin.controller.response.Admin${className}Resp;
|
||||
import ${basePackage}.${moduleName}.service.Admin${className}Service;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ${className}控制器
|
||||
*
|
||||
* @author ${author}
|
||||
* @since ${date?string("yyyy-MM-dd")}
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/${moduleName}/${className}")
|
||||
@Api(tags = "${className}管理")
|
||||
public class ${prefix}${className}Controller {
|
||||
|
||||
private final ${prefix}${className}Service admin${className}Service;
|
||||
|
||||
@GetMapping("/paged")
|
||||
@ApiOperation("分页查询${className}")
|
||||
public ResultBean<PageListBean<${prefix}${className}Resp>> pageList(@RequestBody Admin${className}PageReq pageRequest) {
|
||||
return ResultBean.success(admin${className}Service.pageList(pageRequest));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@ApiOperation("获取${className}列表")
|
||||
public ResultBean<List<${prefix}${className}Resp>> list(Admin${className}QueryReq queryRequest) {
|
||||
return ResultBean.success(admin${className}Service.list(queryRequest));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
@ApiOperation("根据ID获取${className}")
|
||||
public ResultBean<${prefix}${className}Resp> getById(@PathVariable Integer id) {
|
||||
return ResultBean.success(admin${className}Service.getDetail(id));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
@ApiOperation("新增${className}")
|
||||
public ResultBean<Boolean> save(@RequestBody Admin${className}Req requestParam) {
|
||||
return ResultBean.success(admin${className}Service.save(requestParam));
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
@ApiOperation("更新${className}")
|
||||
public ResultBean<Boolean> update(@RequestBody Admin${className}Req requestParam) {
|
||||
return ResultBean.success(admin${className}Service.updateById(requestParam));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@ApiOperation("删除${className}")
|
||||
public ResultBean<Boolean> delete(@PathVariable Integer id) {
|
||||
return ResultBean.success(admin${className}Service.deleteById(id));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package ${basePackage}.${moduleName}.admin.controller.request;
|
||||
|
||||
import com.seer.teach.common.request.PageRequest;
|
||||
import lombok.Data;
|
||||
<#if hasDateField>
|
||||
import java.util.Date;
|
||||
</#if>
|
||||
<#if hasBigDecimalField>
|
||||
import java.math.BigDecimal;
|
||||
</#if>
|
||||
|
||||
/**
|
||||
* 分页请求基类
|
||||
*/
|
||||
@Data
|
||||
public class Admin${className}PageReq extends PageRequest {
|
||||
<#if columns??>
|
||||
<#list columns as column>
|
||||
<#assign javaType = column.javaType>
|
||||
<#if javaType == "Date">
|
||||
private Date ${column.propertyName};
|
||||
<#elseif javaType == "BigDecimal">
|
||||
private BigDecimal ${column.propertyName};
|
||||
<#elseif javaType == "Boolean">
|
||||
private Boolean ${column.propertyName};
|
||||
<#elseif javaType == "Integer">
|
||||
private Integer ${column.propertyName};
|
||||
<#elseif javaType == "Long">
|
||||
private Long ${column.propertyName};
|
||||
<#elseif javaType == "Double">
|
||||
private Double ${column.propertyName};
|
||||
<#else>
|
||||
private String ${column.propertyName};
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package ${basePackage}.${moduleName}.admin.controller.request;
|
||||
|
||||
import lombok.Data;
|
||||
<#if hasDateField>
|
||||
import java.util.Date;
|
||||
</#if>
|
||||
<#if hasBigDecimalField>
|
||||
import java.math.BigDecimal;
|
||||
</#if>
|
||||
|
||||
/**
|
||||
* ${className}查询请求类
|
||||
*/
|
||||
@Data
|
||||
public class Admin${className}QueryReq {
|
||||
<#if columns??>
|
||||
<#list columns as column>
|
||||
<#assign javaType = column.javaType>
|
||||
<#if javaType == "Date">
|
||||
private Date ${column.propertyName};
|
||||
<#elseif javaType == "BigDecimal">
|
||||
private BigDecimal ${column.propertyName};
|
||||
<#elseif javaType == "Boolean">
|
||||
private Boolean ${column.propertyName};
|
||||
<#elseif javaType == "Integer">
|
||||
private Integer ${column.propertyName};
|
||||
<#elseif javaType == "Long">
|
||||
private Long ${column.propertyName};
|
||||
<#elseif javaType == "Double">
|
||||
private Double ${column.propertyName};
|
||||
<#else>
|
||||
private String ${column.propertyName};
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package ${basePackage}.controller.request;
|
||||
|
||||
import lombok.Data;
|
||||
<#if hasDateField>
|
||||
import java.util.Date;
|
||||
</#if>
|
||||
<#if hasBigDecimalField>
|
||||
import java.math.BigDecimal;
|
||||
</#if>
|
||||
|
||||
/**
|
||||
* ${className}请求类
|
||||
*/
|
||||
@Data
|
||||
public class Admin${className}Req {
|
||||
<#if columns??>
|
||||
<#list columns as column>
|
||||
<#assign javaType = column.javaType>
|
||||
<#if javaType == "Date">
|
||||
private Date ${column.propertyName};
|
||||
<#elseif javaType == "BigDecimal">
|
||||
private BigDecimal ${column.propertyName};
|
||||
<#elseif javaType == "Boolean">
|
||||
private Boolean ${column.propertyName};
|
||||
<#elseif javaType == "Integer">
|
||||
private Integer ${column.propertyName};
|
||||
<#elseif javaType == "Long">
|
||||
private Long ${column.propertyName};
|
||||
<#elseif javaType == "Double">
|
||||
private Double ${column.propertyName};
|
||||
<#else>
|
||||
private String ${column.propertyName};
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package ${basePackage}.${moduleName}.admin.controller.response;
|
||||
|
||||
import lombok.Data;
|
||||
<#if hasDateField>
|
||||
import java.util.Date;
|
||||
</#if>
|
||||
<#if hasBigDecimalField>
|
||||
import java.math.BigDecimal;
|
||||
</#if>
|
||||
|
||||
/**
|
||||
* ${className}响应类
|
||||
*/
|
||||
@Data
|
||||
public class Admin${className}Resp {
|
||||
<#if columns??>
|
||||
<#list columns as column>
|
||||
<#assign javaType = column.javaType>
|
||||
<#if javaType == "Date">
|
||||
private Date ${column.propertyName};
|
||||
<#elseif javaType == "BigDecimal">
|
||||
private BigDecimal ${column.propertyName};
|
||||
<#elseif javaType == "Boolean">
|
||||
private Boolean ${column.propertyName};
|
||||
<#elseif javaType == "Integer">
|
||||
private Integer ${column.propertyName};
|
||||
<#elseif javaType == "Long">
|
||||
private Long ${column.propertyName};
|
||||
<#elseif javaType == "Double">
|
||||
private Double ${column.propertyName};
|
||||
<#else>
|
||||
private String ${column.propertyName};
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
package ${basePackage}.${moduleName}.admin.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.seer.teach.common.PageListBean;
|
||||
import com.seer.teach.common.utils.PageConverterUtils;
|
||||
import ${basePackage}.${moduleName}.controller.request.${className}PageRequest;
|
||||
import ${basePackage}.${moduleName}.controller.request.${className}Req;
|
||||
import ${basePackage}.${moduleName}.controller.response.${className}Response;
|
||||
import ${basePackage}.${moduleName}.convert.${className}Convert;
|
||||
import ${basePackage}.entity.${className}Entity;
|
||||
import ${basePackage}.service.I${className}Service;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class Admin${className}Service {
|
||||
|
||||
private final I${className}Service ${varName}Service;
|
||||
|
||||
public PageListBean<${prefix}${className}Resp> pageList(${prefix}${className}PageReq pageRequest) {
|
||||
IPage<${className}Entity> page = new Page<>(pageRequest.getPageNo(), pageRequest.getPageSize());
|
||||
|
||||
IPage<${className}Entity> result = ${varName}Service.page(page, new LambdaQueryWrapper<${className}Entity>()
|
||||
<#if columns?? && columns?size gt 0>
|
||||
<#list columns as column>
|
||||
.eq(Objects.nonNull(pageRequest.get${column.propertyName?cap_first}()), ${className}Entity::get${column.propertyName?cap_first}, pageRequest.get${column.propertyName?cap_first}())
|
||||
</#list>
|
||||
</#if>
|
||||
);
|
||||
|
||||
return PageConverterUtils.convertPageListBean(result, ${prefix}${className}Convert.INSTANCE::entityListToResponseList);
|
||||
}
|
||||
|
||||
public List<${prefix}${className}Resp> list(${prefix}${className}QueryReq queryParam) {
|
||||
List<${className}Entity> result = ${varName}Service.list(new LambdaQueryWrapper<${className}Entity>()
|
||||
<#if columns?? && columns?size gt 0>
|
||||
<#list columns as column>
|
||||
.eq(Objects.nonNull(queryParam.get${column.propertyName?cap_first}()), ${className}Entity::get${column.propertyName?cap_first}, queryParam.get${column.propertyName?cap_first}())
|
||||
</#list>
|
||||
</#if>
|
||||
);
|
||||
return ${prefix}${className}Convert.INSTANCE.entityListToResponseList(result);
|
||||
}
|
||||
|
||||
public ${prefix}${className}Resp getDetail(Integer id) {
|
||||
${className}Entity result = ${varName}Service.getById(id);
|
||||
log.info("getById:{}", result);
|
||||
return ${prefix}${className}Convert.INSTANCE.entityToResponse(result);
|
||||
}
|
||||
|
||||
public boolean save(${prefix}${className}Req ${varName}) {
|
||||
${className}Entity entity = ${prefix}${className}Convert.INSTANCE.reqToEntity(${varName});
|
||||
boolean saved = ${varName}Service.save(entity);
|
||||
log.info("save:{}", saved);
|
||||
return saved;
|
||||
}
|
||||
|
||||
public boolean updateById(${prefix}${className}Req ${varName}) {
|
||||
${className}Entity entity = ${prefix}${className}Convert.INSTANCE.reqToEntity(${varName});
|
||||
boolean updated = ${varName}Service.updateById(entity);
|
||||
log.info("updateById:{}", updated);
|
||||
return updated;
|
||||
}
|
||||
|
||||
public boolean deleteById(Integer id) {
|
||||
boolean updated = ${varName}Service.removeById(id);
|
||||
log.info("deleteById:{}", updated);
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
47
src/main/resources/templates/frontend/api/api.js.ftl
Normal file
47
src/main/resources/templates/frontend/api/api.js.ftl
Normal file
@ -0,0 +1,47 @@
|
||||
import axios from 'axios'
|
||||
|
||||
// 创建axios实例
|
||||
const service = axios.create({
|
||||
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
|
||||
timeout: 5000 // 请求超时时间
|
||||
})
|
||||
|
||||
// 请求拦截器
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
// 在发送请求之前做些什么
|
||||
// 如果有token,就添加到请求头中
|
||||
if ([token]) {
|
||||
config.headers['Authorization'] = [token]
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
// 对请求错误做些什么
|
||||
console.log(error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截器
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
const res = response.data
|
||||
|
||||
// 如果返回的状态码不是200,则判断为错误
|
||||
if (res.code !== 200) {
|
||||
// 处理错误信息
|
||||
console.log('Error: ' + res.message)
|
||||
return Promise.reject(new Error(res.message || 'Error'))
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
},
|
||||
error => {
|
||||
// 对响应错误做些什么
|
||||
console.log('err' + error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default service
|
||||
112
src/main/resources/templates/frontend/vue2/form.vue.ftl
Normal file
112
src/main/resources/templates/frontend/vue2/form.vue.ftl
Normal file
@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="title"
|
||||
:visible.sync="visible"
|
||||
width="500px"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form
|
||||
ref="form"
|
||||
:model="model"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
>
|
||||
<!-- 这里可以根据实际表结构动态生成表单字段 -->
|
||||
<el-form-item label="ID" v-if="model.id">
|
||||
<el-input v-model="model.id" disabled></el-input>
|
||||
</el-form-item>
|
||||
<#if columns?? && columns.columns??>
|
||||
<#list columns.columns as column>
|
||||
<#assign columnName = column.columnName>
|
||||
<#assign propertyName = column.propertyName>
|
||||
<#assign comment = column.comment!columnName>
|
||||
<#if !["id", "createTime", "updateTime", "createBy", "updateBy", "deleted"].contains(propertyName)>
|
||||
<el-form-item label="${comment}" prop="${propertyName}">
|
||||
<#if column.javaType == "String">
|
||||
<el-input v-model="model.${propertyName}" placeholder="请输入${comment}" />
|
||||
<#elseif column.javaType == "Integer" || column.javaType == "Long" || column.javaType == "Double">
|
||||
<el-input-number v-model="model.${propertyName}" placeholder="请输入${comment}" />
|
||||
<#elseif column.javaType == "Boolean">
|
||||
<el-switch v-model="model.${propertyName}" />
|
||||
<#elseif column.javaType == "Date">
|
||||
<el-date-picker v-model="model.${propertyName}" type="date" placeholder="请选择${comment}" />
|
||||
<#else>
|
||||
<el-input v-model="model.${propertyName}" placeholder="请输入${comment}" />
|
||||
</#if>
|
||||
</el-form-item>
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
</el-form>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { save${className}, update${className} } from '@/api/${varName}'
|
||||
|
||||
export default {
|
||||
name: '${className}Form',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rules: {
|
||||
// 这里可以根据实际表结构动态生成表单验证规则
|
||||
<#if columns?? && columns.columns??>
|
||||
<#list columns.columns as column>
|
||||
<#assign propertyName = column.propertyName>
|
||||
</#if>
|
||||
</#list>
|
||||
</#if>
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return this.model.id ? '编辑${className}' : '新增${className}'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSubmit() {
|
||||
this.$refs.form.validate((valid) => {
|
||||
if (valid) {
|
||||
const isEdit = !!this.model.id
|
||||
const request = isEdit ? update${className}(this.model) : save${className}(this.model)
|
||||
|
||||
request.then(response => {
|
||||
if (response.code === 200) {
|
||||
this.$message.success(isEdit ? '更新成功' : '新增成功')
|
||||
this.$emit('success')
|
||||
} else {
|
||||
this.$message.error(response.msg)
|
||||
}
|
||||
}).catch(error => {
|
||||
this.$message.error(isEdit ? '更新失败' : '新增失败')
|
||||
console.error(error)
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
handleCancel() {
|
||||
this.$emit('close')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
165
src/main/resources/templates/frontend/vue2/list.vue.ftl
Normal file
165
src/main/resources/templates/frontend/vue2/list.vue.ftl
Normal file
@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="filter-container">
|
||||
<el-input v-model="searchParams.keyword" placeholder="请输入关键词" style="width: 200px;" class="filter-item" @keyup.enter.native="handleQuery" />
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery" class="filter-item">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery" class="filter-item">重置</el-button>
|
||||
<el-button type="primary" icon="el-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>
|
||||
<#assign comment = column.comment!columnName>
|
||||
<el-table-column label="${comment}" prop="${propertyName}" />
|
||||
</#list>
|
||||
</#if>
|
||||
|
||||
<el-table-column label="操作" width="200" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" @click="handleView(scope.row)">查看</el-button>
|
||||
<el-button size="mini" type="text" @click="handleEdit(scope.row)">编辑</el-button>
|
||||
<el-button size="mini" 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 :visible.sync="dialogVisible" :title="dialogTitle" width="500px">
|
||||
<${entityName}Form ref="form" :data="formData" />
|
||||
<div slot="footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { get${entityName}List, delete${entityName} } from '@/api/${lowerEntityName}'
|
||||
import ${entityName}Form from './${entityName}Form'
|
||||
|
||||
export default {
|
||||
name: '${entityName}List',
|
||||
components: { ${entityName}Form },
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
listLoading: false,
|
||||
searchParams: {
|
||||
keyword: ''
|
||||
},
|
||||
pagination: {
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
},
|
||||
dialogVisible: false,
|
||||
dialogTitle: '',
|
||||
formData: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.handleQuery()
|
||||
},
|
||||
methods: {
|
||||
handleQuery() {
|
||||
this.listLoading = true
|
||||
get${entityName}List({
|
||||
pageNum: this.pagination.currentPage,
|
||||
pageSize: this.pagination.pageSize,
|
||||
...this.searchParams
|
||||
}).then(response => {
|
||||
this.list = response.data.records
|
||||
this.pagination.total = response.data.total
|
||||
this.listLoading = false
|
||||
}).catch(() => {
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
resetQuery() {
|
||||
this.searchParams = {
|
||||
keyword: ''
|
||||
}
|
||||
this.pagination.currentPage = 1
|
||||
this.handleQuery()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.pagination.pageSize = val
|
||||
this.handleQuery()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.pagination.currentPage = val
|
||||
this.handleQuery()
|
||||
},
|
||||
handleAdd() {
|
||||
this.dialogTitle = '新增${entityName}'
|
||||
this.formData = {}
|
||||
this.dialogVisible = true
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.dialogTitle = '编辑${entityName}'
|
||||
this.formData = { ...row }
|
||||
this.dialogVisible = true
|
||||
},
|
||||
handleView(row) {
|
||||
this.dialogTitle = '查看${entityName}'
|
||||
this.formData = { ...row }
|
||||
this.dialogVisible = true
|
||||
},
|
||||
handleDelete(row) {
|
||||
this.$confirm('确定要删除这条记录吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
delete${entityName}(row.id).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.handleQuery()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleSubmit() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (valid) {
|
||||
// 调用保存方法,实际项目中需要根据新增/编辑调用不同接口
|
||||
this.$message.success('保存成功')
|
||||
this.dialogVisible = false
|
||||
this.handleQuery()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.filter-container {
|
||||
padding: 10px 0;
|
||||
}
|
||||
.filter-item {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
</file5>
|
||||
92
src/main/resources/templates/frontend/vue3/form.vue.ftl
Normal file
92
src/main/resources/templates/frontend/vue3/form.vue.ftl
Normal file
@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="title"
|
||||
v-model="visible"
|
||||
width="500px"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="model"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
>
|
||||
<!-- 这里可以根据实际表结构动态生成表单字段 -->
|
||||
<el-form-item label="ID" v-if="model.id">
|
||||
<el-input v-model="model.id" disabled></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit">确定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, defineProps, defineEmits } from 'vue'
|
||||
import { save${className}, update${className} } from '@/api/${varName}'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
// 定义属性
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
model: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
// 定义事件
|
||||
const emit = defineEmits(['success', 'close'])
|
||||
|
||||
// 表单引用
|
||||
const formRef = ref(null)
|
||||
|
||||
// 表单数据
|
||||
const formModel = ref({ ...props.model })
|
||||
|
||||
// 验证规则
|
||||
const rules = ref({
|
||||
// 这里可以根据实际表结构动态生成表单验证规则
|
||||
})
|
||||
|
||||
// 标题
|
||||
const title = computed(() => {
|
||||
return formModel.value.id ? '编辑${className}' : '新增${className}'
|
||||
})
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
await formRef.value.validate()
|
||||
|
||||
const isEdit = !!formModel.value.id
|
||||
const request = isEdit ? update${className}(formModel.value) : save${className}(formModel.value)
|
||||
|
||||
const response = await request
|
||||
if (response.code === 200) {
|
||||
ElMessage.success(isEdit ? '更新成功' : '新增成功')
|
||||
emit('success')
|
||||
} else {
|
||||
ElMessage.error(response.msg)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('表单验证失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 取消
|
||||
const handleCancel = () => {
|
||||
emit('close')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
176
src/main/resources/templates/frontend/vue3/list.vue.ftl
Normal file
176
src/main/resources/templates/frontend/vue3/list.vue.ftl
Normal file
@ -0,0 +1,176 @@
|
||||
<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" />
|
||||
<!-- 这里可以根据实际字段动态生成表格列 -->
|
||||
|
||||
<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>
|
||||
Loading…
x
Reference in New Issue
Block a user