工作流 Flowable 发布流程, 删除模型 的实现

This commit is contained in:
jason 2022-02-11 00:01:46 +08:00
parent d6a6a01252
commit b1d6baaad8
17 changed files with 750 additions and 272 deletions

View File

@ -1,11 +1,14 @@
package cn.iocoder.yudao.module.bpm.service.definition; package cn.iocoder.yudao.module.bpm.service.definition;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils; import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -21,8 +24,11 @@ public abstract class BpmAbstractModelService {
protected final BpmFormService bpmFormService; protected final BpmFormService bpmFormService;
public BpmAbstractModelService(BpmFormService bpmFormService) { protected final BpmTaskAssignRuleService taskAssignRuleService;
public BpmAbstractModelService(BpmFormService bpmFormService,BpmTaskAssignRuleService taskAssignRuleService) {
this.bpmFormService = bpmFormService; this.bpmFormService = bpmFormService;
this.taskAssignRuleService = taskAssignRuleService;
} }
/** /**
@ -47,6 +53,26 @@ public abstract class BpmAbstractModelService {
return null; return null;
} }
/**
* 校验流程模型的任务分配规则全部都配置了
* 目的如果有规则未配置会导致流程任务找不到负责人进而流程无法进行下去
*
* @param id 流程模型编号
*/
protected void checkTaskAssignRuleAllConfig(String id) {
// 一个用户任务都没配置所以无需配置规则
List<BpmTaskAssignRuleRespVO> taskAssignRules = taskAssignRuleService.getTaskAssignRuleList(id, null);
if (CollUtil.isEmpty(taskAssignRules)) {
return;
}
// 校验未配置规则的任务
taskAssignRules.forEach(rule -> {
if (CollUtil.isEmpty(rule.getOptions())) {
throw exception(MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG, rule.getTaskDefinitionName());
}
});
}
protected void checkKeyNCName(String key) { protected void checkKeyNCName(String key) {
if (!ValidationUtils.isXmlNCName(key)) { if (!ValidationUtils.isXmlNCName(key)) {

View File

@ -0,0 +1,69 @@
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.process.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import javax.validation.Valid;
/**
* 流程定义通用接口
* Activiti flowable 通用的流程定义接口
*
* @author yunlong.li
* @author ZJQ
* @author 芋道源码
* @author jason
*/
public interface BpmProcessDefinitionCommonService {
/**
* 获得流程定义分页
*
* @param pageReqVO 分页入参
* @return 流程定义 Page
*/
PageResult<BpmProcessDefinitionPageItemRespVO> getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageReqVO);
/**
* 创建流程定义
*
* @param createReqDTO 创建信息
* @return 流程编号
*/
String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO);
/**
* 更新流程定义状态
*
* @param id 流程定义的编号
* @param state 状态
*/
void updateProcessDefinitionState(String id, Integer state);
/**
* 获得流程定义对应的 BPMN XML
*
* @param id 流程定义编号
* @return BPMN XML
*/
String getProcessDefinitionBpmnXML(String id);
/**
* 获得需要创建的流程定义是否和当前激活的流程定义相等
*
* @param createReqDTO 创建信息
* @return 是否相等
*/
boolean isProcessDefinitionEquals(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO);
/**
* 获得编号对应的 BpmProcessDefinitionExtDO
*
* @param id 编号
* @return 流程定义拓展
*/
BpmProcessDefinitionExtDO getProcessDefinitionExt(String id);
}

View File

@ -52,13 +52,9 @@ public class BpmModelServiceImpl extends BpmAbstractModelService implements BpmM
@Resource @Resource
private BpmProcessDefinitionService processDefinitionService; private BpmProcessDefinitionService processDefinitionService;
@Resource
@Lazy // 解决循环依赖
private BpmTaskAssignRuleService taskAssignRuleService;
public BpmModelServiceImpl(BpmFormService bpmFormService,BpmTaskAssignRuleService taskAssignRuleService) {
public BpmModelServiceImpl(BpmFormService bpmFormService) { super(bpmFormService, taskAssignRuleService);
super(bpmFormService);
} }
@Override @Override
@ -196,26 +192,6 @@ public class BpmModelServiceImpl extends BpmAbstractModelService implements BpmM
taskAssignRuleService.copyTaskAssignRules(id, definition.getId()); taskAssignRuleService.copyTaskAssignRules(id, definition.getId());
} }
/**
* 校验流程模型的任务分配规则全部都配置了
* 目的如果有规则未配置会导致流程任务找不到负责人进而流程无法进行下去
*
* @param id 流程模型编号
*/
private void checkTaskAssignRuleAllConfig(String id) {
// 一个用户任务都没配置所以无需配置规则
List<BpmTaskAssignRuleRespVO> taskAssignRules = taskAssignRuleService.getTaskAssignRuleList(id, null);
if (CollUtil.isEmpty(taskAssignRules)) {
return;
}
// 校验未配置规则的任务
taskAssignRules.forEach(rule -> {
if (CollUtil.isEmpty(rule.getOptions())) {
throw exception(MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG, rule.getTaskDefinitionName());
}
});
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void deleteModel(String id) { public void deleteModel(String id) {

View File

@ -24,15 +24,7 @@ import java.util.Set;
* @author ZJQ * @author ZJQ
* @author 芋道源码 * @author 芋道源码
*/ */
public interface BpmProcessDefinitionService { public interface BpmProcessDefinitionService extends BpmProcessDefinitionCommonService {
/**
* 获得流程定义分页
*
* @param pageReqVO 分页入参
* @return 流程定义 Page
*/
PageResult<BpmProcessDefinitionPageItemRespVO> getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageReqVO);
/** /**
* 获得流程定义列表 * 获得流程定义列表
@ -42,14 +34,6 @@ public interface BpmProcessDefinitionService {
*/ */
List<BpmProcessDefinitionRespVO> getProcessDefinitionList(BpmProcessDefinitionListReqVO listReqVO); List<BpmProcessDefinitionRespVO> getProcessDefinitionList(BpmProcessDefinitionListReqVO listReqVO);
/**
* 获得流程定义对应的 BPMN XML
*
* @param id 流程定义编号
* @return BPMN XML
*/
String getProcessDefinitionBpmnXML(String id);
/** /**
* 获得 Bpmn 模型 * 获得 Bpmn 模型
* *
@ -84,14 +68,6 @@ public interface BpmProcessDefinitionService {
*/ */
ProcessDefinition getActiveProcessDefinition(String key); ProcessDefinition getActiveProcessDefinition(String key);
/**
* 获得编号对应的 BpmProcessDefinitionExtDO
*
* @param id 编号
* @return 流程定义拓展
*/
BpmProcessDefinitionExtDO getProcessDefinitionExt(String id);
/** /**
* 获得 id 对应的 Deployment * 获得 id 对应的 Deployment
* *
@ -134,28 +110,4 @@ public interface BpmProcessDefinitionService {
*/ */
List<ProcessDefinition> getProcessDefinitionListByDeploymentIds(Set<String> deploymentIds); List<ProcessDefinition> getProcessDefinitionListByDeploymentIds(Set<String> deploymentIds);
/**
* 获得需要创建的流程定义是否和当前激活的流程定义相等
*
* @param createReqDTO 创建信息
* @return 是否相等
*/
boolean isProcessDefinitionEquals(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO);
/**
* 创建流程定义
*
* @param createReqDTO 创建信息
* @return 流程编号
*/
String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO);
/**
* 更新流程定义的挂起状态
*
* @param id 流程定义的编号
* @param state 挂起状态 {@link org.activiti.engine.impl.persistence.entity.SuspensionState}
*/
void updateProcessDefinitionState(String id, Integer state);
} }

View File

@ -4,8 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.io.IoUtils; import cn.iocoder.yudao.framework.common.util.io.IoUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*;
import cn.iocoder.yudao.module.bpm.convert.definition.ModelConvert; import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert;
import cn.iocoder.yudao.module.bpm.service.definition.FlowableModelService; import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@ -24,10 +24,10 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@RestController @RestController
@RequestMapping("/bpm/model") @RequestMapping("/bpm/model")
@Validated @Validated
public class FlowableModelController { public class BpmModelController {
@Resource @Resource
private FlowableModelService modelService; private BpmModelService modelService;
@GetMapping("/page") @GetMapping("/page")
@ApiOperation(value = "获得模型分页") @ApiOperation(value = "获得模型分页")
@ -62,7 +62,7 @@ public class FlowableModelController {
@PostMapping("/import") @PostMapping("/import")
@ApiOperation(value = "导入模型") @ApiOperation(value = "导入模型")
public CommonResult<String> importModel(@Valid BpmModeImportReqVO importReqVO) throws IOException { public CommonResult<String> importModel(@Valid BpmModeImportReqVO importReqVO) throws IOException {
BpmModelCreateReqVO createReqVO = ModelConvert.INSTANCE.convert(importReqVO); BpmModelCreateReqVO createReqVO = BpmModelConvert.INSTANCE.convert(importReqVO);
// 读取文件 // 读取文件
String bpmnXml = IoUtils.readUtf8(importReqVO.getBpmnFile().getInputStream(), false); String bpmnXml = IoUtils.readUtf8(importReqVO.getBpmnFile().getInputStream(), false);
return success(modelService.createModel(createReqVO, bpmnXml)); return success(modelService.createModel(createReqVO, bpmnXml));
@ -76,4 +76,21 @@ public class FlowableModelController {
modelService.deployModel(id); modelService.deployModel(id);
return success(true); return success(true);
} }
@PutMapping("/update-state")
@ApiOperation(value = "修改模型的状态", notes = "实际更新的部署的流程定义的状态")
@PreAuthorize("@ss.hasPermission('bpm:model:update')")
public CommonResult<Boolean> updateModelState(@Valid @RequestBody BpmModelUpdateStateReqVO reqVO) {
modelService.updateModelState(reqVO.getId(), reqVO.getState());
return success(true);
}
@DeleteMapping("/delete")
@ApiOperation("删除模型")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('bpm:model:delete')")
public CommonResult<Boolean> deleteModel(@RequestParam("id") String id) {
modelService.deleteModel(id);
return success(true);
}
} }

View File

@ -0,0 +1,47 @@
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.process.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO;
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
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.RequestParam;
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/process-definition")
@Validated
public class BpmProcessDefinitionController {
@Resource
private BpmProcessDefinitionService bpmDefinitionService;
@GetMapping("/page")
@ApiOperation(value = "获得流程定义分页")
@PreAuthorize("@ss.hasPermission('bpm:process-definition:query')")
public CommonResult<PageResult<BpmProcessDefinitionPageItemRespVO>> getProcessDefinitionPage(
BpmProcessDefinitionPageReqVO pageReqVO) {
return success(bpmDefinitionService.getProcessDefinitionPage(pageReqVO));
}
@GetMapping ("/get-bpmn-xml")
@ApiOperation(value = "获得流程定义的 BPMN XML")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('bpm:process-definition:query')")
public CommonResult<String> getProcessDefinitionBpmnXML(@RequestParam("id") String id) {
String bpmnXML = bpmDefinitionService.getProcessDefinitionBpmnXML(id);
return success(bpmnXML);
}
}

View File

@ -25,9 +25,9 @@ import java.util.Objects;
* @author yunlongn * @author yunlongn
*/ */
@Mapper @Mapper
public interface ModelConvert { public interface BpmModelConvert {
ModelConvert INSTANCE = Mappers.getMapper(ModelConvert.class); BpmModelConvert INSTANCE = Mappers.getMapper(BpmModelConvert.class);
default List<BpmModelPageItemRespVO> convertList(List<Model> list, Map<Long, BpmFormDO> formMap, default List<BpmModelPageItemRespVO> convertList(List<Model> list, Map<Long, BpmFormDO> formMap,
Map<String, Deployment> deploymentMap, Map<String, Deployment> deploymentMap,

View File

@ -1,10 +1,22 @@
package cn.iocoder.yudao.module.bpm.convert.definition; package cn.iocoder.yudao.module.bpm.convert.definition;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
/** /**
* Bpm 流程定义的 Convert * Bpm 流程定义的 Convert
* *
@ -12,7 +24,38 @@ import org.mapstruct.factory.Mappers;
*/ */
@Mapper @Mapper
public interface BpmProcessDefinitionConvert { public interface BpmProcessDefinitionConvert {
BpmProcessDefinitionConvert INSTANCE = Mappers.getMapper(BpmProcessDefinitionConvert.class); BpmProcessDefinitionConvert INSTANCE = Mappers.getMapper(BpmProcessDefinitionConvert.class);
BpmProcessDefinitionPageItemRespVO convert(ProcessDefinition bean);
BpmProcessDefinitionExtDO convert2(BpmProcessDefinitionCreateReqDTO bean); BpmProcessDefinitionExtDO convert2(BpmProcessDefinitionCreateReqDTO bean);
default List<BpmProcessDefinitionPageItemRespVO> convertList(List<ProcessDefinition> list, Map<String, Deployment> deploymentMap,
Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap, Map<Long, BpmFormDO> formMap) {
return CollectionUtils.convertList(list, definition -> {
Deployment deployment = definition.getDeploymentId() != null ? deploymentMap.get(definition.getDeploymentId()) : null;
BpmProcessDefinitionExtDO definitionDO = processDefinitionDOMap.get(definition.getId());
BpmFormDO form = definitionDO != null ? formMap.get(definitionDO.getFormId()) : null;
return convert(definition, deployment, definitionDO, form);
});
}
default BpmProcessDefinitionPageItemRespVO convert(ProcessDefinition bean, Deployment deployment,
BpmProcessDefinitionExtDO processDefinitionExtDO, BpmFormDO form) {
BpmProcessDefinitionPageItemRespVO respVO = convert(bean);
respVO.setSuspensionState(bean.isSuspended() ? SuspensionState.SUSPENDED.getStateCode() : SuspensionState.ACTIVE.getStateCode());
if (deployment != null) {
respVO.setDeploymentTime(deployment.getDeploymentTime());
}
if (form != null) {
respVO.setFormName(form.getName());
}
// 复制通用属性
copyTo(processDefinitionExtDO, respVO);
return respVO;
}
@Mapping(source = "from.id", target = "to.id", ignore = true)
void copyTo(BpmProcessDefinitionExtDO from, @MappingTarget BpmProcessDefinitionRespVO to);
} }

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.bpm.convert.definition;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import org.flowable.bpmn.model.UserTask;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
@Mapper
public interface BpmTaskAssignRuleConvert {
BpmTaskAssignRuleConvert INSTANCE = Mappers.getMapper(BpmTaskAssignRuleConvert.class);
default List<BpmTaskAssignRuleRespVO> convertList(List<UserTask> tasks, List<BpmTaskAssignRuleDO> rules) {
Map<String, BpmTaskAssignRuleDO> ruleMap = CollectionUtils.convertMap(rules, BpmTaskAssignRuleDO::getTaskDefinitionKey);
// UserTask 为主维度原因是流程图编辑后一些规则实际就没用了
return CollectionUtils.convertList(tasks, task -> {
BpmTaskAssignRuleRespVO respVO = convert(ruleMap.get(task.getId()));
if (respVO == null) {
respVO = new BpmTaskAssignRuleRespVO();
respVO.setTaskDefinitionKey(task.getId());
}
respVO.setTaskDefinitionName(task.getName());
return respVO;
});
}
BpmTaskAssignRuleRespVO convert(BpmTaskAssignRuleDO bean);
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import org.flowable.bpmn.model.BpmnModel;
/**
* Flowable流程模型接口
*
* @author yunlongn
*/
public interface BpmModelService extends BpmModelCommonService {
/**
* 获得流程模型编号对应的 BPMN Model
*
* @param id 流程模型编号
* @return BPMN Model
*/
BpmnModel getBpmnModel(String id);
}

View File

@ -1,17 +1,21 @@
package cn.iocoder.yudao.module.bpm.service.definition; package cn.iocoder.yudao.module.bpm.service.definition;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 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.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*;
import cn.iocoder.yudao.module.bpm.convert.definition.ModelConvert; import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.common.engine.impl.util.io.BytesStreamSource;
import org.flowable.engine.RepositoryService; import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model; import org.flowable.engine.repository.Model;
@ -41,15 +45,15 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
@Service @Service
@Validated @Validated
@Slf4j @Slf4j
public class FlowableModelServiceImpl extends BpmAbstractModelService implements FlowableModelService { public class BpmModelServiceImpl extends BpmAbstractModelService implements BpmModelService {
@Resource @Resource
private RepositoryService repositoryService; private RepositoryService repositoryService;
@Resource @Resource
private FlowableProcessDefinitionService processDefinitionService; private BpmProcessDefinitionService processDefinitionService;
public FlowableModelServiceImpl(BpmFormService bpmFormService){ public BpmModelServiceImpl(BpmFormService bpmFormService, BpmTaskAssignRuleService taskAssignRuleService){
super(bpmFormService); super(bpmFormService, taskAssignRuleService);
} }
@Override @Override
@ -85,7 +89,7 @@ public class FlowableModelServiceImpl extends BpmAbstractModelService implements
// 拼接结果 // 拼接结果
long modelCount = modelQuery.count(); long modelCount = modelQuery.count();
return new PageResult<>(ModelConvert.INSTANCE.convertList(models, formMap, deploymentMap, processDefinitionMap), modelCount); return new PageResult<>(BpmModelConvert.INSTANCE.convertList(models, formMap, deploymentMap, processDefinitionMap), modelCount);
} }
@Override @Override
@ -100,7 +104,7 @@ public class FlowableModelServiceImpl extends BpmAbstractModelService implements
// 创建流程定义 // 创建流程定义
Model model = repositoryService.newModel(); Model model = repositoryService.newModel();
ModelConvert.INSTANCE.copy(model, createReqVO); BpmModelConvert.INSTANCE.copy(model, createReqVO);
// 保存流程定义 // 保存流程定义
repositoryService.saveModel(model); repositoryService.saveModel(model);
// 保存 BPMN XML // 保存 BPMN XML
@ -108,13 +112,17 @@ public class FlowableModelServiceImpl extends BpmAbstractModelService implements
return model.getId(); return model.getId();
} }
private Model getModelByKey(String key) {
return repositoryService.createModelQuery().modelKey(key).singleResult();
}
@Override @Override
public BpmModelRespVO getModel(String id) { public BpmModelRespVO getModel(String id) {
Model model = repositoryService.getModel(id); Model model = repositoryService.getModel(id);
if (model == null) { if (model == null) {
return null; return null;
} }
BpmModelRespVO modelRespVO = ModelConvert.INSTANCE.convert(model); BpmModelRespVO modelRespVO = BpmModelConvert.INSTANCE.convert(model);
// 拼接 bpmn XML // 拼接 bpmn XML
byte[] bpmnBytes = repositoryService.getModelEditorSource(id); byte[] bpmnBytes = repositoryService.getModelEditorSource(id);
modelRespVO.setBpmnXml(StrUtil.utf8Str(bpmnBytes)); modelRespVO.setBpmnXml(StrUtil.utf8Str(bpmnBytes));
@ -130,7 +138,7 @@ public class FlowableModelServiceImpl extends BpmAbstractModelService implements
} }
// 修改流程定义 // 修改流程定义
ModelConvert.INSTANCE.copy(model, updateReqVO); BpmModelConvert.INSTANCE.copy(model, updateReqVO);
// 更新模型 // 更新模型
repositoryService.saveModel(model); repositoryService.saveModel(model);
// 更新 BPMN XML // 更新 BPMN XML
@ -152,17 +160,17 @@ public class FlowableModelServiceImpl extends BpmAbstractModelService implements
// TODO 芋艿校验流程图的有效性例如说是否有开始的元素是否有结束的元素 // TODO 芋艿校验流程图的有效性例如说是否有开始的元素是否有结束的元素
// 校验表单已配 // 校验表单已配
BpmFormDO form = checkFormConfig(model.getMetaInfo()); BpmFormDO form = checkFormConfig(model.getMetaInfo());
//TODO 校验任务分配规则已配置 //校验任务分配规则已配置
//checkTaskAssignRuleAllConfig(id); checkTaskAssignRuleAllConfig(id);
BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = ModelConvert.INSTANCE.convert2(model, form).setBpmnBytes(bpmnBytes); BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model, form).setBpmnBytes(bpmnBytes);
// TODO 校验模型是否发生修改如果未修改则不允许创建 //校验模型是否发生修改如果未修改则不允许创建
// if (processDefinitionService.isProcessDefinitionEquals(definitionCreateReqDTO)) { // 流程定义的信息相等 if (processDefinitionService.isProcessDefinitionEquals(definitionCreateReqDTO)) { // 流程定义的信息相等
// ProcessDefinition oldProcessInstance = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId()); ProcessDefinition oldProcessInstance = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
// if (oldProcessInstance != null && taskAssignRuleService.isTaskAssignRulesEquals(model.getId(), oldProcessInstance.getId())) { if (oldProcessInstance != null && taskAssignRuleService.isTaskAssignRulesEquals(model.getId(), oldProcessInstance.getId())) {
// throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS); throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS);
// } }
// } }
// 创建流程定义 // 创建流程定义
String definitionId = processDefinitionService.createProcessDefinition(definitionCreateReqDTO); String definitionId = processDefinitionService.createProcessDefinition(definitionCreateReqDTO);
@ -178,23 +186,38 @@ public class FlowableModelServiceImpl extends BpmAbstractModelService implements
//taskAssignRuleService.copyTaskAssignRules(id, definition.getId()); //taskAssignRuleService.copyTaskAssignRules(id, definition.getId());
} }
@Override
public void deleteModel(String id) {
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteModel(String id) {
// 校验流程模型存在
Model model = repositoryService.getModel(id);
if (model == null) {
throw exception(MODEL_NOT_EXISTS);
}
// 执行删除
repositoryService.deleteModel(id);
// 禁用流程实例
updateProcessDefinitionSuspended(model.getDeploymentId());
} }
@Override @Override
public void updateModelState(String id, Integer state) { public void updateModelState(String id, Integer state) {
// 校验流程模型存在
Model model = repositoryService.getModel(id);
if (model == null) {
throw exception(MODEL_NOT_EXISTS);
}
// 校验流程定义存在
ProcessDefinition definition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
if (definition == null) {
throw exception(PROCESS_DEFINITION_NOT_EXISTS);
} }
// 更新状态
processDefinitionService.updateProcessDefinitionState(definition.getId(), state);
private Model getModelByKey(String key) {
return repositoryService.createModelQuery().modelKey(key).singleResult();
} }
private void saveModelBpmnXml(Model model, String bpmnXml) { private void saveModelBpmnXml(Model model, String bpmnXml) {
if (StrUtil.isEmpty(bpmnXml)) { if (StrUtil.isEmpty(bpmnXml)) {
return; return;
@ -202,6 +225,10 @@ public class FlowableModelServiceImpl extends BpmAbstractModelService implements
repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(bpmnXml)); repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(bpmnXml));
} }
/**
* 挂起 deploymentId 对应的流程定义 这里一个deploymentId 只关联一个流程定义
* @param deploymentId 流程发布Id.
*/
private void updateProcessDefinitionSuspended(String deploymentId) { private void updateProcessDefinitionSuspended(String deploymentId) {
if (StrUtil.isEmpty(deploymentId)) { if (StrUtil.isEmpty(deploymentId)) {
return; return;
@ -212,4 +239,14 @@ public class FlowableModelServiceImpl extends BpmAbstractModelService implements
} }
processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode()); processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode());
} }
@Override
public BpmnModel getBpmnModel(String id) {
byte[] bpmnBytes = repositoryService.getModelEditorSource(id);
if (ArrayUtil.isEmpty(bpmnBytes)) {
return null;
}
BpmnXMLConverter converter = new BpmnXMLConverter();
return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true);
}
} }

