工作流引擎项目解析

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() 新建模型

    @Overridepublic 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("开始节点不存在,请检查流程设计是否有误!");}// 获取开始节点配置的表单Keyif (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 XMLbyte[] 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);}}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/311363.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024年nodejs调用小红书最新关注(粉丝)follow接口,api接口分析2004-04-16

一、打开chrome按f12&#xff0c;点击右上角的“关注”按钮&#xff0c;抓包位置如下&#xff1a; (图1 follow接口) 二、follow接口分析 1、请求地址 https://edith.xiaohongshu.com/api/sns/web/v1/user/follow 2、请求方法: POST 3、请求头&#xff1a; :authority: edith…

最新AI创作系统ChatGPT网站源码AI绘画,GPTs,AI换脸支持,GPT联网提问、DALL-E3文生图

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧。已支持GPT…

25. 【Android教程】列表控件 ListView

在学习了 ScrollView 及 Adapter 两节内容之后&#xff0c;大家应该对 ListView 有了一些基本的了解&#xff0c;它是一个列表样式的 ViewGroup&#xff0c;将若干 item 按行排列。ListView 是一个很基本的控件也是 Android 中最重要的控件之一。它可以帮助我们完成多个 View 的…

Udio——革命性的AI音乐生成软件

Udio是一款革命性的AI音乐生成软件&#xff0c;由前谷歌DeepMind的顶尖AI研究人员和工程师共同创立&#xff0c;得到著名风险投资公司a16z的支持。它旨在为音乐爱好者和专业人士提供一个全新的音乐创作和分享平台。用户可以通过文本提示来生成音乐&#xff0c;支持广泛的音乐风…

水牛社:打造你的居家副业利器,让赚钱变得更简单

水牛社&#xff0c;这个已经陪伴我们走过九个春秋的综合性网络任务和项目资源整合平台&#xff0c;真的给我留下了深刻的印象。它不仅仅是一个资源的汇聚地&#xff0c;更是一个帮助无数人实现网络副业梦想的平台。作为一个资深用户&#xff0c;我深感其中的价值和魅力。 水牛…

“香港批准比特币、以太坊ETF”!华夏、博时、嘉实计划发行相关产品!美国ETF分析师泼冷水:别指望香港ETF会有很大流量!

周一(4月15日)&#xff0c;比特币短线迎来反弹行情&#xff0c;币价回升至66000美元上方。华夏基金、博时国际与嘉实投资3家中国头部基金宣布&#xff0c;旗下虚拟资产现货ETF获准在香港发行。 据了解&#xff0c;华夏基金&#xff08;香港&#xff09;现计划发行能够投资于现货…

两部电话机怎样能实现对讲?直接连接能互相通话吗?门卫门房传达室岗亭电话怎么搞?

目录 两部电话机能直接连接吗&#xff1f;用三通头分出来一条电话线两部电话机用一根电话线直接连接能互相通话吗&#xff1f; 什么电话机可以直接连接两部IP电话机&#xff08;网络电话机&#xff09;可以直接连接两部普通电话机之间通过一个电话交换机也可以连接跨区域的两部…

mfc 带有复选框的ListBox

mfc 带有复选框的 ListBox 效果&#xff1a; 添加 ListBox 控件 从工具箱拖拽 ListBox 控件到窗口上&#xff0c;并设置属性&#xff1a; 包含字符串&#xff1a;true所有者描述&#xff1a;Fixed 给ListBox添加控制变量 添加完后&#xff0c;将m_list_box的类型使用CC…

react使用npm i @reduxjs/toolkit react-redux

npm i reduxjs/toolkit react-redux 创建一个 store文件夹&#xff0c;里面创建index.js文件和子模块文件夹 index,js文件写入以下代码 import {configureStore} from reduxjs/toolkit // 导入子模块 import counterReducer from ./modules/one import two from ./modules/tw…

OpenBayes 在线教程|张国荣、鲁迅等老照片秒变高清!即刻上手的超火 SUPIR-AI 图像修复教程

小伙伴们&#xff0c;大家在生活中是不是也会遇到这样的烦恼&#xff1a;心心念念想要打印一张充满回忆的老照片或酷炫动漫壁纸&#xff0c;却发现图像糊得像打了马赛克&#xff1f; 市面上的图像修复工具五花八门&#xff0c;选择困难症人群找得快要崩溃&#xff1f; 终于找…

