工作流引擎项目解析

API

img编辑

在Camunda中,API的继承关系主要体现在各个服务接口之间。以下是Camunda中一些常见服务接口的继承关系:

  1. ProcessEngineServices 接口:

    • RepositoryService: 负责管理流程定义和部署。

    • RuntimeService: 负责管理流程实例的执行。

    • TaskService: 负责管理流程任务。

    • IdentityService: 负责管理用户、组和身份验证。

    • HistoryService: 负责查询流程历史数据。

    • ManagementService: 提供引擎管理和维护的访问。

  2. ProcessEngine 接口:

    • 该接口是ProcessEngineServices接口的顶级接口,表示整个流程引擎的入口点,通过它可以获取各种服务接口的实例。

  3. RepositoryService 接口的继承关系:

    • RepositoryService

      • DeploymentQuery: 用于查询部署信息。

      • ProcessDefinitionQuery: 用于查询流程定义信息。

  4. RuntimeService 接口的继承关系:

    • RuntimeService

      • ExecutionQuery: 用于查询执行实例信息。

      • ProcessInstanceQuery: 用于查询流程实例信息。

      • VariableInstanceQuery: 用于查询流程变量实例信息。

  5. TaskService 接口的继承关系:

    • TaskService

      • TaskQuery: 用于查询任务信息。

  6. IdentityService 接口的继承关系:

    • IdentityService

      • UserQuery: 用于查询用户信息。

      • GroupQuery: 用于查询用户组信息。

  7. HistoryService 接口的继承关系:

    • HistoryService

      • HistoricProcessInstanceQuery: 用于查询历史流程实例信息。

      • HistoricTaskInstanceQuery: 用于查询历史任务实例信息。

这些继承关系有助于组织和理解Camunda引擎提供的各种服务接口,使开发人员能够更加方便地使用和管理工作流引擎。

案例

设计BPMN

插入模型

imgimg

img

编辑

API:repositoryService.newModel() 新建模型

    @Override
    public void insertModel(WfModelBo modelBo) {
        Model model = repositoryService.newModel();
        model.setName(modelBo.getModelName());
        model.setKey(modelBo.getModelKey());
        model.setCategory(modelBo.getCategory());
        String metaInfo = buildMetaInfo(new WfMetaInfoDto(), modelBo.getDescription());
        model.setMetaInfo(metaInfo);
        // 保存流程模型
        repositoryService.saveModel(model);
    }

思想学习:

将元数据封装到一个类中,流程创建者当前登录用户,判断内容是否为空然后设置最后转JSON

后续需要修改又反序列化-》修改信息-》序列化JSONUtils

    /**
     * 构建模型扩展信息
     * @return
     */
    private String buildMetaInfo(WfMetaInfoDto metaInfo, String description) {
        // 只有非空,才进行设置,避免更新时的覆盖
        if (StringUtils.isNotEmpty(description)) {
            metaInfo.setDescription(description);
        }
        if (StringUtils.isNotEmpty(metaInfo.getCreateUser())) {
            metaInfo.setCreateUser(LoginHelper.getUsername());
        }
        return JsonUtils.toJsonString(metaInfo);
    }

保存/更新BPMN内容

img

API:

repositoryService.getModel

repositoryService.saveModel(newModel)

repositoryService.addModelEditorSource(newModel.getId(), bpmnXmlBytes)

获取模型->XML2BPMN->BPMN获取流程名称和开始节点

思想学习:是否为新版本,更新流程版本

