Activiti

workflow,工作流,通过计算机对业务流程自动化执行管理。

Activiti

工作流引擎(一堆jar包API),业务系统访问activiti的接口,就可以方便操作流程相关的数据,这样就可以把工作流环境与业务系统环境集成在一起。

BPM/BPMN

        BPM:Business Process Management,业务流程管理;

        BPMN:Business Process Model And Notation,业务流程模型和符号。业务流程图文件后缀:.bpmn

工作表创建

activiti的流程数据是存储在数据库中的,因此需要先创建activiti工作所需要用到的表(25张表)。工作表的创建方式分为两种:默认配置方式和自定义配置方式。

        默认方式:resource 目录下创建 activiti的配置文件 activiti.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--使用activiti默认的方式来创建mysql表:要求 在resources下创建activiti.cfg.xml文件
(默认方式下路径和文件名不能修改);下面的beanid固定为processEngineConfiguration-->
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!--配置数据库连接参数-->
        <property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql:///activiti?serverTimezone=UTC" />
        <property name="jdbcUsername" value="root" />
        <property name="jdbcPassword" value="003300" />
        <!--activiti 在生成数据库表时的策略,true:如果表存在则直接使用,不存在则创建-->
        <property name="databaseSchemaUpdate" value="true" />
    </bean>
</beans>

        自定义方式:resource目录(包含子目录)下创建 activiti的配置文件(自定义文件名) aciviti.mu.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///activiti?serverTimezone=UTC" />
        <property name="username" value="root"/>
        <property name="password" value="089033"/>
        <property name="maxIdle" value="3"/>
        <property name="minIdle" value="1"/>
    </bean>
    <!--使用activiti自定义的方式来创建mysql表:要求 在resources下创建activiti.mu.xml文件;下面的beanid可自定义名称-->
    <bean id="definedProcessEngine" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!--配置数据库连接参数-->
        <property name="dataSource" ref="dataSource"/>
        <!--activiti 在生成数据库表时的策略,true:如果表存在则直接使用,不存在则创建-->
        <property name="databaseSchemaUpdate" value="true" />
    </bean>
</beans>

创建表的代码分别为:

/**
     * 使用activiti默认的方式来创建mysql的25张表
     */
    @Test
    public void createDefaultTable(){
        /**
         * ProcessEngines.getDefaultProcessEngine() 会默认读取resources路径下的activiti.cfg.xml文件
         * 创建ProcessEngine时就会创建mysql表
         */
        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
    }

    /**
     * 使用自定义的方式来创建mysql表
     */
    @Test
    public void createDefineTable(){
        // 通过指定的配置文件(和指定id的bean)来创建activiti引擎配置ProcessEngineConfiguration,通过buildProcessEngine()创建流程引擎
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
    }

        这些生成的表名以act_开头,分别代表不同的存储用途:

        ACT_RE_*: ’RE’表示repository。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则等)。

        ACT_RU_*: ’RU’表示runtime。这是运行时(记住一定是运行时)的表存储着流程变量,用户任务,变量,等运行时的数据。Activiti只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录。这就保证了这些运行时的表小且快。

        ACT_ID_*: ’ID’表示identity。这些表包含标识的信息,如用户,用户组,等等。

        ACT_HI_*: ’HI’表示history。就是这些表包含着历史的相关数据,如结束的流程实例,变量,任务,等等。

        ACT_GE_*: 普通数据,各种情况都使用的数据。

        由activiti配置文件 ——> ProcessEngineConfiguration ——> ProcessEngine ——> RepositoryServiceRuntimeServiceTaskServiceHistoryServiceManagementService,由这些不同的 service 去操作不同的流程阶段。

创建Activiti工作流

        分为3步:定义流程、部署流程、启动流程

定义流程

        创建bpmn文件(实为xml文件):使用流程定义工具,按照BPMN规范,用流程符号将流程描述出来

 部署流程

        通过ProcessEngine获得repositoryservice,指定流程定义文件进行部署。可以单独部署和zip包部署。

