Flowable 学习流程
本文最后更新于130 天前,其中的信息可能已经过时,如有错误请发送邮件到[email protected]

这里使用的是SpringBoot3.2+Flowable6.8.0。过程中没有使用到Flowable UI

流程分类

分类功能只是简单的增删改查,就不多展示代码了。

新增

/**
 * 新增流程分类
 */
@Operation(description = "新增流程分类")
@PostMapping("save")
public R<Void> add(@Validated(value = AddGroup.class) @RequestBody WfCategoryDTO category) {
    return toAjax(categoryService.insert(category));
}

删除

/**
 * 删除流程分类
 */
@Operation(description = "删除流程分类")
@PutMapping("delete/{categoryIds}")
public R<Void> delete(@NotEmpty(message = "主键不能为空") @PathVariable Long[] categoryIds) {
    return toAjax(categoryService.deleteByIds(categoryIds));
}

修改

/**
 * 修改流程分类
 */
@Operation(description = "修改流程分类")
@PutMapping("edit")
public R<Void> edit(@Validated(value = EditGroup.class)  @RequestBody WfCategoryDTO category) {
    return toAjax(categoryService.update(category));
}

查询

    /**
     * 查询流程分类列表(含分页)
     *
     * @param category  查询条件
     * @param pageQuery 分页参数
     * @return
     */
    @GetMapping("list")
    @Operation(description = "查询流程分类列表")
    public TableDataInfo<WfCategoryVo> list(WfCategoryDTO category, PageQuery pageQuery) {
        return categoryService.queryPageList(category, pageQuery);
    }

表单配置

表单使用的开源的vform

新增

  /**
     * 新增流程表单
     *
     * @param wfFormDTO 表单对象
     */
    @PostMapping("save")
    @Operation(description = "新增流程表单")
    public R<Void> add(@Validated(value = AddGroup.class) @RequestBody WfFormDTO wfFormDTO) {
        return toAjax(wfFormService.insert(wfFormDTO));
    }

删除

/**
 * 删除流程表单
 *
 * @param formIds 主键串
 */
@Operation(description = "删除流程表单")
@DeleteMapping("/{formIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] formIds) {
    return toAjax(wfFormService.deleteByIds(Arrays.asList(formIds)) > 0 ? 1 : 0);
}

修改

/**
 * 修改流程表单
 *
 * @param wfFormDTO 表单对象
 */
@Operation(description = "编辑流程表单")
@PutMapping("edit")
public R<Void> edit(@Validated(value = EditGroup.class) @RequestBody WfFormDTO wfFormDTO) {
    return toAjax(wfFormService.update(wfFormDTO));
}

查询

/**
 * 查询流程表单列表
 */
@Operation(description = "查询流程表单列表")
@GetMapping("/list")
public TableDataInfo<WfFormVo> list(@Validated(QueryGroup.class) WfFormDTO wfFormDTO, PageQuery pageQuery) {
    return wfFormService.queryPageList(wfFormDTO, pageQuery);
}

流程模型

这一部分就涉及到了flowable中的内容了,这里需要先介绍一些概念。

Process Engine(流程引擎)

Process Engine 是 Flowable 的核心,负责管理流程实例的生命周期和所有与流程相关的操作。它为开发者提供了一系列的 API 接口,能够调用相关的服务来进行流程定义、流程实例的启动、任务管理、表单处理等功能。

Process Engine 可以被理解为整个系统的 "中枢",通过它可以访问其他的服务组件。典型的服务组件包括:

- RepositoryService:用于管理流程定义的部署、查询、挂起、删除等操作。
- RuntimeService:处理流程实例的启动、查询、暂停、恢复和变量管理等操作。
- TaskService:用于管理用户任务,任务的查询、认领、完成等。
- IdentityService:负责管理与流程相关的用户和组(如权限、身份验证)。
- HistoryService:提供对流程实例和任务的历史记录查询和管理。
- ManagementService:用于管理和监控流程引擎的系统功能,如作业的查询和执行。

新增

这里我是将新增和流程图设计分开来,首先先新增一个流程模型(包括流程标识、流程名称、流程分类等),然后再此基础上进行流程图的设计。