View File

@ -1,11 +1,10 @@
package cn.iocoder.yudao.module.bpm.service.definition; package cn.iocoder.yudao.module.bpm.service.definition;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.repository.ProcessDefinition;
import javax.validation.Valid;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -16,7 +15,7 @@ import java.util.Set;
* @author ZJQ * @author ZJQ
* @author 芋道源码 * @author 芋道源码
*/ */
public interface FlowableProcessDefinitionService { public interface BpmProcessDefinitionService extends BpmProcessDefinitionCommonService {
/** /**
* 获得编号对应的 ProcessDefinition * 获得编号对应的 ProcessDefinition
@ -42,6 +41,14 @@ public interface FlowableProcessDefinitionService {
*/ */
List<ProcessDefinition> getProcessDefinitionListByDeploymentIds(Set<String> deploymentIds); List<ProcessDefinition> getProcessDefinitionListByDeploymentIds(Set<String> deploymentIds);
/**
* 获得流程定义标识对应的激活的流程定义
*
* @param key 流程定义的标识
* @return 流程定义
*/
ProcessDefinition getActiveProcessDefinition(String key);
/** /**
* 获得 ids 对应的 Deployment Map * 获得 ids 对应的 Deployment Map
* *
@ -69,18 +76,10 @@ public interface FlowableProcessDefinitionService {
Deployment getDeployment(String id); Deployment getDeployment(String id);
/** /**
* 创建流程定义 * 获得 Bpmn 模型
* *
* @param createReqDTO 创建信息 * @param processDefinitionId 流程定义的编号
* @return 流程编号 * @return Bpmn 模型
*/ */
String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO); BpmnModel getBpmnModel(String processDefinitionId);
/**
* 更新流程定义状态
*
* @param id 流程定义的编号
* @param state 状态
*/
void updateProcessDefinitionState(String id, Integer state);
} }

