工作流 Flowable 发布流程的部分实现

This commit is contained in:
jason 2022-02-10 00:16:43 +08:00
parent a207412e8c
commit d6a6a01252
17 changed files with 331 additions and 125 deletions

View File

@ -0,0 +1,56 @@
package cn.iocoder.yudao.module.bpm.service.definition;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
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.service.definition.dto.BpmModelMetaInfoRespDTO;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
/**
* 流程模型通用抽象类
* Activiti flowable 通用的流程模型抽象类 Activiti flowable 两边通用的方法
*
* @author yunlongn
* @author jason
*/
public abstract class BpmAbstractModelService {
protected final BpmFormService bpmFormService;
public BpmAbstractModelService(BpmFormService bpmFormService) {
this.bpmFormService = bpmFormService;
}
/**
* 校验流程表单已配置
*
* @param metaInfoStr 流程模型 metaInfo 字段
* @return 流程表单
*/
protected BpmFormDO checkFormConfig(String metaInfoStr) {
BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(metaInfoStr, BpmModelMetaInfoRespDTO.class);
if (metaInfo == null || metaInfo.getFormType() == null) {
throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG);
}
// 校验表单存在
if (Objects.equals(metaInfo.getFormType(), BpmModelFormTypeEnum.NORMAL.getType())) {
BpmFormDO form = bpmFormService.getForm(metaInfo.getFormId());
if (form == null) {
throw exception(FORM_NOT_EXISTS);
}
return form;
}
return null;
}
protected void checkKeyNCName(String key) {
if (!ValidationUtils.isXmlNCName(key)) {
throw exception(MODEL_KEY_VALID);
}
}
}

View File

@ -44,4 +44,26 @@ public interface BpmModelCommonService {
* @param updateReqVO 更新信息 * @param updateReqVO 更新信息
*/ */
void updateModel(@Valid BpmModelUpdateReqVO updateReqVO); void updateModel(@Valid BpmModelUpdateReqVO updateReqVO);
/**
* 将流程模型部署成一个流程定义
*
* @param id 编号
*/
void deployModel(String id);
/**
* 删除模型
*
* @param id 编号
*/
void deleteModel(String id);
/**
* 修改模型的状态实际更新的部署的流程定义的状态
*
* @param id 编号
* @param state 状态
*/
void updateModelState(String id, Integer state);
} }

View File

@ -5,7 +5,7 @@ import lombok.Data;
/** /**
* BPM 流程 MetaInfo Response DTO * BPM 流程 MetaInfo Response DTO
* 主要用于 {@link org.activiti.engine.repository.Model#setMetaInfo(String)} 的存储 * 主要用于 { Model#setMetaInfo(String)} 的存储
* *
* @author 芋道源码 * @author 芋道源码
*/ */

View File

@ -2,11 +2,11 @@ package cn.iocoder.yudao.module.bpm.convert.definition;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
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.service.definition.dto.BpmModelMetaInfoRespDTO;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
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.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.BpmProcessDefinitionCreateReqDTO;
import org.activiti.engine.impl.persistence.entity.SuspensionState; import org.activiti.engine.impl.persistence.entity.SuspensionState;
import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model; import org.activiti.engine.repository.Model;

View File

@ -1,11 +1,11 @@
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.BpmProcessDefinitionPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; 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.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 cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import org.activiti.engine.impl.persistence.entity.SuspensionState; import org.activiti.engine.impl.persistence.entity.SuspensionState;
import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.repository.ProcessDefinition;

View File