@Transactional
@Override
public void insert(WfModelDTO wfModelDTO) {
    // 创建一个模型,Model是由flowable提供的
    Model model = repositoryService.newModel();
    model.setCategory(wfModelDTO.getCategory());
    model.setKey(wfModelDTO.getKey());
    model.setName(wfModelDTO.getName());
    model.setVersion(1);
    // 创建一个ModelMetaInfo对象,MetaInfo 是 Flowable 中的 Model 对象的一个属性,通常用来存储模型的元数据信息。这些元数据通常以 JSON 格式存储,用来描述模型的额外信息,包括模型的描述信息、版本号、作者或创建者的名字、创建时间或最后修改时间、其他自定义的元数据信息
    ModelMetaInfoBO modelMetaInfoBO = new ModelMetaInfoBO();
    modelMetaInfoBO.setCreateUser("admin");
    modelMetaInfoBO.setCreateTime(new Date());
    modelMetaInfoBO.setVersion(1);
    modelMetaInfoBO.setDesc(wfModelDTO.getDesc());

    model.setMetaInfo(JSON.toJSONString(modelMetaInfoBO));
    // 通过RepositoryService保存
    repositoryService.saveModel(model);
}

设计

这个方法就是对新增的流程模型进行流程图设计,流程图是以xml格式进行保存的。

/**
 * 这里要这样理解,设计流程图不能是在原来的基础上修改,而是新增,对版本号+1,然后保存,这里可以看实际需求,有些业务认为设计流程图也是算对流程的一次修改,所  * 以这里看自己业务需求决定
 *
 * @param wfModelDTO
 */
@Override
@Transactional
public void saveBpmnXml(WfBpmnModelDTO wfModelDTO) {
    //查询模型信息
    String modelId = wfModelDTO.getModeId();
    Model model = repositoryService.getModel(modelId);
    if (ObjectUtil.isNull(model)) {
        throw new ServiceException("流程模型不存在!");
    }
    if (StrUtil.isBlank(wfModelDTO.getBpmnXml())) {
        throw new RuntimeException("获取模型设计图失败!");
    }
    BpmnModel bpmnModel = ModelUtils.getBpmnModel(wfModelDTO.getBpmnXml());
    if (ObjectUtil.isNull(bpmnModel)) {
        throw new RuntimeException("请检查流程设计图!");
    }
    // 获取开始节点,因为在设计的时候必须要进行表单的绑定,表单的id会在开始节点中进行属性的添加比如: <bpmn2:startEvent id="Event_11o3kf7" name="开始节点" flowable:formKey="key_1827225021857669121">,这个key_1827225021857669121就是key_表单ID
    StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
    if (ObjectUtil.isNull(startEvent)) {
        throw new RuntimeException("开始节点不存在,请检查流程设计是否有误!");
    }
    // 获取表单id
    String formKey = startEvent.getFormKey();
    if (StrUtil.isBlank(formKey)) {
        throw new RuntimeException("请配置流程表单");
    }

    Model newModel = model;
    // 如果是第一次设计图,流程版本不新增
    if (Boolean.TRUE.equals(wfModelDTO.getNewVersion())) {
        // 如果当前版本不是1,创建新版本
        newModel = repositoryService.newModel();
        newModel.setName(model.getName());
        newModel.setKey(model.getKey());
        newModel.setCategory(model.getCategory());
        Integer latestVersion = model.getVersion() + 1;
        ModelMetaInfoBO modelMetaInfoBO = JSON.parseObject(model.getMetaInfo(), ModelMetaInfoBO.class);
        long formId = Long.parseLong(StrUtil.removePrefix(formKey, "key_"));
        modelMetaInfoBO.setFormId(formId);
        newModel.setMetaInfo(rebuildMetaInfo(modelMetaInfoBO, latestVersion));
        newModel.setVersion(latestVersion);
    }
    repositoryService.saveModel(newModel);
    // 保存流程图
    byte[] xmlByte = StrUtil.bytes(wfModelDTO.getBpmnXml(), CharsetUtil.UTF_8);
    repositoryService.addModelEditorSource(newModel.getId(), xmlByte);
}

历史

每一次的修改都要进行一次版本号的的变更,我们需要看到所有的历史设计