/**
     * 流程部署,通过processEngine获取部署服务进行部署,将数据写入数据库中
     */
    @Test
    public void testDeployment(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        // 定义流程的名字,流程文件bpmn和png
        Deployment deployment = processEngine.getRepositoryService().createDeployment().name("出差申请").addClasspathResource("bpmn/envction.bpmn").addClasspathResource("bpmn/envction.png").deploy();
        System.out.println("出差申请id:"+deployment.getId());
        System.out.println("出差申请名称"+deployment.getName());
    }

    /**
     * 使用zip包方式部署
     */
    @Test
    public void testZipDeployment(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        DeploymentBuilder deployment = repositoryService.createDeployment();
        // 获取打包文件的输入流
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/envction.zip");
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        Deployment deploy = deployment.addZipInputStream(zipInputStream).deploy();
    }

        部署完成后会在表:act_re_deployment、act_re_procdef、act_ge_bytearray 中生成数据。

        部署完成就可进行流程的查询及删除操作

/**
     * 流程定义信息查询: 主要操作表 act_re_procdef
     * 创建流程定义查询:createProcessDefinitionQuery(),指定流程key
     */
    @Test
    public void queryDefinition(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        List<ProcessDefinition> myEnvction = repositoryService.createProcessDefinitionQuery().processDefinitionKey("myEnvction").orderByProcessDefinitionVersion().desc().list();
        for (ProcessDefinition processDefinition : myEnvction) {
            System.out.println("流程定义id:"+processDefinition.getId());
            System.out.println("流程部署id:"+processDefinition.getDeploymentId());
            System.out.println("流程定义名称:"+processDefinition.getName());
            System.out.println("流程定义key"+processDefinition.getKey());
        }
    }

    /**
     * 删除流程定义信息, 级联删除
     */
    @Test
    public void deleteDefinition(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        repositoryService.deleteDeployment("1", true);
    }

启动流程

        使用runtimeService启动流程后生成流程实例

        工作流程需要与业务挂钩,才能知道该工作流是干什么的,所以需要在启动流程实例的同时添加业务的 BusinessKey,此key会存入act_ru_execution表中

/**
     * 启动流程实例
     * act_hi_actinst: 流程实例执行历史
     * act_hi_identitylink: 流程参与者的历史信息
     * act_hi_procinst: 流程实例的历史信息
     * act_hi_taskinst: 任务的历史信息
     * act_ru_execution: 流程执行的信息
     * act_ru_identitylink: 流程参与者信息
     * act_ru_task: 流程任务信息
     */
    @Test
    public void testRun(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 根据bpmn定义的流程id启动流程实例
        // ProcessInstance myEnvction = runtimeService.startProcessInstanceByKey("myEnvction");
        ProcessInstance myEnvction = runtimeService.startProcessInstanceByKey("myEnvction","envctionbusiness");
        System.out.println("流程定义id:"+myEnvction.getProcessDefinitionId());
        System.out.println("流程实例id:"+myEnvction.getId());
        System.out.println("当前活动的id:"+myEnvction.getActivityId());
    }

    /**
     * 查询个人待执行的任务
     */
    @Test
    public void testQueryTask(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        // 指定流程key和任务负责人
        List<Task> list = taskService.createTaskQuery().processDefinitionKey("myEnvction").taskAssignee("张三").list();
        for (Task task : list) {
            System.out.println("任务负责人:"+task.getAssignee());
            System.out.println("任务名称:"+task.getName());
            System.out.println(task.getTaskDefinitionKey());
            System.out.println("任务id:"+task.getId());
            System.out.println("流程id:"+task.getProcessDefinitionId());
        }
    }

    /**
     * 完成个人任务
     */
    @Test
    public void testCompleteTask(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        // 指定任务id
//        taskService.complete("5005");

        List<Task> list = taskService.createTaskQuery().processDefinitionKey("myEnvction").taskAssignee("赵六").list();
        for (Task task : list) {
            taskService.complete(task.getId());
        }
    }

下载流程定义文件