Linux: softirq 简介

文章目录 1. 前言2. softirq 实现2.1 softirq 初始化2.1.1 注册各类 softirq 处理接口2.1.2 创建 softirq 处理线程 2.2 softirq 的 触发 和 处理2.1.1 softirq 触发2.1.2 softirq 处理2.1.2.1 在 中断上下文 处理 softirq2.1.2.2 在 ksoftirqd 内核线程上下文 处理 softirq 3.…

电子烟特效音语音方案选型-WTN6020-8S-E

随着科技的迅猛进步&#xff0c;电子烟行业亦在持续创新与突破&#xff0c;引领着全新的潮流。其中&#xff0c;电子烟产品所特有的吸烟声音特效播报功能&#xff0c;无疑成为了技术革新的璀璨亮点。这一设计巧妙地将吸烟的声效融入使用体验中&#xff0c;使得用户在吸电子烟时…

CSS3 立体 3D 变换

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 ✍CSS3 立体 3D 变换&#x1f48e;1 坐标轴&#x1f48e;2 perspective 透视视…

linux管理进程

一、程序 程序&#xff1a;执行特定任务的一串代码 1.是一组计算机能识别和执行的指令&#xff0c;运行于电子计算机上&#xff0c;满足人们某种需求的信息化工具 2.用于描述进程要完成的功能&#xff0c;是控制进程执行的指令集 二、进程和线程 1.进程 进程是程序的执行…

vue2 二次封装element 组件,继承组件原属性,事件,插槽 示例

测试页面代码 这里主要记录如何封装element的el-input 并且封装后具有el-input原本的属性 事件 插槽 下面为测试页面即组件调用 <script> import CustomInput from /components/CustomInput.vue;export default {name: TestPage,components: { CustomInput },data() …

jenkins构建微信小程序并展示二维码

测试小程序的过程中&#xff0c;很多都是在回头和前端开发说一句&#xff0c;兄弟帮我打一个测试版本的测试码&#xff0c;开发有时间的情况下还好&#xff0c;就直接协助了&#xff0c;但是很多时候他们只修复了其中几个bug&#xff0c;其他需要修复的bug代码正在编写&#xf…

【蓝桥杯嵌入式】蓝桥杯嵌入式第十四届省赛程序真题,真题分析与代码讲解

&#x1f38a;【蓝桥杯嵌入式】专题正在持续更新中&#xff0c;原理图解析✨&#xff0c;各模块分析✨以及历年真题讲解✨都已更新完毕&#xff0c;欢迎大家前往订阅本专题&#x1f38f; &#x1f38f;【蓝桥杯嵌入式】蓝桥杯第十届省赛真题 &#x1f38f;【蓝桥杯嵌入式】蓝桥…

BTI功能验证与异常解析

BTI分支目标识别精讲与实践系列 思考 1、什么是代码重用攻击&#xff1f;什么是ROP攻击&#xff1f;区别与联系&#xff1f; 2、什么是JOP攻击&#xff1f;间接分支跳转指令&#xff1f; 3、JOP攻击的缓解技术&#xff1f;控制流完整性保护&#xff1f; 4、BTI下的JOP如何…

论文略读:Window Attention is Bugged: How not to Interpolate Position Embeddings

iclr 2024 reviewer 打分 6666 窗口注意力、位置嵌入以及高分辨率微调是现代Transformer X CV 时代的核心概念。论文发现&#xff0c;将这些几乎无处不在的组件简单地结合在一起&#xff0c;可能会对性能产生不利影响问题很简单&#xff1a;在使用窗口注意力时对位置嵌入进行插…

密码学 | 椭圆曲线数字签名方法 ECDSA(下)

目录 10 ECDSA 算法 11 创建签名 12 验证签名 13 ECDSA 的安全性 14 随机 k 值的重要性 15 结语 ⚠️ 原文&#xff1a;Understanding How ECDSA Protects Your Data. ⚠️ 写在前面&#xff1a;本文属于搬运博客&#xff0c;自己留着学习。同时&#xff0c;经过几…