@Override
public TableDataInfo<WfModelVo> historyList(WfModelDTO wfModelDTO, PageQuery pageQuery) {
    // 根据当前模型的key构建模型查询器,并对版本号倒序
    ModelQuery modelQuery = repositoryService.createModelQuery()
            .modelKey(wfModelDTO.getKey())
            .orderByModelVersion()
            .desc();

    // TODO: 目前还无法实现在历史模型中进行条件检索,因为如果在modelQuery中添加检索条件,可能会导致排除的第一条记录不是最新的记录
    // 去掉最新版
    long pageTotal = modelQuery.count() - 1;
    if (pageTotal <= 0) {
        return TableDataInfo.build();
    }
    int offset = (pageQuery.getPageNum() - 1) * pageQuery.getPageSize();

    // 如果是第一页,则跳过第一条记录
    if (pageQuery.getPageNum() == 1) {
        offset += 1;
    }
    int pageSize = pageQuery.getPageSize();

    // 获取分页数据
    List<Model> models = modelQuery.listPage(offset, pageSize);

    // 构建WfModelVo列表
    List<WfModelVo> list = buildModelVo(models, false);

    // 创建分页对象
    Page<WfModelVo> page = new Page<>();
    page.setTotal(pageTotal);
    page.setRecords(list);

    // 构建TableDataInfo对象并返回
    return TableDataInfo.build(page);
}

/**
 * 构建model对象
 *
 * @param models  model集合
 * @param bpmnXml 是否需要封装bpmnXml
 * @return 模型集合
 */
private List<WfModelVo> buildModelVo(List<Model> models, boolean bpmnXml) {
    return models.stream().map(model -> {
        WfModelVo wfModelVo = new WfModelVo();

        // 设置模型ID
        wfModelVo.setModelId(model.getId());
        // 设置模型名称
        wfModelVo.setModelName(model.getName());
        // 设置模型键
        wfModelVo.setModelKey(model.getKey());
        // 设置模型分类
        wfModelVo.setCategory(model.getCategory());
        // 设置模型版本
        wfModelVo.setVersion(model.getVersion());

        String metaInfo = model.getMetaInfo();
        if (StrUtil.isNotBlank(metaInfo)) {
            // 解析元数据信息
            ModelMetaInfoBO modelMetaInfoBO = JSON.parseObject(metaInfo, ModelMetaInfoBO.class);

            // 设置模型描述
            wfModelVo.setDescription(modelMetaInfoBO.getDesc());
            // 设置表单ID
            wfModelVo.setFormId(modelMetaInfoBO.getFormId());
            // 设置创建时间
            wfModelVo.setCreateTime(modelMetaInfoBO.getCreateTime());
            // 设置更新时间
            wfModelVo.setUpdateTime(modelMetaInfoBO.getUpdateTime());
            // 设置创建用户
            wfModelVo.setCreateUser(modelMetaInfoBO.getCreateUser());
            // 设置更新用户
            wfModelVo.setUpdateUser(modelMetaInfoBO.getUpdateUser());
        }

        if (bpmnXml) {
            // 获取模型编辑器的源数据
            byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId());
            // 将字节数组转换为UTF-8字符串
            String bpmn = StrUtil.utf8Str(modelEditorSource);
            // 设置BPMN XML
            wfModelVo.setBpmnXml(bpmn);
        }

        return wfModelVo;
    }).collect(Collectors.toList());
}

最新

根据历史列表中的模型,选择一个进行设置为最新版本。

@Override
@Transactional
public void latest(String modelId) {
    // 获取模型
    Model model = repositoryService.getModel(modelId);
    if (ObjectUtil.isNull(model)) {
        throw new ServiceException("流程模型不存在!");
    }
    // 获取最新的模型版本号,模型的key是不变的
    String modelKey = model.getKey();
    Model latestModel = repositoryService.createModelQuery().modelKey(modelKey).latestVersion().singleResult();
    // 判断当前模型是不是最新的
    if (model.getVersion().equals(latestModel.getVersion())) {
        throw new ServiceException("当前模型就是最新版本!");
    }
    // 最新版本号
    Integer latestVersion = latestModel.getVersion() + 1;
    // 将id设置为空,保存为新模型
    Model newModel = repositoryService.newModel();
    newModel.setName(model.getName());
    newModel.setKey(model.getKey());
    newModel.setCategory(model.getCategory());
    newModel.setVersion(latestVersion);
    newModel.setMetaInfo(model.getName());
    String metaInfo = model.getMetaInfo();
    ModelMetaInfoBO modelMetaInfoBO = JSON.parseObject(metaInfo, ModelMetaInfoBO.class);
    newModel.setMetaInfo(rebuildMetaInfo(modelMetaInfoBO, latestVersion));
    // 保存流程模型
    repositoryService.saveModel(newModel);
}

