SpringBoot之集成activiti5.22.0

目录

  • 一、Activiti简介
  • 二、Maven配置文件的引入
  • 三、添加yml配置
  • 四、配置文件
  • 五、添加工具类
  • 六、添加编辑器
  • 七、添加业务类

一、Activiti简介

Activiti项目是一项新的基于Apache许可的开源BPM平台,从基础开始构建,旨在提供支持新的BPMN 2.0标准,包括支持对象管理组(OMG),面对新技术的机遇,诸如互操作性和云架构,提供技术实现。
其实Activiti就是一个工作流框架,用于实现我们自己业务系统的各种工作流程。

二、Maven配置文件的引入

我们先看Maven的配置
这里排除了org.mybatis、spring-security、slf4j-log4j12等包,org.mybatis是因为我们项目一般都会单独引入,这个包下面的就可以排除掉,spring-security是spring的授权、认证框架,跟shiro功能差不多,这里由于我们项目使用的是shiro,所以把这个排除掉,不然会出现Please sign in的画面,slf4j-log4j12是log4j的日志实现,我们本项目用的是logback-spring实现日志系统,所以这个也排除了,不然springboot启动会报错。

<dependency>
    <groupId>org.activitigroupId>
    <artifactId>activiti-spring-boot-starter-basicartifactId>
    <version>${activiti.version}version>
    <exclusions>
        <exclusion>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
        exclusion>
        
        <exclusion>
            <groupId>de.odysseus.juelgroupId>
            <artifactId>juel-spiartifactId>
        exclusion>
    exclusions>
dependency>
<dependency>
    <groupId>org.activitigroupId>
    <artifactId>activiti-modelerartifactId>
    <version>${activiti.version}version>
    <exclusions>
        <exclusion>
            <artifactId>slf4j-log4j12artifactId>
            <groupId>org.slf4jgroupId>
        exclusion>
        <exclusion>
            <artifactId>spring-security-configartifactId>
            <groupId>org.springframework.securitygroupId>
        exclusion>
        <exclusion>
            <artifactId>spring-security-cryptoartifactId>
            <groupId>org.springframework.securitygroupId>
        exclusion>
        <exclusion>
            <artifactId>spring-security-webartifactId>
            <groupId>org.springframework.securitygroupId>
        exclusion>
    exclusions>
dependency>
<dependency>
    <groupId>org.activitigroupId>
    <artifactId>activiti-diagram-restartifactId>
    <version>${activiti.version}version>
    <exclusions>
        <exclusion>
            <artifactId>spring-security-configartifactId>
            <groupId>org.springframework.securitygroupId>
        exclusion>
        <exclusion>
            <artifactId>spring-security-coreartifactId>
            <groupId>org.springframework.securitygroupId>
        exclusion>
        <exclusion>
            <artifactId>spring-security-webartifactId>
            <groupId>org.springframework.securitygroupId>
        exclusion>
        <exclusion>
            <artifactId>spring-security-cryptoartifactId>
            <groupId>org.springframework.securitygroupId>
        exclusion>
    exclusions>
dependency>
<dependency>
    <groupId>org.activitigroupId>
    <artifactId>activiti-process-validationartifactId>
    <version>${activiti.version}version>
dependency>
<dependency>
    <groupId>org.activitigroupId>
    <artifactId>activiti-restartifactId>
    <version>${activiti.version}version>
    <exclusions>
        <exclusion>
            <artifactId>spring-security-coreartifactId>
            <groupId>org.springframework.securitygroupId>
        exclusion>
        <exclusion>
            <artifactId>spring-security-configartifactId>
            <groupId>org.springframework.securitygroupId>
        exclusion>
        <exclusion>
            <artifactId>spring-security-cryptoartifactId>
            <groupId>org.springframework.securitygroupId>
        exclusion>
        <exclusion>
            <artifactId>spring-security-webartifactId>
            <groupId>org.springframework.securitygroupId>
        exclusion>
        <exclusion>
            <artifactId>slf4j-log4j12artifactId>
            <groupId>org.slf4jgroupId>
        exclusion>
    exclusions>
dependency>
<dependency>
    <groupId>org.activitigroupId>
    <artifactId>activiti-json-converterartifactId>
    <version>${activiti.version}version>
dependency>
<dependency>
    <groupId>org.activitigroupId>
    <artifactId>activiti-image-generatorartifactId>
    <version>${activiti.version}version>
dependency>
<dependency>
    <groupId>org.activitigroupId>
    <artifactId>activiti-common-restartifactId>
    <version>${activiti.version}version>
dependency>
<dependency>
    <groupId>org.activitigroupId>
    <artifactId>activiti-bpmn-modelartifactId>
    <version>${activiti.version}version>
dependency>
<dependency>
    <groupId>org.activitigroupId>
    <artifactId>activiti-bpmn-converterartifactId>
    <version>${activiti.version}version>
dependency>
<dependency>
    <groupId>com.fasterxml.uuidgroupId>
    <artifactId>java-uuid-generatorartifactId>
    <version>3.1.4version>
dependency>

三、添加yml配置

activiti及数据库连接的配置

Activiti提供了history-level属性对其进行配置。history-level属性有点像log4j的日志输出级别,该属性有以下四个值:
none:不保存任何的历史数据,因此,在流程执行过程中,这是最高效的。
activity:级别高于none,保存流程实例与流程行为,其他数据不保存。
audit:除activity级别会保存的数据外,还会保存全部的流程任务及其属性。audit为history的默认值。
full:保存历史数据的最高级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括一些流程参数等。