@ -13,29 +13,6 @@ import javax.validation.Valid;
*/ */
public interface BpmModelService extends BpmModelCommonService { public interface BpmModelService extends BpmModelCommonService {
/**
* 将流程模型部署成一个流程定义
*
* @param id 编号
*/
void deployModel(String id);
/**
* 删除模型
*
* @param id 编号
*/
void deleteModel(String id);
/**
* 修改模型的状态实际更新的部署的流程定义的状态
*
* @param id 编号
* @param state 状态 {@link org.activiti.engine.impl.persistence.entity.SuspensionState}
*/
void updateModelState(String id, Integer state);
/** /**
* 获得流程模型编号对应的 BPMN Model * 获得流程模型编号对应的 BPMN Model
* *

View File

@ -6,16 +6,14 @@ import cn.hutool.core.util.StrUtil;
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.BpmModelConvert; import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert;
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.framework.activiti.core.util.ActivitiUtils; import cn.iocoder.yudao.framework.activiti.core.util.ActivitiUtils;
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.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; 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.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel; import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService; import org.activiti.engine.RepositoryService;
@ -47,18 +45,22 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
@Service @Service
@Validated @Validated
@Slf4j @Slf4j
public class BpmModelServiceImpl implements BpmModelService { public class BpmModelServiceImpl extends BpmAbstractModelService implements BpmModelService {
@Resource @Resource
private RepositoryService repositoryService; private RepositoryService repositoryService;
@Resource
private BpmFormService bpmFormService;
@Resource @Resource
private BpmProcessDefinitionService processDefinitionService; private BpmProcessDefinitionService processDefinitionService;
@Resource @Resource
@Lazy // 解决循环依赖 @Lazy // 解决循环依赖
private BpmTaskAssignRuleService taskAssignRuleService; private BpmTaskAssignRuleService taskAssignRuleService;
public BpmModelServiceImpl(BpmFormService bpmFormService) {
super(bpmFormService);
}
@Override @Override
public PageResult<BpmModelPageItemRespVO> getModelPage(BpmModelPageReqVO pageVO) { public PageResult<BpmModelPageItemRespVO> getModelPage(BpmModelPageReqVO pageVO) {
ModelQuery modelQuery = repositoryService.createModelQuery(); ModelQuery modelQuery = repositoryService.createModelQuery();
@ -167,7 +169,7 @@ public class BpmModelServiceImpl implements BpmModelService {
} }
// TODO 芋艿校验流程图的有效性例如说是否有开始的元素是否有结束的元素 // TODO 芋艿校验流程图的有效性例如说是否有开始的元素是否有结束的元素
// 校验表单已配 // 校验表单已配
BpmFormDO form = checkFormConfig(model); BpmFormDO form = checkFormConfig(model.getMetaInfo());
// 校验任务分配规则已配置 // 校验任务分配规则已配置
checkTaskAssignRuleAllConfig(id); checkTaskAssignRuleAllConfig(id);
@ -214,28 +216,6 @@ public class BpmModelServiceImpl implements BpmModelService {
}); });
} }
/**
* 校验流程表单已配置
*
* @param model 流程模型
* @return 流程表单
*/
private BpmFormDO checkFormConfig(Model model) {
BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
if (metaInfo == null || metaInfo.getFormType() == null) {
throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG);
}
// 校验表单存在
if (Objects.equals(metaInfo.getFormType(), BpmModelFormTypeEnum.NORMAL.getType())) {
BpmFormDO form = bpmFormService.getForm(metaInfo.getFormId());
if (form == null) {
throw exception(FORM_NOT_EXISTS);
}
return form;
}
return null;
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void deleteModel(String id) { public void deleteModel(String id) {
@ -291,10 +271,4 @@ public class BpmModelServiceImpl implements BpmModelService {
return repositoryService.createModelQuery().modelKey(key).singleResult(); return repositoryService.createModelQuery().modelKey(key).singleResult();
} }
private void checkKeyNCName(String key) {
if (!ValidationUtils.isXmlNCName(key)) {
throw exception(MODEL_KEY_VALID);
}
}
} }

View File

@ -5,9 +5,9 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmPro
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionRespVO;
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.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.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import org.activiti.bpmn.model.BpmnModel; import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.repository.ProcessDefinition;

View File

@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert; import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import cn.iocoder.yudao.framework.activiti.core.util.ActivitiUtils; import cn.iocoder.yudao.framework.activiti.core.util.ActivitiUtils;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils;
@ -15,6 +14,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmPro
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.dal.dataobject.definition.BpmProcessDefinitionExtDO; 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.dal.mysql.definition.BpmProcessDefinitionExtMapper;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.BpmnModel; import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService; import org.activiti.engine.RepositoryService;

View File

@ -67,4 +67,13 @@ public class FlowableModelController {
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));
} }
@PostMapping("/deploy")
@ApiOperation(value = "部署模型")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = String.class)
@PreAuthorize("@ss.hasPermission('bpm:model:deploy')")
public CommonResult<Boolean> deployModel(@RequestParam("id") String id) {
modelService.deployModel(id);
return success(true);
}
} }

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.module.bpm.convert.definition;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* Bpm 流程定义的 Convert
*
* @author yunlong.li
*/
@Mapper
public interface BpmProcessDefinitionConvert {
BpmProcessDefinitionConvert INSTANCE = Mappers.getMapper(BpmProcessDefinitionConvert.class);
BpmProcessDefinitionExtDO convert2(BpmProcessDefinitionCreateReqDTO bean);
}

