houzhongjian
2024-08-02 4a47e4b93f62b5e636ac0e76f3e4ee98e2b83154
提交 | 用户 | 时间
e7c126 1 package com.iailab.module.bpm.service.definition;
H 2
3 import cn.hutool.core.util.StrUtil;
4 import com.iailab.framework.common.pojo.PageResult;
5 import com.iailab.framework.common.util.json.JsonUtils;
6 import com.iailab.framework.common.util.object.PageUtils;
7 import com.iailab.framework.common.util.validation.ValidationUtils;
8 import com.iailab.module.bpm.controller.admin.definition.vo.model.BpmModelCreateReqVO;
9 import com.iailab.module.bpm.controller.admin.definition.vo.model.BpmModelPageReqVO;
10 import com.iailab.module.bpm.controller.admin.definition.vo.model.BpmModelUpdateReqVO;
11 import com.iailab.module.bpm.convert.definition.BpmModelConvert;
12 import com.iailab.module.bpm.dal.dataobject.definition.BpmFormDO;
13 import com.iailab.module.bpm.enums.definition.BpmModelFormTypeEnum;
14 import com.iailab.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
15 import com.iailab.module.bpm.framework.flowable.core.util.BpmnModelUtils;
16 import com.iailab.module.bpm.framework.flowable.core.util.FlowableUtils;
17 import com.iailab.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO;
18 import lombok.extern.slf4j.Slf4j;
19 import org.flowable.bpmn.model.BpmnModel;
20 import org.flowable.bpmn.model.StartEvent;
21 import org.flowable.bpmn.model.UserTask;
22 import org.flowable.common.engine.impl.db.SuspensionState;
23 import org.flowable.engine.RepositoryService;
24 import org.flowable.engine.repository.Model;
25 import org.flowable.engine.repository.ModelQuery;
26 import org.flowable.engine.repository.ProcessDefinition;
27 import org.springframework.stereotype.Service;
28 import org.springframework.transaction.annotation.Transactional;
29 import org.springframework.util.ObjectUtils;
30 import org.springframework.validation.annotation.Validated;
31
32 import javax.annotation.Resource;
33 import javax.validation.Valid;
34 import java.util.List;
35 import java.util.Objects;
36
37 import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception;
38 import static com.iailab.module.bpm.enums.ErrorCodeConstants.*;
39
40 /**
41  * Flowable流程模型实现
42  * 主要进行 Flowable {@link Model} 的维护
43  *
44  * @author yunlongn
45  * @author iailab
46  * @author jason
47  */
48 @Service
49 @Validated
50 @Slf4j
51 public class BpmModelServiceImpl implements BpmModelService {
52
53     @Resource
54     private RepositoryService repositoryService;
55     @Resource
56     private BpmProcessDefinitionService processDefinitionService;
57     @Resource
58     private BpmFormService bpmFormService;
59
60     @Resource
61     private BpmTaskCandidateInvoker taskCandidateInvoker;
62
63     @Override
64     public PageResult<Model> getModelPage(BpmModelPageReqVO pageVO) {
65         ModelQuery modelQuery = repositoryService.createModelQuery();
66         if (StrUtil.isNotBlank(pageVO.getKey())) {
67             modelQuery.modelKey(pageVO.getKey());
68         }
69         if (StrUtil.isNotBlank(pageVO.getName())) {
70             modelQuery.modelNameLike("%" + pageVO.getName() + "%"); // 模糊匹配
71         }
72         if (StrUtil.isNotBlank(pageVO.getCategory())) {
73             modelQuery.modelCategory(pageVO.getCategory());
74         }
75         // 执行查询
76         long count = modelQuery.count();
77         if (count == 0) {
78             return PageResult.empty(count);
79         }
4a47e4 80         // 关闭多租户查询,不添加tenantId条件
H 81         if (StrUtil.isNotBlank(FlowableUtils.getTenantId())) {
82             modelQuery.modelTenantId(FlowableUtils.getTenantId());
83         }
e7c126 84         List<Model> models = modelQuery
H 85                 .orderByCreateTime().desc()
86                 .listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
87         return new PageResult<>(models, count);
88     }
89
90     @Override
91     @Transactional(rollbackFor = Exception.class)
92     public String createModel(@Valid BpmModelCreateReqVO createReqVO, String bpmnXml) {
93         if (!ValidationUtils.isXmlNCName(createReqVO.getKey())) {
94             throw exception(MODEL_KEY_VALID);
95         }
96         // 校验流程标识已经存在
97         Model keyModel = getModelByKey(createReqVO.getKey());
98         if (keyModel != null) {
99             throw exception(MODEL_KEY_EXISTS, createReqVO.getKey());
100         }
101
102         // 创建流程定义
103         Model model = repositoryService.newModel();
104         BpmModelConvert.INSTANCE.copyToCreateModel(model, createReqVO);
105         model.setTenantId(FlowableUtils.getTenantId());
106         // 保存流程定义
107         repositoryService.saveModel(model);
108         // 保存 BPMN XML
109         saveModelBpmnXml(model, bpmnXml);
110         return model.getId();
111     }
112
113     @Override
114     @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务
115     public void updateModel(@Valid BpmModelUpdateReqVO updateReqVO) {
116         // 校验流程模型存在
117         Model model = getModel(updateReqVO.getId());
118         if (model == null) {
119             throw exception(MODEL_NOT_EXISTS);
120         }
121
122         // 修改流程定义
123         BpmModelConvert.INSTANCE.copyToUpdateModel(model, updateReqVO);
124         // 更新模型
125         repositoryService.saveModel(model);
126         // 更新 BPMN XML
127         saveModelBpmnXml(model, updateReqVO.getBpmnXml());
128     }
129
130     @Override
131     @Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务
132     public void deployModel(String id) {
133         // 1.1 校验流程模型存在
134         Model model = getModel(id);
135         if (ObjectUtils.isEmpty(model)) {
136             throw exception(MODEL_NOT_EXISTS);
137         }
138         // 1.2 校验流程图
139         byte[] bpmnBytes = getModelBpmnXML(model.getId());
140         validateBpmnXml(bpmnBytes);
141         // 1.3 校验表单已配
142         BpmModelMetaInfoRespDTO metaInfo = JsonUtils.parseObject(model.getMetaInfo(), BpmModelMetaInfoRespDTO.class);
143         BpmFormDO form = validateFormConfig(metaInfo);
144         // 1.4 校验任务分配规则已配置
145         taskCandidateInvoker.validateBpmnConfig(bpmnBytes);
146
147         // 2.1 创建流程定义
148         String definitionId = processDefinitionService.createProcessDefinition(model, metaInfo, bpmnBytes, form);
149
150         // 2.2 将老的流程定义进行挂起。也就是说,只有最新部署的流程定义,才可以发起任务。
151         updateProcessDefinitionSuspended(model.getDeploymentId());
152
153         // 2.3 更新 model 的 deploymentId,进行关联
154         ProcessDefinition definition = processDefinitionService.getProcessDefinition(definitionId);
155         model.setDeploymentId(definition.getDeploymentId());
156         repositoryService.saveModel(model);
157     }
158
159     private void validateBpmnXml(byte[] bpmnBytes) {
160         BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes);
161         if (bpmnModel == null) {
162             throw exception(MODEL_NOT_EXISTS);
163         }
164         // 1. 没有 StartEvent
165         StartEvent startEvent = BpmnModelUtils.getStartEvent(bpmnModel);
166         if (startEvent == null) {
167             throw exception(MODEL_DEPLOY_FAIL_BPMN_START_EVENT_NOT_EXISTS);
168         }
169         // 2. 校验 UserTask 的 name 都配置了
170         List<UserTask> userTasks = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class);
171         userTasks.forEach(userTask -> {
172             if (StrUtil.isEmpty(userTask.getName())) {
173                 throw exception(MODEL_DEPLOY_FAIL_BPMN_USER_TASK_NAME_NOT_EXISTS, userTask.getId());
174             }
175         });
176     }
177
178     @Override
179     @Transactional(rollbackFor = Exception.class)
180     public void deleteModel(String id) {
181         // 校验流程模型存在
182         Model model = getModel(id);
183         if (model == null) {
184             throw exception(MODEL_NOT_EXISTS);
185         }
186         // 执行删除
187         repositoryService.deleteModel(id);
188         // 禁用流程定义
189         updateProcessDefinitionSuspended(model.getDeploymentId());
190     }
191
192     @Override
193     public void updateModelState(String id, Integer state) {
194         // 1.1 校验流程模型存在
195         Model model = getModel(id);
196         if (model == null) {
197             throw exception(MODEL_NOT_EXISTS);
198         }
199         // 1.2 校验流程定义存在
200         ProcessDefinition definition = processDefinitionService.getProcessDefinitionByDeploymentId(model.getDeploymentId());
201         if (definition == null) {
202             throw exception(PROCESS_DEFINITION_NOT_EXISTS);
203         }
204
205         // 2. 更新状态
206         processDefinitionService.updateProcessDefinitionState(definition.getId(), state);
207     }
208
209     @Override
210     public BpmnModel getBpmnModelByDefinitionId(String processDefinitionId) {
211         return repositoryService.getBpmnModel(processDefinitionId);
212     }
213
214     /**
215      * 校验流程表单已配置
216      *
217      * @param metaInfo 流程模型元数据
218      * @return 表单配置
219      */
220     private BpmFormDO validateFormConfig(BpmModelMetaInfoRespDTO  metaInfo) {
221         if (metaInfo == null || metaInfo.getFormType() == null) {
222             throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG);
223         }
224         // 校验表单存在
225         if (Objects.equals(metaInfo.getFormType(), BpmModelFormTypeEnum.NORMAL.getType())) {
226             if (metaInfo.getFormId() == null) {
227                 throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG);
228             }
229             BpmFormDO form = bpmFormService.getForm(metaInfo.getFormId());
230             if (form == null) {
231                 throw exception(FORM_NOT_EXISTS);
232             }
233             return form;
234         } else {
235             if (StrUtil.isEmpty(metaInfo.getFormCustomCreatePath()) || StrUtil.isEmpty(metaInfo.getFormCustomViewPath())) {
236                 throw exception(MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG);
237             }
238             return null;
239         }
240     }
241
242     private void saveModelBpmnXml(Model model, String bpmnXml) {
243         if (StrUtil.isEmpty(bpmnXml)) {
244             return;
245         }
246         repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(bpmnXml));
247     }
248
249     /**
250      * 挂起 deploymentId 对应的流程定义
251      *
252      * 注意:这里一个 deploymentId 只关联一个流程定义
253      *
254      * @param deploymentId 流程发布Id
255      */
256     private void updateProcessDefinitionSuspended(String deploymentId) {
257         if (StrUtil.isEmpty(deploymentId)) {
258             return;
259         }
260         ProcessDefinition oldDefinition = processDefinitionService.getProcessDefinitionByDeploymentId(deploymentId);
261         if (oldDefinition == null) {
262             return;
263         }
264         processDefinitionService.updateProcessDefinitionState(oldDefinition.getId(), SuspensionState.SUSPENDED.getStateCode());
265     }
266
267     private Model getModelByKey(String key) {
268         return repositoryService.createModelQuery().modelKey(key).singleResult();
269     }
270
271     @Override
272     public Model getModel(String id) {
273         return repositoryService.getModel(id);
274     }
275
276     @Override
277     public byte[] getModelBpmnXML(String id) {
278         return repositoryService.getModelEditorSource(id);
279     }
280
281 }