ActProcessService.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /**
  2. * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
  3. */
  4. package com.jeeplus.modules.act.service;
  5. import java.io.File;
  6. import java.io.IOException;
  7. import java.io.InputStream;
  8. import java.io.InputStreamReader;
  9. import java.io.UnsupportedEncodingException;
  10. import java.util.ArrayList;
  11. import java.util.HashMap;
  12. import java.util.List;
  13. import java.util.Map;
  14. import java.util.zip.ZipInputStream;
  15. import javax.xml.stream.XMLInputFactory;
  16. import javax.xml.stream.XMLStreamException;
  17. import javax.xml.stream.XMLStreamReader;
  18. import com.google.common.collect.Lists;
  19. import com.jeeplus.common.json.AjaxJson;
  20. import com.jeeplus.core.persistence.ActEntity;
  21. import com.jeeplus.modules.act.entity.Act;
  22. import com.jeeplus.modules.act.utils.ProcessDefCache;
  23. import org.activiti.bpmn.converter.BpmnXMLConverter;
  24. import org.activiti.bpmn.model.BpmnModel;
  25. import org.activiti.editor.constants.ModelDataJsonConstants;
  26. import org.activiti.editor.language.json.converter.BpmnJsonConverter;
  27. import org.activiti.engine.*;
  28. import org.activiti.engine.history.HistoricProcessInstance;
  29. import org.activiti.engine.history.HistoricProcessInstanceQuery;
  30. import org.activiti.engine.impl.ProcessEngineImpl;
  31. import org.activiti.engine.repository.Deployment;
  32. import org.activiti.engine.repository.ProcessDefinition;
  33. import org.activiti.engine.repository.ProcessDefinitionQuery;
  34. import org.activiti.engine.runtime.ProcessInstance;
  35. import org.activiti.engine.runtime.ProcessInstanceQuery;
  36. import org.activiti.engine.task.Task;
  37. import org.apache.commons.io.FileUtils;
  38. import org.apache.commons.io.FilenameUtils;
  39. import org.springframework.beans.factory.annotation.Autowired;
  40. import org.springframework.stereotype.Service;
  41. import org.springframework.transaction.annotation.Transactional;
  42. import org.springframework.web.multipart.MultipartFile;
  43. import com.fasterxml.jackson.databind.ObjectMapper;
  44. import com.fasterxml.jackson.databind.node.ObjectNode;
  45. import com.jeeplus.common.utils.StringUtils;
  46. import com.jeeplus.core.persistence.Page;
  47. import com.jeeplus.core.service.BaseService;
  48. /**
  49. * 流程定义相关Controller
  50. * @author jeeplus
  51. * @version 2016-11-03
  52. */
  53. @Service
  54. @Transactional(readOnly = true)
  55. public class ActProcessService extends BaseService {
  56. @Autowired
  57. private RepositoryService repositoryService;
  58. @Autowired
  59. private RuntimeService runtimeService;
  60. @Autowired
  61. private HistoryService historyService;
  62. @Autowired
  63. private ActTaskService actTaskService;
  64. /**
  65. * 流程定义列表
  66. */
  67. public Page<Map> processList(Page<Map> page, String category) {
  68. ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
  69. .latestVersion().orderByProcessDefinitionKey().asc();
  70. if (StringUtils.isNotEmpty(category)){
  71. processDefinitionQuery.processDefinitionCategory(category);
  72. }
  73. page.setCount(processDefinitionQuery.count());
  74. List<ProcessDefinition> processDefinitionList = Lists.newArrayList();
  75. if(page.getMaxResults() == -1){//不分页
  76. processDefinitionList = processDefinitionQuery.list();
  77. }else {
  78. processDefinitionList = processDefinitionQuery.listPage(page.getFirstResult(), page.getMaxResults());
  79. }
  80. for (ProcessDefinition processDefinition : processDefinitionList) {
  81. String deploymentId = processDefinition.getDeploymentId();
  82. Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
  83. Map pMap = new HashMap<>();
  84. pMap.put("id", processDefinition.getId());
  85. pMap.put("category", processDefinition.getCategory());
  86. pMap.put("key", processDefinition.getKey());
  87. pMap.put("name", processDefinition.getName());
  88. pMap.put("version","V:"+processDefinition.getVersion());
  89. pMap.put("resourceName", processDefinition.getResourceName());
  90. pMap.put("description", processDefinition.getDescription());
  91. pMap.put("diagramResourceName", processDefinition.getDiagramResourceName());
  92. pMap.put("deploymentId", processDefinition.getDeploymentId());
  93. pMap.put("suspended", processDefinition.isSuspended());
  94. pMap.put("deploymentTime",deployment.getDeploymentTime());
  95. page.getList().add(pMap);
  96. }
  97. return page;
  98. }
  99. /**
  100. * 运行中的流程
  101. */
  102. public Page<HashMap<String,Object>> runningList(Page<ProcessInstance> page, String procInsId, String procDefKey) throws Exception{
  103. List<HashMap<String,Object>> result = new ArrayList<HashMap<String,Object>>();
  104. Page<HashMap<String,Object>> resultPage = new Page<>();
  105. ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery().includeProcessVariables();
  106. if (StringUtils.isNotBlank(procInsId)){
  107. processInstanceQuery.processInstanceId(procInsId);
  108. }
  109. if (StringUtils.isNotBlank(procDefKey)){
  110. processInstanceQuery.processDefinitionKey(procDefKey);
  111. }
  112. page.setCount(processInstanceQuery.count());
  113. resultPage.setCount(processInstanceQuery.count());
  114. List<ProcessInstance> runningList = Lists.newArrayList();
  115. if(page.getMaxResults() == -1){//不分页
  116. runningList = processInstanceQuery.list();
  117. }else{
  118. runningList = processInstanceQuery.listPage(page.getFirstResult(), page.getMaxResults());
  119. }
  120. for (ProcessInstance p : runningList) {
  121. String state = actTaskService.queryProcessState(p.getId());
  122. HashMap<String,Object> map = new HashMap<String,Object>();
  123. map.put("id", p.getId());
  124. map.put("processDefinitionName", p.getProcessDefinitionName());
  125. map.put("processInstanceId", p.getProcessInstanceId());
  126. map.put("processDefinitionId", p.getProcessDefinitionId());
  127. map.put("activityId", p.getActivityId());
  128. map.put("vars",p.getProcessVariables());
  129. map.put("state", state);
  130. result.add(map);
  131. }
  132. resultPage.setList(result);
  133. return resultPage;
  134. }
  135. /**
  136. * 已结束的流程
  137. */
  138. public Page<HistoricProcessInstance> historyList(Page<HistoricProcessInstance> page, String procInsId, String procDefKey) {
  139. HistoricProcessInstanceQuery query=historyService.createHistoricProcessInstanceQuery().includeProcessVariables().finished()
  140. .orderByProcessInstanceEndTime().desc();
  141. if (StringUtils.isNotBlank(procInsId)){
  142. query.processInstanceId(procInsId);
  143. }
  144. if (StringUtils.isNotBlank(procDefKey)){
  145. query.processDefinitionKey(procDefKey);
  146. }
  147. page.setCount(query.count());
  148. List list = Lists.newArrayList();
  149. if(page.getMaxResults() == -1){
  150. list = query.list();
  151. }else {
  152. list = query.listPage(page.getFirstResult(), page.getMaxResults());
  153. }
  154. page.setList(list);
  155. return page;
  156. }
  157. /**
  158. * 读取资源,通过部署ID
  159. */
  160. public InputStream resourceRead(String procDefId, String proInsId, String resType) throws Exception {
  161. if (StringUtils.isBlank(procDefId)){
  162. ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(proInsId).singleResult();
  163. procDefId = processInstance.getProcessDefinitionId();
  164. }
  165. ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId).singleResult();
  166. String resourceName = "";
  167. if (resType.equals("image")) {
  168. resourceName = processDefinition.getDiagramResourceName();
  169. } else if (resType.equals("xml")) {
  170. resourceName = processDefinition.getResourceName();
  171. }
  172. InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
  173. return resourceAsStream;
  174. }
  175. /**
  176. * 部署流程 - 保存
  177. * @param file
  178. * @return
  179. */
  180. @Transactional(readOnly = false)
  181. public AjaxJson deploy(String exportDir, String category, MultipartFile file) {
  182. AjaxJson j = new AjaxJson();
  183. String message = "";
  184. String fileName = file.getOriginalFilename();
  185. try {
  186. InputStream fileInputStream = file.getInputStream();
  187. Deployment deployment = null;
  188. String extension = FilenameUtils.getExtension(fileName);
  189. if (extension.equals("zip") || extension.equals("bar")) {
  190. ZipInputStream zip = new ZipInputStream(fileInputStream);
  191. deployment = repositoryService.createDeployment().addZipInputStream(zip).deploy();
  192. } else if (extension.equals("png")) {
  193. deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
  194. } else if (fileName.indexOf("bpmn20.xml") != -1) {
  195. deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
  196. } else if (extension.equals("bpmn")) { // bpmn扩展名特殊处理,转换为bpmn20.xml
  197. String baseName = FilenameUtils.getBaseName(fileName);
  198. deployment = repositoryService.createDeployment().addInputStream(baseName + ".bpmn20.xml", fileInputStream).deploy();
  199. } else {
  200. j.setSuccess(false);
  201. j.setMsg("不支持的文件类型:" + extension);
  202. return j;
  203. }
  204. List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();
  205. // 设置流程分类
  206. for (ProcessDefinition processDefinition : list) {
  207. // ActUtils.exportDiagramToFile(repositoryService, processDefinition, exportDir);
  208. repositoryService.setProcessDefinitionCategory(processDefinition.getId(), category);
  209. message += "部署成功,流程ID=" + processDefinition.getId() + "<br/>";
  210. }
  211. if (list.size() == 0){
  212. j.setSuccess(false);
  213. j.setMsg( "部署失败,没有流程。");
  214. return j;
  215. }
  216. } catch (Exception e) {
  217. throw new ActivitiException("部署失败!", e);
  218. }
  219. j.setMsg(message);
  220. return j;
  221. }
  222. /**
  223. * 设置流程分类
  224. */
  225. @Transactional(readOnly = false)
  226. public void updateCategory(String procDefId, String category) {
  227. repositoryService.setProcessDefinitionCategory(procDefId, category);
  228. }
  229. /**
  230. * 挂起、激活流程实例
  231. */
  232. @Transactional(readOnly = false)
  233. public String updateState(String state, String procDefId) {
  234. if (state.equals("active")) {
  235. repositoryService.activateProcessDefinitionById(procDefId, true, null);
  236. return "已激活ID为[" + procDefId + "]的流程定义。";
  237. } else if (state.equals("suspend")) {
  238. repositoryService.suspendProcessDefinitionById(procDefId, true, null);
  239. return "已挂起ID为[" + procDefId + "]的流程定义。";
  240. }
  241. return "无操作";
  242. }
  243. /**
  244. * 将部署的流程转换为模型
  245. * @param procDefId
  246. * @throws UnsupportedEncodingException
  247. * @throws XMLStreamException
  248. */
  249. @Transactional(readOnly = false)
  250. public org.activiti.engine.repository.Model convertToModel(String procDefId) throws UnsupportedEncodingException, XMLStreamException {
  251. ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId).singleResult();
  252. InputStream bpmnStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
  253. processDefinition.getResourceName());
  254. XMLInputFactory xif = XMLInputFactory.newInstance();
  255. InputStreamReader in = new InputStreamReader(bpmnStream, "UTF-8");
  256. XMLStreamReader xtr = xif.createXMLStreamReader(in);
  257. BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);
  258. BpmnJsonConverter converter = new BpmnJsonConverter();
  259. ObjectNode modelNode = converter.convertToJson(bpmnModel);
  260. org.activiti.engine.repository.Model modelData = repositoryService.newModel();
  261. modelData.setKey(processDefinition.getKey());
  262. modelData.setName(processDefinition.getResourceName());
  263. modelData.setCategory(processDefinition.getCategory());//.getDeploymentId());
  264. modelData.setDeploymentId(processDefinition.getDeploymentId());
  265. modelData.setVersion(Integer.parseInt(String.valueOf(repositoryService.createModelQuery().modelKey(modelData.getKey()).count()+1)));
  266. ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
  267. modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, processDefinition.getName());
  268. modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, modelData.getVersion());
  269. modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, processDefinition.getDescription());
  270. modelData.setMetaInfo(modelObjectNode.toString());
  271. repositoryService.saveModel(modelData);
  272. repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8"));
  273. return modelData;
  274. }
  275. /**
  276. * 导出图片文件到硬盘
  277. */
  278. public List<String> exportDiagrams(String exportDir) throws IOException {
  279. List<String> files = new ArrayList<String>();
  280. List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
  281. for (ProcessDefinition processDefinition : list) {
  282. String diagramResourceName = processDefinition.getDiagramResourceName();
  283. String key = processDefinition.getKey();
  284. int version = processDefinition.getVersion();
  285. String diagramPath = "";
  286. InputStream resourceAsStream = repositoryService.getResourceAsStream(
  287. processDefinition.getDeploymentId(), diagramResourceName);
  288. byte[] b = new byte[resourceAsStream.available()];
  289. @SuppressWarnings("unused")
  290. int len = -1;
  291. resourceAsStream.read(b, 0, b.length);
  292. // create file if not exist
  293. String diagramDir = exportDir + "/" + key + "/" + version;
  294. File diagramDirFile = new File(diagramDir);
  295. if (!diagramDirFile.exists()) {
  296. diagramDirFile.mkdirs();
  297. }
  298. diagramPath = diagramDir + "/" + diagramResourceName;
  299. File file = new File(diagramPath);
  300. // 文件存在退出
  301. if (file.exists()) {
  302. // 文件大小相同时直接返回否则重新创建文件(可能损坏)
  303. logger.debug("diagram exist, ignore... : {}", diagramPath);
  304. files.add(diagramPath);
  305. } else {
  306. file.createNewFile();
  307. logger.debug("export diagram to : {}", diagramPath);
  308. // wirte bytes to file
  309. FileUtils.writeByteArrayToFile(file, b, true);
  310. files.add(diagramPath);
  311. }
  312. }
  313. return files;
  314. }
  315. /**
  316. * 删除部署的流程,级联删除流程实例
  317. * @param deploymentId 流程部署ID
  318. */
  319. @Transactional(readOnly = false)
  320. public void deleteDeployment(String deploymentId) {
  321. repositoryService.deleteDeployment(deploymentId, true);
  322. }
  323. /**
  324. * 删除运行中的流程实例
  325. * @param procInsId 流程实例ID
  326. * @param deleteReason 删除原因,可为空
  327. */
  328. @Transactional(readOnly = false)
  329. public void deleteProcIns(String procInsId, String deleteReason) {
  330. runtimeService.deleteProcessInstance(procInsId, deleteReason);
  331. }
  332. /**
  333. * 删除历史流程
  334. */
  335. @Transactional(readOnly = false)
  336. public void delHistoryProcInsById(String procInsId) {
  337. historyService.deleteHistoricProcessInstance(procInsId);
  338. }
  339. /**
  340. * 获取流程定义
  341. */
  342. public ProcessDefinition getProcessDefinition(String proDefId) {
  343. ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
  344. .latestVersion().orderByProcessDefinitionKey().asc();
  345. if (StringUtils.isNotBlank(proDefId)){
  346. processDefinitionQuery.processDefinitionId(proDefId);
  347. }
  348. /* if (StringUtils.isNotBlank(procDefKey)){获取流程图节点信息
  349. processInstanceQuery.processDefinitionKey(procDefKey);
  350. }*/
  351. ProcessDefinition p = processDefinitionQuery.singleResult();
  352. // act.setProcDefKey(procDefKey);
  353. return p;
  354. }
  355. }