houzhongjian
3 天以前 f4f9405f99cb35e2fd6cfeae4c54617304228fda
提交 | 用户 | 时间
e7c126 1 package com.iailab.module.bpm.service.definition;
H 2
bb2880 3 import cn.hutool.core.collection.CollUtil;
H 4 import cn.hutool.core.util.ArrayUtil;
f4f940 5 import cn.hutool.core.util.ObjUtil;
e7c126 6 import cn.hutool.core.util.StrUtil;
H 7 import com.iailab.framework.common.util.json.JsonUtils;
8 import com.iailab.framework.common.util.validation.ValidationUtils;
bb2880 9 import com.iailab.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
H 10 import com.iailab.module.bpm.controller.admin.definition.vo.model.BpmModelSaveReqVO;
11 import com.iailab.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
12 import com.iailab.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelUpdateReqVO;
e7c126 13 import com.iailab.module.bpm.convert.definition.BpmModelConvert;
H 14 import com.iailab.module.bpm.dal.dataobject.definition.BpmFormDO;
15 import com.iailab.module.bpm.enums.definition.BpmModelFormTypeEnum;
f4f940 16 import com.iailab.module.bpm.enums.definition.BpmModelTypeEnum;
e7c126 17 import com.iailab.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
H 18 import com.iailab.module.bpm.framework.flowable.core.util.BpmnModelUtils;
19 import com.iailab.module.bpm.framework.flowable.core.util.FlowableUtils;
bb2880 20 import com.iailab.module.bpm.framework.flowable.core.util.SimpleModelUtils;
e7c126 21 import lombok.extern.slf4j.Slf4j;
H 22 import org.flowable.bpmn.model.BpmnModel;
23 import org.flowable.bpmn.model.StartEvent;
24 import org.flowable.bpmn.model.UserTask;
25 import org.flowable.common.engine.impl.db.SuspensionState;
26 import org.flowable.engine.RepositoryService;
27 import org.flowable.engine.repository.Model;
28 import org.flowable.engine.repository.ModelQuery;
29 import org.flowable.engine.repository.ProcessDefinition;
30 import org.springframework.stereotype.Service;
31 import org.springframework.transaction.annotation.Transactional;
32 import org.springframework.validation.annotation.Validated;
33
34 import javax.annotation.Resource;
35 import javax.validation.Valid;
36 import java.util.List;
bb2880 37 import java.util.Map;
e7c126 38 import java.util.Objects;
H 39
40 import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception;
bb2880 41 import static com.iailab.framework.common.util.collection.CollectionUtils.convertMap;
e7c126 42 import static com.iailab.module.bpm.enums.ErrorCodeConstants.*;
H 43
44 /**
45  * Flowable流程模型实现
46  * 主要进行 Flowable {@link Model} 的维护
47  *
48  * @author iailab
49  */
50 @Service
51 @Validated
52 @Slf4j
53 public class BpmModelServiceImpl implements BpmModelService {
54
55     @Resource
56     private RepositoryService repositoryService;
57     @Resource
58     private BpmProcessDefinitionService processDefinitionService;
59     @Resource
60     private BpmFormService bpmFormService;
61
62     @Resource
63     private BpmTaskCandidateInvoker taskCandidateInvoker;
64
65     @Override
bb2880 66     public List<Model> getModelList(String name) {
e7c126 67         ModelQuery modelQuery = repositoryService.createModelQuery();
bb2880 68         if (StrUtil.isNotEmpty(name)) {
f4f940 69             modelQuery.modelNameLike("%" + name + "%");
e7c126 70         }
bb2880 71         return modelQuery.list();
e7c126 72     }
H 73
74     @Override
75     @Transactional(rollbackFor = Exception.class)
bb2880 76     public String createModel(@Valid BpmModelSaveReqVO createReqVO) {
e7c126 77         if (!ValidationUtils.isXmlNCName(createReqVO.getKey())) {
H 78             throw exception(MODEL_KEY_VALID);
79         }
bb2880 80         // 1. 校验流程标识已经存在
e7c126 81         Model keyModel = getModelByKey(createReqVO.getKey());
H 82         if (keyModel != null) {
83             throw exception(MODEL_KEY_EXISTS, createReqVO.getKey());
84         }
85
f4f940 86         // 2. 创建 Model 对象
bb2880 87         createReqVO.setSort(System.currentTimeMillis()); // 使用当前时间,作为排序
e7c126 88         Model model = repositoryService.newModel();
bb2880 89         BpmModelConvert.INSTANCE.copyToModel(model, createReqVO);
e7c126 90         model.setTenantId(FlowableUtils.getTenantId());
f4f940 91
H 92         // 3. 保存模型
93         saveModel(model, createReqVO);
e7c126 94         return model.getId();
H 95     }
96
97     @Override
98     @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务
f4f940 99     public void updateModel(Long userId, BpmModelSaveReqVO updateReqVO) {
bb2880 100         // 1. 校验流程模型存在
H 101         Model model = validateModelManager(updateReqVO.getId(), userId);
102
f4f940 103         // 2. 填充 Model 信息
bb2880 104         BpmModelConvert.INSTANCE.copyToModel(model, updateReqVO);
f4f940 105
H 106         // 3. 保存模型
107         saveModel(model, updateReqVO);
108     }
109
110     /**
111      * 保存模型的基本信息、流程图
112      *
113      * @param model 模型
114      * @param saveReqVO 保存信息
115      */
116     private void saveModel(Model model, BpmModelSaveReqVO saveReqVO) {
117         // 1. 保存模型的基础信息
bb2880 118         repositoryService.saveModel(model);
f4f940 119
H 120         // 2. 保存流程图
121         if (ObjUtil.equals(BpmModelTypeEnum.BPMN.getType(), saveReqVO.getType())
122                 && StrUtil.isNotEmpty(saveReqVO.getBpmnXml())) {
123             updateModelBpmnXml(model.getId(), saveReqVO.getBpmnXml());
124         } else if (ObjUtil.equals(BpmModelTypeEnum.SIMPLE.getType(), saveReqVO.getType())
125                 && saveReqVO.getSimpleModel() != null) {
126             // JSON 转换成 bpmnModel
127             BpmnModel bpmnModel = SimpleModelUtils.buildBpmnModel(model.getKey(), model.getName(),
128                     saveReqVO.getSimpleModel());
129             // 保存 Bpmn XML
130             updateModelBpmnXml(model.getId(), BpmnModelUtils.getBpmnXml(bpmnModel));
131             // 保存 JSON 数据
132             updateModelSimpleJson(model.getId(), saveReqVO.getSimpleModel());
133         }
bb2880 134     }
H 135
136     @Override
137     @Transactional(rollbackFor = Exception.class)
138     public void updateModelSortBatch(Long userId, List<String> ids) {
139         // 1.1 校验流程模型存在
140         List<Model> models = repositoryService.createModelQuery()
141                 .modelTenantId(FlowableUtils.getTenantId()).list();
f4f940 142         models.removeIf(model -> !ids.contains(model.getId()));
bb2880 143         if (ids.size() != models.size()) {
H 144             throw exception(MODEL_NOT_EXISTS);
145         }
146         Map<String, Model> modelMap = convertMap(models, Model::getId);
147         // 1.2 校验是否为管理员
148         ids.forEach(id -> validateModelManager(id, userId));
149
150         // 保存排序
151         long sort = System.currentTimeMillis(); // 使用时间戳 - i 作为排序
152         for (int i = ids.size() - 1; i > 0; i--) {
153             Model model = modelMap.get(ids.get(i));
154             // 更新模型
155             BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model).setSort(sort);
156             model.setMetaInfo(JsonUtils.toJsonString(metaInfo));
157             repositoryService.saveModel(model);
158             // 更新排序
159             processDefinitionService.updateProcessDefinitionSortByModelId(model.getId(), sort);
160             sort--;
161         }
162     }
163
164     private Model validateModelExists(String id) {
165         Model model = repositoryService.getModel(id);
e7c126 166         if (model == null) {
H 167             throw exception(MODEL_NOT_EXISTS);
168         }
bb2880 169         return model;
H 170     }
e7c126 171
bb2880 172     /**
H 173      * 校验是否有流程模型的管理权限
174      *
175      * @param id     流程模型编号
176      * @param userId 用户编号
177      * @return 流程模型
178      */
179     private Model validateModelManager(String id, Long userId) {
180         Model model = validateModelExists(id);
181         BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model);
182         if (metaInfo == null || !CollUtil.contains(metaInfo.getManagerUserIds(), userId)) {
183             throw exception(MODEL_UPDATE_FAIL_NOT_MANAGER, model.getName());
184         }
185         return model;
e7c126 186     }
H 187
188     @Override
189     @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务
bb2880 190     public void deployModel(Long userId, String id) {
e7c126 191         // 1.1 校验流程模型存在
bb2880 192         Model model = validateModelManager(id, userId);
e7c126 193         // 1.2 校验流程图
H 194         byte[] bpmnBytes = getModelBpmnXML(model.getId());
195         validateBpmnXml(bpmnBytes);
196         // 1.3 校验表单已配
bb2880 197         BpmModelMetaInfoVO metaInfo = BpmModelConvert.INSTANCE.parseMetaInfo(model);
e7c126 198         BpmFormDO form = validateFormConfig(metaInfo);
H 199         // 1.4 校验任务分配规则已配置
200         taskCandidateInvoker.validateBpmnConfig(bpmnBytes);
bb2880 201         // 1.5 获取仿钉钉流程设计器模型数据
H 202         String simpleJson = getModelSimpleJson(model.getId());
e7c126 203
H 204         // 2.1 创建流程定义
f4f940 205         String definitionId = processDefinitionService.createProcessDefinition(model, metaInfo, bpmnBytes, simpleJson,
H 206                 form);
e7c126 207
H 208         // 2.2 将老的流程定义进行挂起。也就是说,只有最新部署的流程定义,才可以发起任务。
209         updateProcessDefinitionSuspended(model.getDeploymentId());
210
211         // 2.3 更新 model 的 deploymentId,进行关联
212         ProcessDefinition definition = processDefinitionService.getProcessDefinition(definitionId);
213         model.setDeploymentId(definition.getDeploymentId());
214         repositoryService.saveModel(model);
215     }
216
217     private void validateBpmnXml(byte[] bpmnBytes) {
218         BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes);
219         if (bpmnModel == null) {
220             throw exception(MODEL_NOT_EXISTS);
221         }
222         // 1. 没有 StartEvent
223         StartEvent startEvent = BpmnModelUtils.getStartEvent(bpmnModel);
224         if (startEvent == null) {
225             throw exception(MODEL_DEPLOY_FAIL_BPMN_START_EVENT_NOT_EXISTS);
226         }
227         // 2. 校验 UserTask 的 name 都配置了
228         List<UserTask> userTasks = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class);
229         userTasks.forEach(userTask -> {
230             if (StrUtil.isEmpty(userTask.getName())) {
231                 throw exception(MODEL_DEPLOY_FAIL_BPMN_USER_TASK_NAME_NOT_EXISTS, userTask.getId());
232             }
233         });
234     }
235
236     @Override
237     @Transactional(rollbackFor = Exception.class)
bb2880 238     public void deleteModel(Long userId, String id) {
e7c126 239         // 校验流程模型存在
bb2880 240         Model model = validateModelManager(id, userId);
H 241
e7c126 242         // 执行删除
H 243         repositoryService.deleteModel(id);
244         // 禁用流程定义
245         updateProcessDefinitionSuspended(model.getDeploymentId());
246     }
247
248     @Override
bb2880 249     public void updateModelState(Long userId, String id, Integer state) {
e7c126 250         // 1.1 校验流程模型存在
bb2880 251         Model model = validateModelManager(id, userId);
e7c126 252         // 1.2 校验流程定义存在
f4f940 253         ProcessDefinition definition = processDefinitionService
H 254                 .getProcessDefinitionByDeploymentId(model.getDeploymentId());
e7c126 255         if (definition == null) {
H 256             throw exception(PROCESS_DEFINITION_NOT_EXISTS);
257         }
258
259         // 2. 更新状态
260         processDefinitionService.updateProcessDefinitionState(definition.getId(), state);
261     }
262
263     @Override
264     public BpmnModel getBpmnModelByDefinitionId(String processDefinitionId) {
265         return repositoryService.getBpmnModel(processDefinitionId);
266     }
267
bb2880 268     @Override
H 269     public BpmSimpleModelNodeVO getSimpleModel(String modelId) {
270         Model model = validateModelExists(modelId);
271         // 通过 ACT_RE_MODEL 表 EDITOR_SOURCE_EXTRA_VALUE_ID_ ,获取仿钉钉快搭模型的 JSON 数据
272         String json = getModelSimpleJson(model.getId());
273         return JsonUtils.parseObject(json, BpmSimpleModelNodeVO.class);
274     }
275
276     @Override
277     public void updateSimpleModel(Long userId, BpmSimpleModelUpdateReqVO reqVO) {
278         // 1. 校验流程模型存在
279         Model model = validateModelManager(reqVO.getId(), userId);
280
281         // 2.1 JSON 转换成 bpmnModel
282         BpmnModel bpmnModel = SimpleModelUtils.buildBpmnModel(model.getKey(), model.getName(), reqVO.getSimpleModel());
283         // 2.2 保存 Bpmn XML
284         updateModelBpmnXml(model.getId(), BpmnModelUtils.getBpmnXml(bpmnModel));
285         // 2.3 保存 JSON 数据
286         updateModelSimpleJson(model.getId(), reqVO.getSimpleModel());
287     }
288
e7c126 289     /**
H 290      * 校验流程表单已配置
291      *
292      * @param metaInfo 流程模型元数据
293      * @return 表单配置
294      */
bb2880 295     private BpmFormDO validateFormConfig(BpmModelMetaInfoVO metaInfo) {
e7c126 296         if (metaInfo == null || metaInfo.getFormType() == null) {
H 297             throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG);
298         }
299         // 校验表单存在
300         if (Objects.equals(metaInfo.getFormType(), BpmModelFormTypeEnum.NORMAL.getType())) {
301             if (metaInfo.getFormId() == null) {
302                 throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG);
303             }
304             BpmFormDO form = bpmFormService.getForm(metaInfo.getFormId());
305             if (form == null) {
306                 throw exception(FORM_NOT_EXISTS);
307             }
308             return form;
309         } else {
f4f940 310             if (StrUtil.isEmpty(metaInfo.getFormCustomCreatePath())
H 311                     || StrUtil.isEmpty(metaInfo.getFormCustomViewPath())) {
e7c126 312                 throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG);
H 313             }
314             return null;
315         }
316     }
317
bb2880 318     @Override
H 319     public void updateModelBpmnXml(String id, String bpmnXml) {
e7c126 320         if (StrUtil.isEmpty(bpmnXml)) {
H 321             return;
322         }
bb2880 323         repositoryService.addModelEditorSource(id, StrUtil.utf8Bytes(bpmnXml));
H 324     }
325
326     @SuppressWarnings("JavaExistingMethodCanBeUsed")
327     private String getModelSimpleJson(String id) {
328         byte[] bytes = repositoryService.getModelEditorSourceExtra(id);
329         if (ArrayUtil.isEmpty(bytes)) {
330             return null;
331         }
332         return StrUtil.utf8Str(bytes);
333     }
334
335     private void updateModelSimpleJson(String id, BpmSimpleModelNodeVO node) {
336         if (node == null) {
337             return;
338         }
339         byte[] bytes = JsonUtils.toJsonByte(node);
340         repositoryService.addModelEditorSourceExtra(id, bytes);
e7c126 341     }
H 342
343     /**
344      * 挂起 deploymentId 对应的流程定义
bb2880 345      * <p>
e7c126 346      * 注意:这里一个 deploymentId 只关联一个流程定义
H 347      *
348      * @param deploymentId 流程发布Id
349      */
350     private void updateProcessDefinitionSuspended(String deploymentId) {
351         if (StrUtil.isEmpty(deploymentId)) {
352             return;
353         }
354         ProcessDefinition oldDefinition = processDefinitionService.getProcessDefinitionByDeploymentId(deploymentId);
355         if (oldDefinition == null) {
356             return;
357         }
f4f940 358         processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(),
H 359                 SuspensionState.SUSPENDED.getStateCode());
e7c126 360     }
H 361
362     private Model getModelByKey(String key) {
bb2880 363         return repositoryService.createModelQuery()
H 364                 .modelTenantId(FlowableUtils.getTenantId())
365                 .modelKey(key).singleResult();
e7c126 366     }
H 367
368     @Override
369     public Model getModel(String id) {
370         return repositoryService.getModel(id);
371     }
372
373     @Override
374     public byte[] getModelBpmnXML(String id) {
375         return repositoryService.getModelEditorSource(id);
376     }
377 }