View File

@ -0,0 +1,265 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO;
import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmProcessDefinitionExtMapper;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.common.engine.impl.util.io.BytesStreamSource;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_KEY_NOT_MATCH;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_NAME_NOT_MATCH;
import static java.util.Collections.emptyList;
/**
* 流程定义实现
* 主要进行 Flowable {@link ProcessDefinition} {@link Deployment} 的维护
*
* @author yunlongn
* @author ZJQ
* @author 芋道源码
*/
@Service
@Validated
@Slf4j
public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionService {
private static final String BPMN_FILE_SUFFIX = ".bpmn";
@Resource
private RepositoryService repositoryService;
@Resource
private BpmProcessDefinitionExtMapper processDefinitionMapper;
@Resource
private BpmFormService formService;
@Override
public ProcessDefinition getProcessDefinition(String id) {
return repositoryService.getProcessDefinition(id);
}
@Override
public ProcessDefinition getProcessDefinitionByDeploymentId(String deploymentId) {
if (StrUtil.isEmpty(deploymentId)) {
return null;
}
return repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
}
@Override
public List<ProcessDefinition> getProcessDefinitionListByDeploymentIds(Set<String> deploymentIds) {
if (CollUtil.isEmpty(deploymentIds)) {
return emptyList();
}
return repositoryService.createProcessDefinitionQuery().deploymentIds(deploymentIds).list();
}
@Override
public ProcessDefinition getActiveProcessDefinition(String key) {
return repositoryService.createProcessDefinitionQuery().processDefinitionKey(key).active().singleResult();
}
@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();
}
@Override
public BpmnModel getBpmnModel(String processDefinitionId) {
return repositoryService.getBpmnModel(processDefinitionId);
}
@Override
public String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO) {
// 创建 Deployment 部署
Deployment deploy = repositoryService.createDeployment()
.key(createReqDTO.getKey()).name(createReqDTO.getName()).category(createReqDTO.getCategory())
.addBytes(createReqDTO.getKey() + BPMN_FILE_SUFFIX, createReqDTO.getBpmnBytes())
.deploy();
// 设置 ProcessDefinition category 分类
ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult();
repositoryService.setProcessDefinitionCategory(definition.getId(), createReqDTO.getCategory());
// 注意 1ProcessDefinition key name 是通过 BPMN 中的 <bpmn2:process /> id name 决定
// 注意 2目前该项目的设计上需要保证 ModelDeploymentProcessDefinition 使用相同的 key保证关联性
// 否则会导致 ProcessDefinition 的分页无法查询到
if (!Objects.equals(definition.getKey(), createReqDTO.getKey())) {
throw exception(PROCESS_DEFINITION_KEY_NOT_MATCH, createReqDTO.getKey(), definition.getKey());
}
if (!Objects.equals(definition.getName(), createReqDTO.getName())) {
throw exception(PROCESS_DEFINITION_NAME_NOT_MATCH, createReqDTO.getName(), definition.getName());
}
// 插入拓展表
BpmProcessDefinitionExtDO definitionDO = BpmProcessDefinitionConvert.INSTANCE.convert2(createReqDTO)
.setProcessDefinitionId(definition.getId());
processDefinitionMapper.insert(definitionDO);
return definition.getId();
}
@Override
public void updateProcessDefinitionState(String id, Integer state) {
// 激活
if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), state)) {
repositoryService.activateProcessDefinitionById(id, false, null);
return;
}
// 挂起
if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), state)) {
// suspendProcessInstances = false进行中的任务不进行挂起
// 原因只要新的流程不允许发起即可老流程继续可以执行
repositoryService.suspendProcessDefinitionById(id, false, null);
return;
}
log.error("[updateProcessDefinitionState][流程定义({}) 修改未知状态({})]", id, state);
}
@Override
public String getProcessDefinitionBpmnXML(String id) {
BpmnModel bpmnModel = repositoryService.getBpmnModel(id);
if (bpmnModel == null) {
return null;
}
BpmnXMLConverter converter = new BpmnXMLConverter();
return StrUtil.utf8Str(converter.convertToXML(bpmnModel));
}
@Override
public boolean isProcessDefinitionEquals(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO) {
// 校验 namedescription 是否更新
ProcessDefinition oldProcessDefinition = getActiveProcessDefinition(createReqDTO.getKey());
if (oldProcessDefinition == null) {
return false;
}
BpmProcessDefinitionExtDO oldProcessDefinitionExt = getProcessDefinitionExt(oldProcessDefinition.getId());
if (!StrUtil.equals(createReqDTO.getName(), oldProcessDefinition.getName())
|| !StrUtil.equals(createReqDTO.getDescription(), oldProcessDefinitionExt.getDescription())
|| !StrUtil.equals(createReqDTO.getCategory(), oldProcessDefinition.getCategory())) {
return false;
}
// 校验 form 信息是否更新
if (!ObjectUtil.equal(createReqDTO.getFormType(), oldProcessDefinitionExt.getFormType())
|| !ObjectUtil.equal(createReqDTO.getFormId(), oldProcessDefinitionExt.getFormId())
|| !ObjectUtil.equal(createReqDTO.getFormConf(), oldProcessDefinitionExt.getFormConf())
|| !ObjectUtil.equal(createReqDTO.getFormFields(), oldProcessDefinitionExt.getFormFields())
|| !ObjectUtil.equal(createReqDTO.getFormCustomCreatePath(), oldProcessDefinitionExt.getFormCustomCreatePath())
|| !ObjectUtil.equal(createReqDTO.getFormCustomViewPath(), oldProcessDefinitionExt.getFormCustomViewPath())) {
return false;
}
// 校验 BPMN XML 信息
BpmnModel newModel = buildBpmnModel(createReqDTO.getBpmnBytes());
BpmnModel oldModel = getBpmnModel(oldProcessDefinition.getId());
//TODO 貌似 flowable 不修改这个也不同需要看看 sourceSystemId 不同
if (equals(oldModel, newModel)) {
return false;
}
// 最终发现都一致则返回 true
return true;
}
/**
* 构建对应的 BPMN Model
*
* @param bpmnBytes 原始的 BPMN XML 字节数组
* @return BPMN Model
*/
private BpmnModel buildBpmnModel(byte[] bpmnBytes) {
// 转换成 BpmnModel 对象
BpmnXMLConverter converter = new BpmnXMLConverter();
return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true);
}
//TODO 移出去
public boolean equals(BpmnModel oldModel, BpmnModel newModel) {
// 由于 BpmnModel 未提供 equals 方法所以只能转成字节数组进行比较
return Arrays.equals(getBpmnBytes(oldModel), getBpmnBytes(newModel));
}
//TODO 移出去
public byte[] getBpmnBytes(BpmnModel model) {
if (model == null) {
return new byte[0];
}
BpmnXMLConverter converter = new BpmnXMLConverter();
return converter.convertToXML(model);
}
@Override
public BpmProcessDefinitionExtDO getProcessDefinitionExt(String id) {
return processDefinitionMapper.selectByProcessDefinitionId(id);
}
@Override
public PageResult<BpmProcessDefinitionPageItemRespVO> getProcessDefinitionPage(BpmProcessDefinitionPageReqVO pageVO) {
ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
if (StrUtil.isNotBlank(pageVO.getKey())) {
definitionQuery.processDefinitionKey(pageVO.getKey());
}
// 执行查询
List<ProcessDefinition> processDefinitions = definitionQuery.orderByProcessDefinitionVersion().desc()
.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
if (CollUtil.isEmpty(processDefinitions)) {
return new PageResult<>(emptyList(), definitionQuery.count());
}
// 获得 Deployment Map
Set<String> deploymentIds = new HashSet<>();
processDefinitions.forEach(definition -> addIfNotNull(deploymentIds, definition.getDeploymentId()));
Map<String, Deployment> deploymentMap = getDeploymentMap(deploymentIds);
// 获得 BpmProcessDefinitionDO Map
List<BpmProcessDefinitionExtDO> processDefinitionDOs = processDefinitionMapper.selectListByProcessDefinitionIds(
convertList(processDefinitions, ProcessDefinition::getId));
Map<String, BpmProcessDefinitionExtDO> processDefinitionDOMap = convertMap(processDefinitionDOs,
BpmProcessDefinitionExtDO::getProcessDefinitionId);
// 获得 Form Map
Set<Long> formIds = convertSet(processDefinitionDOs, BpmProcessDefinitionExtDO::getFormId);
Map<Long, BpmFormDO> formMap = formService.getFormMap(formIds);
// 拼接结果
long definitionCount = definitionQuery.count();
return new PageResult<>(BpmProcessDefinitionConvert.INSTANCE.convertList(processDefinitions, deploymentMap,
processDefinitionDOMap, formMap), definitionCount);
}
}

