重构: 引入 site_snapshots 表统一站点配置快照管理
- 新增 site_snapshots 表 (V16 迁移),统一存储脚本+页面+规则的合并快照
- 新增 SiteSnapshot 实体、Mapper、Service
- 配置变更时自动触发快照更新 (checksum 去重)
- 新增 SnapshotController 提供 /api/v1/snapshots/{siteId} 端点,支持 ETag/304
- 重构 publishManifest 使用快照服务,只发布变更站点
- 保留七牛云 CDN 作为灾备层
- 兼容旧 /bundle 和 /bundles/ 路径
This commit is contained in:
78
par-core/src/main/java/com/par/core/entity/SiteSnapshot.java
Normal file
78
par-core/src/main/java/com/par/core/entity/SiteSnapshot.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package com.par.core.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 站点配置快照实体
|
||||
* 统一存储站点的脚本 + 页面配置 + 风险规则合并快照
|
||||
*/
|
||||
@Data
|
||||
@TableName("site_snapshots")
|
||||
public class SiteSnapshot {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@TableField("site_id")
|
||||
private String siteId;
|
||||
|
||||
@TableField("version")
|
||||
private Integer version;
|
||||
|
||||
/** Groovy 脚本源码 */
|
||||
@TableField("script")
|
||||
private String script;
|
||||
|
||||
/** 脚本来源版本号 */
|
||||
@TableField("script_version")
|
||||
private String scriptVersion;
|
||||
|
||||
/** 脚本来源: custom / default */
|
||||
@TableField("script_source")
|
||||
private String scriptSource;
|
||||
|
||||
/** 页面配置条目 JSON */
|
||||
@TableField("pages")
|
||||
private String pages;
|
||||
|
||||
/** 页面配置版本号 */
|
||||
@TableField("pages_version")
|
||||
private String pagesVersion;
|
||||
|
||||
/** 页面来源: custom / default */
|
||||
@TableField("pages_source")
|
||||
private String pagesSource;
|
||||
|
||||
/** 风险规则 JSON */
|
||||
@TableField("rules")
|
||||
private String rules;
|
||||
|
||||
/** 风险规则版本号 */
|
||||
@TableField("rules_version")
|
||||
private Integer rulesVersion;
|
||||
|
||||
/** SHA-256 内容校验 */
|
||||
@TableField("checksum")
|
||||
private String checksum;
|
||||
|
||||
/** 状态: draft / published */
|
||||
@TableField("status")
|
||||
private String status;
|
||||
|
||||
/** 七牛云 CDN 地址 */
|
||||
@TableField("cdn_url")
|
||||
private String cdnUrl;
|
||||
|
||||
/** 发布时间 */
|
||||
@TableField("published_at")
|
||||
private LocalDateTime publishedAt;
|
||||
|
||||
@TableField(value = "created_at", fill = FieldFill.INSERT)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@TableField(value = "updated_at", fill = FieldFill.INSERT_UPDATE)
|
||||
private LocalDateTime updatedAt;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.par.core.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.par.core.entity.SiteSnapshot;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
/**
|
||||
* 站点配置快照 Mapper
|
||||
*/
|
||||
@Mapper
|
||||
public interface SiteSnapshotMapper extends BaseMapper<SiteSnapshot> {
|
||||
|
||||
/** 查询站点最新的 draft 快照 */
|
||||
@Select("SELECT * FROM site_snapshots WHERE site_id = #{siteId} AND status = 'draft' ORDER BY version DESC LIMIT 1")
|
||||
SiteSnapshot selectLatestDraft(@Param("siteId") String siteId);
|
||||
|
||||
/** 查询站点最新的 published 快照 */
|
||||
@Select("SELECT * FROM site_snapshots WHERE site_id = #{siteId} AND status = 'published' ORDER BY version DESC LIMIT 1")
|
||||
SiteSnapshot selectLatestPublished(@Param("siteId") String siteId);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.par.core.service;
|
||||
|
||||
import com.par.core.entity.SiteSnapshot;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 站点配置快照服务
|
||||
* 统一管理站点脚本 + 页面配置 + 风险规则的合并快照
|
||||
*/
|
||||
public interface SiteSnapshotService {
|
||||
|
||||
/**
|
||||
* 构建站点配置快照(不持久化,仅返回)
|
||||
* @return null 表示该站点没有任何有效配置
|
||||
*/
|
||||
Map<String, Object> buildSnapshot(String siteId);
|
||||
|
||||
/**
|
||||
* 更新站点的 draft 快照(任意配置变更后调用)
|
||||
* 内容未变化(checksum 相同)则不产生新版本
|
||||
* @return 新快照或 null(内容未变)
|
||||
*/
|
||||
SiteSnapshot updateSnapshot(String siteId);
|
||||
|
||||
/**
|
||||
* 发布指定站点的快照(draft → published)
|
||||
* 同时上传到七牛云 CDN 作为灾备
|
||||
*/
|
||||
SiteSnapshot publish(String siteId);
|
||||
|
||||
/**
|
||||
* 获取站点当前生效快照(最新 published)
|
||||
*/
|
||||
SiteSnapshot getActive(String siteId);
|
||||
|
||||
/**
|
||||
* 按 checksum 判断是否需要更新
|
||||
*/
|
||||
boolean isChanged(String siteId, String checksum);
|
||||
|
||||
/**
|
||||
* 批量发布有变更的站点(只发布 checksum 变化的)
|
||||
* @return 成功发布的站点数
|
||||
*/
|
||||
int publishChanged();
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import com.par.core.enums.ConfigStatus;
|
||||
import com.par.core.mapper.SiteConfigMapper;
|
||||
import com.par.core.service.ConfigService;
|
||||
import com.par.core.service.ManifestVersionService;
|
||||
import com.par.core.service.SiteSnapshotService;
|
||||
import com.par.core.storage.CachedStorageService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -21,13 +22,16 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
private final ManifestVersionService versionService;
|
||||
private final SiteConfigMapper siteConfigMapper;
|
||||
private final CachedStorageService storageService;
|
||||
private final SiteSnapshotService snapshotService;
|
||||
|
||||
public ConfigServiceImpl(ManifestVersionService versionService,
|
||||
SiteConfigMapper siteConfigMapper,
|
||||
CachedStorageService storageService) {
|
||||
CachedStorageService storageService,
|
||||
SiteSnapshotService snapshotService) {
|
||||
this.versionService = versionService;
|
||||
this.siteConfigMapper = siteConfigMapper;
|
||||
this.storageService = storageService;
|
||||
this.snapshotService = snapshotService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,6 +89,8 @@ public class ConfigServiceImpl implements ConfigService {
|
||||
|
||||
siteConfigMapper.insert(config);
|
||||
versionService.increment(siteId);
|
||||
// 触发快照更新(异步更新 draft)
|
||||
try { snapshotService.updateSnapshot(siteId); } catch (Exception e) { log.warn("快照更新失败 siteId={}: {}", siteId, e.getMessage()); }
|
||||
log.info("Config submitted: siteId={}, version={}, id={}, scriptPath={}", siteId, version, config.getId(), scriptPath);
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.par.core.entity.RiskRule;
|
||||
import com.par.core.mapper.RiskRuleMapper;
|
||||
import com.par.core.service.ManifestVersionService;
|
||||
import com.par.core.service.RiskRuleService;
|
||||
import com.par.core.service.SiteSnapshotService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -21,6 +22,7 @@ public class RiskRuleServiceImpl implements RiskRuleService {
|
||||
private final RiskRuleMapper mapper;
|
||||
private final com.par.core.storage.CachedStorageService storageService;
|
||||
private final com.par.core.service.SiteService siteService;
|
||||
private final SiteSnapshotService snapshotService;
|
||||
private static final ObjectMapper om = new ObjectMapper();
|
||||
|
||||
private RiskRule findByIdentifier(String identifier) {
|
||||
@@ -77,6 +79,8 @@ public class RiskRuleServiceImpl implements RiskRuleService {
|
||||
String storagePath = String.format("rules/%s/v%d.json", siteType, nextVer);
|
||||
storageService.store(storagePath, json);
|
||||
versionService.incrementByType(siteType);
|
||||
// 触发同类型所有站点快照更新
|
||||
updateSnapshotsByType(siteType);
|
||||
log.info("风险规则已保存: key={}, version={}, path={}", siteType, nextVer, storagePath);
|
||||
} catch (Exception e) {
|
||||
log.error("保存风险规则失败 key={}", siteType, e);
|
||||
@@ -108,6 +112,22 @@ public class RiskRuleServiceImpl implements RiskRuleService {
|
||||
public void deleteRules(String siteType) {
|
||||
mapper.delete(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<RiskRule>()
|
||||
.eq(RiskRule::getSiteId, siteType).eq(RiskRule::getDeleted, 0));
|
||||
updateSnapshotsByType(siteType);
|
||||
}
|
||||
|
||||
/** 触发同类型下所有站点的快照更新 */
|
||||
private void updateSnapshotsByType(String siteType) {
|
||||
try {
|
||||
var sites = siteService.listAllSites().stream()
|
||||
.filter(s -> s.getSiteType() != null && siteType.equals(s.getSiteType().getValue()))
|
||||
.toList();
|
||||
for (var site : sites) {
|
||||
try { snapshotService.updateSnapshot(site.getSiteId()); }
|
||||
catch (Exception e) { log.warn("快照更新失败 siteId={}: {}", site.getSiteId(), e.getMessage()); }
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("批量快照更新失败 siteType={}: {}", siteType, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.par.core.entity.SitePages;
|
||||
import com.par.core.mapper.SitePagesMapper;
|
||||
import com.par.core.service.ManifestVersionService;
|
||||
import com.par.core.service.SitePagesService;
|
||||
import com.par.core.service.SiteSnapshotService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -20,6 +21,7 @@ public class SitePagesServiceImpl implements SitePagesService {
|
||||
private final ManifestVersionService versionService;
|
||||
private final SitePagesMapper mapper;
|
||||
private final com.par.core.storage.CachedStorageService storageService;
|
||||
private final SiteSnapshotService snapshotService;
|
||||
private static final ObjectMapper om = new ObjectMapper();
|
||||
|
||||
@Override
|
||||
@@ -82,6 +84,8 @@ public class SitePagesServiceImpl implements SitePagesService {
|
||||
String storagePath = String.format("pages/%s/v%s.json", siteId, version);
|
||||
storageService.store(storagePath, json);
|
||||
versionService.increment(siteId);
|
||||
// 触发快照更新
|
||||
try { snapshotService.updateSnapshot(siteId); } catch (Exception e) { log.warn("快照更新失败 siteId={}: {}", siteId, e.getMessage()); }
|
||||
log.info("页面配置已保存: siteId={}, version={}, path={}", siteId, version, storagePath);
|
||||
} catch (Exception e) {
|
||||
log.error("保存页面配置失败 siteId={}", siteId, e);
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
package com.par.core.service.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.par.common.util.HmacUtil;
|
||||
import com.par.core.adapter.GroovyScriptEngine;
|
||||
import com.par.core.entity.RiskRule;
|
||||
import com.par.core.entity.SiteConfig;
|
||||
import com.par.core.entity.SiteSnapshot;
|
||||
import com.par.core.mapper.RiskRuleMapper;
|
||||
import com.par.core.mapper.SiteConfigMapper;
|
||||
import com.par.core.mapper.SiteMapper;
|
||||
import com.par.core.mapper.SiteSnapshotMapper;
|
||||
import com.par.core.service.ConfigService;
|
||||
import com.par.core.service.SitePagesService;
|
||||
import com.par.core.service.SiteSnapshotService;
|
||||
import com.par.core.storage.CachedStorageService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 站点配置快照服务实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SiteSnapshotServiceImpl implements SiteSnapshotService {
|
||||
|
||||
private final SiteSnapshotMapper snapshotMapper;
|
||||
private final SiteConfigMapper siteConfigMapper;
|
||||
private final SiteMapper siteMapper;
|
||||
private final ConfigService configService;
|
||||
private final SitePagesService sitePagesService;
|
||||
private final RiskRuleMapper riskRuleMapper;
|
||||
private final CachedStorageService storageService;
|
||||
private static final ObjectMapper om = new ObjectMapper();
|
||||
|
||||
@Override
|
||||
public Map<String, Object> buildSnapshot(String siteId) {
|
||||
Map<String, Object> snapshot = new LinkedHashMap<>();
|
||||
snapshot.put("siteId", siteId);
|
||||
snapshot.put("generatedAt", LocalDateTime.now().toString());
|
||||
|
||||
var site = siteMapper.selectBySiteId(siteId);
|
||||
String siteType = site != null && site.getSiteType() != null ? site.getSiteType().getValue() : null;
|
||||
|
||||
// 1. 脚本
|
||||
SiteConfig latest = configService.getLatestConfig(siteId);
|
||||
if (latest != null && latest.getScriptStoragePath() != null && !latest.getScriptStoragePath().isBlank()) {
|
||||
try {
|
||||
String script = storageService.read(latest.getScriptStoragePath());
|
||||
if (script != null && !script.isBlank()) {
|
||||
snapshot.put("script", script);
|
||||
snapshot.put("scriptVersion", latest.getVersion());
|
||||
snapshot.put("scriptSource", "custom");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("读取脚本失败 siteId={}: {}", siteId, e.getMessage());
|
||||
}
|
||||
}
|
||||
if (!snapshot.containsKey("script") && siteType != null) {
|
||||
String defScript = GroovyScriptEngine.loadDefaultByType(siteType);
|
||||
if (defScript != null) {
|
||||
snapshot.put("script", defScript);
|
||||
snapshot.put("scriptSource", "default");
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 页面配置
|
||||
Map<String, Object> pages = sitePagesService.getPages(siteId);
|
||||
if (pages == null && siteType != null) {
|
||||
pages = sitePagesService.getPages("default:" + siteType);
|
||||
}
|
||||
if (pages != null) {
|
||||
snapshot.put("pages", pages.get("entries"));
|
||||
snapshot.put("pagesVersion", pages.get("version"));
|
||||
snapshot.put("pagesSource", pages.containsKey("source") ? pages.get("source") : "custom");
|
||||
}
|
||||
|
||||
// 3. 风险规则
|
||||
if (siteType != null) {
|
||||
var rules = riskRuleMapper.selectList(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<RiskRule>()
|
||||
.eq(RiskRule::getSiteType, siteType)
|
||||
.eq(RiskRule::getDeleted, 0)
|
||||
.orderByDesc(RiskRule::getId));
|
||||
if (!rules.isEmpty()) {
|
||||
var latestRule = rules.get(0);
|
||||
try {
|
||||
List<Map<String, Object>> rulesList = om.readValue(latestRule.getRulesJson(),
|
||||
new TypeReference<List<Map<String, Object>>>() {});
|
||||
snapshot.put("riskRules", rulesList);
|
||||
snapshot.put("riskRulesVersion", latestRule.getVersion());
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
return snapshot.containsKey("script") ? snapshot : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public SiteSnapshot updateSnapshot(String siteId) {
|
||||
Map<String, Object> data = buildSnapshot(siteId);
|
||||
if (data == null) {
|
||||
log.debug("站点 {} 无有效配置,跳过快照更新", siteId);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// 计算 checksum
|
||||
String contentJson = om.writeValueAsString(data);
|
||||
String checksum = HmacUtil.sha256(contentJson);
|
||||
|
||||
// 查询最新 draft
|
||||
SiteSnapshot latestDraft = snapshotMapper.selectLatestDraft(siteId);
|
||||
if (latestDraft != null && checksum.equals(latestDraft.getChecksum())) {
|
||||
log.debug("站点 {} 配置未变化,跳过快照生成", siteId);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 确定新版本号
|
||||
int newVersion = (latestDraft != null) ? latestDraft.getVersion() + 1 : 1;
|
||||
|
||||
SiteSnapshot snapshot = new SiteSnapshot();
|
||||
snapshot.setSiteId(siteId);
|
||||
snapshot.setVersion(newVersion);
|
||||
|
||||
// 脚本
|
||||
if (data.containsKey("script")) {
|
||||
snapshot.setScript((String) data.get("script"));
|
||||
snapshot.setScriptVersion((String) data.get("scriptVersion"));
|
||||
snapshot.setScriptSource((String) data.get("scriptSource"));
|
||||
}
|
||||
|
||||
// 页面
|
||||
if (data.containsKey("pages")) {
|
||||
snapshot.setPages(om.writeValueAsString(data.get("pages")));
|
||||
snapshot.setPagesVersion((String) data.get("pagesVersion"));
|
||||
snapshot.setPagesSource((String) data.get("pagesSource"));
|
||||
}
|
||||
|
||||
// 规则
|
||||
if (data.containsKey("riskRules")) {
|
||||
snapshot.setRules(om.writeValueAsString(data.get("riskRules")));
|
||||
snapshot.setRulesVersion((Integer) data.get("riskRulesVersion"));
|
||||
}
|
||||
|
||||
snapshot.setChecksum(checksum);
|
||||
snapshot.setStatus("draft");
|
||||
|
||||
snapshotMapper.insert(snapshot);
|
||||
log.info("快照已更新: siteId={}, version={}, checksum={}", siteId, newVersion, checksum.substring(0, 8));
|
||||
return snapshot;
|
||||
} catch (Exception e) {
|
||||
log.error("更新快照失败 siteId={}", siteId, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public SiteSnapshot publish(String siteId) {
|
||||
SiteSnapshot draft = snapshotMapper.selectLatestDraft(siteId);
|
||||
if (draft == null) {
|
||||
log.warn("站点 {} 无 draft 快照可发布", siteId);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 如果已经是最新 published(相同 checksum),跳过
|
||||
SiteSnapshot current = snapshotMapper.selectLatestPublished(siteId);
|
||||
if (current != null && draft.getChecksum().equals(current.getChecksum())) {
|
||||
log.info("站点 {} 已是最新版本,跳过发布", siteId);
|
||||
return current;
|
||||
}
|
||||
|
||||
// 更新状态为 published
|
||||
draft.setStatus("published");
|
||||
draft.setPublishedAt(LocalDateTime.now());
|
||||
snapshotMapper.updateById(draft);
|
||||
|
||||
// 上传到七牛云 CDN 作为灾备
|
||||
try {
|
||||
String bundleJson = toBundleJson(draft);
|
||||
String cdnPath = "snapshots/" + siteId + ".json";
|
||||
storageService.store(cdnPath, bundleJson);
|
||||
// 也保存版本化副本
|
||||
storageService.store("snapshots/" + siteId + "/v" + draft.getVersion() + ".json", bundleJson);
|
||||
draft.setCdnUrl(cdnPath);
|
||||
snapshotMapper.updateById(draft);
|
||||
log.info("快照已发布到 CDN: siteId={}, path={}", siteId, cdnPath);
|
||||
} catch (Exception e) {
|
||||
log.error("上传快照到 CDN 失败 siteId={}: {}", siteId, e.getMessage());
|
||||
// 不影响数据库状态
|
||||
}
|
||||
|
||||
log.info("快照已发布: siteId={}, version={}", siteId, draft.getVersion());
|
||||
return draft;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SiteSnapshot getActive(String siteId) {
|
||||
return snapshotMapper.selectLatestPublished(siteId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChanged(String siteId, String checksum) {
|
||||
if (checksum == null) return true;
|
||||
SiteSnapshot active = getActive(siteId);
|
||||
return active == null || !checksum.equals(active.getChecksum());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int publishChanged() {
|
||||
var allSites = siteMapper.selectList(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.par.core.entity.Site>()
|
||||
.eq(com.par.core.entity.Site::getDeleted, 0));
|
||||
int count = 0;
|
||||
for (var site : allSites) {
|
||||
try {
|
||||
SiteSnapshot result = publish(site.getSiteId());
|
||||
if (result != null) count++;
|
||||
} catch (Exception e) {
|
||||
log.error("发布快照失败 siteId={}: {}", site.getSiteId(), e.getMessage());
|
||||
}
|
||||
}
|
||||
log.info("批量发布完成: {}/{} 个站点", count, allSites.size());
|
||||
return count;
|
||||
}
|
||||
|
||||
/** 将快照转为 mediabot 可用的 JSON 字符串 */
|
||||
private String toBundleJson(SiteSnapshot snapshot) {
|
||||
try {
|
||||
Map<String, Object> bundle = new LinkedHashMap<>();
|
||||
bundle.put("siteId", snapshot.getSiteId());
|
||||
bundle.put("generatedAt", snapshot.getPublishedAt() != null
|
||||
? snapshot.getPublishedAt().toString() : LocalDateTime.now().toString());
|
||||
|
||||
if (snapshot.getScript() != null) {
|
||||
bundle.put("script", snapshot.getScript());
|
||||
bundle.put("scriptVersion", snapshot.getScriptVersion());
|
||||
bundle.put("scriptSource", snapshot.getScriptSource());
|
||||
}
|
||||
|
||||
if (snapshot.getPages() != null) {
|
||||
bundle.put("pages", om.readValue(snapshot.getPages(), new TypeReference<List<Map<String, Object>>>() {}));
|
||||
bundle.put("pagesVersion", snapshot.getPagesVersion());
|
||||
bundle.put("pagesSource", snapshot.getPagesSource());
|
||||
}
|
||||
|
||||
if (snapshot.getRules() != null) {
|
||||
bundle.put("riskRules", om.readValue(snapshot.getRules(), new TypeReference<List<Map<String, Object>>>() {}));
|
||||
bundle.put("riskRulesVersion", snapshot.getRulesVersion());
|
||||
}
|
||||
|
||||
return om.writeValueAsString(bundle);
|
||||
} catch (Exception e) {
|
||||
log.error("序列化 bundle 失败 siteId={}", snapshot.getSiteId(), e);
|
||||
return "{}";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user