FlowProcessController.java 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. *
  7. * Redistributions of source code must retain the above copyright notice,
  8. * this list of conditions and the following disclaimer.
  9. * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * Neither the name of the dreamlu.net developer nor the names of its
  13. * contributors may be used to endorse or promote products derived from
  14. * this software without specific prior written permission.
  15. * Author: Chill 庄骞 (smallchill@163.com)
  16. */
  17. package org.springblade.flow.engine.controller;
  18. import lombok.AllArgsConstructor;
  19. import lombok.extern.slf4j.Slf4j;
  20. import org.flowable.bpmn.model.BpmnModel;
  21. import org.flowable.common.engine.impl.util.IoUtil;
  22. import org.flowable.engine.*;
  23. import org.flowable.engine.history.HistoricActivityInstance;
  24. import org.flowable.engine.history.HistoricProcessInstance;
  25. import org.flowable.engine.repository.ProcessDefinition;
  26. import org.flowable.engine.runtime.ProcessInstance;
  27. import org.flowable.image.ProcessDiagramGenerator;
  28. import org.springblade.core.launch.constant.AppConstant;
  29. import org.springblade.core.tenant.annotation.NonDS;
  30. import org.springblade.core.tool.api.R;
  31. import org.springblade.core.tool.utils.StringUtil;
  32. import org.springblade.flow.core.entity.BladeFlow;
  33. import org.springblade.flow.engine.service.FlowEngineService;
  34. import org.springframework.web.bind.annotation.GetMapping;
  35. import org.springframework.web.bind.annotation.RequestMapping;
  36. import org.springframework.web.bind.annotation.RequestParam;
  37. import org.springframework.web.bind.annotation.RestController;
  38. import springfox.documentation.annotations.ApiIgnore;
  39. import javax.servlet.http.HttpServletResponse;
  40. import java.io.IOException;
  41. import java.io.InputStream;
  42. import java.io.OutputStream;
  43. import java.util.ArrayList;
  44. import java.util.List;
  45. /**
  46. * 流程通用控制器
  47. *
  48. * @author Chill
  49. */
  50. @NonDS
  51. @Slf4j
  52. @RestController
  53. @AllArgsConstructor
  54. @RequestMapping(AppConstant.APPLICATION_FLOW_NAME + "/process")
  55. @ApiIgnore
  56. public class FlowProcessController {
  57. private static final String IMAGE_NAME = "image";
  58. private static final String XML_NAME = "xml";
  59. private static final Integer INT_1024 = 1024;
  60. private final RepositoryService repositoryService;
  61. private final RuntimeService runtimeService;
  62. private final HistoryService historyService;
  63. private final ProcessEngine processEngine;
  64. private final FlowEngineService flowEngineService;
  65. /**
  66. * 获取流转历史列表
  67. *
  68. * @param processInstanceId 流程实例id
  69. * @param startActivityId 开始节点id
  70. * @param endActivityId 结束节点id
  71. */
  72. @GetMapping(value = "history-flow-list")
  73. public R<List<BladeFlow>> historyFlowList(@RequestParam String processInstanceId, String startActivityId, String endActivityId) {
  74. return R.data(flowEngineService.historyFlowList(processInstanceId, startActivityId, endActivityId));
  75. }
  76. /**
  77. * 流程图展示
  78. *
  79. * @param processDefinitionId 流程id
  80. * @param processInstanceId 实例id
  81. * @param resourceType 资源类型
  82. * @param response 响应
  83. */
  84. @GetMapping("resource-view")
  85. public void resourceView(@RequestParam String processDefinitionId, String processInstanceId, @RequestParam(defaultValue = IMAGE_NAME) String resourceType, HttpServletResponse response) throws Exception {
  86. if (StringUtil.isAllBlank(processDefinitionId, processInstanceId)) {
  87. return;
  88. }
  89. if (StringUtil.isBlank(processDefinitionId)) {
  90. ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
  91. processDefinitionId = processInstance.getProcessDefinitionId();
  92. }
  93. ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
  94. String resourceName = "";
  95. if (resourceType.equals(IMAGE_NAME)) {
  96. resourceName = processDefinition.getDiagramResourceName();
  97. } else if (resourceType.equals(XML_NAME)) {
  98. resourceName = processDefinition.getResourceName();
  99. }
  100. InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
  101. byte[] b = new byte[1024];
  102. int len;
  103. while ((len = resourceAsStream.read(b, 0, INT_1024)) != -1) {
  104. response.getOutputStream().write(b, 0, len);
  105. }
  106. }
  107. /**
  108. * 获取流程节点进程图
  109. *
  110. * @param processInstanceId 流程实例id
  111. * @param httpServletResponse http响应
  112. */
  113. @GetMapping(value = "diagram-view")
  114. public void diagramView(String processInstanceId, HttpServletResponse httpServletResponse) {
  115. diagram(processInstanceId, httpServletResponse);
  116. }
  117. /**
  118. * 根据流程节点绘图
  119. *
  120. * @param processInstanceId 流程实例id
  121. * @param httpServletResponse http响应
  122. */
  123. private void diagram(String processInstanceId, HttpServletResponse httpServletResponse) {
  124. // 获得当前活动的节点
  125. String processDefinitionId;
  126. // 如果流程已经结束,则得到结束节点
  127. if (this.isFinished(processInstanceId)) {
  128. HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
  129. processDefinitionId = pi.getProcessDefinitionId();
  130. } else {
  131. // 如果流程没有结束,则取当前活动节点
  132. // 根据流程实例ID获得当前处于活动状态的ActivityId合集
  133. ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
  134. processDefinitionId = pi.getProcessDefinitionId();
  135. }
  136. List<String> highLightedActivities = new ArrayList<>();
  137. // 获得活动的节点
  138. List<HistoricActivityInstance> highLightedActivityList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
  139. for (HistoricActivityInstance tempActivity : highLightedActivityList) {
  140. String activityId = tempActivity.getActivityId();
  141. highLightedActivities.add(activityId);
  142. }
  143. List<String> flows = new ArrayList<>();
  144. // 获取流程图
  145. BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
  146. ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration();
  147. ProcessDiagramGenerator diagramGenerator = engConf.getProcessDiagramGenerator();
  148. InputStream in = diagramGenerator.generateDiagram(bpmnModel, "bmp", highLightedActivities, flows, engConf.getActivityFontName(),
  149. engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true);
  150. OutputStream out = null;
  151. byte[] buf = new byte[1024];
  152. int length;
  153. try {
  154. out = httpServletResponse.getOutputStream();
  155. while ((length = in.read(buf)) != -1) {
  156. out.write(buf, 0, length);
  157. }
  158. } catch (IOException e) {
  159. log.error("操作异常", e);
  160. } finally {
  161. IoUtil.closeSilently(out);
  162. IoUtil.closeSilently(in);
  163. }
  164. }
  165. /**
  166. * 是否已完结
  167. *
  168. * @param processInstanceId 流程实例id
  169. * @return bool
  170. */
  171. private boolean isFinished(String processInstanceId) {
  172. return historyService.createHistoricProcessInstanceQuery().finished()
  173. .processInstanceId(processInstanceId).count() > 0;
  174. }
  175. }