public void saveModel(WfModelBo modelBo) {
        // 查询模型信息
        Model model = repositoryService.getModel(modelBo.getModelId());
        if (ObjectUtil.isNull(model)) {
            throw new RuntimeException("流程模型不存在!");
        }
        BpmnModel bpmnModel = ModelUtils.getBpmnModel(modelBo.getBpmnXml());
        if (ObjectUtil.isEmpty(bpmnModel)) {
            throw new RuntimeException("获取模型设计失败!");
        }
        String processName = bpmnModel.getMainProcess().getName();
        // 获取开始节点
        StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
        if (ObjectUtil.isNull(startEvent)) {
            throw new RuntimeException("开始节点不存在,请检查流程设计是否有误!");
        }
        // 获取开始节点配置的表单Key
       if (StrUtil.isBlank(startEvent.getFormKey())) {
           throw new RuntimeException("请配置流程表单");
       }
        Model newModel;
        if (Boolean.TRUE.equals(modelBo.getNewVersion())) {
            newModel = repositoryService.newModel();
            newModel.setName(processName);
            newModel.setKey(model.getKey());
            newModel.setCategory(model.getCategory());
            newModel.setMetaInfo(model.getMetaInfo());
            newModel.setVersion(model.getVersion() + 1);
        } else {
            newModel = model;
            // 设置流程名称
            newModel.setName(processName);
        }
        // 保存流程模型
        repositoryService.saveModel(newModel);
        // 保存 BPMN XML
        byte[] bpmnXmlBytes = StringUtils.getBytes(modelBo.getBpmnXml(), StandardCharsets.UTF_8);
        repositoryService.addModelEditorSource(newModel.getId(), bpmnXmlBytes);
    }

部署(进行流程定义)

API

repositoryService.createDeployment()

repositoryService.createProcessDefinitionQuery()

repositoryService.setProcessDefinitionCategory

核心学习:保存关联表单

img

获取流程名称-》获取BPMN-》部署-》创建流程定义并设计流程分类-》保存关联表单

    public boolean deployModel(String modelId) {
        // 获取流程模型
        Model model = repositoryService.getModel(modelId);
        if (ObjectUtil.isNull(model)) {
            throw new RuntimeException("流程模型不存在!");
        }
        // 获取流程图
        byte[] bpmnBytes = repositoryService.getModelEditorSource(modelId);
        if (ArrayUtil.isEmpty(bpmnBytes)) {
            throw new RuntimeException("请先设计流程图!");
        }
        String bpmnXml = StringUtils.toEncodedString(bpmnBytes, StandardCharsets.UTF_8);
        BpmnModel bpmnModel = ModelUtils.getBpmnModel(bpmnXml);
        String processName = model.getName() + ProcessConstants.SUFFIX;
        // 部署流程
        Deployment deployment = repositoryService.createDeployment()
            .name(model.getName())
            .key(model.getKey())
            .category(model.getCategory())
            .addBytes(processName, bpmnBytes)
            .deploy();
        ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery()
            .deploymentId(deployment.getId())
            .singleResult();
        // 修改流程定义的分类,便于搜索流程
        repositoryService.setProcessDefinitionCategory(procDef.getId(), model.getCategory());
        // 保存部署表单
        return deployFormService.saveInternalDeployForm(deployment.getId(), bpmnModel);
    }

考虑子流程,回朔 

    public boolean saveInternalDeployForm(String deployId, BpmnModel bpmnModel) {
        List<WfDeployForm> deployFormList = new ArrayList<>();
        // 获取开始节点
        StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
        if (ObjectUtil.isNull(startEvent)) {
            throw new RuntimeException("开始节点不存在,请检查流程设计是否有误!");
        }
        // 保存开始节点表单信息
        WfDeployForm startDeployForm = buildDeployForm(deployId, startEvent);
        if (ObjectUtil.isNotNull(startDeployForm)) {
//            System.out.println(startDeployForm.getFormKey());
            deployFormList.add(startDeployForm);
        }
        // 保存用户节点表单信息
        Collection<UserTask> userTasks = ModelUtils.getAllUserTaskEvent(bpmnModel);
        if (CollUtil.isNotEmpty(userTasks)) {
            for (UserTask userTask : userTasks) {
                WfDeployForm userTaskDeployForm = buildDeployForm(deployId, userTask);
                if (ObjectUtil.isNotNull(userTaskDeployForm)) {
//                    System.out.println(userTaskDeployForm.getFormKey());
                    deployFormList.add(userTaskDeployForm);
                }
            }
        }
        // 批量新增部署流程和表单关联信息
        return baseMapper.insertBatch(deployFormList);
    }
    
    /**
     * 构建部署表单关联信息对象
     * @param deployId 部署ID
     * @param node 节点信息
     * @return 部署表单关联对象。若无表单信息(formKey),则返回null
     */
    private WfDeployForm buildDeployForm(String deployId, FlowNode node) {
        String formKey = ModelUtils.getFormKey(node);
        if (StringUtils.isEmpty(formKey)) {
            return null;
        }
        Long formId = Convert.toLong(StringUtils.substringAfter(formKey, "key_"));
        //mybatisPlus还是不太懂,待学习
        WfForm wfForm = formMapper.selectById(formId);
        if (ObjectUtil.isNull(wfForm)) {
            throw new ServiceException("表单信息查询错误");
        }
        WfDeployForm deployForm = new WfDeployForm();
        deployForm.setDeployId(deployId);
        deployForm.setFormKey(formKey);
        deployForm.setNodeKey(node.getId());
        deployForm.setFormName(wfForm.getFormName());
        deployForm.setNodeName(node.getName());
        deployForm.setContent(wfForm.getContent());
        return deployForm;
    }