/**
     * 获取流程定义文件
     * 关键:获取流程定义文件png和bpmn的输入流
     */
    @Test
    public void getDefinitionResource() throws IOException {
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 获取流程定义信息
        List<ProcessDefinition> myEnvction = repositoryService.createProcessDefinitionQuery().processDefinitionKey("myEnvction").orderByProcessDefinitionVersion().desc().list();
        ProcessDefinition processDefinition = myEnvction.get(0);
        // 获取png和bpmn的输入流
        InputStream bpmnInputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
        InputStream pngInputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getDiagramResourceName());
        // 定义输出流
        File bpmnFile = new File("e:/evc.bpmn");
        File pngFile = new File("e:/evc.png");
        FileOutputStream bpmnOutputStream = new FileOutputStream(bpmnFile);
        FileOutputStream pngOutputStream = new FileOutputStream(pngFile);
        IOUtils.copy(bpmnInputStream, bpmnOutputStream);
        IOUtils.copy(pngInputStream, pngOutputStream);
        pngOutputStream.close();
        bpmnOutputStream.close();
        pngInputStream.close();
        bpmnInputStream.close();
    }

动态指定流程负责人

        指定负责人:在定义流程bpmn时写死(实用性不强);动态指定

        动态指定:uel表达式(流程变量);监听器

        uel表达式方式:bpmn设计时使用${a0},${a1},...来指定负责人,在启动实例时再具体指定a0,a1,...的值,启动时全部指定好。

/**
     * 启动流程时指定对应的流程负责人
     * 启动时全部指定好了
     */
    @Test
    public void runUelInstance(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        Map<String, Object> map = new HashMap<String, Object>();
        // 指定流程图中预设的负责人
        map.put("assignee0","张1");
        map.put("assignee1","李2");
        map.put("assignee2","王3");
        map.put("assignee3","赵4");
        runtimeService.startProcessInstanceByKey("myProcess_1","businessKey", map);
    }

        监听器方式

        创建监听器实现TaskListener接口,每创建一个节点时指定节点的负责人

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;

public class MyTaskListener implements TaskListener {

    public void notify(DelegateTask delegateTask) {
        String eventName = delegateTask.getEventName();
        String name = delegateTask.getName();
        if("创建出差申请".equals(name) && "create".equals(eventName))
            delegateTask.setAssignee("王一");
        else if("经理审批".equals(name) && "create".equals(eventName))
            delegateTask.setAssignee("王二");
        else if("总经理审批".equals(name) && "create".equals(eventName))
            delegateTask.setAssignee("王三");
        else if("财务审批".equals(name) && "create".equals(eventName))
            delegateTask.setAssignee("王四");
        else if("申请完成".equals(name) && "create".equals(eventName))
            delegateTask.setAssignee("王五");
    }
}

         在bpmn流程节点指定Task Listener 对应的监听器class的全限定名

/**
     * 使用 指定监听器(实现TaskListener接口) 监听流程节点信息同时指定流程负责人5
     *
     * 启动一个节点指定一个
     */
    @Test
    public void runUelListener(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        runtimeService.startProcessInstanceByKey("myProcess_listener1234", "businessKey");
    }

