fix:【bpm 工作流】跨进程调用,无法回调 crm 的工作流结果的问题

pull/150/MERGE
YunaiV 2025-07-30 18:46:32 +08:00
parent b46f29e45f
commit 8eea97add4
7 changed files with 100 additions and 15 deletions

View File

@ -15,6 +15,7 @@ import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfigu
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.RestController;
@ -124,6 +125,7 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer {
*/
@Bean
@ConditionalOnMissingBean
@LoadBalanced
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder.build();
}

View File

@ -34,6 +34,11 @@ public class BpmProcessInstanceStatusEvent extends ApplicationEvent {
*/
private String businessKey;
public BpmProcessInstanceStatusEvent() {
// new Object() 保证非空
super(new Object());
}
public BpmProcessInstanceStatusEvent(Object source) {
super(source);
}

View File

@ -40,7 +40,7 @@ public interface ErrorCodeConstants {
ErrorCode PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS = new ErrorCode(1_009_004_004, "任务({})的候选人({})不存在");
ErrorCode PROCESS_INSTANCE_START_USER_CAN_START = new ErrorCode(1_009_004_005, "发起流程失败,你没有权限发起该流程");
ErrorCode PROCESS_INSTANCE_CANCEL_FAIL_NOT_ALLOW = new ErrorCode(1_009_004_005, "流程取消失败,该流程不允许取消");
ErrorCode PROCESS_INSTANCE_HTTP_TRIGGER_CALL_ERROR = new ErrorCode(1_009_004_006, "流程 Http 触发器请求调用失败");
ErrorCode PROCESS_INSTANCE_HTTP_CALL_ERROR = new ErrorCode(1_009_004_006, "流程 Http 请求调用失败");
ErrorCode PROCESS_INSTANCE_APPROVE_USER_SELECT_ASSIGNEES_NOT_CONFIG = new ErrorCode(1_009_004_007, "下一个任务({})的审批人未配置");
ErrorCode PROCESS_INSTANCE_CANCEL_CHILD_FAIL_NOT_ALLOW = new ErrorCode(1_009_004_008, "子流程取消失败,子流程不允许取消");

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.bpm.api.event;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmHttpRequestUtils;
import jakarta.validation.Valid;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
/**
*
*
* @author
*/
public class CrmReceivableStatusListener extends BpmProcessInstanceStatusEventListener {
@Override
public String getProcessDefinitionKey() {
return "crm-receivable-audit";
}
@Override
public void onEvent(@RequestBody @Valid BpmProcessInstanceStatusEvent event) {
BpmHttpRequestUtils.executeBpmHttpRequest(event,
"http://crm-server/rpc-api/crm/receivable/update-audit-status");
}
}

View File

@ -6,15 +6,15 @@ import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.spring.SpringUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmHttpRequestParamTypeEnum;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
@ -26,7 +26,7 @@ import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_INSTANCE_HTTP_TRIGGER_CALL_ERROR;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_INSTANCE_HTTP_CALL_ERROR;
/**
* HTTP
@ -42,7 +42,6 @@ public class BpmHttpRequestUtils {
List<BpmSimpleModelNodeVO.HttpRequestParam> bodyParams,
Boolean handleResponse,
List<KeyValue<String, String>> response) {
RestTemplate restTemplate = SpringUtils.getBean(RestTemplate.class);
BpmProcessInstanceService processInstanceService = SpringUtils.getBean(BpmProcessInstanceService.class);
// 1.1 设置请求头
@ -51,6 +50,7 @@ public class BpmHttpRequestUtils {
MultiValueMap<String, String> body = buildHttpBody(processInstance, bodyParams);
// 2. 发起请求
RestTemplate restTemplate = SpringUtils.getBean(RestTemplate.class);
ResponseEntity<String> responseEntity = sendHttpRequest(url, headers, body, restTemplate);
// 3. 处理返回
@ -78,27 +78,55 @@ public class BpmHttpRequestUtils {
}
}
public static void executeBpmHttpRequest(BpmProcessInstanceStatusEvent event,
String url) {
// 1.1 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
if (TenantContextHolder.getTenantId() != null) {
headers.add(HEADER_TENANT_ID, String.valueOf(TenantContextHolder.getTenantId()));
} else {
BpmProcessInstanceService processInstanceService = SpringUtils.getBean(BpmProcessInstanceService.class);
ProcessInstance processInstance = processInstanceService.getProcessInstance(event.getId());
if (processInstance != null) {
headers.add(HEADER_TENANT_ID, String.valueOf(TenantContextHolder.getTenantId()));
}
}
// 1.2 设置请求体
// MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
// body.add("id", event.getId());
// body.add("processDefinitionKey", event.getProcessDefinitionKey());
// body.add("status", event.getStatus().toString());
// if (StrUtil.isNotEmpty(event.getBusinessKey())) {
// body.add("businessKey", event.getBusinessKey());
// }
// 2. 发起请求
RestTemplate restTemplate = SpringUtils.getBean(RestTemplate.class);
sendHttpRequest(url, headers, event, restTemplate);
}
public static ResponseEntity<String> sendHttpRequest(String url,
MultiValueMap<String, String> headers,
MultiValueMap<String, String> body,
Object body,
RestTemplate restTemplate) {
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers);
HttpEntity<Object> requestEntity = new HttpEntity<>(body, headers);
ResponseEntity<String> responseEntity;
try {
responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
log.info("[sendHttpRequest][HTTP 触发器,请求头:{},请求体:{},响应结果:{}]", headers, body, responseEntity);
log.info("[sendHttpRequest][HTTP 请求,请求头:{},请求体:{},响应结果:{}]", headers, body, responseEntity);
} catch (RestClientException e) {
log.error("[sendHttpRequest][HTTP 触发器,请求头:{},请求体:{},请求出错:{}]", headers, body, e.getMessage());
throw exception(PROCESS_INSTANCE_HTTP_TRIGGER_CALL_ERROR);
log.error("[sendHttpRequest][HTTP 请求,请求头:{},请求体:{},请求出错:{}]", headers, body, e.getMessage());
throw exception(PROCESS_INSTANCE_HTTP_CALL_ERROR);
}
return responseEntity;
}
public static MultiValueMap<String, String> buildHttpHeaders(ProcessInstance processInstance,
List<BpmSimpleModelNodeVO.HttpRequestParam> headerSettings) {
Map<String, Object> processVariables = processInstance.getProcessVariables();
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add(HEADER_TENANT_ID, processInstance.getTenantId());
Map<String, Object> processVariables = processInstance.getProcessVariables();
addHttpRequestParam(headers, headerSettings, processVariables);
return headers;
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.bpm.framework.rpc.config;
import cn.iocoder.yudao.module.bpm.api.event.CrmReceivableStatusListener;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.PostApi;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
@ -7,11 +8,22 @@ import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.sms.SmsSendApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration(value = "bpmRpcConfiguration", proxyBeanMethods = false)
@EnableFeignClients(clients = {RoleApi.class, DeptApi.class, PostApi.class, AdminUserApi.class, SmsSendApi.class, DictDataApi.class,
PermissionApi.class})
public class RpcConfiguration {
// ========== 特殊:解决微 yudao-cloud 微服务场景下,跨服务(进程)无法 Listener 的问题 ==========
@Bean
@ConditionalOnMissingBean(name = "crmReceivableStatusListener")
public CrmReceivableStatusListener crmReceivableStatusListener() {
return new CrmReceivableStatusListener();
}
}

View File

@ -1,20 +1,30 @@
package cn.iocoder.yudao.module.crm.service.receivable.listener;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener;
import cn.iocoder.yudao.module.crm.enums.ApiConstants;
import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableService;
import cn.iocoder.yudao.module.crm.service.receivable.CrmReceivableServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
*
*
* @author HUIHUI
*/
@Component
@RestController
@Validated
@FeignClient(name = ApiConstants.NAME) // TODO 芋艿fallbackFactory =
public class CrmReceivableStatusListener extends BpmProcessInstanceStatusEventListener {
private static final String PREFIX = ApiConstants.PREFIX + "/receivable";
@Resource
private CrmReceivableService receivableService;
@ -24,7 +34,8 @@ public class CrmReceivableStatusListener extends BpmProcessInstanceStatusEventLi
}
@Override
public void onEvent(BpmProcessInstanceStatusEvent event) {
@PostMapping(PREFIX + "/update-audit-status") // 目的:提供给 bpm-server rpc 调用
public void onEvent(@RequestBody BpmProcessInstanceStatusEvent event) {
receivableService.updateReceivableAuditStatus(Long.parseLong(event.getBusinessKey()), event.getStatus());
}