- FlowCenterClient:apply/getInstanceByBiz/registerCallback 由 ad-hoc TargetSpec
改走 YschFlowOpenApi 门面(ApplyBody/CallbackRegBody/ApplyResultVo/CallbackRegVo
继承 SDK DTO);instance 走 raw() 预绑视图保留 Map 全字段透传。
- CmsSiteDirectoryImpl:DIRECTORY_KEY 包可见;目录未配且 svcchall.cms.base-url
缺失时构造期 fail-fast(原 @Value 无默认值会直接炸启动,无明确提示)。
- FlowCenterClient:svchall.flow.base-url 默认值去掉 + 同款 fail-fast(enabled=false 不校验)。
- application.yml:新增 yh.open.services.{flowcenter,cms},删 svchall.cms.base-url /
svchall.flow.base-url —— 地址唯一来源=服务目录。
- 测试:新增 FlowCenterClientFacadeTest(6 例,冻结门面/归一目标/回落/fail-fast);
CmsSiteDirectoryImplTest 加目录命名目标 + fail-fast 用例。112 测试全绿。
This commit is contained in:
@@ -471,11 +471,35 @@ public final class SvcModels {
|
||||
private Integer pageSize = 10;
|
||||
}
|
||||
|
||||
// ===== 流程(管理端回显) =====
|
||||
// ===== 流程(管理端回显 + flow-center 门面出入参) =====
|
||||
|
||||
/** 字段单一事实源=SDK 门面 DTO(可直接作 YschFlowOpenApi 泛型出入参) */
|
||||
@Data
|
||||
@lombok.EqualsAndHashCode(callSuper = true)
|
||||
public static class FlowSummaryVo extends com.yunhai.platform.openapi.flow.model.FlowSummary {
|
||||
}
|
||||
|
||||
/** 代发起请求体(门面 {@code YschFlowOpenApi.apply} 的 B 绑定;字段继承 SDK FlowApplyBody) */
|
||||
@Data
|
||||
@lombok.EqualsAndHashCode(callSuper = true)
|
||||
public static class ApplyBody extends com.yunhai.platform.openapi.flow.model.FlowApplyBody {
|
||||
}
|
||||
|
||||
/** 代发起响应(门面 R 绑定;{@code duplicated=true} 表示命中 biz uk 幂等返回既有办件) */
|
||||
@Data
|
||||
@lombok.EqualsAndHashCode(callSuper = true)
|
||||
public static class ApplyResultVo extends com.yunhai.platform.openapi.flow.model.FlowApplyResult {
|
||||
}
|
||||
|
||||
/** 回调注册请求体(门面 {@code YschFlowOpenApi.registerCallback} 的 B 绑定) */
|
||||
@Data
|
||||
@lombok.EqualsAndHashCode(callSuper = true)
|
||||
public static class CallbackRegBody extends com.yunhai.platform.openapi.flow.model.FlowCallbackRegBody {
|
||||
}
|
||||
|
||||
/** 回调注册响应(下发的 secret 用于验 X-Flw-Signature) */
|
||||
@Data
|
||||
@lombok.EqualsAndHashCode(callSuper = true)
|
||||
public static class CallbackRegVo extends com.yunhai.platform.openapi.flow.model.FlowCallbackRegResult {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,21 +43,28 @@ public class CmsSiteDirectoryImpl implements SiteDirectory {
|
||||
.build();
|
||||
|
||||
/** 服务目录命名目标(cms 未晋升枚举,按名直调);目录未配置时为 null=走 legacy ad-hoc spec */
|
||||
private static final String DIRECTORY_KEY = "cms";
|
||||
static final String DIRECTORY_KEY = "cms";
|
||||
|
||||
private static final String LEGACY_KEY = "svchall.cms.base-url";
|
||||
|
||||
private final YschOpenCall openCall;
|
||||
private final TargetSpec cmsSpec;
|
||||
private final boolean directoryResolved;
|
||||
|
||||
public CmsSiteDirectoryImpl(YschOpenCall openCall,
|
||||
@Value("${svchall.cms.base-url}") String cmsBaseUrl) {
|
||||
@Value("${svchall.cms.base-url:}") String cmsBaseUrl) {
|
||||
this.openCall = openCall;
|
||||
this.directoryResolved = openCall.hasTarget(DIRECTORY_KEY);
|
||||
this.directoryResolved = openCall != null && openCall.hasTarget(DIRECTORY_KEY);
|
||||
if (directoryResolved) {
|
||||
this.cmsSpec = null;
|
||||
return;
|
||||
}
|
||||
String base = trimTrailing(cmsBaseUrl == null ? "" : cmsBaseUrl.trim());
|
||||
if (base.isEmpty()) {
|
||||
// 目录未配且 legacy 键也空:构造期 fail-fast——别把"地址没配"伪装成"站点服务不可达"
|
||||
throw new IllegalStateException("CMS 站点目录调用地址未配置:请配置服务目录 yh.open.services."
|
||||
+ DIRECTORY_KEY + "(推荐,容器直连完整 URL)或回落键 " + LEGACY_KEY);
|
||||
}
|
||||
URI uri = URI.create(base);
|
||||
String host = uri.getScheme() + "://" + uri.getRawAuthority();
|
||||
String path = uri.getRawPath() == null ? "" : uri.getRawPath();
|
||||
|
||||
@@ -42,20 +42,27 @@ public class FlowCenterClient implements FlowClient {
|
||||
|
||||
public FlowCenterClient(YschOpenCall openCall, ObjectMapper objectMapper,
|
||||
@Value("${svchall.flow.enabled:false}") boolean enabled,
|
||||
@Value("${svchall.flow.base-url:http://localhost:8085}") String baseUrl) {
|
||||
@Value("${svchall.flow.base-url:}") String baseUrl) {
|
||||
this.openCall = openCall;
|
||||
this.objectMapper = objectMapper;
|
||||
this.enabled = enabled;
|
||||
String base = trimTrailing(baseUrl == null ? "" : baseUrl.trim());
|
||||
URI uri = URI.create(base);
|
||||
String host = uri.getScheme() + "://" + uri.getRawAuthority();
|
||||
String path = uri.getRawPath() == null ? "" : uri.getRawPath();
|
||||
this.flowSpec = TargetSpec.of(host, path);
|
||||
this.directoryResolved = openCall.hasTarget(
|
||||
this.directoryResolved = openCall != null && openCall.hasTarget(
|
||||
com.yunhai.platform.openapi.core.PlatformService.FLOWCENTER.key());
|
||||
if (directoryResolved) {
|
||||
com.yunhai.platform.openapi.flow.YschFlowOpenApi.setCall(openCall);
|
||||
}
|
||||
if (enabled && base.isEmpty() && !directoryResolved) {
|
||||
// 目录未配且 legacy 键也空:构造期 fail-fast——别把"地址没配"伪装成"流程中心不可达"。
|
||||
// enabled=false(显式未接入)时不校验——地址本就不需要。
|
||||
throw new IllegalStateException("流程中心调用地址未配置:请配置服务目录 yh.open.services."
|
||||
+ com.yunhai.platform.openapi.core.PlatformService.FLOWCENTER.key()
|
||||
+ "(推荐,容器直连完整 URL)或回落键 svchall.flow.base-url");
|
||||
}
|
||||
URI uri = URI.create(base);
|
||||
String host = uri.getScheme() + "://" + uri.getRawAuthority();
|
||||
String path = uri.getRawPath() == null ? "" : uri.getRawPath();
|
||||
this.flowSpec = TargetSpec.of(host, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,26 +104,30 @@ public class FlowCenterClient implements FlowClient {
|
||||
String bizUrl, String bizSnapshot, Integer submitterId, String submitterName,
|
||||
String formDataJson) {
|
||||
requireEnabled();
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("flowGuid", flowGuid);
|
||||
body.put("bizType", bizType);
|
||||
body.put("bizId", bizId);
|
||||
body.put("bizTitle", bizTitle);
|
||||
if (bizUrl != null) {
|
||||
body.put("bizUrl", bizUrl);
|
||||
}
|
||||
if (bizSnapshot != null) {
|
||||
body.put("bizSnapshot", bizSnapshot);
|
||||
}
|
||||
body.put("submitterId", submitterId);
|
||||
body.put("submitterName", submitterName);
|
||||
SvcModels.ApplyBody body = new SvcModels.ApplyBody();
|
||||
body.setFlowGuid(flowGuid);
|
||||
body.setBizType(bizType);
|
||||
body.setBizId(bizId);
|
||||
body.setBizTitle(bizTitle);
|
||||
body.setBizUrl(bizUrl);
|
||||
body.setBizSnapshot(bizSnapshot);
|
||||
body.setSubmitterId(submitterId);
|
||||
body.setSubmitterName(submitterName);
|
||||
if (formDataJson != null && !formDataJson.isEmpty()) {
|
||||
try {
|
||||
body.put("formData", objectMapper.readValue(formDataJson, Map.class));
|
||||
body.setFormData(objectMapper.readValue(formDataJson, Map.class));
|
||||
} catch (Exception e) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "表单数据不是合法 JSON 对象");
|
||||
}
|
||||
}
|
||||
if (directoryResolved) {
|
||||
SvcModels.ApplyResultVo result = com.yunhai.platform.openapi.flow.YschFlowOpenApi.apply(
|
||||
schId, body, SvcModels.ApplyResultVo.class);
|
||||
if (result == null || result.getInstanceId() == null) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "流程中心代发起返回异常(缺少 instanceId)");
|
||||
}
|
||||
return new ApplyResult(result.getInstanceId(), result.isDuplicated());
|
||||
}
|
||||
JsonNode data = openCall.post(flowSpec, "/oapi/flow/apply",
|
||||
Collections.singletonMap("schId", String.valueOf(schId)), body, JsonNode.class);
|
||||
if (data == null || data.get("instanceId") == null) {
|
||||
@@ -133,24 +144,38 @@ public class FlowCenterClient implements FlowClient {
|
||||
query.put("schId", String.valueOf(schId));
|
||||
query.put("bizType", bizType);
|
||||
query.put("bizId", bizId);
|
||||
if (directoryResolved) {
|
||||
// 门面 instance(...) 只反序列化 FlowInstance 的字段子集;本方法契约是 Map 全字段透传
|
||||
// (对账/查看守卫要 status/version/assigneeIds/nodeSummary…),故走预绑 flowcenter 的
|
||||
// 泛化视图 raw()——目标名由门面承载,不再回落应用专属地址。
|
||||
return com.yunhai.platform.openapi.flow.YschFlowOpenApi.raw()
|
||||
.get("/oapi/flow/instance", query, Map.class);
|
||||
}
|
||||
return openCall.get(flowSpec, "/oapi/flow/instance", query, Map.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String registerCallback(Long schId, String flowGuid, String callbackUrl, String eventTypes) {
|
||||
requireEnabled();
|
||||
Map<String, Object> body = new HashMap<>();
|
||||
body.put("flowGuid", flowGuid);
|
||||
body.put("callbackUrl", callbackUrl);
|
||||
if (eventTypes != null && !eventTypes.isEmpty()) {
|
||||
body.put("eventTypes", eventTypes);
|
||||
}
|
||||
SvcModels.CallbackRegBody body = new SvcModels.CallbackRegBody();
|
||||
body.setFlowGuid(flowGuid);
|
||||
body.setCallbackUrl(callbackUrl);
|
||||
body.setEventTypes(eventTypes);
|
||||
// 申报本服务 context-path(从回调 URL path 段推导,去掉尾部 /callback/flow):
|
||||
// 推送方按它剥离后再签应用签名,与本服务 AppAuthFilter/FlowCallbackVerifyFilter 剥
|
||||
// contextPath 后的 target 对齐——本地裸地址(无 ctx)推导为空串,行为不变。
|
||||
// contextPath 后的 target 对齐——本地裸地址(无 ctx)推导为空串,行为不变(不下发空串)。
|
||||
String basePath = deriveCallbackBasePath(callbackUrl);
|
||||
if (basePath != null && !basePath.isEmpty()) {
|
||||
body.put("basePath", basePath);
|
||||
body.setBasePath(basePath);
|
||||
}
|
||||
if (directoryResolved) {
|
||||
SvcModels.CallbackRegVo result = com.yunhai.platform.openapi.flow.YschFlowOpenApi
|
||||
.registerCallback(schId, body, SvcModels.CallbackRegVo.class);
|
||||
Object secret = result == null ? null : result.getSecret();
|
||||
if (secret == null) {
|
||||
throw new BizException(ErrorCode.PARAM_ERROR, "流程中心回调注册返回异常(缺少 secret)");
|
||||
}
|
||||
return String.valueOf(secret);
|
||||
}
|
||||
Map<?, ?> data = openCall.post(flowSpec, "/oapi/flow/callback/reg",
|
||||
Collections.singletonMap("schId", String.valueOf(schId)), body, Map.class);
|
||||
|
||||
Reference in New Issue
Block a user