工作流 Flowable 流程模型 接口

This commit is contained in:
jason 2022-02-08 22:30:25 +08:00
parent 167baed952
commit 9c452ee612
17 changed files with 449 additions and 9 deletions

View File

@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelPageReqVO;
/**
* 流程模型通用接口
* Activiti flowable 通用的流程模型接口
*
* @author yunlongn
* @author jason
*/
public interface BpmModelCommonService {
/**
* 获得流程模型分页
*
* @param pageVO 分页查询
* @return 流程模型分页
*/
PageResult<BpmModelPageItemRespVO> getModelPage(BpmModelPageReqVO pageVO);
}

View File

@ -11,15 +11,7 @@ import javax.validation.Valid;
* *
* @author yunlongn * @author yunlongn
*/ */
public interface BpmModelService { public interface BpmModelService extends BpmModelCommonService {
/**
* 获得流程模型分页
*
* @param pageVO 分页查询
* @return 流程模型分页
*/
PageResult<BpmModelPageItemRespVO> getModelPage(BpmModelPageReqVO pageVO);
/** /**
* 获得流程模块 * 获得流程模块

View File

@ -16,6 +16,11 @@
</description> </description>
<dependencies> <dependencies>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-bpm-base</artifactId>
<version>${revision}</version>
</dependency>
<!-- 工作流相关 --> <!-- 工作流相关 -->
<dependency> <dependency>
<groupId>org.flowable</groupId> <groupId>org.flowable</groupId>

View File

@ -0,0 +1,4 @@
/**
* bpm API 实现类定义暴露给其它模块的 API
*/
package cn.iocoder.yudao.module.bpm.api;

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.bpm.api.task;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import javax.validation.Valid;
/**
* Flowable 流程实例 Api 实现类
*
* @author 芋道源码
* @author jason
*/
@Service
@Validated
public class FlowableProcessInstanceApiImpl implements BpmProcessInstanceApi {
@Override
public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO reqDTO) {
//TODO
return null;
}
}

View File

@ -0,0 +1,33 @@
package cn.iocoder.yudao.module.bpm.controller.admin.definition;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelPageReqVO;
import cn.iocoder.yudao.module.bpm.service.definition.FlowableModelService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Api(tags = "管理后台 - 流程模型")
@RestController
@RequestMapping("/bpm/model")
@Validated
public class FlowableModelController {
@Resource
private FlowableModelService modelService;
@GetMapping("/page")
@ApiOperation(value = "获得模型分页")
public CommonResult<PageResult<BpmModelPageItemRespVO>> getModelPage(BpmModelPageReqVO pageVO) {
return success(modelService.getModelPage(pageVO));
}
}

View File

@ -0,0 +1,4 @@
/**
* 占位
*/
package cn.iocoder.yudao.module.bpm.controller.app;

View File

@ -0,0 +1,6 @@
/**
* 提供 RESTful API 给前端
* 1. admin 提供给管理后台 yudao-ui-admin 前端项目
* 2. app 提供给用户 APP yudao-ui-app 前端项目它的 Controller VO 都要添加 App 前缀用于和管理后台进行区分
*/
package cn.iocoder.yudao.module.bpm.controller;

View File

@ -0,0 +1,85 @@
package cn.iocoder.yudao.module.bpm.convert.definition;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelBaseVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelRespVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.module.bpm.service.definition.dto.ModelMetaInfoRespDTO;
import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ProcessDefinition;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
/**
* 流程模型 Convert
*
* @author yunlongn
*/
@Mapper
public interface ModelConvert {
ModelConvert INSTANCE = Mappers.getMapper(ModelConvert.class);
default List<BpmModelPageItemRespVO> convertList(List<Model> list, Map<Long, BpmFormDO> formMap,
Map<String, Deployment> deploymentMap,
Map<String, ProcessDefinition> processDefinitionMap) {
return CollectionUtils.convertList(list, model -> {
ModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), ModelMetaInfoRespDTO.class);
BpmFormDO form = metaInfo != null ? formMap.get(metaInfo.getFormId()) : null;
Deployment deployment = model.getDeploymentId() != null ? deploymentMap.get(model.getDeploymentId()) : null;
ProcessDefinition processDefinition = model.getDeploymentId() != null ? processDefinitionMap.get(model.getDeploymentId()) : null;
return convert(model, form, deployment, processDefinition);
});
}
default BpmModelPageItemRespVO convert(Model model, BpmFormDO form, Deployment deployment, ProcessDefinition processDefinition) {
BpmModelPageItemRespVO modelRespVO = new BpmModelPageItemRespVO();
modelRespVO.setId(model.getId());
modelRespVO.setCreateTime(model.getCreateTime());
// 通用 copy
copyTo(model, modelRespVO);
// Form
if (form != null) {
modelRespVO.setFormId(form.getId());
modelRespVO.setFormName(form.getName());
}
// ProcessDefinition
modelRespVO.setProcessDefinition(this.convert(processDefinition));
if (modelRespVO.getProcessDefinition() != null) {
modelRespVO.getProcessDefinition().setSuspensionState(processDefinition.isSuspended() ?
SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode());
modelRespVO.getProcessDefinition().setDeploymentTime(deployment.getDeploymentTime());
}
return modelRespVO;
}
default BpmModelRespVO convert(Model model) {
BpmModelRespVO modelRespVO = new BpmModelRespVO();
modelRespVO.setId(model.getId());
modelRespVO.setCreateTime(model.getCreateTime());
// 通用 copy
copyTo(model, modelRespVO);
return modelRespVO;
}
default void copyTo(Model model, BpmModelBaseVO to) {
to.setName(model.getName());
to.setKey(model.getKey());
to.setCategory(model.getCategory());
// metaInfo
ModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), ModelMetaInfoRespDTO.class);
copyTo(metaInfo, to);
}
void copyTo(ModelMetaInfoRespDTO from, @MappingTarget BpmModelBaseVO to);
BpmModelPageItemRespVO.ProcessDefinition convert(ProcessDefinition bean);
}