/**
 * 重构MetaInfo
 *
 * @param modelMetaInfoBO 模型元数据对象
 * @param latestVersion   最新版本
 * @return {@link ModelMetaInfoBO}
 */
private static String rebuildMetaInfo(ModelMetaInfoBO modelMetaInfoBO, Integer latestVersion) {
    if (ObjectUtil.isNull(modelMetaInfoBO)) {
        return "{}";
    }
    modelMetaInfoBO.setVersion(latestVersion);
    modelMetaInfoBO.setUpdateTime(new Date());
    modelMetaInfoBO.setUpdateUser("admin");
    return JSON.toJSONString(modelMetaInfoBO);
}

部署

@Override
public boolean deploy(String modelId) {
    Model model = repositoryService.getModel(modelId);
    if (ObjectUtil.isNull(model)) {
        throw new ServiceException("流程模型不存在!");
    }

    // 以字节数组返回流程设计图
    byte[] bpmXmlByte = repositoryService.getModelEditorSource(modelId);
    if (ArrayUtil.isEmpty(bpmXmlByte)) {
        throw new ServiceException("请先设计流程图!");
    }

    // 将字节数组转换为UTF-8编码的字符串
    String xml = StrUtil.utf8Str(bpmXmlByte);

    // 解析流程设计图的字符串,获取BpmnModel对象
    BpmnModel bpmnModel = ModelUtils.getBpmnModel(xml);

    // 获取流程名称,并加上后缀
    String processName = model.getName() + ProcessConstants.SUFFIX;

    // 创建部署对象,并设置相关属性
    Deployment deployment = repositoryService.createDeployment()
            .category(model.getCategory())
            .name(model.getName())
            .key(model.getKey())
            .addBpmnModel(processName, bpmnModel)
            .deploy();

    // 创建一个查询流程对象,根据部署ID查询,如果不构建这个对象,以后部署的流程无法查询
    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .deploymentId(deployment.getId())
            .singleResult();

    // 修改流程定义的分类,以便于搜索
    repositoryService.setProcessDefinitionCategory(processDefinition.getId(), model.getCategory());

    // 设置流程发起的权限,这里都是假数据
    // 用户
    repositoryService.addCandidateStarterUser(processDefinition.getId(), "123L");

    // 组
    repositoryService.addCandidateStarterGroup(processDefinition.getId(), "321L");

    // 保存部署表单
    return wfDeployService.saveInternalDeployForm(deployment.getId(), bpmnModel);
}

/**
 * 保存内部部署表单信息,这里不使用flowable提供的form表,需要自己创建两张表 tb_form、tb_deploy_form
 *
 * @param deployId 部署ID
 * @param bpmnModel BPMN模型
 * @return 保存是否成功
 * @throws ServiceException 如果开始节点不存在,抛出此异常
 * @Transactional(rollbackFor = Exception.class) 如果在执行方法时发生异常,则回滚事务
 */
@Override
@Transactional(rollbackFor = Exception.class)
public boolean saveInternalDeployForm(String deployId, BpmnModel bpmnModel) {
    // 获取每个节点上的form表单ID进行保存
    List<WfDeployForm> deployFormList = new ArrayList<>();
    // 获取开始节点
    StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
    if (ObjectUtil.isNull(startEvent)) {
        throw new ServiceException("开始节点不存在,请检查流程设计是否有误!");
    }
    // 保存开始节点表单信息
    WfDeployForm startDeployForm = buildDeployForm(deployId, startEvent);
    if (ObjectUtil.isNotNull(startDeployForm)) {
        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)) {
                deployFormList.add(userTaskDeployForm);
            }
        }
    }
    // 批量新增部署流程和表单关联信息
    return wfDeployFormMapper.insertBatch(deployFormList);
}