View File

@ -0,0 +1,141 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
import cn.iocoder.yudao.module.bpm.convert.definition.BpmTaskAssignRuleConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* BPM 任务分配规则 Service 实现类
*/
@Service
@Validated
@Slf4j
public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService{
@Resource
private BpmTaskAssignRuleMapper taskRuleMapper;
@Resource
@Lazy // 解决循环依赖
private BpmModelService modelService;
@Resource
private BpmProcessDefinitionService processDefinitionService;
@Override
public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId, String taskDefinitionKey) {
return taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, taskDefinitionKey);
}
@Override
public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByModelId(String modelId) {
return taskRuleMapper.selectListByModelId(modelId);
}
@Override
public List<BpmTaskAssignRuleRespVO> getTaskAssignRuleList(String modelId, String processDefinitionId) {
// 获得规则
List<BpmTaskAssignRuleDO> rules = Collections.emptyList();
BpmnModel model = null;
if (StrUtil.isNotEmpty(modelId)) {
rules = getTaskAssignRuleListByModelId(modelId);
model = modelService.getBpmnModel(modelId);
} else if (StrUtil.isNotEmpty(processDefinitionId)) {
rules = getTaskAssignRuleListByProcessDefinitionId(processDefinitionId, null);
model = processDefinitionService.getBpmnModel(processDefinitionId);
}
if (model == null) {
return Collections.emptyList();
}
// 获得用户任务只有用户任务才可以设置分配规则
List<UserTask> userTasks = getBpmnModelElements(model, UserTask.class);
if (CollUtil.isEmpty(userTasks)) {
return Collections.emptyList();
}
// 转换数据
return BpmTaskAssignRuleConvert.INSTANCE.convertList(userTasks, rules);
}
/**
* TODO 需要移出去
* 获得 BPMN 流程中指定的元素们
*
* @param model
* @param clazz 指定元素例如说{@link org.flowable.bpmn.model.UserTask}{@link org.flowable.bpmn.model.Gateway} 等等
* @return 元素们
*/
public static <T extends FlowElement> List<T> getBpmnModelElements(BpmnModel model, Class<T> clazz) {
List<T> result = new ArrayList<>();
model.getProcesses().forEach(process -> {
process.getFlowElements().forEach(flowElement -> {
if (flowElement.getClass().isAssignableFrom(clazz)) {
result.add((T) flowElement);
}
});
});
return result;
}
@Override
public Long createTaskAssignRule(@Valid BpmTaskAssignRuleCreateReqVO reqVO) {
return null;
}
@Override
public void updateTaskAssignRule(@Valid BpmTaskAssignRuleUpdateReqVO reqVO) {
}
@Override
public boolean isTaskAssignRulesEquals(String modelId, String processDefinitionId) {
// 调用 VO 接口的原因是过滤掉流程模型不需要的规则保持和 copyTaskAssignRules 方法的一致性
List<BpmTaskAssignRuleRespVO> modelRules = getTaskAssignRuleList(modelId, null);
List<BpmTaskAssignRuleRespVO> processInstanceRules = getTaskAssignRuleList(null, processDefinitionId);
if (modelRules.size() != processInstanceRules.size()) {
return false;
}
// 遍历匹配对应的规则
Map<String, BpmTaskAssignRuleRespVO> processInstanceRuleMap = CollectionUtils.convertMap(processInstanceRules,
BpmTaskAssignRuleRespVO::getTaskDefinitionKey);
for (BpmTaskAssignRuleRespVO modelRule : modelRules) {
BpmTaskAssignRuleRespVO processInstanceRule = processInstanceRuleMap.get(modelRule.getTaskDefinitionKey());
if (processInstanceRule == null) {
return false;
}
if (!ObjectUtil.equals(modelRule.getType(), processInstanceRule.getType())
|| !ObjectUtil.equal(modelRule.getOptions(), processInstanceRule.getOptions())) {
return false;
}
}
return true;
}
@Override
public void copyTaskAssignRules(String fromModelId, String toProcessDefinitionId) {
}
}

