flowable工作流--实操篇

flowable

    • 简单介绍
    • 一、画流程图
      • 申请发工资流程预览
    • 二、设置流程信息
      • 1.设置流程标识
      • 2.设置流程变量
      • 3.设置信号定义和信号引用
      • 4.设置服务任务的实现类
      • 5.用户任务--通过变量设置审批人
    • 三、部署流程
    • 四、使用流程
      • 1.启动流程
      • 2.用户任务(财务审批)
      • 3.服务任务(银行处理)
      • 4.中间信号捕获事件(等待银行处理结果回调)

简单介绍

本文通过申请发工资的业务场景来介绍使用工作流的全流程,包括画流程图,设置属性,以及代码编写
使用工作流大致分为四步
第一步:根据自己的业务画好流程图
第二步:设置流程图的属性和变量,保存模型
第三步:部署画好的流程图(发布)
第四步:根据业务和流程图写一些服务和监听器
这里主要介绍以下几个任务的使用
1.用户任务的分配和提交
2.服务任务的使用
3.中间信号捕捉事件的触发
4.排他网关的使用
5.通过设置流程变量,实现流程的不同流转

一、画流程图

申请发工资流程预览

flowable工作流--实操篇_第1张图片

二、设置流程信息

1.设置流程标识

设置流程的唯一标识为payrollApplication也就是模型KEY,后续部署和启动都会用到
flowable工作流--实操篇_第2张图片

2.设置流程变量

设置通过的流转条件为${approval==‘pass’}其中approval为变量名称,pass为变量值,工作流会自动解析表达式进行判断
flowable工作流--实操篇_第3张图片

设置不通过的流转条件为${approval==‘notPass’}
flowable工作流--实操篇_第4张图片

设置打款成功的流转条件为${payment == ‘success’}
flowable工作流--实操篇_第5张图片

设置打款失败的流转条件为${payment == ‘fail’}
flowable工作流--实操篇_第6张图片

3.设置信号定义和信号引用

主要用于接收银行打款处理通知,未通知会一直停留在中间信号接收事件节点上
flowable工作流--实操篇_第7张图片
flowable工作流--实操篇_第8张图片
设置信号引用为方才设置的信号定义
flowable工作流--实操篇_第9张图片

4.设置服务任务的实现类

设置事先写好的服务任务的实现类(下面有实现代码)
flowable工作流--实操篇_第10张图片

5.用户任务–通过变量设置审批人

设置审批人为${Assignee},通过设置变量Assignee,动态设置审批人
flowable工作流--实操篇_第11张图片
flowable工作流--实操篇_第12张图片

三、部署流程

flowable工作流--实操篇_第13张图片

四、使用流程

1.启动流程

启动流程实例并跟业务ID关联,并设置流程变量
1.processDefinitionKey 要启动的流程模型KEY (本次演示场景为payrollApplication)
2.businessKey 业务标识,跟流程进行关联,不需要可不填
3.variables 流程变量,启动流程时设置的变量,类型为Map,JSONObject也可以,不需要可不填 (本次场景是通过变量动态设置的代理人,所以需要在启动时设置变量Assignee,值为审批人ID,否则用户任务会因为没有指定处理人而报错)

 	/**
     * 启动流程实例并跟业务ID关联,并设置流程变量
     * @param processDefinitionKey 流程模型KEY
     * @param businessKey 业务ID跟流程进行关联
     * @param variables 流程变量
     * @return 流程实例ID
     */
    public string startProcessByBusinessKey(String processDefinitionKey, String businessKey , Map<String,Object> variables) {
        // 启动流程实例
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
        logger.debug("流程实例ID:{},流程定义ID:{},业务标识:{}", instance.getId(), instance.getProcessDefinitionId(), businessKey);
        return instance.getId();
    }

2.用户任务(财务审批)

businessKey为启动时设置的业务标识,不需要可不填
userId为启动流程时设置的流程变量Assignee的值
approval为审批结果值为pass或者notPass