修改

@Override
@Transactional
public void update(WfModelDTO wfModelDTO) {
    String modelId = wfModelDTO.getId();
    Model model = repositoryService.getModel(modelId);
    if (ObjectUtil.isNull(model)) {
        throw new ServiceException("流程模型不存在!");
    }
    // 将wfModelDTO的属性复制到model对象中,忽略key属性
    BeanUtil.copyProperties(wfModelDTO, model, CopyOptions.create(Model.class, true, "key"));

    // 获取model的元数据信息
    // 这里并不设计流程编辑图编辑,版本不增加
    String metaInfo = model.getMetaInfo();
    ModelMetaInfoBO modelMetaInfoBO = JSON.parseObject(metaInfo, ModelMetaInfoBO.class);

    // 如果wfModelDTO的desc不为空,则更新modelMetaInfoBO的desc
    if (StrUtil.isNotBlank(wfModelDTO.getDesc())) {
        modelMetaInfoBO.setDesc(wfModelDTO.getDesc());
    }

    // 如果wfModelDTO的category不为空,则更新modelMetaInfoBO的category
    if (StrUtil.isNotBlank(wfModelDTO.getCategory())) {
        modelMetaInfoBO.setCategory(wfModelDTO.getCategory());
    }

    // 设置更新用户为"admin"
    modelMetaInfoBO.setUpdateUser("admin");

    // 设置更新时间为当前时间
    modelMetaInfoBO.setUpdateTime(new Date());

    // 将更新后的modelMetaInfoBO转为JSON字符串,并设置给model的metaInfo属性
    model.setMetaInfo(JSON.toJSONString(modelMetaInfoBO));

    // 保存更新后的model对象
    repositoryService.saveModel(model);
}

删除

@Transactional
@Override
public void deleteByIds(List<String> ids) {
    for (String id : ids) {
        Model model = repositoryService.getModel(id);
        if (ObjectUtil.isNull(model)) {
            throw new ServiceException("流程模型不存在!");
        }
        repositoryService.deleteModel(id);
    }
}

查询

@Override
public TableDataInfo<WfModelVo> list(WfModelDTO wfModelDTO, PageQuery pageQuery) {
    // 构建一个查询对象,查询最新的版本,历史版本在单独的历史分支查看
    ModelQuery modelQuery = repositoryService.createModelQuery().latestVersion();
    // 按照创建时间降序排列
    modelQuery.orderByCreateTime().desc();

    // 构建查询条件
    // 如果流程模型key不为空,则添加查询条件
    if (StrUtil.isNotBlank(wfModelDTO.getKey())) {
        modelQuery.modelKey(wfModelDTO.getKey());
    }
    // 如果流程模型名称不为空,则添加模糊查询条件
    if (StrUtil.isNotBlank(wfModelDTO.getName())) {
        modelQuery.modelNameLike("%" + wfModelDTO.getName() + "%");
    }
    // 如果流程模型分类不为空,则添加模糊查询条件
    if (StrUtil.isNotBlank(wfModelDTO.getCategory())) {
        modelQuery.modelCategoryLike("%" + wfModelDTO.getCategory() + "%");
    }

    // 查询总数
    long count = modelQuery.count();
    // 如果没有记录,则返回空的TableDataInfo对象
    if (count <= 0) {
        return TableDataInfo.build();
    }

    // 计算偏移量
    int offset = (pageQuery.getPageNum() - 1) * pageQuery.getPageSize();

    // 执行分页查询
    List<Model> models = modelQuery.listPage(offset, pageQuery.getPageSize());

    // 将查询结果转换为WfModelVo列表
    List<WfModelVo> modelVos = buildModelVo(models, false);

    // 创建分页对象,并设置总记录数和记录列表
    Page<WfModelVo> page = new Page<>();
    page.setTotal(count);
    page.setRecords(modelVos);

    // 返回包含分页信息的TableDataInfo对象
    return TableDataInfo.build(page);
}
/**
 * 构建model对象
 *
 * @param models  model集合
 * @param bpmnXml 是否需要封装bpmnXml
 * @return 模型集合
 */