流程变量

        activiti在管理工作流时根据管理需要而设置的变量,存储在act_ru_variable 表中。

        流程变量的数据类型有:String、integer、short、long、double、boolean、date、binary、对象(需实现序列化接口Serializable

        变量作用域:globa(默认流程实例),变量名不允许重复,重名后会被后一个同名的覆盖。

        local(作用域在节点):作用域互不影响,可与globa变量重名。

        使用方式:在节点属性上使用uel表达式:${xxx}或${pojo.attr},如指定负责人、分组...

                          在连线上使用uel表达式:${xxx}或${pojo.attr},根据表达式的布尔值决定流程的执行方向。

        指定连线上流程变量时机:实例启动前;实例启动时;任务完成前;任务完成时。

定死灵活
runtimeService实例启动前实例启动时
taskService任务完成前任务完成时
@Test
    public void complete1(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        String assignee = "猪组长0";
        Task myEvection_var = taskService.createTaskQuery().processDefinitionKey("myEvection_var").taskAssignee(assignee).singleResult();
        Map<String, Object> map = new HashMap<String, Object>();
//         指定连线中的流程变量 pojo方式
        Evection evection = new Evection();
        evection.setNum(3);
        map.put("evection",evection);
        taskService.complete(myEvection_var.getId(),map);
    }

        当连线未设置条件时,会按照bpmn中flow值小的执行。

组任务

        一个任务可以由不止一个特定的负责人来完成,将其他候选人放入bpmn的candidate User中,组员之间用,分隔。

        1. 查询特定候选人的某个流程实例;

        2.拾取任务:指定当前候选人为此任务的负责人,claim(taskId,userId);

        3.归还任务:设置当前任务的负责人为null,setAssignee(taskId,null);

        4.交接任务:设置当前任务的负责人为其他的候选人,serAssignee(taskId,otherUserId)

    @Test
    public void runInstance(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("assignee","小员工");
        // 指定任务组中候选人,组员用  , 隔开
        map.put("approve0","审批1,审批2");
        runtimeService.startProcessInstanceByKey("myEvection_candidate",map);
    }

    /**
     * 拾取任务
     */
    @Test
    public void pickTask(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        // 查询指定候选人的任务
        Task myEvection_candidate = taskService.createTaskQuery().processDefinitionKey("myEvection_candidate").taskCandidateUser("审批2").singleResult();
        if (myEvection_candidate != null){
            // 给任务指定负责人
            taskService.claim(myEvection_candidate.getId(),"审批2");
        }
    }

    /**
     * 归还任务(当前任务先要有负责人)
     */
    @Test
    public void resetTask(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        // 查询指定候选人的任务
        Task myEvection_candidate = taskService.createTaskQuery().processDefinitionKey("myEvection_candidate").taskAssignee("审批2").singleResult();
        if (myEvection_candidate != null){
            // 给任务指定负责人
            taskService.setAssignee(myEvection_candidate.getId(),null);
        }
    }

    /**
     * 交接任务-改变负责人(当前任务先要有负责人)
     */
    @Test
    public void changeAssigneeTask(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        // 查询指定候选人的任务
        Task myEvection_candidate = taskService.createTaskQuery().processDefinitionKey("myEvection_candidate").taskAssignee("审批2").singleResult();
        if (myEvection_candidate != null){
            // 给任务指定负责人
            taskService.setAssignee(myEvection_candidate.getId(),"审批1");
        }
    }

流程的挂起和激活

挂起方式批量挂起非批量挂起
apirepositoryServiceruntimeService
影响的数据表

act_re_procedef

act_ru_task

act_ru_execution

act_ru_task

act_ru_execution

影响的表字段SUSPENDSION_STATUS:1-激活,2-挂起

        判断激活或挂起:.isSuspended(),挂起的流程不能被完成。

    /**
     * 批量流程实例的挂起和激活(流程定义下的所有流程实例挂起):使用的是 repositoryService
     * 会操作 act_re_procdef  act_ru_task  act_ru_execution 这3张表的 SUSPENSION_STATE_ 字段:1-激活,2-挂起
     */
    @Test
    public void testBatchSuspended(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        // 挂起和激活使用的是 repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        List<ProcessDefinition> myEnvction = repositoryService.createProcessDefinitionQuery().processDefinitionKey("myEnvction").list();
        for (ProcessDefinition processDefinition : myEnvction) {
            String id = processDefinition.getId();
            // 判断当前流程是否被挂起
            boolean suspended = processDefinition.isSuspended();
            if(suspended) {
                // 要激活流程的id;是否要激活;激活时间
                repositoryService.activateProcessDefinitionById(id, true, null);
            } else {
                // 要挂起的流程id;是否要挂起;挂起时间
                repositoryService.suspendProcessDefinitionById(id,true,null);
            }
        }
    }

    /**
     * 单个流程实例的激活和挂起
     * 只操作 act_ru_task  act_ru_execution 这两张表
     */
    @Test
    public void testSingleSuspended(){
        ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
        ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
        // 使用 runtimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processInstanceId("5001").list();
        for (ProcessInstance processInstance : list) {
            boolean suspended = processInstance.isSuspended();
            if(suspended){
                runtimeService.activateProcessInstanceById(processInstance.getId());
            } else {
                runtimeService.suspendProcessInstanceById(processInstance.getId());
            }
        }
    }

网关

        排他网关

        根据分支条件的boolean值决定执行的任务,当分支条件都为true时,选择下个任务id小的执行。

         并行网关

        并行网关不会解析判断条件,即使定义了分支条件也会别忽略。会执行并行网关后的每一个分支,每个并行网关分支都执行完成后,流程才会继续往下走。

         包含网关

        集成了排他网关和并行网关的特点,会根据分支条件进入包含网关后的任务分支,当进入的任务分支都执行完成汇聚后才会继续执行后续的流程。

完整过程

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

public class TestReal {

    @Autowired
    RepositoryService repositoryService;
    @Autowired
    RuntimeService runtimeService;
    @Autowired
    TaskService taskService;

    /**
     * 上传打包好的流程文件,并部署
     * @param file
     * @param deployName 流程部署名称
     */
    void deploy(MultipartFile file, String deployName){
        DeploymentBuilder deployment = repositoryService.createDeployment();
        // 获取打包文件的输入流
        ZipInputStream zipInputStream = null;
        try {
            zipInputStream = new ZipInputStream(file.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        Deployment deploy = deployment.addZipInputStream(zipInputStream).name(deployName).deploy();
    }

    /**
     * 新建业务后,业务发起指定流程,同时传入该业务的id(业务表数据的id)到流程实例中
     * @param evectionId
     * @param instanceKey
     */
    void startInstance(String evectionId, String instanceKey) {
        // 1 根据evectionId查询业务信息
        Evection evection = new Evection();
        // 设置处理人
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("loadPeople", evection.getName());// 流程图上动态参数
        runtimeService.startProcessInstanceByKey(instanceKey, evectionId, map);
        // 修改业务单状态 审核中
        evection.setStatus("审核中");
        // evection 业务更新入数据库
    }

    /**
     * 查询指定人正在执行中的任务列表
     * @return
     */
    List<Task> queryMyTask(){
        return taskService.createTaskQuery().taskAssignee("指定的人").orderByTaskId().desc().list();
    }

    /**
     * 根据任务查询业务详情
     * @param taskId
     */
    void queryTaskBusiness(String taskId) {
        // 查询任务对应的业务信息
        // 1. 根据taskId查询任务信息
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        // 2. 根据流程实例id查询流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
        // 3. 根据流程实例查询业务id
        String businessKey = processInstance.getBusinessKey();
        // 4. 根据据业务id查询业务详情

        // 获取流程的整个批注信息
        List<Comment> taskComments = taskService.getTaskComments(taskId);
    }

    /**
     * 查询某任务节点的流向连线集合,按钮形式展示到前端,供前端点击流程走向
     * @param taskId
     * @return
     */
    List<String> queryLines(String taskId) {
        // 1. 根据taskId查询任务信息
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        // 2. 获取当前流程模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        // 3. 获取当前流程节点
        FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
        // 这里不转也有方法拿到,我这是为了后人阅读方便
        UserTask userTask = (UserTask)flowElement;
        // 获取节点出口线段
        List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
        List<String> flowNames = new ArrayList<>();
        outgoingFlows.forEach(flow -> {
            flowNames.add(flow.getName());
        });
        return flowNames;
    }

    /**
     * 完成任务
     * @param taskId 任务id
     * @param buttonValue 前端点击的按钮,即流程连线的值
     * @param comment 批注信息
     */
    void completeMyTask(String taskId, String buttonValue, String comment) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        // 先设置批注人
        Authentication.setAuthenticatedUserId("批注人");
        // 后添加批注信息
        taskService.addComment(taskId, task.getProcessInstanceId(), comment);
        Map<String, Object> map = new HashMap<>();
        // 赋值流程图的连线动态定义的条件参数 lineValue
        map.put("lineValue", buttonValue);
        taskService.complete(taskId, map);
        // 修改请假单状态
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
        if (processInstance == null) {// 流程实例查不到则整个流程结束
            evection.setStatus("审核完成");
        }
    }
}

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值