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