private List<WfModelVo> buildModelVo(List<Model> models, boolean bpmnXml) {
    return models.stream().map(model -> {
        WfModelVo wfModelVo = new WfModelVo();

        // 设置模型信息
        // 设置模型ID
        wfModelVo.setModelId(model.getId());
        // 设置模型名称
        wfModelVo.setModelName(model.getName());
        // 设置模型键
        wfModelVo.setModelKey(model.getKey());
        // 设置模型分类
        wfModelVo.setCategory(model.getCategory());
        // 设置模型版本
        wfModelVo.setVersion(model.getVersion());

        String metaInfo = model.getMetaInfo();
        if (StrUtil.isNotBlank(metaInfo)) {
            // 解析元数据信息
            ModelMetaInfoBO modelMetaInfoBO = JSON.parseObject(metaInfo, ModelMetaInfoBO.class);

            // 设置模型详细信息
            // 设置模型描述
            wfModelVo.setDescription(modelMetaInfoBO.getDesc());
            // 设置表单ID
            wfModelVo.setFormId(modelMetaInfoBO.getFormId());
            // 设置创建时间
            wfModelVo.setCreateTime(modelMetaInfoBO.getCreateTime());
            // 设置更新时间
            wfModelVo.setUpdateTime(modelMetaInfoBO.getUpdateTime());
            // 设置创建用户
            wfModelVo.setCreateUser(modelMetaInfoBO.getCreateUser());
            // 设置更新用户
            wfModelVo.setUpdateUser(modelMetaInfoBO.getUpdateUser());
        }

        if (bpmnXml) {
            // 如果需要封装bpmnXml,则执行以下操作
            // 获取模型编辑器的源数据
            byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId());
            // 将字节数组转换为UTF-8字符串
            String bpmn = StrUtil.utf8Str(modelEditorSource);
            // 设置BPMN XML
            wfModelVo.setBpmnXml(bpmn);
        }

        return wfModelVo;
    }).collect(Collectors.toList());
}

流程部署

查询

@Override
public TableDataInfo<WfDeployVo> queryPageList(ProcessQuery processQuery, PageQuery pageQuery) {
    // 比如这里查询出来用户的id和组
    String userId = "123L";
    String groupId = "321L";
    // 创建查询对象
    ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
            .startableByUserOrGroups(userId, Collections.singleton(groupId))
            .latestVersion()
            .orderByProcessDefinitionKey()
            .desc();
    // 封装查询条件
    ProcessUtils.buildProcessSearch(processDefinitionQuery, processQuery);
    long total = processDefinitionQuery.count();
    if (total <= 0) {
        return TableDataInfo.build();
    }
    int offset = pageQuery.getPageSize() * (pageQuery.getPageNum() - 1);
    int pageSize = pageQuery.getPageSize();
    List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage(offset, pageSize);

    // 批量查询部署流程
    List<Deployment> deployments = repositoryService.createDeploymentQuery().deploymentIds(processDefinitionList.stream().map(ProcessDefinition::getDeploymentId).collect(Collectors.toList())).list();
    List<WfDeployVo> list = processDefinitionList.stream().map(processDefinition -> {
        // 查询部署
        WfDeployVo wfDeployVo = new WfDeployVo();
        wfDeployVo.setProcessDefId(processDefinition.getId());
        wfDeployVo.setProcessDefKey(processDefinition.getKey());
        wfDeployVo.setProcessDefName(processDefinition.getName());
        wfDeployVo.setVersion(processDefinition.getVersion());
        wfDeployVo.setCategory(processDefinition.getCategory());
        wfDeployVo.setDeployId(processDefinition.getDeploymentId());
        wfDeployVo.setSuspended(processDefinition.isSuspended());
        Deployment deployment = CollUtil.findOne(deployments, d -> d.getId().equals(processDefinition.getDeploymentId()));
        wfDeployVo.setDeployTime(deployment.getDeploymentTime());
        return wfDeployVo;
    }).collect(Collectors.toList());
    Page<WfDeployVo> page = new Page();
    page.setTotal(total);
    page.setRecords(list);
    return TableDataInfo.build(page);
}

版本管理

image-20240928103634572

