API
编辑
在Camunda中,API的继承关系主要体现在各个服务接口之间。以下是Camunda中一些常见服务接口的继承关系:
-
ProcessEngineServices 接口:
-
RepositoryService: 负责管理流程定义和部署。
-
RuntimeService: 负责管理流程实例的执行。
-
TaskService: 负责管理流程任务。
-
IdentityService: 负责管理用户、组和身份验证。
-
HistoryService: 负责查询流程历史数据。
-
ManagementService: 提供引擎管理和维护的访问。
-
-
ProcessEngine 接口:
-
该接口是ProcessEngineServices接口的顶级接口,表示整个流程引擎的入口点,通过它可以获取各种服务接口的实例。
-
-
RepositoryService 接口的继承关系:
-
RepositoryService
-
DeploymentQuery: 用于查询部署信息。
-
ProcessDefinitionQuery: 用于查询流程定义信息。
-
-
-
RuntimeService 接口的继承关系:
-
RuntimeService
-
ExecutionQuery: 用于查询执行实例信息。
-
ProcessInstanceQuery: 用于查询流程实例信息。
-
VariableInstanceQuery: 用于查询流程变量实例信息。
-
-
-
TaskService 接口的继承关系:
-
TaskService
-
TaskQuery: 用于查询任务信息。
-
-
-
IdentityService 接口的继承关系:
-
IdentityService
-
UserQuery: 用于查询用户信息。
-
GroupQuery: 用于查询用户组信息。
-
-
-
HistoryService 接口的继承关系:
-
HistoryService
-
HistoricProcessInstanceQuery: 用于查询历史流程实例信息。
-
HistoricTaskInstanceQuery: 用于查询历史任务实例信息。
-
-
这些继承关系有助于组织和理解Camunda引擎提供的各种服务接口,使开发人员能够更加方便地使用和管理工作流引擎。
案例
设计BPMN
插入模型
编辑
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内容
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
核心学习:保存关联表单
获取流程名称-》获取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);}}}}