瀏覽代碼

降低activiti版本解决图片渲染bug

赵冬冬 3 年之前
父節點
當前提交
0669203869

+ 6 - 10
src/main/java/com/ruoyi/framework/config/activiti/ProcessDiagramGenarateExt.java

@@ -12,10 +12,10 @@ import java.util.List;
 
 public class ProcessDiagramGenarateExt extends DefaultProcessDiagramGenerator {
 
-    public InputStream generateDiagram(boolean end,BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows,
+    public InputStream generateDiagram(boolean end,BpmnModel bpmnModel, String imageType,List<String>  nowActivityIdList,List<String> highLightedActivities, List<String> highLightedFlows,
                                        String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {
 
-        return generateProcessDiagram(end,bpmnModel, imageType, highLightedActivities, highLightedFlows,
+        return generateProcessDiagram(end,bpmnModel, imageType,nowActivityIdList,highLightedActivities, highLightedFlows,
                 activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor).generateImage(imageType);
     }
 
@@ -88,7 +88,7 @@ public class ProcessDiagramGenarateExt extends DefaultProcessDiagramGenerator {
 
 
     //@Override
-    protected DefaultProcessDiagramCanvas generateProcessDiagram(boolean end, BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {
+    protected DefaultProcessDiagramCanvas generateProcessDiagram(boolean end, BpmnModel bpmnModel, String imageType,List<String>  nowActivityIdList, List<String> highLightedActivities, List<String> highLightedFlows, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor) {
         this.prepareBpmnModel(bpmnModel);
         DefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
         // Draw pool shape, if process is participant in collaboration
@@ -132,13 +132,9 @@ public class ProcessDiagramGenarateExt extends DefaultProcessDiagramGenerator {
                 }
             }
         }
-        if(!end){
-            int size = highLightedActivities.size();
-            if(size>0){
-                String s = highLightedActivities.get( size- 1);
-                GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(s);
-                drawHighLight(processDiagramCanvas,graphicInfo , Color.RED);
-            }
+        for (String s : nowActivityIdList) {
+            GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(s);
+            drawHighLight(processDiagramCanvas,graphicInfo , Color.RED);
         }
         return processDiagramCanvas;
     }

+ 24 - 6
src/main/java/com/ruoyi/project/activiti/controller/LeaveNewController.java

@@ -8,21 +8,21 @@ import com.ruoyi.framework.web.domain.AjaxResult;
 import com.ruoyi.framework.web.page.TableDataInfo;
 import com.ruoyi.project.activiti.domain.*;
 import com.ruoyi.project.activiti.service.LeaveNewService;
+import com.ruoyi.project.activiti.service.impl.MyProcessInstanceHighlightsResource;
 import com.ruoyi.project.system.domain.SysUser;
 import org.activiti.bpmn.model.*;
 import org.activiti.bpmn.model.Process;
-import org.activiti.engine.HistoryService;
-import org.activiti.engine.ProcessEngine;
-import org.activiti.engine.RepositoryService;
-import org.activiti.engine.RuntimeService;
+import org.activiti.engine.*;
 import org.activiti.engine.history.HistoricActivityInstance;
 import org.activiti.engine.history.HistoricProcessInstance;
 import org.activiti.engine.history.HistoricTaskInstance;
 import org.activiti.engine.impl.RepositoryServiceImpl;
 import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
+import org.activiti.engine.impl.pvm.process.ActivityImpl;
 import org.activiti.engine.repository.ProcessDefinition;
 import org.activiti.engine.repository.ProcessDefinitionQuery;
 import org.activiti.engine.runtime.ProcessInstance;
+import org.activiti.engine.task.Task;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
@@ -47,6 +47,9 @@ public class LeaveNewController extends BaseController {
     @Autowired
     private LeaveNewService leaveNewService;
 
+    @Autowired
+    private TaskService taskService;
+
     /**
      * 更具流程key获取开始表单key
      *
@@ -233,6 +236,8 @@ public class LeaveNewController extends BaseController {
 
     @Autowired
     private RuntimeService runtimeService;
+    @Autowired
+    private MyProcessInstanceHighlightsResource myProcessInstanceHighlightsResource;
 
     private void showImage(String processDefinitionKey, Integer version, String processInstanceId, HttpServletResponse response) throws IOException {
         //logger.info("[开始]-获取流程图图像");
@@ -262,7 +267,18 @@ public class LeaveNewController extends BaseController {
                 // 已执行的线集合
                 List<String> flowIds = new ArrayList<>();
                 // 获取流程走过的线 (getHighLightedFlows是下面的方法)
-                flowIds = executedFlowIdList(bpmnModel, processDefinition, historicActivityInstanceList);
+                //flowIds = executedFlowIdList(bpmnModel, processDefinition, historicActivityInstanceList);
+                flowIds = myProcessInstanceHighlightsResource.getHighLightedFlows(processDefinition, processInstanceId);
+
+                List<Task> listTask = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
+
+
+                //当前节点信息
+                List<String> nowActivityIdList = new ArrayList<String>();
+                for (Task task : listTask) {
+                    String taskDefinitionKey = task.getTaskDefinitionKey();
+                    nowActivityIdList.add(taskDefinitionKey);
+                }
                 // 获取流程图图像字符流
                 ProcessDiagramGenarateExt pec = new ProcessDiagramGenarateExt();
 
@@ -272,7 +288,7 @@ public class LeaveNewController extends BaseController {
                     end = true;
                 }
                 //配置字体
-                InputStream imageStream = pec.generateDiagram(end, bpmnModel, "png", executedActivityIdList, flowIds, "宋体", "宋体", "宋体", null, 2.0);
+                InputStream imageStream = pec.generateDiagram(end, bpmnModel, "png",nowActivityIdList, executedActivityIdList, flowIds, "宋体", "宋体", "宋体", null, 2.0);
 //                InputStream inputStream = pec.generateDiagram(bpmnModel, "png", executedActivityIdList);
 
                 response.setContentType("image/png");
@@ -294,6 +310,7 @@ public class LeaveNewController extends BaseController {
     }
 
 
+
     private static List<String> executedFlowIdList(BpmnModel bpmnModel, ProcessDefinitionEntity processDefinitionEntity,
                                                    List<HistoricActivityInstance> historicActivityInstanceList) {
 
@@ -301,6 +318,7 @@ public class LeaveNewController extends BaseController {
         Set<String> ids = new HashSet<>();
         Map<String, SequenceFlow> flowHashMap = new HashMap<>();
         List<String> activityIds = historicActivityInstanceList.stream().map(X -> X.getActivityId()).collect(Collectors.toList());
+
         for (int i = 0; i < historicActivityInstanceList.size(); i++) {
             HistoricActivityInstance hai = historicActivityInstanceList.get(i);
             String activityId = hai.getActivityId();

+ 251 - 0
src/main/java/com/ruoyi/project/activiti/service/impl/MyProcessInstanceHighlightsResource.java

@@ -0,0 +1,251 @@
+package com.ruoyi.project.activiti.service.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.activiti.engine.HistoryService;
+import org.activiti.engine.RepositoryService;
+import org.activiti.engine.RuntimeService;
+import org.activiti.engine.history.HistoricActivityInstance;
+import org.activiti.engine.history.HistoricProcessInstance;
+import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
+import org.activiti.engine.impl.pvm.PvmTransition;
+import org.activiti.engine.impl.pvm.process.ActivityImpl;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.*;
+
+@Service
+public class MyProcessInstanceHighlightsResource {
+
+    @Autowired
+    private RuntimeService runtimeService;
+
+    @Autowired
+    private RepositoryService repositoryService;
+
+    @Autowired
+    private HistoryService historyService;
+
+    protected ObjectMapper objectMapper = new ObjectMapper();
+
+//    @RequestMapping(value = "/process-instance/{processInstanceId}/highlights", method = RequestMethod.GET, produces = "application/json")
+//    public ObjectNode getHighlighted(@PathVariable String processInstanceId) {
+//
+//        ObjectNode responseJSON = objectMapper.createObjectNode();
+//
+//        responseJSON.put("processInstanceId", processInstanceId);
+//
+//        ArrayNode activitiesArray = objectMapper.createArrayNode();
+//        ArrayNode flowsArray = objectMapper.createArrayNode();
+//
+//        try {
+//            //  获取历史流程实例
+//            HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery()
+//                    .processInstanceId(processInstanceId).singleResult();
+//            //ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
+//            ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(processInstance.getProcessDefinitionId());
+//
+//            responseJSON.put("processDefinitionId", processInstance.getProcessDefinitionId());
+//            // 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
+//            List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
+//                    .processInstanceId(processInstanceId).orderByHistoricActivityInstanceId().asc().list();
+//            // 已执行的节点ID集合
+//            List<String> highLightedActivities = new ArrayList<String>();
+//            //logger.info("获取已经执行的节点ID");
+//            for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
+//                highLightedActivities.add(activityInstance.getActivityId());
+//            }
+//            //List<String> highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId);
+//            List<String> highLightedFlows = getHighLightedFlows(processDefinition, processInstanceId);
+//
+//            for (String activityId : highLightedActivities) {
+//                activitiesArray.add(activityId);
+//            }
+//
+//            for (String flow : highLightedFlows) {
+//                flowsArray.add(flow);
+//            }
+//
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        }
+//
+//        responseJSON.put("activities", activitiesArray);
+//        responseJSON.put("flows", flowsArray);
+//
+//        return responseJSON;
+//    }
+
+
+    /**
+     * getHighLightedFlows
+     *
+     * @param processDefinition
+     * @param processInstanceId
+     * @return
+     */
+    public List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinition, String processInstanceId) {
+
+        List<String> highLightedFlows = new ArrayList<String>();
+
+        List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
+                .processInstanceId(processInstanceId)
+                //order by startime asc is not correct. use default order is correct.
+                //.orderByHistoricActivityInstanceStartTime().asc()/*.orderByActivityId().asc()*/
+                .list();
+
+        LinkedList<HistoricActivityInstance> hisActInstList = new LinkedList<HistoricActivityInstance>();
+        hisActInstList.addAll(historicActivityInstances);
+
+        getHighlightedFlows(processDefinition.getActivities(), hisActInstList, highLightedFlows);
+
+        return highLightedFlows;
+    }
+
+    /**
+     * getHighlightedFlows
+     * <p>
+     * code logic:
+     * 1. Loop all activities by id asc order;
+     * 2. Check each activity's outgoing transitions and eventBoundery outgoing transitions, if outgoing transitions's destination.id is in other executed activityIds, add this transition to highLightedFlows List;
+     * 3. But if activity is not a parallelGateway or inclusiveGateway, only choose the earliest flow.
+     *
+     * @param activityList
+     * @param hisActInstList
+     * @param highLightedFlows
+     */
+    private void getHighlightedFlows(List<ActivityImpl> activityList, LinkedList<HistoricActivityInstance> hisActInstList, List<String> highLightedFlows) {
+
+        //check out startEvents in activityList
+        List<ActivityImpl> startEventActList = new ArrayList<ActivityImpl>();
+        Map<String, ActivityImpl> activityMap = new HashMap<String, ActivityImpl>(activityList.size());
+        for (ActivityImpl activity : activityList) {
+
+            activityMap.put(activity.getId(), activity);
+
+            String actType = (String) activity.getProperty("type");
+            if (actType != null && actType.toLowerCase().indexOf("startevent") >= 0) {
+                startEventActList.add(activity);
+            }
+        }
+
+        //These codes is used to avoid a bug:
+        //ACT-1728 If the process instance was started by a callActivity, it will be not have the startEvent activity in ACT_HI_ACTINST table
+        //Code logic:
+        //Check the first activity if it is a startEvent, if not check out the startEvent's highlight outgoing flow.
+        HistoricActivityInstance firstHistActInst = hisActInstList.getFirst();
+        String firstActType = (String) firstHistActInst.getActivityType();
+        if (firstActType != null && firstActType.toLowerCase().indexOf("startevent") < 0) {
+            PvmTransition startTrans = getStartTransaction(startEventActList, firstHistActInst);
+            if (startTrans != null) {
+                highLightedFlows.add(startTrans.getId());
+            }
+        }
+
+        while (!hisActInstList.isEmpty()) {
+            HistoricActivityInstance histActInst = hisActInstList.removeFirst();
+            ActivityImpl activity = activityMap.get(histActInst.getActivityId());
+            if (activity != null) {
+                boolean isParallel = false;
+                String type = histActInst.getActivityType();
+                if ("parallelGateway".equals(type) || "inclusiveGateway".equals(type)) {
+                    isParallel = true;
+                } else if ("subProcess".equals(histActInst.getActivityType())) {
+                    getHighlightedFlows(activity.getActivities(), hisActInstList, highLightedFlows);
+                }
+
+                List<PvmTransition> allOutgoingTrans = new ArrayList<PvmTransition>();
+                allOutgoingTrans.addAll(activity.getOutgoingTransitions());
+                allOutgoingTrans.addAll(getBoundaryEventOutgoingTransitions(activity));
+                List<String> activityHighLightedFlowIds = getHighlightedFlows(allOutgoingTrans, hisActInstList, isParallel);
+                highLightedFlows.addAll(activityHighLightedFlowIds);
+            }
+        }
+    }
+
+    /**
+     * Check out the outgoing transition connected to firstActInst from startEventActList
+     *
+     * @param startEventActList
+     * @param firstActInst
+     * @return
+     */
+    private PvmTransition getStartTransaction(List<ActivityImpl> startEventActList, HistoricActivityInstance firstActInst) {
+        for (ActivityImpl startEventAct : startEventActList) {
+            for (PvmTransition trans : startEventAct.getOutgoingTransitions()) {
+                if (trans.getDestination().getId().equals(firstActInst.getActivityId())) {
+                    return trans;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * getBoundaryEventOutgoingTransitions
+     *
+     * @param activity
+     * @return
+     */
+    private List<PvmTransition> getBoundaryEventOutgoingTransitions(ActivityImpl activity) {
+        List<PvmTransition> boundaryTrans = new ArrayList<PvmTransition>();
+        for (ActivityImpl subActivity : activity.getActivities()) {
+            String type = (String) subActivity.getProperty("type");
+            if (type != null && type.toLowerCase().indexOf("boundary") >= 0) {
+                boundaryTrans.addAll(subActivity.getOutgoingTransitions());
+            }
+        }
+        return boundaryTrans;
+    }
+
+    /**
+     * find out single activity's highlighted flowIds
+     *
+     * @param activity
+     * @param hisActInstList
+     * @param isExclusive    if true only return one flowId(Such as exclusiveGateway, BoundaryEvent On Task)
+     * @return
+     */
+    private List<String> getHighlightedFlows(List<PvmTransition> pvmTransitionList, LinkedList<HistoricActivityInstance> hisActInstList, boolean isParallel) {
+
+        List<String> highLightedFlowIds = new ArrayList<String>();
+
+        PvmTransition earliestTrans = null;
+        HistoricActivityInstance earliestHisActInst = null;
+
+        for (PvmTransition pvmTransition : pvmTransitionList) {
+
+            String destActId = pvmTransition.getDestination().getId();
+            HistoricActivityInstance destHisActInst = findHisActInst(hisActInstList, destActId);
+            if (destHisActInst != null) {
+                if (isParallel) {
+                    highLightedFlowIds.add(pvmTransition.getId());
+                } else if (earliestHisActInst == null || (earliestHisActInst.getId().compareTo(destHisActInst.getId()) > 0)) {
+                    earliestTrans = pvmTransition;
+                    earliestHisActInst = destHisActInst;
+                }
+            }
+        }
+
+        if ((!isParallel) && earliestTrans != null) {
+            highLightedFlowIds.add(earliestTrans.getId());
+        }
+
+        return highLightedFlowIds;
+    }
+
+    private HistoricActivityInstance findHisActInst(LinkedList<HistoricActivityInstance> hisActInstList, String actId) {
+        for (HistoricActivityInstance hisActInst : hisActInstList) {
+            if (hisActInst.getActivityId().equals(actId)) {
+                return hisActInst;
+            }
+        }
+        return null;
+    }
+}

+ 7 - 7
src/main/resources/application.yml

@@ -41,7 +41,7 @@ spring:
   messages:
     # 国际化资源文件路径
     basename: i18n/messages
-  profiles: 
+  profiles:
     active: druid
   # 文件上传
   servlet:
@@ -93,8 +93,8 @@ token:
     # 令牌秘钥
     secret: abcdefghijklmnopqrstuvwxyz
     # 令牌有效期(默认30分钟)
-    expireTime: 30
-  
+    expireTime: 300
+
 # MyBatis配置
 mybatis:
     # 搜索指定包别名
@@ -105,17 +105,17 @@ mybatis:
     configLocation: classpath:mybatis/mybatis-config.xml
 
 # PageHelper分页插件
-pagehelper: 
+pagehelper:
   helperDialect: mysql
   reasonable: true
   supportMethodsArguments: true
-  params: count=countSql 
+  params: count=countSql
 
 # 防止XSS攻击
-xss: 
+xss:
   # 过滤开关
   enabled: true
   # 排除链接(多个用逗号分隔)
   excludes: /system/notice/*,/prod-api/*
   # 匹配链接
-  urlPatterns: /system/*,/monitor/*,/tool/*
+  urlPatterns: /system/*,/monitor/*,/tool/*