// 这里会一并查询出当前部署的所有版本信息,包括最新的
@Override
public TableDataInfo<WfDeployVo> queryPublishList(String processKey, PageQuery pageQuery) {
    ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey(processKey)
            .orderByProcessDefinitionVersion()
            .desc();
    long total = processDefinitionQuery.count();
    if (total <= 0) {
        return TableDataInfo.build();
    }
    // 根据查询条件,查询所有版本
    int offset = pageQuery.getPageSize() * (pageQuery.getPageNum() - 1);
    int pageSize = pageQuery.getPageSize();

    List<ProcessDefinition> list = processDefinitionQuery.listPage(offset, pageSize);
    //查询部署信息
    List<Deployment> deployments = repositoryService.createDeploymentQuery().deploymentIds(list.stream().map(ProcessDefinition::getDeploymentId).collect(Collectors.toList())).list();
    if (CollUtil.isEmpty(deployments)) {
        throw new ServiceException("部署信息有误!");
    }
    Map<String, Date> dateMap = deployments.stream().collect(Collectors.toMap(deployment -> deployment.getId(), deployment -> deployment.getDeploymentTime()));
    List<WfDeployVo> wfDeployVos = list.stream().map(item -> {
        WfDeployVo vo = new WfDeployVo();
        vo.setProcessDefId(item.getId());
        vo.setProcessDefKey(item.getKey());
        vo.setProcessDefName(item.getName());
        vo.setVersion(item.getVersion());
        vo.setCategory(item.getCategory());
        vo.setDeployId(item.getDeploymentId());
        vo.setSuspended(item.isSuspended());
        vo.setDeployTime(dateMap.get(item.getDeploymentId()));
        return vo;
    }).collect(Collectors.toList());
    Page<WfDeployVo> page = new Page<>();
    page.setRecords(wfDeployVos);
    page.setTotal(total);
    return TableDataInfo.build(page);
}

删除

/**
 * 根据部署ID列表删除部署
 *
 * @param list 部署ID列表
 * @return 无返回值
 */
@Override
@Transactional
public void deleteByIds(List<String> list) {
    for (String deployId : list) {
        repositoryService.deleteDeployment(deployId, true);
    }
}

激活/挂起

/**
 * 更新流程定义状态
 *
 * @param definitionId 流程定义ID
 * @param state 流程定义状态(ACTIVE激活或SUSPENDED挂起)
 * @throws IllegalArgumentException 如果state参数不为ACTIVE或SUSPENDED则抛出此异常
 */
@Override
@Transactional
public void updateState(String definitionId, String state) {
    if (SuspensionState.ACTIVE.toString().equals(state)) {
        // 激活
        repositoryService.activateProcessDefinitionById(definitionId, true, null);
    } else if (SuspensionState.SUSPENDED.toString().equals(state)) {
        // 挂起
        repositoryService.suspendProcessDefinitionById(definitionId, true, null);
    }
}

新建流程

查询

/**
 * 查询流程定义列表,这里要查询最新版本并且是有发起权限的流程
 *
 * @param processQuery 流程查询对象
 * @param pageQuery    分页查询对象
 * @return 流程定义列表
 */
