含10-22精修: 对账有限重试(retry_count/指数退避/work_version防旧覆盖)+接缝身份(source-app-key空拒收)+应急对账闸让位FlowApplyRecoveryService+同attempt指令不重开终态。SQL未执行。
This commit is contained in:
@@ -94,6 +94,22 @@ public class ServiceItemService {
|
||||
private final com.yunhai.platform.flowcallback.FlowCallbackRegistrar callbackRegistrar;
|
||||
private final TransactionTemplate transactionTemplate;
|
||||
|
||||
/**
|
||||
* 表单中心目录/核验客户端(v3/TASK_1)。
|
||||
*
|
||||
* <p><b>用 setter 而不是加进 {@code @RequiredArgsConstructor} 的构造参数</b>:本类那 11 参构造
|
||||
* 已被 {@code ServiceItemEffectiveFlowTest}/{@code ServiceItemFlowRegTest} 逐位钉住,而那两份测试
|
||||
* 不在本任务的可改清单里——多一个入参会让它们直接编译不过。绑定核验必须在
|
||||
* {@link #adminSave} 的事务内发生(远端失败=整次保存回滚,不留半个绑定),所以客户端装配在这里,
|
||||
* 而不是挪到控制器入口。</p>
|
||||
*/
|
||||
private FormCenterCatalogClient formCenterClient;
|
||||
|
||||
@org.springframework.beans.factory.annotation.Autowired
|
||||
void setFormCenterClient(FormCenterCatalogClient formCenterClient) {
|
||||
this.formCenterClient = formCenterClient;
|
||||
}
|
||||
|
||||
// ===== 管理端 =====
|
||||
|
||||
public Map<String, Object> adminPage(BoaUser user, SvcItemPageQuery query) {
|
||||
@@ -196,7 +212,15 @@ public class ServiceItemService {
|
||||
item.setNoticeCategoryId(req.getNoticeCategoryId());
|
||||
item.setRuleCategoryId(req.getRuleCategoryId());
|
||||
item.setCoverImage(toRelativeIfLocal(req.getCoverImage()));
|
||||
item.setFormCode(emptyToNull(req.getFormCode()));
|
||||
// 本地 form_code 停写(v3/TASK_1):原样回传=保留历史绑定(不清空存量行),改值即拒;
|
||||
// 新表单一律走表单中心坐标,且已在 validateBindings 里经远端核验
|
||||
String legacyFormCode = emptyToNull(req.getFormCode());
|
||||
if (legacyFormCode != null && !legacyFormCode.equals(item.getFormCode())) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR,
|
||||
"本地表单定义已停用:不能在事项上写新的 form_code,请到表单中心建表后选择表单");
|
||||
}
|
||||
item.setFcFormUuid(trimToNull(req.getFcFormUuid()));
|
||||
item.setFcFormVersion(req.getFcFormVersion());
|
||||
item.setFlowGuid(emptyToNull(req.getFlowGuid()));
|
||||
item.setApplyUrl(applyUrl);
|
||||
// 服务承诺(P1-1):空串归一为 null,避免库里出现 "" 与 null 两种空值
|
||||
@@ -740,12 +764,28 @@ public class ServiceItemService {
|
||||
}
|
||||
|
||||
/** 绑定校验:表单必须存在(含草稿——允许先绑后发布,发起按已发布版本解析);
|
||||
* 流程按 FlowClient 可用性校验;onlineFlag=1 ⇒ 生效流程(事项自身或绑定表单的)非空 */
|
||||
* 流程按 FlowClient 可用性校验;onlineFlag=1 ⇒ 生效流程(事项自身或绑定表单的)非空。
|
||||
* <br>v3/TASK_1 追加:表单中心绑定必须<b>成对</b>提交,且必须在写库前经远端核验
|
||||
* (核验失败=抛错=整次 {@code adminSave} 回滚,不存在"uuid 落了、版本没落"的半个绑定)。
|
||||
* 这里刻意不做"没有表单中心坐标时回落本地 form_code"的第二套口径:本地轨只读不写。 */
|
||||
private void validateBindings(SiteInfo site, SvcItemSaveRequest req) {
|
||||
String formCode = emptyToNull(req.getFormCode());
|
||||
if (formCode != null && !formRepository.existsBySchIdAndCode(site.getSchId(), formCode)) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "办理表单不存在:" + formCode);
|
||||
}
|
||||
String fcFormUuid = trimToNull(req.getFcFormUuid());
|
||||
Integer fcFormVersion = req.getFcFormVersion();
|
||||
if ((fcFormUuid == null) != (fcFormVersion == null)) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR,
|
||||
"表单中心绑定必须成对提交(fcFormUuid 与 fcFormVersion 同传或都不传;"
|
||||
+ "当前 uuid=" + fcFormUuid + ",version=" + fcFormVersion + ")");
|
||||
}
|
||||
if (fcFormUuid != null) {
|
||||
if (formCenterClient == null) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "表单中心客户端未装配,无法核验绑定坐标");
|
||||
}
|
||||
formCenterClient.requireBindable(site.getSchId(), fcFormUuid, fcFormVersion);
|
||||
}
|
||||
String flowGuid = emptyToNull(req.getFlowGuid());
|
||||
if (flowGuid != null && flowClient.enabled()) {
|
||||
if (flowClient.getFlow(site.getSchId(), flowGuid) == null) {
|
||||
@@ -889,6 +929,15 @@ public class ServiceItemService {
|
||||
return StringUtils.hasText(value) ? value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 跨服务坐标用(表单中心 uuid):去空白后入库,空串归 null。
|
||||
* {@link #emptyToNull} 不去空白——历史列里"首尾带空格的 code"从来不是问题,
|
||||
* 但 uuid 要和中心逐字等值比对,留着空格会让核验通过后存进一个查不回的值。
|
||||
*/
|
||||
private static String trimToNull(String value) {
|
||||
return StringUtils.hasText(value) ? value.trim() : null;
|
||||
}
|
||||
|
||||
/** 封面:本应用上传的相对路径原样入库;外部完整 URL 截取 /upload/ 相对段(与附件同口径);折叠历史叠加段自愈 */
|
||||
private static String toRelativeIfLocal(String coverImage) {
|
||||
if (!StringUtils.hasText(coverImage)) {
|
||||
|
||||
Reference in New Issue
Block a user