fix: 优化导出功能
优化项目导出逻辑
This commit is contained in:
parent
8cfe070b9a
commit
18a5ab367b
@ -1,38 +1,46 @@
|
|||||||
package io.gisbi.application.appcode.controller;
|
package io.gisbi.application.appcode.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import io.gisbi.application.appcode.doman.TableData;
|
import io.gisbi.application.appcode.doman.TableData;
|
||||||
import io.gisbi.application.appcode.service.DatabaseService;
|
import io.gisbi.application.appcode.service.DatabaseService;
|
||||||
import io.gisbi.application.appcode.utils.ZipUtils;
|
import io.gisbi.application.appcode.utils.ZipUtils;
|
||||||
|
import io.gisbi.application.module.domain.Module;
|
||||||
|
import io.gisbi.application.module.service.IModuleService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.util.FileCopyUtils;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.yaml.snakeyaml.DumperOptions;
|
||||||
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/project")
|
@RequestMapping("/project")
|
||||||
public class ProjectExportController {
|
public class ProjectExportController {
|
||||||
|
|
||||||
|
|
||||||
// 模板 ZIP 文件路径
|
// 模板 ZIP 文件路径
|
||||||
private static final String FIXED_ZIP_PATH = "E:/opt/gisbi2.0/";
|
private static final String FIXED_ZIP_PATH = "E:/opt/gisbi2.0/";
|
||||||
|
|
||||||
private static final String FIXED_ZIP_NAME = "backend.zip";
|
private static final String FIXED_ZIP_NAME = "stdproject.zip";
|
||||||
|
|
||||||
private static final String FIXED_ZIP_FULL_PATH = FIXED_ZIP_PATH + FIXED_ZIP_NAME;
|
private static final String FIXED_ZIP_FULL_PATH = FIXED_ZIP_PATH + FIXED_ZIP_NAME;
|
||||||
|
|
||||||
// 自定义数据库服务类
|
// 自定义数据库服务类
|
||||||
@Autowired
|
@Autowired
|
||||||
private DatabaseService databaseService;
|
private DatabaseService databaseService;
|
||||||
|
@Resource
|
||||||
|
private IModuleService moduleService;
|
||||||
/**
|
/**
|
||||||
* 接口:导出项目 ZIP 包,插入数据库 SQL 文件后重新打包
|
* 接口:导出项目 ZIP 包,插入数据库 SQL 文件后重新打包
|
||||||
*/
|
*/
|
||||||
@ -46,9 +54,7 @@ public class ProjectExportController {
|
|||||||
|
|
||||||
// 创建时间戳和输出 ZIP 名称
|
// 创建时间戳和输出 ZIP 名称
|
||||||
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
||||||
String outputZipName = FIXED_ZIP_NAME.replaceFirst("\\..*$", "") +
|
String outputZipName = FIXED_ZIP_NAME.replaceFirst("\\..*$", "") + "_" + timestamp + ".zip";
|
||||||
"-with-sql-" + timestamp + ".zip";
|
|
||||||
|
|
||||||
// 定义解压目标路径和最终 ZIP 输出路径
|
// 定义解压目标路径和最终 ZIP 输出路径
|
||||||
// File extractDir = new File(FIXED_ZIP_PATH, "extracted-project");
|
// File extractDir = new File(FIXED_ZIP_PATH, "extracted-project");
|
||||||
String extractTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
String extractTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
||||||
@ -75,10 +81,11 @@ public class ProjectExportController {
|
|||||||
createAndGenerateSqlFile(extractDir, id);
|
createAndGenerateSqlFile(extractDir, id);
|
||||||
|
|
||||||
//TODO 4. 给后端配置文件加上必要的配置
|
//TODO 4. 给后端配置文件加上必要的配置
|
||||||
modifyBackendConfigFiles(extractDir);
|
// modifyBackendConfigFiles(extractDir);
|
||||||
|
modifyDeepConfigWithYaml(extractDir);
|
||||||
|
|
||||||
//TODO 5. 生成前端vue文件
|
//TODO 5. 生成前端vue文件
|
||||||
generateFrontendVueFiles(extractDir);
|
generateFrontendVueFiles(extractDir, id);
|
||||||
|
|
||||||
// 6. 重新打包整个解压后的目录内容
|
// 6. 重新打包整个解压后的目录内容
|
||||||
ZipUtils.zipDirectoryContents(extractDir, finalZip);
|
ZipUtils.zipDirectoryContents(extractDir, finalZip);
|
||||||
@ -96,7 +103,7 @@ public class ProjectExportController {
|
|||||||
* 创建 db 目录并生成 data.sql 文件
|
* 创建 db 目录并生成 data.sql 文件
|
||||||
*/
|
*/
|
||||||
private void createAndGenerateSqlFile(File extractDir, String id) throws IOException {
|
private void createAndGenerateSqlFile(File extractDir, String id) throws IOException {
|
||||||
File dbDir = new File(extractDir, "backend/db");
|
File dbDir = new File(extractDir, "stdproject/backend/db");
|
||||||
if (!dbDir.exists() && !dbDir.mkdirs()) {
|
if (!dbDir.exists() && !dbDir.mkdirs()) {
|
||||||
throw new IOException("无法创建 db 目录: " + dbDir.getAbsolutePath());
|
throw new IOException("无法创建 db 目录: " + dbDir.getAbsolutePath());
|
||||||
}
|
}
|
||||||
@ -105,10 +112,74 @@ public class ProjectExportController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改后端配置文件(支持嵌套 YAML 结构)
|
* 修改后端配置文件(支持嵌套 YAML 结构) 通过yaml格式修改
|
||||||
|
*/
|
||||||
|
private static void modifyDeepConfigWithYaml(File extractDir) throws IOException {
|
||||||
|
File configPath = new File(extractDir, "stdproject/backend/src/main/resources/application.yml");
|
||||||
|
if (!configPath.exists()) {
|
||||||
|
throw new FileNotFoundException("配置文件不存在: " + configPath.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
Yaml yaml = new Yaml();
|
||||||
|
List<Object> allDocuments = new ArrayList<>();
|
||||||
|
// 读取所有文档
|
||||||
|
try (InputStream in = new FileInputStream(configPath)) {
|
||||||
|
for (Object doc : yaml.loadAll(in)) {
|
||||||
|
allDocuments.add(doc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allDocuments.isEmpty()) {
|
||||||
|
throw new IOException("配置文件内容为空");
|
||||||
|
}
|
||||||
|
// 获取第一个文档作为主配置
|
||||||
|
Object firstDoc = allDocuments.getFirst();
|
||||||
|
if (!(firstDoc instanceof Map)) {
|
||||||
|
throw new IOException("第一个文档不是 Map 类型,格式错误");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> root = (Map<String, Object>) firstDoc;
|
||||||
|
|
||||||
|
// 修改 spring.datasource.url 字段
|
||||||
|
if (root.containsKey("spring")) {
|
||||||
|
Map<String, Object> spring = (Map<String, Object>) root.get("spring");
|
||||||
|
if (spring.containsKey("datasource")) {
|
||||||
|
Map<String, Object> datasource = (Map<String, Object>) spring.get("datasource");
|
||||||
|
datasource.put("url", "jdbc:mysql://localhost:3306/newdb");
|
||||||
|
datasource.put("username", "root");
|
||||||
|
datasource.put("password", "123456");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改 server.port 字段
|
||||||
|
if (root.containsKey("server")) {
|
||||||
|
Map<String, Object> server = (Map<String, Object>) root.get("server");
|
||||||
|
server.put("port", 8081);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新第一个文档
|
||||||
|
allDocuments.set(0, root);
|
||||||
|
|
||||||
|
// 写回 YAML 文件
|
||||||
|
DumperOptions options = new DumperOptions();
|
||||||
|
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||||
|
// 美化输出格式
|
||||||
|
options.setPrettyFlow(true);
|
||||||
|
// 缩进两个空格
|
||||||
|
options.setIndent(2);
|
||||||
|
|
||||||
|
Yaml newYaml = new Yaml(options);
|
||||||
|
|
||||||
|
try (Writer writer = new FileWriter(configPath)) {
|
||||||
|
newYaml.dump(root, writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改后端配置文件(支持嵌套 YAML 结构)直接根据字符串修改
|
||||||
*/
|
*/
|
||||||
private void modifyBackendConfigFiles(File extractDir) throws IOException {
|
private void modifyBackendConfigFiles(File extractDir) throws IOException {
|
||||||
File configPath = new File(extractDir, "backend/src/main/resources/application.yml");
|
File configPath = new File(extractDir, "stdproject/backend/src/main/resources/application.yml");
|
||||||
if (!configPath.exists()) {
|
if (!configPath.exists()) {
|
||||||
throw new FileNotFoundException("配置文件不存在: " + configPath.getAbsolutePath());
|
throw new FileNotFoundException("配置文件不存在: " + configPath.getAbsolutePath());
|
||||||
}
|
}
|
||||||
@ -147,27 +218,30 @@ public class ProjectExportController {
|
|||||||
/**
|
/**
|
||||||
* 在前端目录下生成一个 Vue 文件
|
* 在前端目录下生成一个 Vue 文件
|
||||||
*/
|
*/
|
||||||
private void generateFrontendVueFiles(File extractDir) throws IOException {
|
private void generateFrontendVueFiles(File extractDir, String id) throws IOException {
|
||||||
File vueDir = new File(extractDir, "frontend/src/views/generated");
|
File vueDir = new File(extractDir, "stdproject/frontend/src/views/generated");
|
||||||
if (!vueDir.exists() && !vueDir.mkdirs()) {
|
if (!vueDir.exists() && !vueDir.mkdirs()) {
|
||||||
throw new IOException("无法创建 Vue 文件目录: " + vueDir.getAbsolutePath());
|
throw new IOException("无法创建 Vue 文件目录: " + vueDir.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
List<Map<String, Object>> modules =
|
||||||
|
moduleService.listMaps(new LambdaQueryWrapper<Module>().eq(Module::getAppId, id).in(Module::getType,
|
||||||
|
"01", "02").isNotNull(Module::getCanvasStyleData).select(Module::getCanvasStyleData,
|
||||||
|
Module::getName));
|
||||||
|
String fileName = "GeneratedPage";
|
||||||
|
int i = 1;
|
||||||
|
for (Map<String, Object> module : modules) {
|
||||||
|
|
||||||
File vueFile = new File(vueDir, "GeneratedPage.vue");
|
if (ObjectUtil.isEmpty(module.get("canvas_style_data"))) {
|
||||||
|
continue;
|
||||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(vueFile))) {
|
|
||||||
writer.write("<template>");
|
|
||||||
writer.newLine();
|
|
||||||
writer.write(" <div>这是自动生成的页面</div>");
|
|
||||||
writer.newLine();
|
|
||||||
writer.write("</template>");
|
|
||||||
writer.newLine();
|
|
||||||
writer.write("<script>");
|
|
||||||
writer.newLine();
|
|
||||||
writer.write("export default { name: 'GeneratedPage' };");
|
|
||||||
writer.newLine();
|
|
||||||
writer.write("</script>");
|
|
||||||
}
|
}
|
||||||
|
String canvasStyleData = module.get("canvas_style_data").toString();
|
||||||
|
File vueFile = new File(vueDir, fileName + i+".vue");
|
||||||
|
try (BufferedWriter writer = new BufferedWriter(new FileWriter(vueFile))) {
|
||||||
|
writer.write(canvasStyleData);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -298,6 +298,9 @@ public class DatabaseService {
|
|||||||
// 对字符串进行转义
|
// 对字符串进行转义
|
||||||
values.append(escapeSql(s));
|
values.append(escapeSql(s));
|
||||||
case null -> values.append("NULL");
|
case null -> values.append("NULL");
|
||||||
|
case Boolean b ->
|
||||||
|
// 将布尔值转换为 0 和 1
|
||||||
|
values.append(b ? 1 : 0);
|
||||||
case Number ignored -> values.append(value); // 数字不需要加引号
|
case Number ignored -> values.append(value); // 数字不需要加引号
|
||||||
default ->
|
default ->
|
||||||
// 其他类型统一转为字符串处理
|
// 其他类型统一转为字符串处理
|
||||||
|
@ -2,12 +2,13 @@ package io.gisbi.application.module.domain;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import java.io.Serializable;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.apache.ibatis.type.JdbcType;
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* 应用_系统模块
|
* 应用_系统模块
|
||||||
|
Loading…
Reference in New Issue
Block a user