@Override
public TableDataInfo<WfDefinitionVo> selectPageStartProcessList(ProcessQuery processQuery, PageQuery pageQuery) {
    String userId = "123L";
    String groupId = "321L";
    // 创建查询对象
    ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
            .latestVersion()                //最新版本
            .active()                       //活跃状态
            .orderByProcessDefinitionKey()  //根据标识排序
            .startableByUserOrGroups(userId, Collections.singleton(groupId))  //权限
            .desc();//倒叙

    // 构建查询参数
    ProcessUtils.buildProcessSearch(processDefinitionQuery, processQuery);
    long pageTotal = processDefinitionQuery.count();
    if (pageTotal <= 0) {
        return TableDataInfo.build();
    }
    int pageSize = pageQuery.getPageSize();
    int offset = pageSize * (pageQuery.getPageNum() - 1);
    List<ProcessDefinition> processDefinitions = processDefinitionQuery.listPage(offset, pageSize);
    // 查询部署时间
    Map<String, Date> deployMap = new HashMap<>();
    List<Deployment> deployments = repositoryService.createDeploymentQuery().deploymentIds(processDefinitions.stream().map(ProcessDefinition::getDeploymentId).collect(Collectors.toList())).list();
    if (CollectionUtil.isNotEmpty(deployments)) {
        deployMap = CollUtil.toMap(deployments, deployMap, Deployment::getId, Deployment::getDeploymentTime);
    }
    // 封装对象
    List<WfDefinitionVo> wfDefinitionVos = new ArrayList<>();
    for (ProcessDefinition processDefinition : processDefinitions) {
        WfDefinitionVo vo = new WfDefinitionVo();
        vo.setProcessDefinitionId(processDefinition.getId());
        vo.setProcessDefinitionKey(processDefinition.getKey());
        vo.setProcessDefinitionName(processDefinition.getName());
        vo.setVersion(processDefinition.getVersion());
        vo.setCategory(processDefinition.getCategory());
        vo.setSuspended(processDefinition.isSuspended());
        vo.setDeploymentTime(deployMap.get(processDefinition.getDeploymentId()));
        wfDefinitionVos.add(vo);
    }
    Page<WfDefinitionVo> page = new Page<>();
    page.setTotal(pageTotal);
    page.setRecords(wfDefinitionVos);
    return TableDataInfo.build(page);
}

发起

点击发起后,需要填写表单内容需要先查询出表单数据。

/**
 * 根据流程定义ID、部署ID和流程实例ID查询对应的流程表单内容
 *
 * @param definitionId 流程定义ID
 * @param deployId 部署ID
 * @param procInsId 流程实例ID
 * @return 流程表单对象
 */
@Override
public ProcessFormVo selectFormContent(String definitionId, String deployId, String procInsId) {
    // 初始化流程表单对象
    ProcessFormVo processFormVo = new ProcessFormVo();
    // 根据流程定义ID获取BPMN模型
    BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionId);
    // 如果BPMN模型为空,则抛出异常
    if (ObjectUtil.isNull(bpmnModel)) throw new ServiceException("流程图设计为空!");
    // 从BPMN模型中获取开始事件
    StartEvent startEvent = ModelUtils.getStartEvent(bpmnModel);
    // 如果开始事件为空,则抛出异常
    if (ObjectUtil.isNull(startEvent)) throw new ServiceException("流程图中没有开始节点,请检查流程设计!");
    // 根据部署ID和开始事件的信息查询对应的流程表单
    WfDeployForm wfDeployForm = wfDeployFormMapper.selectOne(new LambdaQueryWrapper<>(WfDeployForm.class)
            .eq(WfDeployForm::getDeployId, deployId)
            .eq(WfDeployForm::getFormKey, startEvent.getFormKey())
            .eq(WfDeployForm::getNodeKey, startEvent.getId()));
    // 如果查询到的流程表单为空,则抛出异常
    if (ObjectUtil.isNull(wfDeployForm)) throw new ServiceException("流程表单为空!");
    // 获取流程表单的内容
    String formContent = wfDeployForm.getContent();
    // 如果表单内容为空或仅包含空白字符,则抛出异常
    if (StrUtil.isBlank(formContent)) throw new ServiceException("获取流程表单失败!");
    // 将表单内容解析为Map对象
    Map<String, Object> formModel = JSON.parseObject(formContent, Map.class);
    // 设置表单按钮的显示状态为不显示
    processFormVo.setFormBtns(false);
    // 设置表单模型
    processFormVo.setFormModel(formModel);
    // 如果流程实例ID不为空,则执行以下逻辑
    if (StrUtil.isNotBlank(procInsId)) {
        // 根据流程实例ID查询历史流程实例信息,并包含流程变量
        HistoricProcessInstance historicProcIns = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(procInsId)
                .includeProcessVariables()
                .singleResult();
        // 设置流程表单的数据为历史流程实例中的流程变量
        processFormVo.setFormData(historicProcIns.getProcessVariables());
    }
    // 返回流程表单对象
    return processFormVo;
}
欢迎来到我的 ChatGPT 中转站,极具性价比,为付费不方便的朋友提供便利,有需求的可以添加左侧 QQ 二维码,另外,邀请新用户能获取余额哦!最后说一句,那啥:请自觉遵守《生成式人工智能服务管理暂行办法》。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