View File

@ -0,0 +1,6 @@
/**
* 提供 POJO 类的实体转换
*
* 目前使用 MapStruct 框架
*/
package cn.iocoder.yudao.module.bpm.convert;

View File

@ -0,0 +1,12 @@
/**
* bpm 包下业务流程管理Business Process Management我们放工作流的功能基于 activiti 7 版本实现
* 例如说流程定义表单配置审核中心我的申请我的待办我的已办等等
*
* bpm 解释https://baike.baidu.com/item/BPM/1933
*
* 1. Controller URL /bpm/ 开头避免和其它 Module 冲突
* 2. DataObject 表名 bpm_ 开头方便在数据库中区分
*
* 注意由于 Bpm 模块下容易和其它模块重名所以类名都加载 Pay 的前缀~
*/
package cn.iocoder.yudao.module.bpm;

View File

@ -0,0 +1,10 @@
package cn.iocoder.yudao.module.bpm.service.definition;
/**
* Flowable流程模型接口
*
* @author yunlongn
*/
public interface FlowableModelService extends BpmModelCommonService {
}

View File

@ -0,0 +1,83 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelPageReqVO;
import cn.iocoder.yudao.module.bpm.convert.definition.ModelConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.module.bpm.service.definition.dto.ModelMetaInfoRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ModelQuery;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
/**
* Flowable流程模型实现
* 主要进行 Flowable {@link Model} 的维护
*
* @author yunlongn
* @author 芋道源码
*/
@Service
@Validated
@Slf4j
public class FlowableModelServiceImpl implements FlowableModelService {
@Resource
private RepositoryService repositoryService;
@Resource
private BpmFormService bpmFormService;
@Resource
private FlowableProcessDefinitionService processDefinitionService;
@Override
public PageResult<BpmModelPageItemRespVO> getModelPage(BpmModelPageReqVO pageVO) {
ModelQuery modelQuery = repositoryService.createModelQuery();
if (StrUtil.isNotBlank(pageVO.getKey())) {
modelQuery.modelKey(pageVO.getKey());
}
if (StrUtil.isNotBlank(pageVO.getName())) {
modelQuery.modelNameLike("%" + pageVO.getName() + "%"); // 模糊匹配
}
if (StrUtil.isNotBlank(pageVO.getCategory())) {
modelQuery.modelCategory(pageVO.getCategory());
}
// 执行查询
List<Model> models = modelQuery.orderByCreateTime().desc()
.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
// 获得 Form Map
Set<Long> formIds = CollectionUtils.convertSet(models, model -> {
ModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), ModelMetaInfoRespDTO.class);
return metaInfo != null ? metaInfo.getFormId() : null;
});
Map<Long, BpmFormDO> formMap = bpmFormService.getFormMap(formIds);
// 获得 Deployment Map
Set<String> deploymentIds = new HashSet<>();
models.forEach(model -> CollectionUtils.addIfNotNull(deploymentIds, model.getDeploymentId()));
Map<String, Deployment> deploymentMap = processDefinitionService.getDeploymentMap(deploymentIds);
// 获得 ProcessDefinition Map
List<ProcessDefinition> processDefinitions = processDefinitionService.getProcessDefinitionListByDeploymentIds(deploymentIds);
Map<String, ProcessDefinition> processDefinitionMap = convertMap(processDefinitions, ProcessDefinition::getDeploymentId);
// 拼接结果
long modelCount = modelQuery.count();
return new PageResult<>(ModelConvert.INSTANCE.convertList(models, formMap, deploymentMap, processDefinitionMap), modelCount);
}
}