View File

@ -5,7 +5,8 @@ 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.module.bpm.controller.admin.definition.vo.model.*; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*;
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.ModelMetaInfoRespDTO; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import org.flowable.common.engine.impl.db.SuspensionState; import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model; import org.flowable.engine.repository.Model;
@ -32,7 +33,7 @@ public interface ModelConvert {
Map<String, Deployment> deploymentMap, Map<String, Deployment> deploymentMap,
Map<String, ProcessDefinition> processDefinitionMap) { Map<String, ProcessDefinition> processDefinitionMap) {
return CollectionUtils.convertList(list, model -> { return CollectionUtils.convertList(list, model -> {
ModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), ModelMetaInfoRespDTO.class); BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
BpmFormDO form = metaInfo != null ? formMap.get(metaInfo.getFormId()) : null; BpmFormDO form = metaInfo != null ? formMap.get(metaInfo.getFormId()) : null;
Deployment deployment = model.getDeploymentId() != null ? deploymentMap.get(model.getDeploymentId()) : null; Deployment deployment = model.getDeploymentId() != null ? deploymentMap.get(model.getDeploymentId()) : null;
ProcessDefinition processDefinition = model.getDeploymentId() != null ? processDefinitionMap.get(model.getDeploymentId()) : null; ProcessDefinition processDefinition = model.getDeploymentId() != null ? processDefinitionMap.get(model.getDeploymentId()) : null;
@ -75,12 +76,32 @@ public interface ModelConvert {
to.setKey(model.getKey()); to.setKey(model.getKey());
to.setCategory(model.getCategory()); to.setCategory(model.getCategory());
// metaInfo // metaInfo
ModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), ModelMetaInfoRespDTO.class); BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
copyTo(metaInfo, to); copyTo(metaInfo, to);
} }
BpmModelCreateReqVO convert(BpmModeImportReqVO bean); BpmModelCreateReqVO convert(BpmModeImportReqVO bean);
void copyTo(ModelMetaInfoRespDTO from, @MappingTarget BpmModelBaseVO to); default BpmProcessDefinitionCreateReqDTO convert2(Model model, BpmFormDO form) {
BpmProcessDefinitionCreateReqDTO createReqDTO = new BpmProcessDefinitionCreateReqDTO();
createReqDTO.setModelId(model.getId());
createReqDTO.setName(model.getName());
createReqDTO.setKey(model.getKey());
createReqDTO.setCategory(model.getCategory());
BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
// metaInfo
copyTo(metaInfo, createReqDTO);
// form
if (form != null) {
createReqDTO.setFormConf(form.getConf());
createReqDTO.setFormFields(form.getFields());
}
return createReqDTO;
}
void copyTo(BpmModelMetaInfoRespDTO from, @MappingTarget BpmProcessDefinitionCreateReqDTO to);
void copyTo(BpmModelMetaInfoRespDTO from, @MappingTarget BpmModelBaseVO to);
BpmModelPageItemRespVO.ProcessDefinition convert(ProcessDefinition bean); BpmModelPageItemRespVO.ProcessDefinition convert(ProcessDefinition bean);
@ -94,15 +115,15 @@ public interface ModelConvert {
default void copy(Model model, BpmModelUpdateReqVO bean) { default void copy(Model model, BpmModelUpdateReqVO bean) {
model.setName(bean.getName()); model.setName(bean.getName());
model.setCategory(bean.getCategory()); model.setCategory(bean.getCategory());
model.setMetaInfo(buildMetaInfoStr(JsonUtils.parseObject(model.getMetaInfo(), ModelMetaInfoRespDTO.class), model.setMetaInfo(buildMetaInfoStr(JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class),
bean.getDescription(), bean.getFormType(), bean.getFormId(), bean.getDescription(), bean.getFormType(), bean.getFormId(),
bean.getFormCustomCreatePath(), bean.getFormCustomViewPath())); bean.getFormCustomCreatePath(), bean.getFormCustomViewPath()));
} }
default String buildMetaInfoStr(ModelMetaInfoRespDTO metaInfo, String description, Integer formType, default String buildMetaInfoStr(BpmModelMetaInfoRespDTO metaInfo, String description, Integer formType,
Long formId, String formCustomCreatePath, String formCustomViewPath) { Long formId, String formCustomCreatePath, String formCustomViewPath) {
if (metaInfo == null) { if (metaInfo == null) {
metaInfo = new ModelMetaInfoRespDTO(); metaInfo = new BpmModelMetaInfoRespDTO();
} }
// 只有非空才进行设置避免更新时的覆盖 // 只有非空才进行设置避免更新时的覆盖
if (StrUtil.isNotEmpty(description)) { if (StrUtil.isNotEmpty(description)) {

View File

@ -5,12 +5,13 @@ 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.framework.common.util.validation.ValidationUtils;
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.ModelConvert;
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.ModelMetaInfoRespDTO; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO;
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.db.SuspensionState;
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;
@ -18,14 +19,12 @@ import org.flowable.engine.repository.ModelQuery;
import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.HashSet; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
@ -42,15 +41,17 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
@Service @Service
@Validated @Validated
@Slf4j @Slf4j
public class FlowableModelServiceImpl implements FlowableModelService { public class FlowableModelServiceImpl extends BpmAbstractModelService implements FlowableModelService {
@Resource @Resource
private RepositoryService repositoryService; private RepositoryService repositoryService;
@Resource @Resource
private BpmFormService bpmFormService;
@Resource
private FlowableProcessDefinitionService processDefinitionService; private FlowableProcessDefinitionService processDefinitionService;
public FlowableModelServiceImpl(BpmFormService bpmFormService){
super(bpmFormService);
}
@Override @Override
public PageResult<BpmModelPageItemRespVO> getModelPage(BpmModelPageReqVO pageVO) { public PageResult<BpmModelPageItemRespVO> getModelPage(BpmModelPageReqVO pageVO) {
ModelQuery modelQuery = repositoryService.createModelQuery(); ModelQuery modelQuery = repositoryService.createModelQuery();
@ -69,7 +70,7 @@ public class FlowableModelServiceImpl implements FlowableModelService {
// 获得 Form Map // 获得 Form Map
Set<Long> formIds = CollectionUtils.convertSet(models, model -> { Set<Long> formIds = CollectionUtils.convertSet(models, model -> {
ModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), ModelMetaInfoRespDTO.class); BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
return metaInfo != null ? metaInfo.getFormId() : null; return metaInfo != null ? metaInfo.getFormId() : null;
}); });
Map<Long, BpmFormDO> formMap = bpmFormService.getFormMap(formIds); Map<Long, BpmFormDO> formMap = bpmFormService.getFormMap(formIds);
@ -136,15 +137,63 @@ public class FlowableModelServiceImpl implements FlowableModelService {
saveModelBpmnXml(model, updateReqVO.getBpmnXml()); saveModelBpmnXml(model, updateReqVO.getBpmnXml());
} }
@Override
public void deployModel(String id) {
// 校验流程模型存在
Model model = repositoryService.getModel(id);
if (ObjectUtils.isEmpty(model)) {
throw exception(MODEL_NOT_EXISTS);
}
// 校验流程图
byte[] bpmnBytes = repositoryService.getModelEditorSource(model.getId());
if (bpmnBytes == null) {
throw exception(MODEL_NOT_EXISTS);
}
// TODO 芋艿校验流程图的有效性例如说是否有开始的元素是否有结束的元素
// 校验表单已配
BpmFormDO form = checkFormConfig(model.getMetaInfo());
//TODO 校验任务分配规则已配置
//checkTaskAssignRuleAllConfig(id);
BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = ModelConvert.INSTANCE.convert2(model, form).setBpmnBytes(bpmnBytes);
// TODO 校验模型是否发生修改如果未修改则不允许创建
// if (processDefinitionService.isProcessDefinitionEquals(definitionCreateReqDTO)) { // 流程定义的信息相等
// ProcessDefinition oldProcessInstance = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
// if (oldProcessInstance != null && taskAssignRuleService.isTaskAssignRulesEquals(model.getId(), oldProcessInstance.getId())) {
// throw exception(MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS);
// }
// }
// 创建流程定义
String definitionId = processDefinitionService.createProcessDefinition(definitionCreateReqDTO);
// 将老的流程定义进行挂起也就是说只有最新部署的流程定义才可以发起任务
updateProcessDefinitionSuspended(model.getDeploymentId());
// 更新 model deploymentId进行关联
ProcessDefinition definition = processDefinitionService.getProcessDefinition(definitionId);
model.setDeploymentId(definition.getDeploymentId());
repositoryService.saveModel(model);
//TODO 复制任务分配规则
//taskAssignRuleService.copyTaskAssignRules(id, definition.getId());
}
@Override
public void deleteModel(String id) {
}
@Override
public void updateModelState(String id, Integer state) {
}
private Model getModelByKey(String key) { private Model getModelByKey(String key) {
return repositoryService.createModelQuery().modelKey(key).singleResult(); return repositoryService.createModelQuery().modelKey(key).singleResult();
} }
private void checkKeyNCName(String key) {
if (!ValidationUtils.isXmlNCName(key)) {
throw exception(MODEL_KEY_VALID);
}
}
private void saveModelBpmnXml(Model model, String bpmnXml) { private void saveModelBpmnXml(Model model, String bpmnXml) {
if (StrUtil.isEmpty(bpmnXml)) { if (StrUtil.isEmpty(bpmnXml)) {
@ -152,4 +201,15 @@ public class FlowableModelServiceImpl implements FlowableModelService {
} }
repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(bpmnXml)); repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(bpmnXml));
} }
private void updateProcessDefinitionSuspended(String deploymentId) {
if (StrUtil.isEmpty(deploymentId)) {
return;
}
ProcessDefinition oldDefinition = processDefinitionService.getProcessDefinitionByDeploymentId(deploymentId);
if (oldDefinition == null) {
return;
}
processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode());
}
} }

View File

@ -1,9 +1,11 @@
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.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,6 +18,22 @@ import java.util.Set;
*/ */
public interface FlowableProcessDefinitionService { public interface FlowableProcessDefinitionService {
/**
* 获得编号对应的 ProcessDefinition
*
* @param id 编号
* @return 流程定义
*/
ProcessDefinition getProcessDefinition(String id);
/**
* 获得 deploymentId 对应的 ProcessDefinition
*
* @param deploymentId 部署编号
* @return 流程定义
*/
ProcessDefinition getProcessDefinitionByDeploymentId(String deploymentId);
/** /**
* 获得 deploymentIds 对应的 ProcessDefinition 数组 * 获得 deploymentIds 对应的 ProcessDefinition 数组
* *
@ -49,4 +67,20 @@ public interface FlowableProcessDefinitionService {
* @return 流程部署 * @return 流程部署
*/ */
Deployment getDeployment(String id); Deployment getDeployment(String id);
/**
* 创建流程定义
*
* @param createReqDTO 创建信息
* @return 流程编号
*/
String createProcessDefinition(@Valid BpmProcessDefinitionCreateReqDTO createReqDTO);
/**
* 更新流程定义状态
*
* @param id 流程定义的编号
* @param state 状态
*/
void updateProcessDefinitionState(String id, Integer state);
} }

View File

@ -2,7 +2,12 @@ package cn.iocoder.yudao.module.bpm.service.definition;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil; 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 lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.impl.db.SuspensionState;
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.ProcessDefinition; import org.flowable.engine.repository.ProcessDefinition;
@ -10,11 +15,16 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; 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.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; import static java.util.Collections.emptyList;
/** /**
@ -29,9 +39,28 @@ import static java.util.Collections.emptyList;
@Validated @Validated
@Slf4j @Slf4j
public class FlowableProcessDefinitionServiceImpl implements FlowableProcessDefinitionService { public class FlowableProcessDefinitionServiceImpl implements FlowableProcessDefinitionService {
private static final String BPMN_FILE_SUFFIX = ".bpmn";
@Resource @Resource
private RepositoryService repositoryService; 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 @Override
public List<ProcessDefinition> getProcessDefinitionListByDeploymentIds(Set<String> deploymentIds) { public List<ProcessDefinition> getProcessDefinitionListByDeploymentIds(Set<String> deploymentIds) {
if (CollUtil.isEmpty(deploymentIds)) { if (CollUtil.isEmpty(deploymentIds)) {
@ -59,4 +88,49 @@ public class FlowableProcessDefinitionServiceImpl implements FlowableProcessDefi
} }
return repositoryService.createDeploymentQuery().deploymentId(id).singleResult(); 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);
}
} }

View File

@ -1,39 +0,0 @@
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;
}