spring:
  activiti:
    database-schema-update: true   #是否更新数据库
    check-process-definitions: false # 自动部署验证设置:true-开启(默认)、false-关闭
    history-level: full #history-level属性
    db-history-used: true #是否使用activti历史表
    db-identity-used: true #是否使用activti身份信息表
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    #druid连接池配置
    druid:
     driverClassName: com.mysql.jdbc.Driver
     url: jdbc:mysql://192.168.1.254:3306/zxhycloudnew2?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false
     username: root
     password: 111111
     initial-size: 10
     # 最大连接数
     max-active: 50
     #最小连接数
     min-idle: 10
     #获取连接等待超时时间
     max-wait: 5000
     pool-prepared-statements: true #是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
     max-pool-prepared-statement-per-connection-size: 20
     validation-query: SELECT 1 FROM DUAL
     validation-query-timeout: 20000
     test-on-borrow: false #申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
     test-on-return: false #归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
     test-while-idle: true #建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
     time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
     min-evictable-idle-time-millis: 300000  #一个连接在池中最小生存的时间,单位是毫秒
     #StatViewServlet配置。(因为暴露的监控信息比较敏感,支持密码加密和访问ip限定)
     stat-view-servlet:
      enabled: true
      url-pattern: /druid/*
      #可以增加访问账号密码【去掉注释就可以】
      #login-username: admin
      #login-password: admin
     filter:
      stat:
        log-slow-sql: true
        slow-sql-millis: 1000
        merge-sql: true
      wall:
        config:
          multi-statement-allow: true

本datasource是DruidDataSource的,大家也可以按照自己的需要进行调整。

四、配置文件

添加java配置文件进行常用的几个service的配置
扫描包"org.activiti.rest.editor", "org.activiti.rest.diagram"下的controller组件,这个是web编辑器需要的。

package com.zxhy.config;

import org.activiti.engine.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;


@Configuration
@ComponentScan(basePackages = {"org.activiti.rest.editor", "org.activiti.rest.diagram"}, includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = org.springframework.web.bind.annotation.RestController.class))
public class ActivitiConfiguration {

    @Autowired
    private ProcessEngine processEngine;

    @Bean
    public ProcessEngineConfiguration processEngineConfiguration(ProcessEngine processEngine) {
        return processEngine.getProcessEngineConfiguration();
    }

    /**
     * RuntimeService
     *
     * @param processEngine
     * @return
     */
    @Bean
    public RuntimeService runtimeService(ProcessEngine processEngine) {
        return processEngine.getRuntimeService();
    }

    /**
     * TaskService
     *
     * @param processEngine
     * @return
     */
    @Bean
    public TaskService taskService(ProcessEngine processEngine) {
        return processEngine.getTaskService();
    }

    /**
     * RepositoryService
     *
     * @param processEngine
     * @return
     */
    @Bean
    public RepositoryService repositoryService(ProcessEngine processEngine) {
        return processEngine.getRepositoryService();
    }

    /**
     * HistoryService
     *
     * @param processEngine
     * @return
     */
    @Bean
    public HistoryService historyService(ProcessEngine processEngine) {
        return processEngine.getHistoryService();
    }

    /**
     * IdentityService
     *
     * @param processEngine
     * @return
     */
    @Bean
    public IdentityService identityService(ProcessEngine processEngine) {
        return processEngine.getIdentityService();
    }

    /**
     * FormService
     *
     * @param processEngine
     * @return
     */
    @Bean
    public FormService formService(ProcessEngine processEngine) {
        return processEngine.getFormService();
    }

    /**
     * ManagementService
     *
     * @param processEngine
     * @return
     */
    @Bean
    public ManagementService managementService(ProcessEngine processEngine) {
        return processEngine.getManagementService();
    }
}

五、添加工具类

package com.zxhy.activiti.utils;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.zxhy.base.common.Constant;
import com.zxhy.base.exception.MyException;
import com.zxhy.base.utils.SpringContextUtils;
import com.zxhy.base.utils.StringUtils;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
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.javax.el.ExpressionFactory;
import org.activiti.engine.impl.javax.el.ValueExpression;
import org.activiti.engine.impl.juel.ExpressionFactoryImpl;
import org.activiti.engine.impl.juel.SimpleContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.engine.task.Task;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * 类的功能描述.
 * 流程工具类
 * @Auther zxhy
 * @Date 2017/7/28
 */
public class ActUtils {
    private static RepositoryService repositoryService = (RepositoryService) SpringContextUtils.getBean("repositoryService");
    private static HistoryService historyService = (HistoryService) SpringContextUtils.getBean("historyService");
    private static RuntimeService runtimeService = (RuntimeService) SpringContextUtils.getBean("runtimeService");
    private static TaskService taskService = (TaskService) SpringContextUtils.getBean("taskService");
    private static ObjectMapper objectMapper = (ObjectMapper) SpringContextUtils.getBean("objectMapper");
    private static ProcessEngineConfiguration processEngineConfiguration = (ProcessEngineConfiguration) SpringContextUtils.getBean("processEngineConfiguration");

    /**
     * 设置会签节点属性
     * 会签相关变量注释:nrOfInstances:实例总数
     *               nrOfActiveInstances:当前活动的,比如,还没完成的,实例数量。 对于顺序执行的多实例,值一直为1
     *               nrOfCompletedInstances:已经完成实例的数目
     *               可以通过execution.getVariable(x)方法获得这些变量
     * @param modelId 模型id
     * @param nodelId 流程对象id
     */
    public static void setMultiInstance(String modelId,String nodelId) throws Exception{
        //获取模型
        byte[] mes = repositoryService.getModelEditorSource(modelId);
        //转换成JsonNode
        JsonNode jsonNode = objectMapper.readTree(mes);
        //转换成BpmnModel
        BpmnJsonConverter bpmnJsonConverter = new BpmnJsonConverter();
        BpmnModel bpmnModel = bpmnJsonConverter.convertToBpmnModel(jsonNode);
        //获取物理形态的流程
        Process process = bpmnModel.getProcesses().get(0);
        //获取节点信息
        FlowElement flowElement = process.getFlowElement(nodelId);
        //只有人工任务才可以设置会签节点
        UserTask userTask = (UserTask)flowElement;
        //设置受理人,这里应该和ElementVariable的值是相同的
        userTask.setAssignee("${"+Constant.ACT_MUIT_VAR_NAME+"}");
        //userTask.setOwner("${user}");

        //获取多实例配置
        MultiInstanceLoopCharacteristics characteristics = new MultiInstanceLoopCharacteristics();
        //设置集合变量,统一设置成users
        characteristics.setInputDataItem(Constant.ACT_MUIT_LIST_NAME);
        //设置变量
        characteristics.setElementVariable(Constant.ACT_MUIT_VAR_NAME);
        //设置为同时接收(false 表示不按顺序执行)
        characteristics.setSequential(false);
        //设置条件(暂时处理成,全部会签完转下步)
        characteristics.setCompletionCondition("${nrOfCompletedInstances==nrOfInstances}");

        userTask.setLoopCharacteristics(characteristics);
        //保存
        ObjectNode objectNode = new BpmnJsonConverter().convertToJson(bpmnModel);
        repositoryService.addModelEditorSource(modelId, objectNode.toString().getBytes("utf-8"));
    }

