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() 新建模型
@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内容
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
核心学习:保存关联表单
获取流程名称-》获取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);
}
}
}
}