Flowable集成钉钉实现抄送发送消息

本文介绍了如何在Flowable中利用serverTask组件配置抄送功能,通过监听器触发钉钉消息发送,以钉钉API为例,详细讲解了配置、监听器实现和消息发送流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目地址:https://gitee.com/lwj/flowable.git 分支flowable-base
视频地址:https://www.bilibili.com/video/av79774697/
** 如何使用serverTask实现抄送功能
使用推送消息的方式实现抄送,抄送不涉及流程审批,没有任何决策权,只是一个查看权
**

由于公司实现的是钉钉,那么抄送就采用钉钉的消息来实现抄送功能

1、 配置serverTask组件

在这里插入图片描述

2、 配置监听器

在这里插入图片描述
在这里插入图片描述
这里一定要设置一下表达式,否则验证错误

3、监听器实现

/**
 * @Description: 发送消息的监听器
 * @Author: Bruce.liu
 * @Since:13:40 2021/1/9
 * 爱拼才会赢 2018 ~ 2030 版权所有
 */
@Component(value = "sendMessageExecutionCallListener")
public class SendMessageExecutionCallListener implements ExecutionListener {

    private static final long serialVersionUID = -5140234938739863473L;
    protected Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ISystemCallBackMqService systemCallBackMqService;
    /**
     * 抄送的用户的表达式 如${userIds}
     */
    private Expression userList;

    @Override
    public void notify(DelegateExecution execution) {
        List<String> userIds = (List<String>) this.userList.getValue(execution);
        if (CollectionUtils.isNotEmpty(userIds)){
            SendMessageVo sendMessageVo = new SendMessageVo();
            String processInstanceId = execution.getProcessInstanceId();
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            String rootProcessInstanceId = historicProcessInstance.getSuperProcessInstanceId();
            if (StringUtils.isNotBlank(rootProcessInstanceId)){
                HistoricProcessInstance superHistoricProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(rootProcessInstanceId).singleResult();
                if (superHistoricProcessInstance != null){
                    sendMessageVo.setSuperModelKey(superHistoricProcessInstance.getProcessDefinitionKey());
                }
            }
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(historicProcessInstance.getProcessDefinitionId()).singleResult();
            sendMessageVo.setBusinessKey(execution.getProcessInstanceBusinessKey());
            sendMessageVo.setModelKey(processDefinition.getKey());
            sendMessageVo.setProcessDefinitionId(processDefinition.getId());
            sendMessageVo.setSystemSn(historicProcessInstance.getTenantId());
            sendMessageVo.setTitle(historicProcessInstance.getName());
            sendMessageVo.setUseridList(userIds);
            systemCallBackMqService.sendMessageMq(sendMessageVo);
        }
    }

}

4、采用Mq消息的方式

这里我们采用的是mq的方式发送,在另一个地方去发送消息,以避免发送消息影响整个流程的流转(消息的重要程度比审批要低)

5、监听这个队列实现发送钉钉消息