    /**
     * 清空会签属性
     * @param modelId 模型id
     * @param nodelId 流程对象id
     * @throws Exception
     */
    public static void clearMultiInstance(String modelId,String nodelId) throws Exception{
        //获取模型
        byte[] mes = repositoryService.getModelEditorSource(modelId);
        //转换成JsonNode
        JsonNode jsonNode = new ObjectMapper().readTree(mes);
        //转换成BpmnModel
        BpmnJsonConverter bpmnJsonConverter = new BpmnJsonConverter();
        BpmnModel bpmnModel = bpmnJsonConverter.convertToBpmnModel(jsonNode);
        //获取物理形态的流程
        Process process = bpmnModel.getProcesses().get(0);
        //获取节点信息
        FlowElement flowElement = process.getFlowElement(nodelId);
        //只有人工任务才可以设置会签节点
        UserTask userTask = (UserTask)flowElement;
        //清空受理人
        userTask.setAssignee("");
        //获取多实例配置
        MultiInstanceLoopCharacteristics characteristics = userTask.getLoopCharacteristics();
        if(characteristics!=null){
            //清空集合
            characteristics.setInputDataItem("");
            //清空变量
            characteristics.setElementVariable("");
            //设置为顺序接收(true 表示不按顺序执行)
            characteristics.setSequential(true);
            //清空条件
            characteristics.setCompletionCondition("");
        }

        //保存
        ObjectNode objectNode = new BpmnJsonConverter().convertToJson(bpmnModel);
        repositoryService.addModelEditorSource(modelId, objectNode.toString().getBytes("utf-8"));
    }

