feat: HCS主数据缓存与附件转传支撑(C103-6/7/12模板分类币种缓存、C103-2附件转传与合规附件ID映射缓存)
This commit is contained in:
+290
@@ -0,0 +1,290 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.support.hcs;
|
||||
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.redis.cache.BladeRedis;
|
||||
import org.springblade.core.tool.jackson.JsonUtil;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.hcs.config.HcsProperties;
|
||||
import org.springblade.hcs.constant.HcsConstant;
|
||||
import org.springblade.hcs.dto.HcsAttachmentVO;
|
||||
import org.springblade.hcs.dto.HcsResult;
|
||||
import org.springblade.hcs.exception.HcsException;
|
||||
import org.springblade.hcs.feign.IHcsClient;
|
||||
import org.springblade.transport.constant.HcsSyncConstant;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* HCS 附件转传支撑组件(C103-2 multipart 上传,设计文档 §6)
|
||||
* <p>
|
||||
* 流程:解析单据附件 JSON 元素(去重键照 ContractManage#attachmentKey 惯例)→
|
||||
* 按元数据 URL 从文件服务拉取流(基址可配 attachment.file-download-base)→
|
||||
* C103-2 上传取得合规附件ID → Redis 映射缓存(blade:third:hcs:att:{attachmentKey},TTL 7 天),
|
||||
* 未命中重传(重复上传仅浪费存储,无业务风险,故不做持久化映射表)。
|
||||
* 任一附件转传失败 → 抛出异常由整单推送失败进补偿重试。
|
||||
* <p>
|
||||
* TODO 待联调确认(§9-U8):v4 的 C103-1 入参未定义附件字段,合同附件向 HCS 的挂载方式待合规方确认,
|
||||
* 本组件先建设通用转传能力并将合规附件ID 缓存备用,确认后按其要求挂载。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class HcsAttachmentSupport {
|
||||
|
||||
/**
|
||||
* 附件元数据去重键候选字段(照 ContractManage#attachmentKey 既有惯例)
|
||||
*/
|
||||
private static final List<String> KEY_FIELDS = List.of("url", "link", "fileUrl", "downloadUrl", "uid", "originalName", "name");
|
||||
|
||||
private final IHcsClient hcsClient;
|
||||
private final HcsProperties hcsProperties;
|
||||
private final BladeRedis bladeRedis;
|
||||
|
||||
/**
|
||||
* 解析单据附件 JSON 并转传,返回合规附件ID 列表(保持行序)
|
||||
*
|
||||
* @param attachmentsJson 附件元数据 JSON 数组
|
||||
* @param operatorLoginName 操作人登录名(C103-2 fdLoginName)
|
||||
* @return 合规附件ID 列表
|
||||
*/
|
||||
public List<String> transferAttachments(String attachmentsJson, String operatorLoginName) {
|
||||
if (StringUtil.isBlank(attachmentsJson)) {
|
||||
return List.of();
|
||||
}
|
||||
List<Map<?, ?>> attachments = parseJsonArray(attachmentsJson);
|
||||
List<String> attachmentFdIds = new ArrayList<>();
|
||||
for (Map<?, ?> attachment : attachments) {
|
||||
attachmentFdIds.add(transferOne(attachment, operatorLoginName));
|
||||
}
|
||||
return attachmentFdIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析合同主文件 JSON(仅 approved=true 的文件)与其它附件 JSON 并转传
|
||||
*
|
||||
* @param contractFileJson 合同主文件 JSON
|
||||
* @param attachmentsJson 其它附件 JSON
|
||||
* @param operatorLoginName 操作人登录名
|
||||
* @return 合规附件ID 列表
|
||||
*/
|
||||
public List<String> transferContractAttachments(String contractFileJson, String attachmentsJson, String operatorLoginName) {
|
||||
List<Map<?, ?>> attachments = new ArrayList<>();
|
||||
for (Map<?, ?> file : parseJsonArray(contractFileJson)) {
|
||||
if (isApproved(file)) {
|
||||
attachments.add(file);
|
||||
}
|
||||
}
|
||||
attachments.addAll(parseJsonArray(attachmentsJson));
|
||||
List<String> attachmentFdIds = new ArrayList<>();
|
||||
for (Map<?, ?> attachment : attachments) {
|
||||
attachmentFdIds.add(transferOne(attachment, operatorLoginName));
|
||||
}
|
||||
return attachmentFdIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转传单个附件:映射缓存命中直接返回,未命中下载上传后写缓存
|
||||
*/
|
||||
private String transferOne(Map<?, ?> attachment, String operatorLoginName) {
|
||||
String attachmentKey = attachmentKey(attachment);
|
||||
String cacheKey = HcsSyncConstant.ATTACHMENT_CACHE_KEY_PREFIX + attachmentKey;
|
||||
String cachedFdId = bladeRedis.get(cacheKey);
|
||||
if (StringUtil.isNotBlank(cachedFdId)) {
|
||||
return cachedFdId;
|
||||
}
|
||||
String url = resolveUrl(attachment);
|
||||
if (StringUtil.isBlank(url)) {
|
||||
throw new HcsException("HCS附件转传失败,附件元数据缺少下载地址(attachmentKey=" + attachmentKey + ")");
|
||||
}
|
||||
byte[] fileBytes = downloadFile(url);
|
||||
String fileName = resolveFileName(attachment, url);
|
||||
log.info("HCS附件转传开始:{},大小 {} 字节", fileName, fileBytes.length);
|
||||
HcsResult<HcsAttachmentVO> result = hcsClient.uploadAttachment(
|
||||
new InMemoryMultipartFile("fdFile", fileName, fileBytes), "false", operatorLoginName);
|
||||
if (result == null || !result.isSuccess() || result.getData() == null || StringUtil.isBlank(result.getData().getFdId())) {
|
||||
log.error("HCS附件转传失败响应:{}", result == null ? "无响应" : String.format("code=%s, msg=%s, traceId=%s",
|
||||
result.getCode(), result.getMsg(), result.getTraceId()));
|
||||
throw new HcsException("HCS附件转传失败:" + (result == null ? "响应为空" : result.getMsg()));
|
||||
}
|
||||
String attachmentFdId = result.getData().getFdId();
|
||||
bladeRedis.getValueOps().setIfAbsent(cacheKey, attachmentFdId, Duration.ofDays(HcsSyncConstant.ATTACHMENT_CACHE_TTL_DAYS));
|
||||
log.info("HCS附件转传完成:{} → 合规附件ID {}", fileName, attachmentFdId);
|
||||
return attachmentFdId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按元数据 URL 从文件服务拉取流:完整 URL 直接下载,相对路径拼可配基址
|
||||
*/
|
||||
private byte[] downloadFile(String url) {
|
||||
String target = url;
|
||||
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||
String base = hcsProperties.getAttachment().getFileDownloadBase();
|
||||
if (StringUtil.isBlank(base)) {
|
||||
throw new HcsException("HCS附件转传失败,文件服务下载基址未配置(thirdParty.hcs.attachment.file-download-base)");
|
||||
}
|
||||
target = base + url;
|
||||
}
|
||||
try {
|
||||
return HttpUtil.downloadBytes(target);
|
||||
} catch (Exception exception) {
|
||||
log.error("HCS附件转传下载失败:{}", target, exception);
|
||||
throw new HcsException("HCS附件转传下载失败:" + target, exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 附件元数据去重键(url|link|fileUrl|downloadUrl|uid|originalName|name 依次取首个非空)
|
||||
*/
|
||||
private String attachmentKey(Map<?, ?> attachment) {
|
||||
for (String field : KEY_FIELDS) {
|
||||
Object value = attachment.get(field);
|
||||
if (value != null && !String.valueOf(value).isBlank()) {
|
||||
return field + ":" + value;
|
||||
}
|
||||
}
|
||||
return String.valueOf(attachment);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取附件下载地址
|
||||
*/
|
||||
private String resolveUrl(Map<?, ?> attachment) {
|
||||
for (String field : List.of("url", "link", "fileUrl", "downloadUrl", "path")) {
|
||||
Object value = attachment.get(field);
|
||||
if (value != null && !String.valueOf(value).isBlank()) {
|
||||
return String.valueOf(value).trim();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取附件文件名(name/originalName 优先,缺失时取 URL 末段)
|
||||
*/
|
||||
private String resolveFileName(Map<?, ?> attachment, String url) {
|
||||
for (String field : List.of("name", "originalName", "fileName")) {
|
||||
Object value = attachment.get(field);
|
||||
if (value != null && !String.valueOf(value).isBlank()) {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
}
|
||||
String lastSegment = url.substring(url.lastIndexOf('/') + 1);
|
||||
return StringUtil.isBlank(lastSegment) ? "hcs-attachment" : lastSegment;
|
||||
}
|
||||
|
||||
/**
|
||||
* 主文件审批标记判定(照 ContractManage#isAttachmentApproved 惯例)
|
||||
*/
|
||||
private boolean isApproved(Map<?, ?> attachment) {
|
||||
Object approved = attachment.get("approved");
|
||||
if (approved == null) {
|
||||
return false;
|
||||
}
|
||||
return Boolean.TRUE.equals(approved) || Objects.equals(approved, 1)
|
||||
|| "1".equals(String.valueOf(approved)) || "true".equalsIgnoreCase(String.valueOf(approved));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 JSON 数组(照 ContractManage#parseJsonArray 惯例,异常返回空列表)
|
||||
*/
|
||||
private List<Map<?, ?>> parseJsonArray(String json) {
|
||||
if (StringUtil.isBlank(json)) {
|
||||
return List.of();
|
||||
}
|
||||
try {
|
||||
return JsonUtil.parse(json, List.class);
|
||||
} catch (Exception exception) {
|
||||
log.warn("HCS附件元数据解析失败,按无附件处理:{}", json);
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 内存 MultipartFile(下载字节流转传 C103-2 用)
|
||||
*/
|
||||
private record InMemoryMultipartFile(String name, String originalFilename, byte[] bytes) implements MultipartFile {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOriginalFilename() {
|
||||
return originalFilename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return MediaType.APPLICATION_OCTET_STREAM_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return bytes == null || bytes.length == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSize() {
|
||||
return bytes == null ? 0 : bytes.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() {
|
||||
return new ByteArrayInputStream(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transferTo(File dest) throws IOException {
|
||||
try (FileOutputStream outputStream = new FileOutputStream(dest)) {
|
||||
outputStream.write(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.support.hcs;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.redis.cache.BladeRedis;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.hcs.config.HcsProperties;
|
||||
import org.springblade.hcs.dto.HcsCategoryVO;
|
||||
import org.springblade.hcs.dto.HcsCurrencyVO;
|
||||
import org.springblade.hcs.dto.HcsPageQueryDTO;
|
||||
import org.springblade.hcs.dto.HcsPageVO;
|
||||
import org.springblade.hcs.dto.HcsTemplateVO;
|
||||
import org.springblade.hcs.exception.HcsException;
|
||||
import org.springblade.hcs.feign.IHcsClient;
|
||||
import org.springblade.hcs.util.HcsPageUtil;
|
||||
import org.springblade.transport.constant.HcsSyncConstant;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* HCS 主数据缓存支撑组件(C103-6 模板 / C103-7 分类 / C103-12 币种,设计文档 §5.9)
|
||||
* <p>
|
||||
* 启动/首次使用时拉取并缓存(Redis,照 BFI token 缓存惯例,TTL 可配 master-data.ttl-minutes):
|
||||
* 模板列表供 template-mapping 校验,币种表供 currency-id-mapping 取值。
|
||||
* 提供管理端"刷新缓存"入口(HcsSyncController)。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class HcsMasterDataSupport {
|
||||
|
||||
/**
|
||||
* 主数据分页拉取页大小
|
||||
*/
|
||||
private static final int PAGE_SIZE = 200;
|
||||
|
||||
private final IHcsClient hcsClient;
|
||||
private final HcsProperties hcsProperties;
|
||||
private final BladeRedis bladeRedis;
|
||||
|
||||
/**
|
||||
* 获取合同模板列表(缓存优先,未命中全量拉取)
|
||||
*/
|
||||
public List<HcsTemplateVO> getTemplates() {
|
||||
List<HcsTemplateVO> cached = readCache(HcsSyncConstant.MASTER_CACHE_TEMPLATES, HcsTemplateVO.class);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
return loadTemplates();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取合同分类列表(缓存优先,未命中全量拉取)
|
||||
*/
|
||||
public List<HcsCategoryVO> getCategories() {
|
||||
List<HcsCategoryVO> cached = readCache(HcsSyncConstant.MASTER_CACHE_CATEGORIES, HcsCategoryVO.class);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
return loadCategories();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取币种列表(缓存优先,未命中全量拉取)
|
||||
*/
|
||||
public List<HcsCurrencyVO> getCurrencies() {
|
||||
List<HcsCurrencyVO> cached = readCache(HcsSyncConstant.MASTER_CACHE_CURRENCIES, HcsCurrencyVO.class);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
return loadCurrencies();
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制刷新三类主数据缓存(管理端入口),并对 template-mapping 做存在性校验
|
||||
*
|
||||
* @return 刷新结果汇总
|
||||
*/
|
||||
public String refreshAll() {
|
||||
int templateCount = loadTemplates().size();
|
||||
int categoryCount = loadCategories().size();
|
||||
int currencyCount = loadCurrencies().size();
|
||||
validateTemplateMapping();
|
||||
String summary = String.format("HCS主数据缓存已刷新:模板 %d 条、分类 %d 条、币种 %d 条", templateCount, categoryCount, currencyCount);
|
||||
log.info(summary);
|
||||
return summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* 全量拉取合同模板并缓存
|
||||
*/
|
||||
private List<HcsTemplateVO> loadTemplates() {
|
||||
HcsPageQueryDTO query = baseQuery();
|
||||
List<HcsTemplateVO> rows = HcsPageUtil.queryAllPages(offset -> {
|
||||
query.setOffset(offset);
|
||||
return hcsClient.templateList(query).getData();
|
||||
});
|
||||
writeCache(HcsSyncConstant.MASTER_CACHE_TEMPLATES, rows);
|
||||
log.info("HCS合同模板列表已缓存,共 {} 条", rows.size());
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 全量拉取合同分类并缓存
|
||||
*/
|
||||
private List<HcsCategoryVO> loadCategories() {
|
||||
HcsPageQueryDTO query = baseQuery();
|
||||
List<HcsCategoryVO> rows = HcsPageUtil.queryAllPages(offset -> {
|
||||
query.setOffset(offset);
|
||||
return hcsClient.categoryList(query).getData();
|
||||
});
|
||||
writeCache(HcsSyncConstant.MASTER_CACHE_CATEGORIES, rows);
|
||||
log.info("HCS合同分类列表已缓存,共 {} 条", rows.size());
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 全量拉取币种并缓存
|
||||
*/
|
||||
private List<HcsCurrencyVO> loadCurrencies() {
|
||||
HcsPageQueryDTO query = baseQuery();
|
||||
List<HcsCurrencyVO> rows = HcsPageUtil.queryAllPages(offset -> {
|
||||
query.setOffset(offset);
|
||||
return hcsClient.currencyList(query).getData();
|
||||
});
|
||||
writeCache(HcsSyncConstant.MASTER_CACHE_CURRENCIES, rows);
|
||||
log.info("HCS币种列表已缓存,共 {} 条", rows.size());
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验 contract.template-mapping 中的模板ID是否存在于 HCS 模板列表(§9-U7,仅告警不阻断)
|
||||
*/
|
||||
private void validateTemplateMapping() {
|
||||
Map<String, String> mapping = hcsProperties.getContract().getTemplateMapping();
|
||||
if (mapping.isEmpty()) {
|
||||
log.warn("HCS合同模板映射(thirdParty.hcs.contract.template-mapping)未配置,合同推送将失败(§9-U7 待合规方提供模板ID清单)");
|
||||
return;
|
||||
}
|
||||
List<String> templateIds = getTemplates().stream().map(HcsTemplateVO::getFdId).toList();
|
||||
mapping.forEach((category, templateId) -> {
|
||||
if (StringUtil.isNotBlank(templateId) && !templateIds.contains(templateId)) {
|
||||
log.warn("HCS合同模板映射校验告警:合同类别 [{}] 映射的模板ID [{}] 不在合规模板列表中", category, templateId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询基础参数(columns 必填)
|
||||
*/
|
||||
private HcsPageQueryDTO baseQuery() {
|
||||
HcsPageQueryDTO query = new HcsPageQueryDTO();
|
||||
query.setPageSize(PAGE_SIZE);
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读缓存(JSON 字符串反序列化)
|
||||
*/
|
||||
private <T> List<T> readCache(String cacheKey, Class<T> itemType) {
|
||||
String json = bladeRedis.get(cacheKey);
|
||||
if (StringUtil.isBlank(json)) {
|
||||
return null;
|
||||
}
|
||||
return JSONUtil.toList(json, itemType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写缓存(JSON 字符串 + 可配 TTL)
|
||||
*/
|
||||
private void writeCache(String cacheKey, List<?> rows) {
|
||||
bladeRedis.getValueOps().setIfAbsent(cacheKey, JSONUtil.toJsonStr(rows),
|
||||
Duration.ofMinutes(hcsProperties.getMasterData().getTtlMinutes()));
|
||||
}
|
||||
}
|
||||
+12
@@ -112,6 +112,10 @@ public class HcsProperties {
|
||||
* 附件转传(C103-2)配置
|
||||
*/
|
||||
private Attachment attachment = new Attachment();
|
||||
/**
|
||||
* 主数据缓存(C103-6/7/12)配置
|
||||
*/
|
||||
private MasterData masterData = new MasterData();
|
||||
|
||||
@Data
|
||||
public static class Push {
|
||||
@@ -252,4 +256,12 @@ public class HcsProperties {
|
||||
*/
|
||||
private String fileDownloadBase = "";
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class MasterData {
|
||||
/**
|
||||
* 模板/分类/币种列表缓存时长(分钟),启动/首次使用时拉取并缓存(设计文档 §5.9)
|
||||
*/
|
||||
private int ttlMinutes = 120;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,3 +144,7 @@ thirdParty:
|
||||
transfer-enabled: ${HCS_ATTACHMENT_TRANSFER_ENABLED:true}
|
||||
# TMS 文件服务下载基址(拉取附件流用)
|
||||
file-download-base: ${HCS_ATTACHMENT_FILE_DOWNLOAD_BASE:}
|
||||
# 主数据缓存(C103-6/7/12,启动/首次使用时拉取并缓存)
|
||||
master-data:
|
||||
# 缓存时长(分钟)
|
||||
ttl-minutes: ${HCS_MASTER_DATA_TTL_MINUTES:120}
|
||||
|
||||
Reference in New Issue
Block a user