public ReturnVo<String> sendDingCorpconversationMessage(MessageDto messageDto) throws Exception {
        ReturnVo returnVo = new ReturnVo<>(ReturnCode.FAIL, "失败");
        if (CollectionUtils.isEmpty(messageDto.getUseridList()) || messageDto.getToAllUser() == null){
            return new ReturnVo<>(ReturnCode.FAIL, "userIdList,toAllUser,不能都为空");
        }
        try {
            if (!CollectionUtils.isEmpty(messageDto.getUseridList())){
                ReturnVo<String> accessToken = dingtalkTokenService.getAccessToken();
                if (!accessToken.isSuccess()){
                    return accessToken;
                }
                DingTalkClient client = new DefaultDingTalkClient(DingtalkUrlConstant.URL_TOPAPI_MESSAGE_CORPCONVERSATION_ASYNCSEND_V2);
                OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
                request.setAgentId(dingtalkProperties.getAgentId());
                StringBuffer userIds = new StringBuffer("");
                for (String userid : messageDto.getUseridList()) {
                    userIds.append(userid).append(",");
                }
                if (userIds.length() > 0){
                    userIds = userIds.deleteCharAt(userIds.length() - 1);
                }
                request.setUseridList(userIds.toString());
                request.setToAllUser(false);
                OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
                if (messageDto.getItemDto() != null){
                    MessageItemDto itemDto = messageDto.getItemDto();
                    String msgtype = itemDto.getMsgtype().getCode();
                    msg.setMsgtype(msgtype);
                    switch (msgtype) {
                        case "text":
                            msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
                            msg.getText().setContent(itemDto.getContent());
                            request.setMsg(msg);
                            break;
                        case "image":
                            //发送图片
                            ReturnVo<String> uploadPicResponse = uploadPic(itemDto, accessToken);
                            String mediaId;
                            if (uploadPicResponse.isSuccess()){
                                mediaId = uploadPicResponse.getData();
                            } else {
                                return new ReturnVo<>(ReturnCode.FAIL, uploadPicResponse.getMsg());
                            }
                            msg.setImage(new OapiMessageCorpconversationAsyncsendV2Request.Image());
                            msg.getImage().setMediaId(mediaId);
                            msg.setImage(new OapiMessageCorpconversationAsyncsendV2Request.Image());
                            request.setMsg(msg);
                            break;
                        case "file":
                            ReturnVo<String> uploadFileResponse = uploadPic(itemDto, accessToken);
                            String fileMediaId = null;
                            if (uploadFileResponse.isSuccess()){
                                fileMediaId = uploadFileResponse.getData();
                            } else {
                                return new ReturnVo<>(ReturnCode.FAIL, uploadFileResponse.getMsg());
                            }
                            msg.setFile(new OapiMessageCorpconversationAsyncsendV2Request.File());
                            msg.getFile().setMediaId(fileMediaId);
                            request.setMsg(msg);
                            break;
                        case "link":
                            msg.setLink(new OapiMessageCorpconversationAsyncsendV2Request.Link());
                            msg.getLink().setTitle(itemDto.getTitle());
                            msg.getLink().setText(itemDto.getContent());
                            msg.getLink().setMessageUrl(itemDto.getMessageUrl());
                            msg.getLink().setPicUrl(itemDto.getPicUrl());
                            request.setMsg(msg);
                            break;
                        default:
                            break;
                    }
                }
                OapiMessageCorpconversationAsyncsendV2Response response = client.execute(request, accessToken.getData());
                if (response.isSuccess()){
                    returnVo = new ReturnVo<>(ReturnCode.SUCCESS, "发送成功");
                    returnVo.setData(response.getTaskId()+"");
                    return returnVo;
                } else {
                    return new ReturnVo<>(ReturnCode.FAIL, response.getErrmsg());
                }
            }

        } catch (ApiException e) {
            logger.error("发送消息失败", e);
            returnVo = new ReturnVo<>(ReturnCode.FAIL, "发送消息失败");
        }
        return returnVo;
    }

6、钉钉显示

在这里插入图片描述

