feat: 报表模板同步功能
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
package com.hotwj.platform.reportStatistics.controller;
|
package com.hotwj.platform.reportStatistics.controller;
|
||||||
|
|
||||||
import com.hotwj.platform.reportStatistics.domain.bo.SysReportTemplateBo;
|
import com.hotwj.platform.reportStatistics.domain.bo.SysReportTemplateBo;
|
||||||
|
import com.hotwj.platform.reportStatistics.domain.bo.SysReportTemplateSyncBo;
|
||||||
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateVo;
|
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateVo;
|
||||||
|
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateSyncCompareVo;
|
||||||
import com.hotwj.platform.reportStatistics.service.ISysReportTemplateService;
|
import com.hotwj.platform.reportStatistics.service.ISysReportTemplateService;
|
||||||
import com.hotwj.platform.reportStatistics.service.ReportRenderService;
|
import com.hotwj.platform.reportStatistics.service.ReportRenderService;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
@@ -97,6 +99,26 @@ public class SysReportTemplateController extends BaseController {
|
|||||||
return R.ok();
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询模板同步差异
|
||||||
|
*/
|
||||||
|
//@SaCheckPermission("report:template:sync")
|
||||||
|
@GetMapping("/sync/diff")
|
||||||
|
public R<List<SysReportTemplateSyncCompareVo>> syncDiff() {
|
||||||
|
return R.ok(sysReportTemplateService.querySyncDiffList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按选中项同步模板
|
||||||
|
*/
|
||||||
|
//@SaCheckPermission("report:template:sync")
|
||||||
|
@Log(title = "按项同步模版", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/sync/selective")
|
||||||
|
public R<Void> selectiveSync(@Validated @RequestBody SysReportTemplateSyncBo bo) {
|
||||||
|
sysReportTemplateService.syncTemplatesFromClasspath(bo.getTemplateCodes());
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除报表模板
|
* 删除报表模板
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.hotwj.platform.reportStatistics.domain.bo;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 报表模板按项同步请求
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SysReportTemplateSyncBo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要同步的模板编码集合
|
||||||
|
*/
|
||||||
|
@NotEmpty(message = "请选择需要同步的模板")
|
||||||
|
private List<String> templateCodes;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.hotwj.platform.reportStatistics.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 报表模板同步差异视图对象
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SysReportTemplateSyncCompareVo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private String templateCode;
|
||||||
|
|
||||||
|
private Long dbId;
|
||||||
|
|
||||||
|
private String localTemplateName;
|
||||||
|
|
||||||
|
private String dbTemplateName;
|
||||||
|
|
||||||
|
private String localContent;
|
||||||
|
|
||||||
|
private String dbContent;
|
||||||
|
|
||||||
|
private String localMockData;
|
||||||
|
|
||||||
|
private String dbMockData;
|
||||||
|
|
||||||
|
private String localRemark;
|
||||||
|
|
||||||
|
private String dbRemark;
|
||||||
|
|
||||||
|
private Boolean existsInLocal;
|
||||||
|
|
||||||
|
private Boolean existsInDb;
|
||||||
|
|
||||||
|
private Boolean syncable;
|
||||||
|
|
||||||
|
private List<String> diffTypes;
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.hotwj.platform.reportStatistics.service;
|
|||||||
|
|
||||||
import com.hotwj.platform.reportStatistics.domain.bo.SysReportTemplateBo;
|
import com.hotwj.platform.reportStatistics.domain.bo.SysReportTemplateBo;
|
||||||
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateVo;
|
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateVo;
|
||||||
|
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateSyncCompareVo;
|
||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
|
|
||||||
@@ -56,6 +57,16 @@ public interface ISysReportTemplateService {
|
|||||||
*/
|
*/
|
||||||
void syncTemplatesFromClasspath();
|
void syncTemplatesFromClasspath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询本地模板与数据库模板的差异
|
||||||
|
*/
|
||||||
|
List<SysReportTemplateSyncCompareVo> querySyncDiffList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按模板编码同步本地模板到数据库
|
||||||
|
*/
|
||||||
|
void syncTemplatesFromClasspath(Collection<String> templateCodes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据模板编码查找对应的 Provider
|
* 根据模板编码查找对应的 Provider
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.hotwj.platform.reportStatistics.domain.SysReportTemplate;
|
import com.hotwj.platform.reportStatistics.domain.SysReportTemplate;
|
||||||
import com.hotwj.platform.reportStatistics.domain.bo.SysReportTemplateBo;
|
import com.hotwj.platform.reportStatistics.domain.bo.SysReportTemplateBo;
|
||||||
|
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateSyncCompareVo;
|
||||||
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateVo;
|
import com.hotwj.platform.reportStatistics.domain.vo.SysReportTemplateVo;
|
||||||
import com.hotwj.platform.reportStatistics.mapper.SysReportTemplateMapper;
|
import com.hotwj.platform.reportStatistics.mapper.SysReportTemplateMapper;
|
||||||
import com.hotwj.platform.reportStatistics.service.IReportDataProvider;
|
import com.hotwj.platform.reportStatistics.service.IReportDataProvider;
|
||||||
@@ -16,6 +17,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.common.core.utils.MapstructUtils;
|
import org.dromara.common.core.utils.MapstructUtils;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
@@ -27,9 +29,15 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 报表模板Service业务层处理
|
* 报表模板Service业务层处理
|
||||||
@@ -42,6 +50,9 @@ import java.util.Map;
|
|||||||
@Service
|
@Service
|
||||||
public class SysReportTemplateServiceImpl implements ISysReportTemplateService {
|
public class SysReportTemplateServiceImpl implements ISysReportTemplateService {
|
||||||
|
|
||||||
|
private static final String CLASSPATH_SCAN_REMARK = "Synced from classpath scan";
|
||||||
|
private static final String PROVIDER_REMARK_PREFIX = "Synced from Provider: ";
|
||||||
|
|
||||||
private final SysReportTemplateMapper baseMapper;
|
private final SysReportTemplateMapper baseMapper;
|
||||||
private final List<IReportDataProvider> reportDataProviders;
|
private final List<IReportDataProvider> reportDataProviders;
|
||||||
|
|
||||||
@@ -153,114 +164,257 @@ public class SysReportTemplateServiceImpl implements ISysReportTemplateService {
|
|||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void syncTemplatesFromClasspath() {
|
public void syncTemplatesFromClasspath() {
|
||||||
// 1. Sync from Providers (Source of truth for Title and MockData)
|
syncTemplatesFromClasspath(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SysReportTemplateSyncCompareVo> querySyncDiffList() {
|
||||||
|
LinkedHashMap<String, LocalTemplateSnapshot> localTemplates = loadLocalTemplateSnapshots();
|
||||||
|
Map<String, SysReportTemplateVo> dbTemplates = queryExistingTemplates(null);
|
||||||
|
|
||||||
|
Set<String> allCodes = new LinkedHashSet<>();
|
||||||
|
allCodes.addAll(localTemplates.keySet());
|
||||||
|
allCodes.addAll(dbTemplates.keySet());
|
||||||
|
|
||||||
|
return allCodes.stream()
|
||||||
|
.map(code -> buildCompareVo(code, localTemplates.get(code), dbTemplates.get(code)))
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void syncTemplatesFromClasspath(Collection<String> templateCodes) {
|
||||||
|
LinkedHashMap<String, LocalTemplateSnapshot> localTemplates = loadLocalTemplateSnapshots();
|
||||||
|
Set<String> targetCodes = normalizeTemplateCodes(templateCodes);
|
||||||
|
if (targetCodes != null && targetCodes.isEmpty()) {
|
||||||
|
throw new ServiceException("请选择需要同步的模板");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetCodes != null) {
|
||||||
|
List<String> missingCodes = targetCodes.stream()
|
||||||
|
.filter(code -> !localTemplates.containsKey(code))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (!missingCodes.isEmpty()) {
|
||||||
|
throw new ServiceException("以下模板在本地不存在,无法同步: " + String.join(", ", missingCodes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, SysReportTemplateVo> dbTemplates = queryExistingTemplates(targetCodes);
|
||||||
|
|
||||||
|
for (LocalTemplateSnapshot snapshot : localTemplates.values()) {
|
||||||
|
if (targetCodes != null && !targetCodes.contains(snapshot.getTemplateCode())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SysReportTemplateVo existing = dbTemplates.get(snapshot.getTemplateCode());
|
||||||
|
if (existing == null) {
|
||||||
|
SysReportTemplate insert = new SysReportTemplate();
|
||||||
|
insert.setTemplateCode(snapshot.getTemplateCode());
|
||||||
|
insert.setTemplateName(snapshot.getTemplateName());
|
||||||
|
insert.setContent(snapshot.getContent());
|
||||||
|
insert.setMockData(snapshot.getMockData());
|
||||||
|
insert.setVersion(1);
|
||||||
|
insert.setRemark(snapshot.getRemark());
|
||||||
|
baseMapper.insert(insert);
|
||||||
|
log.info("Inserted template from local source: {}", snapshot.getTemplateCode());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasDiff(snapshot, existing)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SysReportTemplate update = new SysReportTemplate();
|
||||||
|
update.setId(existing.getId());
|
||||||
|
update.setTemplateCode(snapshot.getTemplateCode());
|
||||||
|
update.setTemplateName(snapshot.getTemplateName());
|
||||||
|
update.setContent(snapshot.getContent());
|
||||||
|
update.setMockData(snapshot.getMockData());
|
||||||
|
update.setRemark(snapshot.getRemark());
|
||||||
|
update.setVersion(existing.getVersion() == null ? 1 : existing.getVersion() + 1);
|
||||||
|
baseMapper.updateById(update);
|
||||||
|
log.info("Updated template from local source: {}", snapshot.getTemplateCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SysReportTemplateSyncCompareVo buildCompareVo(String code, LocalTemplateSnapshot local, SysReportTemplateVo db) {
|
||||||
|
List<String> diffTypes = buildDiffTypes(local, db);
|
||||||
|
if (diffTypes.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
SysReportTemplateSyncCompareVo vo = new SysReportTemplateSyncCompareVo();
|
||||||
|
vo.setTemplateCode(code);
|
||||||
|
vo.setDbId(db == null ? null : db.getId());
|
||||||
|
vo.setLocalTemplateName(local == null ? "" : local.getTemplateName());
|
||||||
|
vo.setDbTemplateName(db == null ? "" : db.getTemplateName());
|
||||||
|
vo.setLocalContent(local == null ? "" : local.getContent());
|
||||||
|
vo.setDbContent(db == null ? "" : normalizeText(db.getContent()));
|
||||||
|
vo.setLocalMockData(toJsonText(local == null ? null : local.getMockData()));
|
||||||
|
vo.setDbMockData(toJsonText(db == null ? null : db.getMockData()));
|
||||||
|
vo.setLocalRemark(local == null ? "" : local.getRemark());
|
||||||
|
vo.setDbRemark(db == null ? "" : normalizeText(db.getRemark()));
|
||||||
|
vo.setExistsInLocal(local != null);
|
||||||
|
vo.setExistsInDb(db != null);
|
||||||
|
vo.setSyncable(local != null);
|
||||||
|
vo.setDiffTypes(diffTypes);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasDiff(LocalTemplateSnapshot local, SysReportTemplateVo db) {
|
||||||
|
return !buildDiffTypes(local, db).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> buildDiffTypes(LocalTemplateSnapshot local, SysReportTemplateVo db) {
|
||||||
|
List<String> diffTypes = new ArrayList<>();
|
||||||
|
if (local == null && db != null) {
|
||||||
|
diffTypes.add("仅数据库");
|
||||||
|
return diffTypes;
|
||||||
|
}
|
||||||
|
if (local != null && db == null) {
|
||||||
|
diffTypes.add("仅本地");
|
||||||
|
return diffTypes;
|
||||||
|
}
|
||||||
|
if (local == null) {
|
||||||
|
return diffTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Objects.equals(normalizeText(local.getTemplateName()), normalizeText(db.getTemplateName()))) {
|
||||||
|
diffTypes.add("名称");
|
||||||
|
}
|
||||||
|
if (!Objects.equals(normalizeText(local.getContent()), normalizeText(db.getContent()))) {
|
||||||
|
diffTypes.add("内容");
|
||||||
|
}
|
||||||
|
if (!Objects.equals(toJsonText(local.getMockData()), toJsonText(db.getMockData()))) {
|
||||||
|
diffTypes.add("模拟数据");
|
||||||
|
}
|
||||||
|
if (!Objects.equals(normalizeText(local.getRemark()), normalizeText(db.getRemark()))) {
|
||||||
|
diffTypes.add("备注");
|
||||||
|
}
|
||||||
|
return diffTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, SysReportTemplateVo> queryExistingTemplates(Set<String> templateCodes) {
|
||||||
|
LambdaQueryWrapper<SysReportTemplate> queryWrapper = Wrappers.lambdaQuery();
|
||||||
|
if (templateCodes != null && !templateCodes.isEmpty()) {
|
||||||
|
queryWrapper.in(SysReportTemplate::getTemplateCode, templateCodes);
|
||||||
|
}
|
||||||
|
return baseMapper.selectVoList(queryWrapper).stream()
|
||||||
|
.collect(Collectors.toMap(SysReportTemplateVo::getTemplateCode, item -> item, (left, right) -> left, LinkedHashMap::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinkedHashMap<String, LocalTemplateSnapshot> loadLocalTemplateSnapshots() {
|
||||||
|
LinkedHashMap<String, LocalTemplateSnapshot> templateMap = new LinkedHashMap<>();
|
||||||
|
|
||||||
if (reportDataProviders != null) {
|
if (reportDataProviders != null) {
|
||||||
for (IReportDataProvider provider : reportDataProviders) {
|
for (IReportDataProvider provider : reportDataProviders) {
|
||||||
try {
|
try {
|
||||||
String code = provider.getTemplateCode();
|
String code = provider.getTemplateCode();
|
||||||
if (StringUtils.isBlank(code)) continue;
|
if (StringUtils.isBlank(code)) {
|
||||||
|
continue;
|
||||||
SysReportTemplateVo existing = queryByCode(code);
|
|
||||||
|
|
||||||
// Read content
|
|
||||||
String content = null;
|
|
||||||
try {
|
|
||||||
ClassPathResource resource = new ClassPathResource(code);
|
|
||||||
if (resource.exists()) {
|
|
||||||
content = IoUtil.read(resource.getInputStream(), StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("Template file not found for provider: {}", provider.getClass().getSimpleName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existing == null) {
|
String content = readTemplateContent(code);
|
||||||
if (StringUtils.isBlank(content)) {
|
if (StringUtils.isBlank(content)) {
|
||||||
log.warn("Skipping provider {} because template file {} not found", provider.getClass().getSimpleName(), code);
|
log.warn("Skipping provider {} because template file {} not found", provider.getClass().getSimpleName(), code);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SysReportTemplate template = new SysReportTemplate();
|
|
||||||
template.setTemplateCode(code);
|
|
||||||
template.setTemplateName(provider.getReportTitle());
|
|
||||||
template.setContent(content);
|
|
||||||
template.setMockData(provider.getMockData());
|
|
||||||
template.setVersion(1);
|
|
||||||
template.setRemark("Synced from Provider: " + provider.getClass().getSimpleName());
|
|
||||||
baseMapper.insert(template);
|
|
||||||
log.info("Inserted template from provider: {}", code);
|
|
||||||
} else {
|
|
||||||
// Update metadata
|
|
||||||
SysReportTemplate update = new SysReportTemplate();
|
|
||||||
update.setId(existing.getId());
|
|
||||||
boolean changed = false;
|
|
||||||
|
|
||||||
// Sync Title
|
LocalTemplateSnapshot snapshot = new LocalTemplateSnapshot();
|
||||||
String title = provider.getReportTitle();
|
snapshot.setTemplateCode(code);
|
||||||
if (StringUtils.isNotBlank(title) && !title.equals(existing.getTemplateName())) {
|
snapshot.setTemplateName(provider.getReportTitle());
|
||||||
update.setTemplateName(title);
|
snapshot.setContent(content);
|
||||||
changed = true;
|
snapshot.setMockData(provider.getMockData());
|
||||||
}
|
snapshot.setRemark(PROVIDER_REMARK_PREFIX + provider.getClass().getSimpleName());
|
||||||
|
templateMap.put(code, snapshot);
|
||||||
// Sync MockData if provided
|
|
||||||
Map<String, Object> mockData = provider.getMockData();
|
|
||||||
if (mockData != null && !mockData.isEmpty()) {
|
|
||||||
update.setMockData(mockData);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optional: Sync content if it was empty in DB (unlikely)
|
|
||||||
if (StringUtils.isBlank(existing.getContent()) && StringUtils.isNotBlank(content)) {
|
|
||||||
update.setContent(content);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
baseMapper.updateById(update);
|
|
||||||
log.info("Updated template metadata from provider: {}", code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error syncing provider template: " + provider.getClass().getSimpleName(), e);
|
log.error("Error loading provider template: {}", provider.getClass().getSimpleName(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Scan remaining files (for layouts and fragments)
|
|
||||||
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||||
try {
|
try {
|
||||||
// Find all .vm files in templates directory
|
|
||||||
Resource[] resources = resolver.getResources("classpath*:templates/**/*.vm");
|
Resource[] resources = resolver.getResources("classpath*:templates/**/*.vm");
|
||||||
for (Resource resource : resources) {
|
for (Resource resource : resources) {
|
||||||
try {
|
try {
|
||||||
String path = resource.getURL().getPath();
|
String code = extractTemplateCode(resource);
|
||||||
// Normalize path separators
|
if (StringUtils.isBlank(code) || templateMap.containsKey(code)) {
|
||||||
path = path.replace("\\", "/");
|
continue;
|
||||||
|
|
||||||
int index = path.lastIndexOf("templates/");
|
|
||||||
if (index > -1) {
|
|
||||||
String code = path.substring(index); // Include "templates/" in the code
|
|
||||||
|
|
||||||
// Check if exists
|
|
||||||
SysReportTemplateVo exist = queryByCode(code);
|
|
||||||
if (exist == null) {
|
|
||||||
String content = IoUtil.read(resource.getInputStream(), StandardCharsets.UTF_8);
|
|
||||||
SysReportTemplate template = new SysReportTemplate();
|
|
||||||
template.setTemplateCode(code);
|
|
||||||
// Use filename as name
|
|
||||||
template.setTemplateName(FileUtil.mainName(resource.getFilename()));
|
|
||||||
template.setContent(content);
|
|
||||||
template.setVersion(1);
|
|
||||||
template.setRemark("Synced from classpath scan");
|
|
||||||
baseMapper.insert(template);
|
|
||||||
log.info("Synced template from scan: {}", code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocalTemplateSnapshot snapshot = new LocalTemplateSnapshot();
|
||||||
|
snapshot.setTemplateCode(code);
|
||||||
|
snapshot.setTemplateName(FileUtil.mainName(resource.getFilename()));
|
||||||
|
snapshot.setContent(IoUtil.read(resource.getInputStream(), StandardCharsets.UTF_8));
|
||||||
|
snapshot.setRemark(CLASSPATH_SCAN_REMARK);
|
||||||
|
templateMap.put(code, snapshot);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error processing resource: " + resource, e);
|
log.error("Error processing resource: {}", resource, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("Failed to sync templates", e);
|
log.error("Failed to load local templates", e);
|
||||||
throw new ServiceException("同步模版失败");
|
throw new ServiceException("读取本地模板失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
return templateMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractTemplateCode(Resource resource) throws IOException {
|
||||||
|
String path = resource.getURL().getPath().replace("\\", "/");
|
||||||
|
int index = path.lastIndexOf("templates/");
|
||||||
|
if (index < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return path.substring(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readTemplateContent(String code) {
|
||||||
|
try {
|
||||||
|
ClassPathResource resource = new ClassPathResource(code);
|
||||||
|
if (!resource.exists()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return IoUtil.read(resource.getInputStream(), StandardCharsets.UTF_8);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("Template file not found: {}", code, e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<String> normalizeTemplateCodes(Collection<String> templateCodes) {
|
||||||
|
if (templateCodes == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return templateCodes.stream()
|
||||||
|
.filter(StringUtils::isNotBlank)
|
||||||
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeText(String value) {
|
||||||
|
return value == null ? "" : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toJsonText(Object value) {
|
||||||
|
if (value == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return JsonUtils.toJsonString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@lombok.Data
|
||||||
|
private static class LocalTemplateSnapshot {
|
||||||
|
|
||||||
|
private String templateCode;
|
||||||
|
|
||||||
|
private String templateName;
|
||||||
|
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
private Object mockData;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user