/**
     * 提交用户任务
     * @param businessKey 业务ID
     * @param userId 用户任务处理人ID
     * @param approval 审批结果
     * @return
     */
    public String completeTaskByUserIdAndBusinessKey(String businessKey, String userId, String approval) {
        // 获取流程实例ID
        String processInstanceId = null;
        // 需要处理的任务ID
        String taskId = null;
        // 查询该用户的所有任务
        List<Task> taskList = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();
        if (null == taskList || taskList.isEmpty()) {
            return "该用户没有分配任务!";
        }
        
        if (StringUtils.isBlank(businessKey)) {
            // 有可能存在多个任务,实际需要根据业务特殊处理
            taskId = taskList.get(0).getId();
            // 获取流程实例ID
            processInstanceId = taskList.get(0).getProcessInstanceId();
        }else {
            // 根据业务ID查找任务ID
            for (Task task : taskList) {
                // 获取流程实例ID
                processInstanceId = task.getProcessInstanceId();
                if (StringUtils.isNotBlank(processInstanceId)) {
                    // 获取流程实例
                    ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
                    // 流程实例
                    if (null == processInstance) {
                        return "未查询到正在运行的流程实例!";
                    }
                    // 流程实例关联的业务ID
                    String processInstanceBusinessKey = processInstance.getBusinessKey();
                    // 流程实例关联的业务ID和该用户的业务ID
                    if (StringUtils.isNotBlank(processInstanceBusinessKey) && StringUtils.equals(processInstanceBusinessKey, businessKey)) {
                        taskId = task.getId();
                        break;
                    }
                }
            }
        }

        if (StringUtils.isBlank(taskId)) {
            return "未查询到关联该业务的任务!";
        }
        
        // 设置变量 设置流条件,告诉工作流下一步的流转节点 审批通过或未通过
        JSONObject variables = new JSONObject();
        variables.put("approval", approval);
        runtimeService.setVariables(processInstanceId, variables);
        // 提交任务
        taskService.complete(taskId, null);
        return "提交任务成功";
    }

3.服务任务(银行处理)

BankPaymentTask 实现类必须实现JavaDelegate接口,工作流才会识别到

public class BankPaymentTask implements JavaDelegate, Serializable {

    @Autowired
    public RuntimeService runtimeService;

    public static BankPaymentTask bankPaymentTask;

    @PostConstruct //通过@PostConstruct实现初始化bean之前进行的操作
    public void init() {
        bankPaymentTask= this;
        bankPaymentTask.runtimeService = this.runtimeService;
    }

    @Override
    public void execute(DelegateExecution execution) {
        // 获取流程实例变量
        Map<String, Object> variables = runtimeService.getVariables(execution.getProcessInstanceId());
        if (variables == null || variables.isEmpty()) {
            log.error("variables不能为空!");
            return;
        }
        if (variables.get("businessKey") == null) {
            log.error("businessKey不能为空!");
            return;
        }
        
        // 配合流程变量,使用http调用其他服务完成银行转账的操作
        // JSONObject result = RestTemplateUtil.postForObject(paymentUrl, params, JSONObject.class);
        
		// 设置流程变量
		JSONObject variables = new JSONObject();
        variables.put("xxx", "xxx");
        runtimeService.setVariables(execution.getProcessInstanceId(), variables);
    }

4.中间信号捕获事件(等待银行处理结果回调)

工作流执行到当前节点会暂停,待银行打款操作结果回调之后,触发中间信号捕获事件信号,根据打款结果设置流程变量值,完成流程流转

    /**
     * 发送触发信号并设置变量
     * @param businessKey 业务ID
     * @param signaler 信号
     * @param payment 银行操作结果
     * @return
     */
    public String callback(String businessKey, String signaler, String payment) {
        // 根据业务标识查询正在运行的流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
        if (processInstance == null) {
            return "没有正在进行的任务!";
        }
        // 流程实例ID
        String processInstanceId = processInstance.getId();
        // 查找是否有等待触发的信号
        // 流程执行流 流程执行流和流程实例的关系:流程执行流表示流程实例中具体地执行路径,流程实例是一次工作流业务的数据实体
        Execution executions = runtimeService.createExecutionQuery().processInstanceId(processInstanceId)
                .signalEventSubscriptionName(signaler).singleResult();
        if (executions == null) {
            return "未查询到该信号事件!";
        }
        logger.debug("executionsId:{},processInstanceId:{}", executions.getId(), processInstanceId);

        // 设置变量 设置流条件,告诉工作流下一步的流转节点
		JSONObject variables = new JSONObject();
		// payment为success或者fail
        variables.put("payment", payment);
        runtimeService.setVariables(processInstanceId, variables);
        // 发送触发信号
        runtimeService.signalEventReceived(signaler, executions.getId());

        return "触发信号接收成功";
    }

你可能感兴趣的:(java,开发语言)