activiti7 消息撤回接口及消息通知实现思路

消息撤回:

用户开启审批流程后,想撤回该条流程,可以在想撤回的节点添加消息边界事件,画图如下:

<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:activiti="http://activiti.org/bpmn" id="sample-diagram" targetNamespace="http://activiti.org/bpmn" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd">
  <bpmn2:process id="verifyNotifyV1" name="文档审阅" isExecutable="true">
    <bpmn2:startEvent id="StartEvent_1" name="开始">
      <bpmn2:outgoing>Flow_125gy0d</bpmn2:outgoing>
    </bpmn2:startEvent>
    <bpmn2:userTask id="Activity_06hj36k" name="文档审阅" activiti:formKey="Activity_06hj36k" activiti:assignee="${verify}">
      <bpmn2:extensionElements>
        <activiti:formProperty id="FormProperty_3v9ukk1--__!!radio--__!!审批意见--__!!i--__!!同意--__--不同意" />
        <activiti:executionListener class="cn.piesat.document.listener.VerifyTaskListener" event="end">
          <activiti:field name="state">
            <activiti:string>0</activiti:string>
          </activiti:field>
        </activiti:executionListener>
        <activiti:taskListener class="cn.piesat.document.listener.NotifyListener" event="create" />
      </bpmn2:extensionElements>
      <bpmn2:incoming>Flow_125gy0d</bpmn2:incoming>
      <bpmn2:outgoing>Flow_03pvffh</bpmn2:outgoing>
      <bpmn2:multiInstanceLoopCharacteristics activiti:collection="${verifies}" activiti:elementVariable="verify">
        <bpmn2:loopCardinality xsi:type="bpmn2:tFormalExpression">${num}</bpmn2:loopCardinality>
        <bpmn2:completionCondition xsi:type="bpmn2:tFormalExpression">${nrOfCompletedInstances/nrOfInstances==1}</bpmn2:completionCondition>
      </bpmn2:multiInstanceLoopCharacteristics>
    </bpmn2:userTask>
    <bpmn2:endEvent id="Event_11jqygc" name="结束">
      <bpmn2:incoming>Flow_03pvffh</bpmn2:incoming>
      <bpmn2:incoming>Flow_14edxvs</bpmn2:incoming>
    </bpmn2:endEvent>
    <bpmn2:sequenceFlow id="Flow_03pvffh" name="监听" sourceRef="Activity_06hj36k" targetRef="Event_11jqygc">
      <bpmn2:extensionElements>
        <activiti:executionListener class="cn.piesat.document.listener.VerifyStateListener" event="take" />
      </bpmn2:extensionElements>
    </bpmn2:sequenceFlow>
    <bpmn2:sequenceFlow id="Flow_14edxvs" sourceRef="Event_1km4ti7" targetRef="Event_11jqygc" />
    <bpmn2:boundaryEvent id="Event_1km4ti7" name="消息撤回" attachedToRef="Activity_06hj36k">
      <bpmn2:outgoing>Flow_14edxvs</bpmn2:outgoing>
      <bpmn2:messageEventDefinition id="MessageEventDefinition_0lylqlx" messageRef="Message_06usbn7" />
    </bpmn2:boundaryEvent>
    <bpmn2:sequenceFlow id="Flow_125gy0d" name="存储消息撤回任务节点" sourceRef="StartEvent_1" targetRef="Activity_06hj36k">
      <bpmn2:extensionElements>
        <activiti:executionListener class="cn.piesat.document.listener.FileWithDrawExecutionListener" event="take">
          <activiti:field name="withdrawTask">
            <activiti:string>Activity_06hj36k:Message_2vb9r75</activiti:string>
          </activiti:field>
          <activiti:field name="countersigned">
            <activiti:string>0</activiti:string>
          </activiti:field>
        </activiti:executionListener>
      </bpmn2:extensionElements>
    </bpmn2:sequenceFlow>
  </bpmn2:process>
  <bpmn2:message id="Message_0o9mw30" name="Message_2fg586j" />
  <bpmn2:message id="Message_1vz3ayq" name="Message_3e0avui" />
  <bpmn2:message id="Message_06usbn7" name="Message_2vb9r75" />
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="verifyNotify">
      <bpmndi:BPMNEdge id="Flow_03pvffh_di" bpmnElement="Flow_03pvffh">
        <di:waypoint x="570" y="258" />
        <di:waypoint x="722" y="258" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="629" y="243" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_14edxvs_di" bpmnElement="Flow_14edxvs">
        <di:waypoint x="550" y="316" />
        <di:waypoint x="550" y="340" />
        <di:waypoint x="740" y="340" />
        <di:waypoint x="740" y="276" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="Flow_125gy0d_di" bpmnElement="Flow_125gy0d">
        <di:waypoint x="378" y="258" />
        <di:waypoint x="470" y="258" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="387" y="226" width="77" height="27" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
        <dc:Bounds x="342" y="240" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="349" y="283" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_11jqygc_di" bpmnElement="Event_11jqygc">
        <dc:Bounds x="722" y="240" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="729" y="216" width="22" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Activity_06hj36k_di" bpmnElement="Activity_06hj36k">
        <dc:Bounds x="470" y="218" width="100" height="80" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="Event_1j1exxy_di" bpmnElement="Event_1km4ti7">
        <dc:Bounds x="532" y="280" width="36" height="36" />
        <bpmndi:BPMNLabel>
          <dc:Bounds x="568" y="303" width="44" height="14" />
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn2:definitions>