View File

@ -0,0 +1,52 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Flowable流程定义接口
*
* @author yunlong.li
* @author ZJQ
* @author 芋道源码
*/
public interface FlowableProcessDefinitionService {
/**
* 获得 deploymentIds 对应的 ProcessDefinition 数组
*
* @param deploymentIds 部署编号的数组
* @return 流程定义的数组
*/
List<ProcessDefinition> getProcessDefinitionListByDeploymentIds(Set<String> deploymentIds);
/**
* 获得 ids 对应的 Deployment Map
*
* @param ids 部署编号的数组
* @return 流程部署 Map
*/
default Map<String, Deployment> getDeploymentMap(Set<String> ids) {
return CollectionUtils.convertMap(getDeployments(ids), Deployment::getId);
}
/**
* 获得 ids 对应的 Deployment 数组
*
* @param ids 部署编号的数组
* @return 流程部署的数组
*/
List<Deployment> getDeployments(Set<String> ids);
/**
* 获得 id 对应的 Deployment
*
* @param id 部署编号
* @return 流程部署
*/
Deployment getDeployment(String id);
}

View File

@ -0,0 +1,62 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.addIfNotNull;
import static java.util.Collections.emptyList;
/**
* 流程定义实现
* 主要进行 Flowable {@link ProcessDefinition} {@link Deployment} 的维护
*
* @author yunlongn
* @author ZJQ
* @author 芋道源码
*/
@Service
@Validated
@Slf4j
public class FlowableProcessDefinitionServiceImpl implements FlowableProcessDefinitionService {
@Resource
private RepositoryService repositoryService;
@Override
public List<ProcessDefinition> getProcessDefinitionListByDeploymentIds(Set<String> deploymentIds) {
if (CollUtil.isEmpty(deploymentIds)) {
return emptyList();
}
return repositoryService.createProcessDefinitionQuery().deploymentIds(deploymentIds).list();
}
@Override
public List<Deployment> getDeployments(Set<String> ids) {
if (CollUtil.isEmpty(ids)) {
return emptyList();
}
List<Deployment> list = new ArrayList<>(ids.size());
for (String id : ids) {
addIfNotNull(list, getDeployment(id));
}
return list;
}
@Override
public Deployment getDeployment(String id) {
if (StrUtil.isEmpty(id)) {
return null;
}
return repositoryService.createDeploymentQuery().deploymentId(id).singleResult();
}
}

View File

@ -0,0 +1,39 @@
package cn.iocoder.yudao.module.bpm.service.definition.dto;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
import lombok.Data;
/**
* BPM 流程 MetaInfo Response DTO
* 主要用于 {@link org.flowable.engine.repository.Model#setMetaInfo(String)} 的存储
*
* @author 芋道源码
*/
@Data
public class ModelMetaInfoRespDTO {
/**
* 流程描述
*/
private String description;
/**
* 表单类型
*/
private Integer formType;
/**
* 表单编号
* 在表单类型为 {@link BpmModelFormTypeEnum#NORMAL}
*/
private Long formId;
/**
* 自定义表单的提交路径使用 Vue 的路由地址
* 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM}
*/
private String formCustomCreatePath;
/**
* 自定义表单的查看路径使用 Vue 的路由地址
* 在表单类型为 {@link BpmModelFormTypeEnum#CUSTOM}
*/
private String formCustomViewPath;
}