    /**
     * 增加流程连线条件
     * @param modelId 模型id
     * @param nodelId 流程对象id
     * @param condition el 条件表达式
     */
    public static void setSequenceFlowCondition(String modelId,String nodelId ,String condition) throws IOException {
        //获取模型--设置连线条件 到 流程中
        byte[] bytes = repositoryService.getModelEditorSource(modelId);
        JsonNode jsonNode = objectMapper.readTree(bytes);
        BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode);
        FlowElement flowElement = bpmnModel.getFlowElement(nodelId);
        if(!(flowElement instanceof SequenceFlow)){
            throw new MyException("不是连线,不能设置条件");
        }
        SequenceFlow sequenceFlow = (SequenceFlow)flowElement;
        sequenceFlow.setConditionExpression(condition);
        ObjectNode objectNode = new BpmnJsonConverter().convertToJson(bpmnModel);
        repositoryService.addModelEditorSource(modelId, objectNode.toString().getBytes("utf-8"));
    }

    /**
     * 根据流程实例Id,获取实时流程图片
     * @param processInstanceId
     * @return
     */
    public static InputStream getFlowImgByInstantId(String processInstanceId){
        if(StringUtils.isEmpty(processInstanceId)){
            return null;
        }
        //获取流程图输入流
        InputStream inputStream = null;
        // 查询历史
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (historicProcessInstance.getEndTime() != null) { // 该流程已经结束
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(historicProcessInstance.getProcessDefinitionId()).singleResult();
            inputStream = repositoryService.getResourceAsStream( processDefinition.getDeploymentId(), processDefinition.getDiagramResourceName());
        } else {
            // 查询当前的流程实例
            ProcessInstance processInstance = runtimeService .createProcessInstanceQuery() .processInstanceId(processInstanceId).singleResult();
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
            ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) repositoryService.createProcessDefinitionQuery().processDefinitionId(processInstance.getProcessDefinitionId()).singleResult();
            List<String> highLightedFlows = new ArrayList<String>();
            List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
            List<String> historicActivityInstanceList = new ArrayList<String>();
            for (HistoricActivityInstance hai : historicActivityInstances) {
                historicActivityInstanceList.add(hai.getActivityId());
            }
            List<String> highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId);
            historicActivityInstanceList.addAll(highLightedActivities);
            for (ActivityImpl activity : processDefinitionEntity.getActivities()) {
                int index = historicActivityInstanceList.indexOf(activity.getId());
                if (index >= 0 && index + 1 < historicActivityInstanceList.size()) {
                    List<PvmTransition> pvmTransitionList = activity.getOutgoingTransitions();
                    for (PvmTransition pvmTransition : pvmTransitionList) {
                        String destinationFlowId = pvmTransition.getDestination().getId();
                        if (destinationFlowId.equals(historicActivityInstanceList.get(index + 1))) {
                            highLightedFlows.add(pvmTransition.getId());
                        }
                    }
                }
            }
            ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
            List<String> activeActivityIds = new ArrayList<String>();
            List<org.activiti.engine.task.Task> tasks = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
            for (org.activiti.engine.task.Task task : tasks) {
                activeActivityIds.add(task.getTaskDefinitionKey());
            }
            inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds, highLightedFlows, "宋体", "宋体", null,null, 1.0);
        }
        return inputStream;
    }

    /**
     * 根据节点Id取得当前节点的下一流向流程节点,如果Id为空则默认为首节点(条件路由则只返回符合条件的流向)
     * @param defid 流程定义Id
     * @param nodelId 流程节点
     * @param elMap 流程变量el表达式集合
     * @return
     */
    public static List<PvmActivity> getNextActNodes(String defid, String nodelId, Map<String,Object> elMap){
        List<PvmActivity> pvmActivities=new ArrayList<PvmActivity>();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(defid).singleResult();
        ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl)repositoryService).getDeployedProcessDefinition(processDefinition.getId());
        //获取所有节点
        List<ActivityImpl> activitiList = def.getActivities();
        //然后循环activitiList 并判断出当前流程所处节点,然后得到当前节点实例,根据节点实例获取所有从当前节点出发的路径,然后根据路径获得下一个节点实例:
        for(ActivityImpl activityImpl:activitiList){
            String id = activityImpl.getId();
            if("".equals(nodelId)){
                Object o = activityImpl.getProperties().get("type");
                if(o.equals("startEvent")){
                    //startEvent节点
                    PvmTransition startEvent = activityImpl.getOutgoingTransitions().get(0);
                    List<PvmTransition> pvmTransitions = startEvent.getDestination().getOutgoingTransitions();
                    pvmActivities=getNextActivities(pvmTransitions, elMap);
                    return pvmActivities;
                }
            }else{
                if(nodelId.equals(id)){
                    List<PvmTransition> pvmTransitions=activityImpl.getOutgoingTransitions();
                    pvmActivities=getNextActivities(pvmTransitions, elMap);
                    return pvmActivities;
                }
            }

        }
        return pvmActivities;
    }

    /**
     * 各种情况的下级节点
     * @param pvmTransitions 流向 列表
     * @param elMap 分支节点变量
     * @return
     */
    public static List<PvmActivity> getNextActivities(List<PvmTransition> pvmTransitions,Map<String,Object> elMap){
        List<PvmActivity> pvmActivities=new ArrayList<PvmActivity>();
        for(PvmTransition p:pvmTransitions){
            PvmActivity pvmActivity = p.getDestination();
            String type=(String)pvmActivity.getProperty("type");
            if("userTask".equals(type)){
                //当前接点下一流向为userTask,则加入下一流向
                pvmActivities.add(pvmActivity);
            }else if ("exclusiveGateway".equals(type)){
                List<PvmTransition> outgoingTransitions = pvmActivity.getOutgoingTransitions();
                for(PvmTransition tr1:outgoingTransitions){
                    //获取分支节点流向中的判断el表达式
                    String conditionText=(String)tr1.getProperty("conditionText");
                    //进行解析el表达式
                    ExpressionFactory factory = new ExpressionFactoryImpl();
                    SimpleContext context = new SimpleContext();
                    for(String key:elMap.keySet()){
                        if(conditionText.indexOf(key) != -1){
                            context.setVariable(key, factory.createValueExpression(elMap.get(key), String.class));
                        }
                    }
                    ValueExpression e = factory.createValueExpression(context, conditionText, boolean.class);
                    //判断该流向是否符合传入的参数条件
                    if((Boolean)e.getValue(context)){
                        pvmActivities.add(tr1.getDestination());
                        break;
                    }
                }

            } else if ("parallelGateWay".equals(type)) {
                //并行路由
                List<PvmTransition> outgoingTransitions = pvmActivity.getOutgoingTransitions();
                for(PvmTransition tr2:outgoingTransitions){
                    pvmActivities.add(tr2.getDestination());
                }
            }else if ("endEvent".equals(type)){
                //结束
                pvmActivities.add(pvmActivity);
            }
        }
        return pvmActivities;
    }

    /**
     * 根据流向,取下级所有流向
     * @param pvmTransitions 流向 列表
     * @return
     */
    public static List<PvmTransition> getNextActivities(List<PvmTransition> pvmTransitions){
        List<PvmTransition> pvmActivities = new ArrayList<>();
        for(PvmTransition p:pvmTransitions){
            PvmActivity pvmActivity = p.getDestination();
            String type=(String)pvmActivity.getProperty("type");
            if("userTask".equals(type)){
                pvmActivities.add(p);
            }else{
                //条件分支
                if("exclusiveGateway".equals(type)){
                    List<PvmTransition> outgoingTransitions = pvmActivity.getOutgoingTransitions();
                    pvmActivities.addAll(outgoingTransitions);
                }else{
                    //并行路由
                    List<PvmTransition> outgoingTransitions = pvmActivity.getOutgoingTransitions();
                    pvmActivities.addAll(outgoingTransitions);
                }
            }
        }
        return pvmActivities;
    }

    /***
     * 根据节点id获取下一流向(也就是线)
     * @param defId 流程定义id
     * @param nodelId 节点id
     */
    public static List<PvmTransition> getNextPvmTransitions(String defId,String nodelId){
        List<PvmTransition> pvmTransitions = new ArrayList<>();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(defId).singleResult();
        ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl)repositoryService).getDeployedProcessDefinition(processDefinition.getId());
        //获取所有节点
        List<ActivityImpl> activitiList = def.getActivities();
        //然后循环activitiList 并判断出当前流程所处节点,然后得到当前节点实例,根据节点实例获取所有从当前节点出发的路径,然后根据路径获得下一个节点实例:
        for(ActivityImpl activityImpl:activitiList){
            String id = activityImpl.getId();
            if(nodelId.equals(id)){
                pvmTransitions=activityImpl.getOutgoingTransitions();
                pvmTransitions = getNextActivities(pvmTransitions);
            }
        }
        return pvmTransitions;
    }

    /*************************回退开始***************************/

    /**
     * 根据任务ID获取对应的流程实例
     *
     * @param taskId 任务ID
     * @return
     * @throws Exception
     */
    public static ProcessInstance findProcessInstanceByTaskId(String taskId)
            throws Exception {
        // 找到流程实例
        ProcessInstance processInstance = runtimeService
                .createProcessInstanceQuery().processInstanceId(
                        findTaskById(taskId).getProcessInstanceId())
                .singleResult();
        if (processInstance == null) {
            throw new MyException("流程实例未找到!");
        }
        return processInstance;
    }

    /**
     * 根据任务ID获得任务实例
     * @param taskId 任务ID
     * @return TaskEntity
     * @throws Exception
     */
    private static TaskEntity findTaskById(String taskId) throws Exception {
        TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(
                taskId).singleResult();
        if (task == null) {
            throw new MyException("任务实例未找到!");
        }
        return task;
    }

    /**
     * 设置任务处理人,根据任务ID
     * @param taskId
     * @param userCode
     */
    public static void setTaskDealerByTaskId(String taskId,String userCode){
        taskService.setAssignee(taskId, userCode);
    }

    /**
     * 根据流程对象Id,查询当前节点Id
     * @param executionId
     * @return
     */
    public static String getActiviIdByExecutionId(String executionId){
        //根据任务获取当前流程执行ID,执行实例以及当前流程节点的ID:
        ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(executionId).singleResult();
        String activitiId = execution.getActivityId();
        return activitiId;
    }

    /**
     * 根据流程实例ID和任务key值查询所有同级任务集合
     *
     * @param processInstanceId
     * @param key
     * @return
     */
    public static List<Task> findTaskListByKey(String processInstanceId, String key) {
        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId).taskDefinitionKey(key).list();
        return list;
    }

    /**
     * 根据任务ID和节点ID获取活动节点 
* * @param taskId 任务ID * @param activityId 活动节点ID
* 如果为null或"",则默认查询当前活动节点
* 如果为"end",则查询结束节点
* @return * @throws Exception */
public static ActivityImpl findActivitiImpl(String taskId, String activityId) throws Exception { // 取得流程定义 ProcessDefinitionEntity processDefinition = findProcessDefinitionEntityByTaskId(taskId); // 获取当前活动节点ID if (StringUtils.isEmpty(activityId)) { activityId = findTaskById(taskId).getTaskDefinitionKey(); } // 根据流程定义,获取该流程实例的结束节点 if (activityId.toUpperCase().equals("END")) { for (ActivityImpl activityImpl : processDefinition.getActivities()) { String type =(String) activityImpl.getProperty("type"); if(type.equals("endEvent")){ return activityImpl; } } } // 根据节点ID,获取对应的活动节点 ActivityImpl activityImpl = ((ProcessDefinitionImpl) processDefinition) .findActivity(activityId); return activityImpl; } /** * 根据任务ID获取流程定义 * * @param taskId 任务ID * @return * @throws Exception */ public static ProcessDefinitionEntity findProcessDefinitionEntityByTaskId( String taskId) throws Exception { // 取得流程定义 ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService) .getDeployedProcessDefinition(findTaskById(taskId) .getProcessDefinitionId()); if (processDefinition == null) { throw new Exception("流程定义未找到!"); } return processDefinition; } /** * 根据任务Id,查找当前任务 * @param taskId 任务Id * @return */ public static Task getTaskById(String taskId){ //当前处理人的任务 Task currenTask = taskService.createTaskQuery().taskId(taskId).singleResult(); return currenTask; } /** * 根据流程实例查询正在执行的任务 * @param processInst * @return */ public static List<Task> getTaskByProcessInst(String processInst){ List<Task> list = taskService.createTaskQuery().processInstanceId(processInst).list(); return list; } /** * 根据activitiId,流程key获取当前节点 * @param processDefinitionKey * @return */ public static ActivityImpl getCurrenActivitiy(String processDefinitionKey,String activitiId){ ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processDefinitionKey).latestVersion().singleResult(); ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl)repositoryService).getDeployedProcessDefinition(processDefinition.getId()); List<ActivityImpl> activitiList = def.getActivities(); for (ActivityImpl activity:activitiList){ if(activitiId.equals(activity.getId())){ return activity; } } return null; } /** * 驳回流程 * @param taskId 当前任务ID * @param activityId 驳回节点ID * @param variables 流程存储参数 * @throws Exception */ public static void backProcess(String taskId, String activityId, Map<String, Object> variables,String comment) throws Exception { Map<String,String> map =new HashMap<>(); if (StringUtils.isEmpty(activityId)) { throw new MyException("驳回目标节点ID为空!"); } if (StringUtils.isEmpty(activityId)) { throw new MyException("任务iD为空!"); } //根据任务ID获取对应的流程实例 ProcessInstance processInstance = findProcessInstanceByTaskId(taskId); //根据任务ID获得任务实例 TaskEntity taskById = findTaskById(taskId); String taskDefinitionKey = taskById.getTaskDefinitionKey(); map.put(taskDefinitionKey,taskDefinitionKey); // 查找所有并行任务节点,同时驳回 Map<String, Object> parallelGateways = getParallelGateways(taskId); //并行开始所有结点 List<PvmTransition> parallelStart=(List<PvmTransition>)parallelGateways.get("pStart"); //并行结束所有结点 List<PvmTransition> parallelEnd=(List<PvmTransition>)parallelGateways.get("pEnd"); //并行节点开始 if(parallelStart !=null && parallelStart.size()>0){ List<PvmActivity> pvmActivities=new ArrayList<PvmActivity>(); for (PvmTransition pvmTransition:parallelStart){ PvmActivity destination = pvmTransition.getDestination(); map.put(destination.getId(),destination.getId()); pvmActivities.add(destination); } startParallelGateways(map,processInstance,variables,activityId,comment); }else if (parallelEnd !=null && parallelEnd.size()>0){ //并行节点结束 List<String> list = new ArrayList<String>(); for (PvmTransition pvmTransition:parallelEnd){ PvmActivity destination = pvmTransition.getSource(); list.add(destination.getId()); } endParallelGateways(map,processInstance,variables,list,comment); }else{ //一般处理 comment(map,processInstance,variables,activityId,comment); } } /** * 根据当前任务ID,查询并行路由的分支 * @param taskId * @return */ public static Map<String,Object> getParallelGateways(String taskId){ Map<String,Object> map =new HashMap<String, Object>(); Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); //然后根据当前任务获取当前流程的流程定义,然后根据流程定义获得所有的节点: ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl)repositoryService).getDeployedProcessDefinition(task.getProcessDefinitionId()); List<ActivityImpl> activitiList = def.getActivities(); //根据任务获取当前流程执行ID,执行实例以及当前流程节点的ID: String excId = task.getExecutionId(); String activitiId=getActiviIdByExecutionId(excId); //然后循环activitiList 并判断出当前流程所处节点,然后得到当前节点实例,根据节点实例获取所有从当前节点出发的路径,然后根据路径获得下一个节点实例: for(ActivityImpl activityImpl:activitiList){ String id = activityImpl.getId(); if(activitiId.equals(id)){ System.out.println("当前任务:"+activityImpl.getProperty("name")); //输出某个节点的某种属性 List<PvmTransition> outTransitions = activityImpl.getIncomingTransitions();//获取从某个节点出来的所有线路 List<PvmTransition> inTransitions = activityImpl.getIncomingTransitions();//获取从某个节点流进的所有线路 //并行开始 for(PvmTransition tr:outTransitions){ PvmActivity ac = tr.getSource(); //获取线路的终点节点 Object o = ac.getProperty("type"); if("parallelGateway".equals(o)){ String gatewayId = ac.getId(); String gatewayType = gatewayId.substring(gatewayId .lastIndexOf("_") + 1); if ("START".equals(gatewayType.toUpperCase())) { List<PvmTransition> outgoingTransitions = ac.getOutgoingTransitions(); List<PvmTransition> pvmTransitions=new ArrayList<PvmTransition>(); outgoingTransitions = forCheckQueryPvm(outgoingTransitions, pvmTransitions); map.put("pStart",outgoingTransitions); } } } //并行结束 for(PvmTransition tr:inTransitions){ PvmActivity ac = tr.getSource(); //获取线路的终点节点 Object o = ac.getProperty("type"); if("parallelGateway".equals(o)){ String gatewayId = ac.getId(); String gatewayType = gatewayId.substring(gatewayId .lastIndexOf("_") + 1); if ("END".equals(gatewayType.toUpperCase())) { List<PvmTransition> ingoingTransitions = ac.getIncomingTransitions(); map.put("pStart",ingoingTransitions); } } } break; } } return map; } /** * 并行路由开始,查询所有正在执行并行任务的节点 * @param pvmTransitions * @param pvmTransitionList * @return */ private static List<PvmTransition> forCheckQueryPvm(List<PvmTransition> pvmTransitions,List<PvmTransition> pvmTransitionList){ for (PvmTransition pvmTransition:pvmTransitions){ PvmActivity destination = pvmTransition.getDestination(); String activitid = destination.getId(); String processDef = destination.getProcessDefinition().getId(); HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskDefinitionKey(activitid).processDefinitionId(processDef) .orderByTaskCreateTime().desc().list().get(0); if("completed".equals(historicTaskInstance.getDeleteReason())){ List<PvmTransition> outgoingTransitions = pvmTransition.getDestination().getOutgoingTransitions(); for(PvmTransition p:outgoingTransitions){ Object type = p.getDestination().getProperty("type"); if("parallelGateway".equals(type)){ continue; }else { forCheckQueryPvm(outgoingTransitions,pvmTransitionList); } } }else { pvmTransitionList.add(pvmTransition); continue; } } return pvmTransitionList; } /** * 并行开始回退处理 * @param map 要回退的节点Id集合 * @param processInstance 流程实例 * @param variables * @param activityId * @throws Exception */ private static void startParallelGateways(Map map,ProcessInstance processInstance,Map<String, Object> variables,String activityId,String comment) throws Exception { List<Task> taskList; Iterator it=map.keySet().iterator(); int i=0; while (it.hasNext()){ String id = (String) it.next(); taskList = findTaskListByKey(processInstance.getId(), id); //第一次回退,正常回退 if(i==0){ for (Task task : taskList) { commitProcess(task.getId(), variables, activityId,comment); } } //多次回退,就只完成任务,不更改流向,不设置回退任务处理人 if(i>0){ for (Task task : taskList) { parallelgateway_end(task.getId(),variables); } } i++; } } /** * 并行开始返回,只执行任务,不做流向转向处理 * * @param taskId 当前任务ID * @param variables 流程变量 * @throws Exception */ private static void parallelgateway_end(String taskId, Map<String, Object> variables ) throws Exception { // 当前节点 ActivityImpl currActivity = findActivitiImpl(taskId, null); // 清空当前流向 List<PvmTransition> oriPvmTransitionList = clearTransition(currActivity); //当前任务 Task task = getTaskById(taskId); task.setDescription("callback"); taskService.saveTask(task); taskService.complete(taskId, variables); // 还原以前流向 restoreTransition(currActivity, oriPvmTransitionList); } /** *并行结束后退处理 * @param map 要回退的节点Id * @param processInstance * @param variables * @param list * @throws Exception */ private static void endParallelGateways(Map map,ProcessInstance processInstance,Map<String, Object> variables,List<String> list,String comment) throws Exception { List<Task> taskList = new ArrayList<Task>(); Iterator it=map.keySet().iterator(); while (it.hasNext()){ String id = (String) it.next(); taskList = findTaskListByKey(processInstance.getId(), id); for (Task task : taskList) { commitProcess(task.getId(), variables, list,comment); } } } /** * 一般式的流程回退处理 * @param map * @param processInstance * @param variables * @param activityId * @throws Exception */ private static void comment(Map map,ProcessInstance processInstance,Map<String, Object> variables,String activityId,String comment) throws Exception { List<Task> taskList = new ArrayList<Task>(); Iterator it=map.keySet().iterator(); while (it.hasNext()){ String id = (String) it.next(); taskList = findTaskListByKey(processInstance.getId(), id); for (Task task : taskList) { commitProcess(task.getId(), variables, activityId,comment); } } } /** * @param taskId 当前任务ID * @param variables 流程变量 * @param activityId 流程转向执行任务节点ID
* 此参数为空,默认为提交操作 * @throws Exception */
public static void commitProcess(String taskId, Map<String, Object> variables, String activityId,String comment) throws Exception { if (variables == null) { variables = new HashMap<String, Object>(); } // 跳转节点为空,默认提交操作 if (StringUtils.isEmpty(activityId)) { taskService.complete(taskId, variables); } else {// 流程转向操作 turnTransition(taskId, activityId, variables,comment); } } /** * @param taskId 当前任务ID * @param variables 流程变量 * @param activityIds 流程转向执行任务节点ID
* 此参数为空,默认为提交操作 * @throws Exception */
private static void commitProcess(String taskId, Map<String, Object> variables, List<String> activityIds,String comment) throws Exception { if (variables == null) { variables = new HashMap<String, Object>(); } // 跳转节点为空,默认提交操作 if (StringUtils.isEmpty(activityIds)) { taskService.complete(taskId, variables); } else {// 流程转向操作 turnTransition(taskId, activityIds, variables,comment); } } /** * 流程转向操作 * * @param taskId 当前任务ID * @param activityIds 目标节点任务ID * @param variables 流程变量 * @throws Exception */ private static void turnTransition(String taskId, List<String> activityIds, Map<String, Object> variables ,String comment) throws Exception { // 当前节点 ActivityImpl currActivity = findActivitiImpl(taskId, null); // 清空当前流向 List<PvmTransition> oriPvmTransitionList = clearTransition(currActivity); List<TransitionImpl> transitions=new ArrayList<TransitionImpl>(); List<ActivityImpl> pointActivitys=new ArrayList<ActivityImpl>(); for(String activityId:activityIds){ // 创建新流向 TransitionImpl newTransition = currActivity.createOutgoingTransition(); // 目标节点 ActivityImpl pointActivity = findActivitiImpl(taskId, activityId); // 设置新流向的目标节点 newTransition.setDestination(pointActivity); transitions.add(newTransition); pointActivitys.add(pointActivity); } // 执行转向任务 Task currenTask = taskService.createTaskQuery().taskId(taskId).singleResult(); taskService.addComment(taskId, currenTask.getProcessInstanceId(), comment); taskService.complete(taskId, variables); // 删除目标节点新流入 for (int i =0;i<transitions.size();i++){ pointActivitys.get(i).getIncomingTransitions().remove(transitions.get(i)); } // 还原以前流向 restoreTransition(currActivity, oriPvmTransitionList); } /** * 流程转向操作 * * @param taskId 当前任务ID * @param activityId 目标节点任务ID * @param variables 流程变量 * @throws Exception */ public static void turnTransition(String taskId, String activityId, Map<String, Object> variables ,String comment) throws Exception { // 当前节点 ActivityImpl currActivity = findActivitiImpl(taskId, null); // 清空当前流向 List<PvmTransition> oriPvmTransitionList = clearTransition(currActivity); // 创建新流向 TransitionImpl newTransition = currActivity.createOutgoingTransition(); // 目标节点 ActivityImpl pointActivity = findActivitiImpl(taskId, activityId); // 设置新流向的目标节点 newTransition.setDestination(pointActivity); //查询当前任务 Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); if(comment==null){ comment=""; } taskService.addComment(taskId, task.getProcessInstanceId(), comment); // 执行转向任务 task.setDescription("callback"); taskService.saveTask(task); taskService.complete(taskId, variables); //顺序会签处理 dealMultiSequential(task.getProcessInstanceId(), comment, task.getTaskDefinitionKey()); //设置回退的任务处理人 setBackTaskDealer(task,activityId); // 删除目标节点新流入 pointActivity.getIncomingTransitions().remove(newTransition); // 还原以前流向 restoreTransition(currActivity, oriPvmTransitionList); } /** * 清空指定活动节点流向 * * @param activityImpl 活动节点 * @return 节点流向集合 */ private static List<PvmTransition> clearTransition(ActivityImpl activityImpl) { // 存储当前节点所有流向临时变量 List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>(); // 获取当前节点所有流向,存储到临时变量,然后清空 List<PvmTransition> pvmTransitionList = activityImpl .getOutgoingTransitions(); for (PvmTransition pvmTransition : pvmTransitionList) { oriPvmTransitionList.add(pvmTransition); } pvmTransitionList.clear(); return oriPvmTransitionList; } /** * 还原指定活动节点流向 * * @param activityImpl 活动节点 * @param oriPvmTransitionList 原有节点流向集合 */ private static void restoreTransition(ActivityImpl activityImpl, List<PvmTransition> oriPvmTransitionList) { // 清空现有流向 List<PvmTransition> pvmTransitionList = activityImpl .getOutgoingTransitions(); pvmTransitionList.clear(); // 还原以前流向 for (PvmTransition pvmTransition : oriPvmTransitionList) { pvmTransitionList.add(pvmTransition); } } /** * 顺序会签后退时处理 * @param instanceId 流程实例 * @param comment 意见 * @param preActivityId 上个已经完成任务ID */ public static void dealMultiSequential(String instanceId,String comment,String preActivityId){ //该流程实例正在运行的任务 List<Task> runTask = getTaskByProcessInst(instanceId); for(Task t:runTask){ String runActivityId=t.getTaskDefinitionKey(); //正在运行的任务节点id和上个已经完成的任务节点id相等,则判定为顺序会签 if(runActivityId.equals(preActivityId)){ if(comment==null){ comment=""; } taskService.addComment(t.getId(), t.getProcessInstanceId(), comment); // 执行转向任务 t.setDescription("callback"); taskService.saveTask(t); taskService.complete(t.getId()); //递归顺序会签,直到正在运行的任务还是顺序会签 dealMultiSequential(t.getProcessInstanceId(), comment, t.getTaskDefinitionKey()); } } } /** * 设置回退的任务处理人 * @param task 当前任务 * @param activityId 回退节点ID */ public static void setBackTaskDealer(Task task,String activityId){ List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().processInstanceId(task.getProcessInstanceId()) .taskDefinitionKey(activityId).taskDeleteReason("completed").orderByTaskCreateTime().desc().list(); HistoricTaskInstance historicTask =null; if(list != null && list.size()>0){ historicTask=list.get(0); //查询回退后的节点正在运行的任务 List<Task> taskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()) .taskDefinitionKey(activityId).active().list(); //同一节点下有多个任务,则认定为会签任务 if(taskList != null && taskList.size()>1){ for(int i=0;i<taskList.size();i++){ //设置会签任务处理人(处理人顺序不管) taskService.setAssignee(taskList.get(i).getId(),list.get(i).getAssignee()); } }else{ Task taskNew = taskList.get(0); //顺序会签流程变量处理人 String variable =(String) runtimeService.getVariable(taskNew.getExecutionId(), "countersign"); if(!StringUtils.isEmpty(variable)){ //设置下个顺序会签处理人 setTaskDealerByTaskId(taskNew.getId(), variable); }else{ //设置一般回退任务处理人 taskService.setAssignee(taskNew.getId(), historicTask.getAssignee()); } } } } /*************************回退结束***************************/ /** * (取上一个任务节点) * 根据节点Id取得当前节点的上一流向,分支路由结束点,需要查询历史任务出现过的分支结点,并行路由则随便取一个 * @param processDefinitionKey 流程定义Key * @param processInstanceId 流程实例ID * @param preNodeId 上个节点id * @return */ public static String getProActivityId(String processDefinitionKey,String activitiId,String processInstanceId,String preNodeId){ List<PvmActivity> pvmActivities=new ArrayList<PvmActivity>(); ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processDefinitionKey).latestVersion().singleResult(); ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl)repositoryService).getDeployedProcessDefinition(processDefinition.getId()); List<ActivityImpl> activitiList = def.getActivities(); //然后循环activitiList 并判断出当前流程所处节点,然后得到当前节点实例,根据节点实例获取所有从当前节点出发的路径,然后根据路径获得下一个节点实例: for(ActivityImpl activityImpl:activitiList){ String id = activityImpl.getId(); if(!StringUtils.isEmpty(activitiId)){ if(activitiId.equals(id)){ List<PvmTransition> pvmTransitions = activityImpl.getIncomingTransitions(); for(PvmTransition tr:pvmTransitions){ PvmActivity ac = tr.getSource(); Object type = ac.getProperty("type"); if("userTask".equals(type)){ preNodeId=ac.getId(); return preNodeId; }else if("exclusiveGateway".equals(type)){ PvmActivity exclusiveActiviti = getExclusiveActiviti(ac,processDefinitionKey,processInstanceId); if(exclusiveActiviti !=null){ preNodeId=exclusiveActiviti.getId(); return preNodeId; } }else{ //其它情况则进行递归 并行路由 preNodeId = getProActivityId(processDefinitionKey,ac.getId(),processInstanceId,preNodeId); } } } } } return preNodeId; } /** * 分支路由结束点,需要查询历史任务出现过的分支结点(取上一个任务节点) * @param ac exclusiveGateway节点 * @param processDefinitionKey * @param processInstanceId * @return */ public static PvmActivity getExclusiveActiviti(PvmActivity ac,String processDefinitionKey,String processInstanceId){ //上一个节点为条件路由,则查询任务历史,查询历史最近走过的分支节点 List<PvmTransition> exclusiveEnds = ac.getIncomingTransitions(); //保存分支路由所有节点的最新记录 List<HistoricTaskInstance> taskList=new ArrayList<HistoricTaskInstance>(); //条件路由结束 for(PvmTransition p:exclusiveEnds){ PvmActivity pvmActivity = p.getSource(); //根据分支路由的节点ID,查询历史任务中最新记录的节点ID HistoricTaskInstance taskInstance = historyService.createHistoricTaskInstanceQuery().processDefinitionKey(processDefinitionKey) .processInstanceId(processInstanceId).taskDefinitionKey(pvmActivity.getId()).orderByTaskCreateTime().desc().list().get(0); //有记录 if(taskInstance != null && !StringUtils.isEmpty(taskInstance.getId())){ taskList.add(taskInstance); } } if(taskList !=null && taskList.size()>1){ //循环判断那个节点是最新操作的节点 按时间从大 for(int i=0;i<taskList.size();i++){ for(int j=i;j<taskList.size();j++){ Date d1 = taskList.get(i).getStartTime(); Date d2 = taskList.get(j).getStartTime(); if(d1.before(d2)){ HistoricTaskInstance temp; temp=taskList.get(i); taskList.set(i, taskList.get(j)); taskList.set(j, temp); } } } } //最新分支节点 String activityId=taskList.get(0).getTaskDefinitionKey(); return getCurrenActivitiy(processDefinitionKey, activityId); } /** * 转办流程 * @param taskId 当前任务节点ID * @param userId 被转办人id */ public static boolean transferAssignee(String taskId, String userId) { try{ taskService.setAssignee(taskId, userId); return true; }catch(Exception e){ return false; } } }

六、添加编辑器

将编辑器的html文件添加至templates里面,然后通过get方式传入模板id就可以编辑流程了,modeler.html?modelId=" + modelId
在这里插入图片描述
如果保存报错,可以更改ModelSaveRestResource.java,这个springboot传参方式和springmvc有区别,参数无法传进来,activiti5.22.0版本比较旧,所以有这个问题。

/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.activiti.rest.editor.model;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;

import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
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.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
 * @author Tijs Rademakers
 */
@RestController
public class ModelSaveRestResource implements ModelDataJsonConstants {

    protected static final Logger LOGGER = LoggerFactory.getLogger(ModelSaveRestResource.class);

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ObjectMapper objectMapper;

    @RequestMapping(value = "/model/{modelId}/save", method = RequestMethod.PUT)
    @ResponseStatus(value = HttpStatus.OK)
    public void saveModel(@PathVariable String modelId, String name, String description, String json_xml,
                          String svg_xml) {
        try {
            Model model = repositoryService.getModel(modelId);

            ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());

            modelJson.put(MODEL_NAME, name);
            modelJson.put(MODEL_DESCRIPTION, description);
            model.setMetaInfo(modelJson.toString());
            model.setName(name);

            repositoryService.saveModel(model);

            repositoryService.addModelEditorSource(model.getId(), json_xml.getBytes("utf-8"));

            InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes("utf-8"));
            TranscoderInput input = new TranscoderInput(svgStream);

            PNGTranscoder transcoder = new PNGTranscoder();
            // Setup output
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            TranscoderOutput output = new TranscoderOutput(outStream);

            // Do the transformation
            transcoder.transcode(input, output);
            final byte[] result = outStream.toByteArray();
            repositoryService.addModelEditorSourceExtra(model.getId(), result);
            outStream.close();

        } catch (Exception e) {
            LOGGER.error("Error saving model", e);
            throw new ActivitiException("Error saving model", e);
        }
    }
}

七、添加业务类

添加业务类这块自己按照自己的需求进行添加就好,由于内容过多,这里不做描述了。

你可能感兴趣的:(Spring,Boot)