Merge branch 'main' of http://121.37.111.42:3000/ThbTech/gis-bi into main
This commit is contained in:
commit
033e7314fc
@ -25,73 +25,150 @@ 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 = "a.zip";
|
private static final String FIXED_ZIP_NAME = "backend.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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 接口:上传项目 ZIP 包,解压 → 导出数据库部分数据 → 插入 SQL 文件 → 重新打包并下载
|
* 接口:导出项目 ZIP 包,插入数据库 SQL 文件后重新打包
|
||||||
*/
|
*/
|
||||||
@PostMapping("/export")
|
@PostMapping("/export")
|
||||||
public void exportProjectWithDbData(
|
public void exportProjectWithDbData(@RequestParam("id") String id) throws Exception {
|
||||||
@RequestParam("id") String id) throws Exception {
|
// 检查原始 ZIP 是否存在
|
||||||
|
File fixedZipFile = new File(FIXED_ZIP_FULL_PATH);
|
||||||
String fixedZipPath = FIXED_ZIP_FULL_PATH;
|
|
||||||
File fixedZipFile = new File(fixedZipPath);
|
|
||||||
if (!fixedZipFile.exists()) {
|
if (!fixedZipFile.exists()) {
|
||||||
throw new FileNotFoundException("指定的 ZIP 文件不存在: " + fixedZipPath);
|
throw new FileNotFoundException("指定的 ZIP 文件不存在: " + FIXED_ZIP_FULL_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建时间戳和临时目录路径
|
// 创建时间戳和输出 ZIP 名称
|
||||||
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
||||||
Path tempExtractDir = Paths.get(FIXED_ZIP_PATH, "temp", "project-" + timestamp);
|
String outputZipName = FIXED_ZIP_NAME.replaceFirst("\\..*$", "") +
|
||||||
|
"-with-sql-" + timestamp + ".zip";
|
||||||
|
|
||||||
|
// 定义解压目标路径和最终 ZIP 输出路径
|
||||||
|
// File extractDir = new File(FIXED_ZIP_PATH, "extracted-project");
|
||||||
|
String extractTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
|
||||||
|
File extractDir = new File(FIXED_ZIP_PATH, "extracted-project-" + extractTime);
|
||||||
|
File finalZip = new File(FIXED_ZIP_PATH + "export/", outputZipName);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(tempExtractDir);
|
// 1. 清空已存在的解压目录(避免旧数据干扰)
|
||||||
|
if (extractDir.exists()) {
|
||||||
// 1. 解压模板 ZIP 到临时目录
|
try {
|
||||||
File uploadedZip = new File(tempExtractDir + ".zip");
|
deleteDirectory(extractDir);
|
||||||
FileCopyUtils.copy(new FileInputStream(fixedZipFile), new FileOutputStream(uploadedZip));
|
} catch (Exception e) {
|
||||||
ZipUtils.unzip(uploadedZip, tempExtractDir.toFile());
|
throw new IOException("无法清理旧的解压目录: " + extractDir.getAbsolutePath(), e);
|
||||||
|
|
||||||
// 2. 获取解压后的根目录(自动识别第一个子目录)
|
|
||||||
File[] extractedRoots = tempExtractDir.toFile().listFiles(File::isDirectory);
|
|
||||||
if (extractedRoots == null || extractedRoots.length == 0) {
|
|
||||||
throw new IOException("ZIP 解压后未找到项目根目录");
|
|
||||||
}
|
|
||||||
File projectRoot = extractedRoots[0];
|
|
||||||
|
|
||||||
// 3. 获取 db 目录
|
|
||||||
File dbDir = new File(projectRoot, "db");
|
|
||||||
if (!dbDir.exists()) {
|
|
||||||
boolean created = dbDir.mkdirs();
|
|
||||||
if (!created) {
|
|
||||||
throw new IOException("无法创建 db 目录: " + dbDir.getAbsolutePath());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!extractDir.mkdirs()) {
|
||||||
|
throw new IOException("无法创建解压目录: " + extractDir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
// 4. 查询数据库并生成 SQL 文件,保存到 db 目录中
|
// 2. 直接解压 ZIP 到目标目录
|
||||||
generateSqlFile(id, new File(dbDir, "data.sql").getAbsolutePath());
|
ZipUtils.unzip(fixedZipFile, extractDir);
|
||||||
|
|
||||||
// 5. 重新打包整个项目根目录为新的 ZIP 文件
|
//TODO 3. 查找 db 目录并生成 SQL 文件
|
||||||
String outputZipName = FIXED_ZIP_NAME.replaceFirst("\\..*$", "") +
|
createAndGenerateSqlFile(extractDir, id);
|
||||||
"-with-sql-" + timestamp + ".zip";
|
|
||||||
File finalZip = new File(FIXED_ZIP_PATH + "export/", outputZipName);
|
//TODO 4. 给后端配置文件加上必要的配置
|
||||||
ZipUtils.zipFolder(projectRoot, finalZip);
|
modifyBackendConfigFiles(extractDir);
|
||||||
}catch (Exception e){
|
|
||||||
|
//TODO 5. 生成前端vue文件
|
||||||
|
generateFrontendVueFiles(extractDir);
|
||||||
|
|
||||||
|
// 6. 重新打包整个解压后的目录内容
|
||||||
|
ZipUtils.zipDirectoryContents(extractDir, finalZip);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}finally {
|
throw new RuntimeException("导出项目出错");
|
||||||
// 7. 清理临时文件(可选)
|
} finally {
|
||||||
deleteDirectory(tempExtractDir.toFile());
|
// 7.删除解压目录
|
||||||
|
deleteDirectory(extractDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建 db 目录并生成 data.sql 文件
|
||||||
|
*/
|
||||||
|
private void createAndGenerateSqlFile(File extractDir, String id) throws IOException {
|
||||||
|
File dbDir = new File(extractDir, "backend/db");
|
||||||
|
if (!dbDir.exists() && !dbDir.mkdirs()) {
|
||||||
|
throw new IOException("无法创建 db 目录: " + dbDir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
String sqlFilePath = new File(dbDir, "data.sql").getAbsolutePath();
|
||||||
|
generateSqlFile(id, sqlFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改后端配置文件(支持嵌套 YAML 结构)
|
||||||
|
*/
|
||||||
|
private void modifyBackendConfigFiles(File extractDir) throws IOException {
|
||||||
|
File configPath = new File(extractDir, "backend/src/main/resources/application.yml");
|
||||||
|
if (!configPath.exists()) {
|
||||||
|
throw new FileNotFoundException("配置文件不存在: " + configPath.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> lines = Files.readAllLines(configPath.toPath());
|
||||||
|
|
||||||
|
boolean inServerBlock = false;
|
||||||
|
for (int i = 0; i < lines.size(); i++) {
|
||||||
|
String line = lines.get(i);
|
||||||
|
|
||||||
|
// 判断是否进入 server 块
|
||||||
|
if (line.trim().startsWith("server:")) {
|
||||||
|
inServerBlock = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果在 server 块中,并且遇到下一个顶级 key,则退出 block
|
||||||
|
if (inServerBlock && line.trim().contains(":") && !line.startsWith(" ") && !line.startsWith("\t")) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改 port 字段
|
||||||
|
if (inServerBlock && line.trim().startsWith("port:")) {
|
||||||
|
// 获取原缩进
|
||||||
|
int indent = line.indexOf("port:");
|
||||||
|
String newLine = " ".repeat(indent) + "port: 8081";
|
||||||
|
lines.set(i, newLine);
|
||||||
|
break; // 找到并修改后退出
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写回文件
|
||||||
|
Files.write(configPath.toPath(), lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在前端目录下生成一个 Vue 文件
|
||||||
|
*/
|
||||||
|
private void generateFrontendVueFiles(File extractDir) throws IOException {
|
||||||
|
File vueDir = new File(extractDir, "frontend/src/views/generated");
|
||||||
|
if (!vueDir.exists() && !vueDir.mkdirs()) {
|
||||||
|
throw new IOException("无法创建 Vue 文件目录: " + vueDir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
File vueFile = new File(vueDir, "GeneratedPage.vue");
|
||||||
|
|
||||||
|
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>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 id 查询数据库,并生成 SQL 文件(CREATE TABLE + INSERT INTO)
|
* 根据 id 查询数据库,并生成 SQL 文件(CREATE TABLE + INSERT INTO)
|
||||||
|
@ -1,43 +1,84 @@
|
|||||||
package io.gisbi.application.appcode.utils;
|
package io.gisbi.application.appcode.utils;
|
||||||
|
|
||||||
import org.springframework.util.FileCopyUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.util.Objects;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
public class ZipUtils {
|
public class ZipUtils {
|
||||||
|
|
||||||
public static void unzip(File zipFile, File outputFolder) throws IOException {
|
|
||||||
|
public static void unzip(File zipFile, File destDir) throws IOException {
|
||||||
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
|
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
|
||||||
ZipEntry entry;
|
ZipEntry entry;
|
||||||
while ((entry = zis.getNextEntry()) != null) {
|
while ((entry = zis.getNextEntry()) != null) {
|
||||||
File file = new File(outputFolder, entry.getName());
|
File entryDestination = new File(destDir, entry.getName());
|
||||||
if (entry.isDirectory()) {
|
if (entry.isDirectory()) {
|
||||||
Files.createDirectories(file.toPath());
|
entryDestination.mkdirs();
|
||||||
} else {
|
} else {
|
||||||
Files.createDirectories(file.getParentFile().toPath());
|
entryDestination.getParentFile().mkdirs();
|
||||||
FileCopyUtils.copy(zis, new FileOutputStream(file));
|
try (FileOutputStream fos = new FileOutputStream(entryDestination)) {
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int len;
|
||||||
|
while ((len = zis.read(buffer)) > 0) {
|
||||||
|
fos.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
zis.closeEntry();
|
zis.closeEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String sanitizePath(String path) {
|
||||||
|
// 替换非法字符
|
||||||
|
return path.replaceAll("[\0<>:\"/\\|?*]", "_");
|
||||||
|
}
|
||||||
|
|
||||||
public static void zipFolder(File folder, File zipFile) throws IOException {
|
public static void zipFolder(File folder, File zipFile) throws IOException {
|
||||||
try (
|
try (
|
||||||
FileOutputStream fos = new FileOutputStream(zipFile);
|
FileOutputStream fos = new FileOutputStream(zipFile);
|
||||||
ZipOutputStream zos = new ZipOutputStream(fos)
|
ZipOutputStream zos = new ZipOutputStream(fos)
|
||||||
) {
|
) {
|
||||||
zipFile(folder, folder.getName(), zos);
|
zipFile(folder, folder.getName(), zos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void zipDirectoryContents(File sourceDir, File outputZip) throws IOException {
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(outputZip);
|
||||||
|
ZipOutputStream zos = new ZipOutputStream(fos)) {
|
||||||
|
|
||||||
|
for (File file : Objects.requireNonNull(sourceDir.listFiles())) {
|
||||||
|
addToZip(file, sourceDir, zos, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addToZip(File file, File baseDir, ZipOutputStream zos, String parent) throws IOException {
|
||||||
|
String entryName = parent + file.getName();
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
for (File child : file.listFiles()) {
|
||||||
|
addToZip(child, baseDir, zos, entryName + "/");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try (FileInputStream fis = new FileInputStream(file)) {
|
||||||
|
ZipEntry entry = new ZipEntry(entryName);
|
||||||
|
zos.putNextEntry(entry);
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int len;
|
||||||
|
while ((len = fis.read(buffer)) > 0) {
|
||||||
|
zos.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
zos.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void zipFile(File fileToZip, String fileName, ZipOutputStream zos) throws IOException {
|
private static void zipFile(File fileToZip, String fileName, ZipOutputStream zos) throws IOException {
|
||||||
if (fileToZip.isDirectory()) {
|
if (fileToZip.isDirectory()) {
|
||||||
if (fileName.endsWith("/")) {
|
if (fileName.endsWith("/")) {
|
||||||
@ -67,4 +108,17 @@ public class ZipUtils {
|
|||||||
zos.closeEntry();
|
zos.closeEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void deleteDirectory(File file) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
File[] files = file.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File f : files) {
|
||||||
|
deleteDirectory(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
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">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>sdk</artifactId>
|
|
||||||
<groupId>io.gisbi</groupId>
|
<groupId>io.gisbi</groupId>
|
||||||
<version>1.0.0</version>
|
<artifactId>sdk</artifactId>
|
||||||
|
<version>2.0.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@ -18,7 +18,7 @@
|
|||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>2.0.0</version>
|
<version>2.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 依赖extensions模块 -->
|
<!-- 依赖extensions模块 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.gisbi</groupId>
|
<groupId>io.gisbi</groupId>
|
||||||
@ -67,4 +67,4 @@
|
|||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
Loading…
Reference in New Issue
Block a user