<think>好的,我现在需要帮助用户解决如何将Flowable钉钉进行集成或数据同步的问题。首先,用户提到了Flowable钉钉集成,可能涉及到API和数据交互。我需要先了解这两个系统的基本情况,然后思考如何将它们连接起来。 首先,Flowable是一个工作流引擎,用于流程管理和自动化。用户可能希望将Flowable中的流程数据同步到钉钉,或者反过来,利用钉钉的审批、通知等功能Flowable的工作流结合。例如,当Flowable中的流程到达某个节点时,触发钉钉的审批通知,审批结果再回传给Flowable,推动流程继续执行。 接下来,我需要考虑集成的方式。通常,系统集成可以通过API调用、Webhook、中间件(如消息队列)或数据库同步等方式实现钉钉提供了开放的API,比如审批API、消息通知API等,而Flowable也支持REST API和事件监听机制。因此,可能的方案是通过Flowable的事件监听触发钉钉的API调用,或者钉钉的事件回调更新Flowable的流程状态。 然后,具体步骤可能包括: 1. 确定集成场景:例如,流程节点触发钉钉审批,审批结果同步回Flowable。 2. 配置钉钉开发者账号,创建应用,获取API凭证(如AppKey和AppSecret)。 3. 在Flowable中配置事件监听器,当流程到达特定节点时,调用钉钉的审批接口发送审批请求。 4. 钉钉审批完成后,通过回调URL通知Flowable,更新流程实例的状态。 5. 处理数据格式转换,确保Flowable钉钉之间的数据兼容。 还需要考虑安全性和错误处理,比如API调用的认证(OAuth2.0)、数据加密、重试机制等。此外,用户可能需要开发自定义的扩展,因为Flowable本身可能不直接支持某些钉钉特定的功能,需要编写自定义逻辑来处理数据同步。 另外,参考用户提供的引用内容,比如引用[3]提到对Activiti的本土化扩展,可能Flowable也有类似的扩展机制,可以通过编程实现驳回、分发等操作。这可能意味着用户需要利用Flowable的API进行自定义开发,以实现钉钉的深度集成。 最后,用户可能需要具体的代码示例或配置步骤,比如如何设置REST API调用,如何处理回调等。因此,在回答中应该包括这些技术细节,并提供相关资源链接,如钉钉开放平台文档和Flowable的REST API文档,帮助用户进一步实施。</think>### Flowable钉钉集成方案 #### 一、集成场景分析 1. **流程审批同步**: Flowable流程节点触发钉钉审批单创建,审批结果回传至Flowable 2. **组织架构同步**: 钉钉部门/用户数据与Flowable身份管理模块自动同步 3. **消息通知集成**: Flowable任务通过钉钉工作通知/群机器人发送提醒 4. **待办事项同步**: 钉钉待办列表展示Flowable任务,操作后状态实时更新 #### 二、技术实现路径 ```mermaid graph LR A[Flowable流程引擎] -->|事件监听| B(自定义监听器) B -->|调用钉钉API| C[钉钉开放平台] C -->|回调通知| D(Spring Boot接口) D -->|更新流程状态| A ``` #### 三、核心API对接实现 1. **钉钉API配置**: ```java // 获取访问令牌 public String getAccessToken(String appKey, String appSecret) { String url = "https://api.dingtalk.com/v1.0/oauth2/accessToken"; Map<String, String> params = new HashMap<>(); params.put("appKey", appKey); params.put("appSecret", appSecret); return restTemplate.postForObject(url, params, String.class); } ``` 2. **Flowable任务监听**: ```java @Component public class DingTaskListener implements TaskListener { @Override public void notify(DelegateTask task) { if ("approvalStep".equals(task.getTaskDefinitionKey())) { // 调用钉钉创建审批实例API createDingApproval(task.getVariables()); } } } ``` 3. **审批回调处理**: ```python # Flask回调接口示例 @app.route('/dingtalk/callback', methods=['POST']) def handle_callback(): signature = request.headers.get('Dingtalk-Signature') # 验证签名 if not validate_signature(signature): abort(403) data = request.json processInstanceId = data['processInstanceId'] result = data['result'] # 更新Flowable流程变量 runtimeService.setVariable(processInstanceId, "approvalResult", result) return jsonify({"code":0}) ``` #### 四、数据交互设计 | Flowable字段 | 钉钉审批字段 | 转换规则 | |--------------|-------------|-------------------| | processDefId | processCode | 预定义映射表 | | taskName | formName | 直接复制 | | variables | formValues | JSON格式转换 | #### 五、安全增强措施 1. HTTPS双向加密传输 2. 请求签名验证(SHA256WithRSA) 3. 敏感数据字段加密存储 4. IP白名单访问控制 5. 限流机制(令牌桶算法) #### 六、扩展开发建议 1. **使用Flowable的ActivityBehavior扩展**: ```java public class DingActivityBehavior extends AbstractBpmnActivityBehavior { @Override public void execute(DelegateExecution execution) { // 实现自定义审批逻辑 handleDingSync(execution.getVariables()); leave(execution); } } ``` 参考Activiti的扩展实现方式[^3] 2. **集成模式选择**: - 轻量级集成:直接API调用(适合简单场景) - 中台化集成:通过ESB企业服务总线(适合多系统对接) - 事件驱动架构:使用Kafka消息队列(适合高并发场景)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小学生05101

flowable

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值