发起流程实例

获取关联表单,进行交互

API

repositoryService.getBpmnModel(definitionId):BpmnModel,通过流程定义获取BPMN(校验

historyService.createHistoricProcessInstanceQuery() .processInstanceId(procInsId),初次获取表单仍未产生流程实例,直接返回表单配置信息。

 historicProcIns.getProcessVariables()

    public FormConf selectFormContent(String definitionId, String deployId, String procInsId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionId);
        if (ObjectUtil.isNull(bpmnModel)) {
            throw new RuntimeException("获取流程设计失败!");
        }
        StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
        WfDeployForm deployForm = deployFormMapper.selectOne(new LambdaQueryWrapper<WfDeployForm>()
            .eq(WfDeployForm::getDeployId, deployId)
            .eq(WfDeployForm::getFormKey, startEvent.getFormKey())
            .eq(WfDeployForm::getNodeKey, startEvent.getId()));
        FormConf formConf = JsonUtils.parseObject(deployForm.getContent(), FormConf.class);
        if (ObjectUtil.isNull(formConf)) {
            throw new RuntimeException("获取流程表单失败!");
        }
        if (ObjectUtil.isNotEmpty(procInsId)) {
            // 获取流程实例
            HistoricProcessInstance historicProcIns = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(procInsId)
                .includeProcessVariables()
                .singleResult();
            // 填充表单信息
            ProcessFormUtils.fillFormData(formConf, historicProcIns.getProcessVariables());
        }
        return formConf;
    }

启动(产生流程实例)

产生流程实例,个人将类与对象类比,流程实例就类似为类实例化的具体对象

API

repositoryService.createProcessDefinitionQuery() .processDefinitionId(procDefId).singleResult();

identityService.setAuthenticatedUserId(userIdStr);

identityService.setAuthenticatedUserId(TaskUtils.getUserId());

runtimeService.startProcessInstanceById(procDef.getId(), variables);(流程实例)

key学习:

获取流程定义-》启动流程实例-》启动任务

    /**
     * 根据流程定义ID启动流程实例
     *
     * @param procDefId 流程定义Id
     * @param variables 流程变量
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void startProcessByDefId(String procDefId, Map<String, Object> variables) {
        try {
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(procDefId).singleResult();
            startProcess(processDefinition, variables);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException("流程启动错误");
        }
    }
    /**
     * 启动流程实例
     */
    private void startProcess(ProcessDefinition procDef, Map<String, Object> variables) {
       //是否为空且是被挂起
         if (ObjectUtil.isNotNull(procDef) && procDef.isSuspended()) {
            throw new ServiceException("流程已被挂起,请先激活流程");
        }
        // 设置流程发起人Id到流程中
        String userIdStr = TaskUtils.getUserId();
        identityService.setAuthenticatedUserId(userIdStr);
        variables.put(BpmnXMLConstants.ATTRIBUTE_EVENT_START_INITIATOR, userIdStr);
        // 设置流程状态为进行中
        variables.put(ProcessConstants.PROCESS_STATUS_KEY, ProcessStatus.RUNNING.getStatus());
        // 发起流程实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDef.getId(), variables);
        // 第一个用户任务为发起人,则自动完成任务
      //  wfTaskService.startFirstTask(processInstance, variables);
    }

任务

任务审批

任务状态

待办任务

基础类

完成通过 Complete

API

taskService.createTaskQuery().taskId(taskBo.getTaskId()).singleResult()//获取任务(.list)

