fix: 脚本导出改为ZIP(每个站点一个.groovy文件)+导入改为上传ZIP
This commit is contained in:
@@ -405,61 +405,77 @@ public class AdminController {
|
||||
// ==================== 脚本批量导入导出 ====================
|
||||
|
||||
/**
|
||||
* 导出所有站点脚本 JSON:{siteId: scriptContent}
|
||||
* 导出所有站点脚本为 ZIP:每个站点一个 .groovy 文件
|
||||
*/
|
||||
@GetMapping("/scripts/export")
|
||||
public ResponseEntity<byte[]> exportScripts(HttpServletRequest request) {
|
||||
checkAdmin(request);
|
||||
Map<String, String> all = new LinkedHashMap<>();
|
||||
for (SiteConfig sc : siteConfigMapper.selectList(
|
||||
List<SiteConfig> configs = siteConfigMapper.selectList(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SiteConfig>()
|
||||
.eq(SiteConfig::getDeleted, 0)
|
||||
.eq(SiteConfig::getIsLatest, true)
|
||||
.isNotNull(SiteConfig::getScriptStoragePath))) {
|
||||
try {
|
||||
String script = storageService.read(sc.getScriptStoragePath());
|
||||
if (script != null && !script.isBlank()) all.put(sc.getSiteId(), script);
|
||||
} catch (Exception ignored) {}
|
||||
.isNotNull(SiteConfig::getScriptStoragePath));
|
||||
try {
|
||||
var baos = new java.io.ByteArrayOutputStream();
|
||||
try (var zos = new java.util.zip.ZipOutputStream(baos)) {
|
||||
for (SiteConfig sc : configs) {
|
||||
String script = storageService.read(sc.getScriptStoragePath());
|
||||
if (script == null || script.isBlank()) continue;
|
||||
var entry = new java.util.zip.ZipEntry(sc.getSiteId() + ".groovy");
|
||||
zos.putNextEntry(entry);
|
||||
zos.write(script.getBytes(StandardCharsets.UTF_8));
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=scripts.zip")
|
||||
.contentType(MediaType.parseMediaType("application/zip"))
|
||||
.body(baos.toByteArray());
|
||||
} catch (Exception e) {
|
||||
log.error("导出脚本失败", e);
|
||||
return ResponseEntity.status(500).build();
|
||||
}
|
||||
byte[] json = new com.fasterxml.jackson.databind.ObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter().writeValueAsBytes(all);
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=scripts-export.json")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(json);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入脚本:{siteId: scriptContent},保存到本地存储
|
||||
* 导入脚本 ZIP:每个 .groovy 文件名 = siteId,保存到本地
|
||||
*/
|
||||
@PostMapping("/scripts/import")
|
||||
public ApiResponse<Map<String, Object>> importScripts(
|
||||
@RequestBody Map<String, String> payload,
|
||||
@RequestParam("file") org.springframework.web.multipart.MultipartFile file,
|
||||
HttpServletRequest request) {
|
||||
checkAdmin(request);
|
||||
int ok = 0, fail = 0;
|
||||
for (Map.Entry<String, String> e : payload.entrySet()) {
|
||||
String siteId = e.getKey();
|
||||
String script = e.getValue();
|
||||
if (script == null || script.isBlank()) continue;
|
||||
try {
|
||||
int nextVersion = 1;
|
||||
List<SiteConfig> approved = siteConfigMapper.selectList(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SiteConfig>()
|
||||
.eq(SiteConfig::getSiteId, siteId)
|
||||
.eq(SiteConfig::getDeleted, 0)
|
||||
.orderByDesc(SiteConfig::getVersion)
|
||||
.last("limit 1"));
|
||||
if (!approved.isEmpty()) {
|
||||
try { nextVersion = Integer.parseInt(approved.get(0).getVersion()) + 1; }
|
||||
catch (NumberFormatException ex) {}
|
||||
try (var zis = new java.util.zip.ZipInputStream(file.getInputStream())) {
|
||||
java.util.zip.ZipEntry entry;
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
if (entry.isDirectory() || !entry.getName().endsWith(".groovy")) continue;
|
||||
String siteId = entry.getName().replace(".groovy", "");
|
||||
String script = new String(zis.readAllBytes(), StandardCharsets.UTF_8);
|
||||
if (script.isBlank()) continue;
|
||||
try {
|
||||
int nextVersion = 1;
|
||||
List<SiteConfig> existing = siteConfigMapper.selectList(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<SiteConfig>()
|
||||
.eq(SiteConfig::getSiteId, siteId)
|
||||
.eq(SiteConfig::getDeleted, 0)
|
||||
.orderByDesc(SiteConfig::getVersion)
|
||||
.last("limit 1"));
|
||||
if (!existing.isEmpty()) {
|
||||
try { nextVersion = Integer.parseInt(existing.get(0).getVersion()) + 1; }
|
||||
catch (NumberFormatException ignored) {}
|
||||
}
|
||||
configService.submitConfig(siteId, String.valueOf(nextVersion), script, null);
|
||||
ok++;
|
||||
} catch (Exception ex) {
|
||||
log.error("导入脚本失败 siteId={}: {}", siteId, ex.getMessage());
|
||||
fail++;
|
||||
}
|
||||
configService.submitConfig(siteId, String.valueOf(nextVersion), script, null);
|
||||
ok++;
|
||||
} catch (Exception ex) {
|
||||
log.error("导入脚本失败 siteId={}: {}", siteId, ex.getMessage());
|
||||
fail++;
|
||||
zis.closeEntry();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解压导入ZIP失败", e);
|
||||
return ApiResponse.error(500, "导入失败: " + e.getMessage());
|
||||
}
|
||||
return ApiResponse.success(Map.of("ok", ok, "fail", fail));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user