View File

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

View File

@ -1,136 +0,0 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmProcessDefinitionExtMapper;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.db.SuspensionState;
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 javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.addIfNotNull;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_KEY_NOT_MATCH;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_NAME_NOT_MATCH;
import static java.util.Collections.emptyList;
/**
* 流程定义实现
* 主要进行 Flowable {@link ProcessDefinition} {@link Deployment} 的维护
*
* @author yunlongn
* @author ZJQ
* @author 芋道源码
*/
@Service
@Validated
@Slf4j
public class FlowableProcessDefinitionServiceImpl implements FlowableProcessDefinitionService {
private static final String BPMN_FILE_SUFFIX = ".bpmn";
@Resource
private RepositoryService repositoryService;
@Resource
private BpmProcessDefinitionExtMapper processDefinitionMapper;
@Override
public ProcessDefinition getProcessDefinition(String id) {
return repositoryService.getProcessDefinition(id);
}
@Override
public ProcessDefinition getProcessDefinitionByDeploymentId(String deploymentId) {
if (StrUtil.isEmpty(deploymentId)) {
return null;
}
return repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
}
@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();
}
@Override
public String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO) {
// 创建 Deployment 部署
Deployment deploy = repositoryService.createDeployment()
.key(createReqDTO.getKey()).name(createReqDTO.getName()).category(createReqDTO.getCategory())
.addBytes(createReqDTO.getKey() + BPMN_FILE_SUFFIX, createReqDTO.getBpmnBytes())
.deploy();
// 设置 ProcessDefinition category 分类
ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult();
repositoryService.setProcessDefinitionCategory(definition.getId(), createReqDTO.getCategory());
// 注意 1ProcessDefinition key name 是通过 BPMN 中的 <bpmn2:process /> id name 决定
// 注意 2目前该项目的设计上需要保证 ModelDeploymentProcessDefinition 使用相同的 key保证关联性
// 否则会导致 ProcessDefinition 的分页无法查询到
if (!Objects.equals(definition.getKey(), createReqDTO.getKey())) {
throw exception(PROCESS_DEFINITION_KEY_NOT_MATCH, createReqDTO.getKey(), definition.getKey());
}
if (!Objects.equals(definition.getName(), createReqDTO.getName())) {
throw exception(PROCESS_DEFINITION_NAME_NOT_MATCH, createReqDTO.getName(), definition.getName());
}
// 插入拓展表
BpmProcessDefinitionExtDO definitionDO = BpmProcessDefinitionConvert.INSTANCE.convert2(createReqDTO)
.setProcessDefinitionId(definition.getId());
processDefinitionMapper.insert(definitionDO);
return definition.getId();
}
@Override
public void updateProcessDefinitionState(String id, Integer state) {
// 激活
if (Objects.equals(SuspensionState.ACTIVE.getStateCode(), state)) {
repositoryService.activateProcessDefinitionById(id, false, null);
return;
}
// 挂起
if (Objects.equals(SuspensionState.SUSPENDED.getStateCode(), state)) {
// suspendProcessInstances = false进行中的任务不进行挂起
// 原因只要新的流程不允许发起即可老流程继续可以执行
repositoryService.suspendProcessDefinitionById(id, false, null);
return;
}
log.error("[updateProcessDefinitionState][流程定义({}) 修改未知状态({})]", id, state);
}
}