在流程图中我配置了监听器,绘制BPMN图时,将能撤回的任务节点编号(任务节点的key)和消息名称通过注入字段存储至数据库(也可以存储到redis等,方便获取就行),从执行监听器中可以获取。此处是会签多实例任务,在任务节点配置了代理人、完成条件等参数信息,同时配置了任务监听和执行监听,任务监听实现消息通知,当到达该节点时,触发事件类型为create,也就是任务创建的时候触发,通过监听器获取到当前任务执行人,这里在监听器里通过websocket给执行人推送消息通知(也可以换成别的方式比如发送短信等)这里没有贴消息推送代码,有点多,需要的话自行百度一下哈,执行监听器在这里注入执行人的审批状态信息,触发事件为任务完成时,通过监听器字段注入获取状态,修改审批人的状态信息。

如果测试可改为普通任务节点,不需要加完成条件,代理人可暂时写审批人的用户名,若不需要消息通知,可将任务监听器去掉。

执行监听器代码如下:

package cn.piesat.document.listener;

import cn.piesat.common.constant.ProcessVariableConstant;
import cn.piesat.common.constant.UserConstants;
import cn.piesat.common.utils.spring.SpringUtils;
import cn.piesat.document.domain.FileBaseInfo;
import cn.piesat.document.service.IFileBaseInfoService;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
import org.activiti.engine.delegate.Expression;


/**
 * 文档字段注入撤回监听器
 */
public class FileWithDrawExecutionListener implements ExecutionListener {

    //撤回节点注入字段信息
    private Expression withdrawTask;
    //注入会签任务key
    private Expression countersigned;

    @Override
    public void notify(DelegateExecution execution) {
        //存储撤回消息名称
        Object withdrawTaskValue = withdrawTask.getValue(execution);
        Object countersignedValue = countersigned.getValue(execution);
        execution.setVariable(ProcessVariableConstant.ACT_COUNTERSIGNED, countersignedValue.toString());
        execution.setVariable(ProcessVariableConstant.ACT_WITHDRAW_TASK, withdrawTaskValue.toString());
        FileBaseInfo baseInfo = FileBaseInfo.builder()
                //设置消息撤回状态  为撤回
                .remark(withdrawTaskValue.toString() + ":" + UserConstants.NORMAL)
                .id(Long.parseLong(execution.getProcessInstanceBusinessKey()))
                .build();
        SpringUtils.getBean(IFileBaseInfoService.class).updateFileBaseInfo(baseInfo);
    }
}

 

package cn.piesat.document.listener;

import cn.piesat.common.constant.Constants;
import cn.piesat.common.constant.ProcessConstant;
import cn.piesat.common.core.domain.model.LoginUser;
import cn.piesat.common.core.redis.RedisCache;
import cn.piesat.common.utils.DateUtils;
import cn.piesat.common.utils.SequenceBuilder;
import cn.piesat.common.utils.spring.SpringUtils;
import cn.piesat.system.domain.SysNotice;
import cn.piesat.system.service.ISysNoticeService;
import cn.piesat.websocket.controller.MessageStompController;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;

import java.util.Arrays;
import java.util.Collection;

/**
 * 文件审批状态监听
 */
public class NotifyListener implements TaskListener {

    @Override
    public void notify(DelegateTask delegateTask) {
        //获取执行人
        String assignee = delegateTask.getAssignee();
        SysNotice notice = new SysNotice();
        notice.setNoticeId(SequenceBuilder.sequenceId());
        notice.setNoticeOperator(assignee);
        notice.setNoticeTitle("您有一条待批任务," + assignee);
        notice.setStatus(ProcessConstant.UNREAD);//未读
        notice.setCreateTime(DateUtils.getNowDate());
        notice.setNoticeType(ProcessConstant.NOTICE);//通知
        System.out.println("消息通知:" + assignee);
        //获取执行人入库,判断是否在线,在线发送通知,不在线入库
        SpringUtils.getBean(ISysNoticeService.class).insertNotice(notice);
        RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
        Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + "*");
        MessageStompController stompController = SpringUtils.getBean(MessageStompController.class);
        for (String key : keys) {
            LoginUser user = redisCache.getCacheObject(key);
            if (user.getUsername().equals(assignee)) {
                //在线发送通知
                stompController.sendToUserChatNotice(assignee, Arrays.asList(notice));
                break;
            }
        }

    }
}

在开启流程时存入任务节点和消息名称,通过监听器存入是否能撤回的状态存入数据库,如Activity_0c0cb45:Message_05se1fv:0,这样 返回任务列表时,前端判断状态显示撤回按钮,当任务审批后,在监听器修改该数据状态为1,页面不显示撤回按钮,撤回消息时,前端将Activity_0c0cb45:Message_05se1fv:0 和实例Id作为参数传到后台,通过这两个参数查询当前任务执行节点,调用runtimeService.messageEventReceived()撤回接口,撤回消息,同时修改数据状态。代码如下:

  /**
     * 撤回文档审批
     */
   
    @GetMapping(value = "msgBack")
    public AjaxResult msgBack(String instanceId, String remark, Long id) {
        if (remark == null) {
            return AjaxResult.error("消息名称为空!");
        }
        String[] split = remark.split(":");
//通过流程id和消息名称,判断当前任务执行节点是否可以消息撤回。
        Execution exec = runtimeService.createExecutionQuery()
                //消息名称
                .messageEventSubscriptionName(split[1])
                .processInstanceId(instanceId)
                .singleResult();
        if (exec != null) {
            runtimeService.messageEventReceived(split[1], exec.getId());
            FileBaseInfo build = FileBaseInfo.builder()
                    .id(id)
                    .approvalStatus(ProcessConstant.WITHDRAW_APPROVAL)
                    .remark(split[0] + ":" + split[1] + ":" + UserConstants.EXCEPTION).build();
            fileBaseInfoService.updateFileBaseInfo(build);
            return AjaxResult.success("撤回成功");
        } else {
            return AjaxResult.error("撤回失败!");
        }
    }

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值