repositoryService.getBpmnModel(task.getProcessDefinitionId())

 taskService.addComment  taskService.setAssignee

 taskService.complete(taskBo.getTaskId(),map, localScope);

    public void complete(WfTaskBo taskBo) {
        //根据taskId获取任务
        Task task = taskService.createTaskQuery().taskId(taskBo.getTaskId()).singleResult();

        if (Objects.isNull(task)) {
            throw new ServiceException("任务不存在");
        }
        // 获取 bpmn 模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        identityService.setAuthenticatedUserId(TaskUtils.getUserId());
        //判断是否为委派
        if (DelegationState.PENDING.equals(task.getDelegationState())) {
            taskService.addComment(taskBo.getTaskId(), taskBo.getProcInsId(), FlowComment.DELEGATE.getType(), taskBo.getComment());
            taskService.resolveTask(taskBo.getTaskId());
        } else {
            taskService.addComment(taskBo.getTaskId(), taskBo.getProcInsId(), FlowComment.NORMAL.getType(), taskBo.getComment());
            //设置审批人
            taskService.setAssignee(taskBo.getTaskId(), TaskUtils.getUserId());
            if (ObjectUtil.isNotEmpty(taskBo.getVariables())) {
                // 获取模型信息
                String localScopeValue = ModelUtils.getUserTaskAttributeValue(bpmnModel, task.getTaskDefinitionKey(), ProcessConstants.PROCESS_FORM_LOCAL_SCOPE);
                System.out.println("localScopeValue"+localScopeValue);
                boolean localScope = Convert.toBool(localScopeValue, false);
                System.out.println("localScope"+localScope);
                Map<String, Object> map = new HashMap<>();

                taskService.complete(taskBo.getTaskId(),map, localScope);

            } else {
                taskService.complete(taskBo.getTaskId());
            }
        }
        // 设置任务节点名称
        taskBo.setTaskName(task.getName());
        // 处理下一级审批人
        if (StringUtils.isNotBlank(taskBo.getNextUserIds())) {
            this.assignNextUsers(bpmnModel, taskBo.getProcInsId(), taskBo.getNextUserIds());
        }
        // 处理抄送用户
        if (!copyService.makeCopy(taskBo)) {
            throw new RuntimeException("抄送任务失败");
        }
    }

Queue ArrayList Iterator

 /**
     * 指派下一任务审批人
     * @param bpmnModel bpmn模型
     * @param processInsId 流程实例id
     * @param userIds 用户ids
     */
    private void assignNextUsers(BpmnModel bpmnModel, String processInsId, String userIds) {
        // 获取所有节点信息
        List<Task> list = taskService.createTaskQuery()
            .processInstanceId(processInsId)
            .list();
        if (list.size() == 0) {
            return;
        }
        Queue<String> assignIds = CollUtil.newLinkedList(userIds.split(","));
        if (list.size() == assignIds.size()) {
            for (Task task : list) {
                taskService.setAssignee(task.getId(), assignIds.poll());
            }
            return;
        }
        // 优先处理非多实例任务
        Iterator<Task> iterator = list.iterator();
        while (iterator.hasNext()) {
            Task task = iterator.next();
            if (!ModelUtils.isMultiInstance(bpmnModel, task.getTaskDefinitionKey())) {
                if (!assignIds.isEmpty()) {
                    taskService.setAssignee(task.getId(), assignIds.poll());
                }
                iterator.remove();
            }
        }
        // 若存在多实例任务,则进行动态加减签
        if (CollUtil.isNotEmpty(list)) {
            if (assignIds.isEmpty()) {
                // 动态减签
                for (Task task : list) {
                    runtimeService.deleteMultiInstanceExecution(task.getExecutionId(), true);
                }
            } else {
                // 动态加签
                for (String assignId : assignIds) {
                    Map<String, Object> assignVariables = Collections.singletonMap(BpmnXMLConstants.ATTRIBUTE_TASK_USER_ASSIGNEE, assignId);
                    runtimeService.addMultiInstanceExecution(list.get(0).getTaskDefinitionKey(), list.get(0).getProcessInstanceId(), assignVariables);
                }
            }
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

GISer_Jinger

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值