zoukankan      html  css  js  c++  java
  • Activiti工作流

    分享一下手把手教你如何玩转Activiti工作流

    还未完善

    场景:学校    

    主角:阿毛  ,   班主任   ,教务处处长

    问题:有一天,阿毛到学校,感觉到身体不舒服,然后想跟班主任请假,然后班主任告诉阿毛说,你想请假,那么就必须要请假条,这个上面必须要我同意,然后再拿到教务处去盖章,然后交给我,这样才可以进行请假。。阿毛,想着,怎么请个假都这么麻烦,这么多层次处理问题,能不能简便一点。。。。好烦好烦~!!~~

    分析:从上面的小例子,我们可以很明显的得到一个结论,就是:

    请假流程:阿毛------》提交申请-----》班主任审批-----》教务处审批-----》请假成功

    也就是说,这种问题就是一种流式的控制管理,当然,这是最简单的,因为里面没有包含着回馈,相当于只是一个方向。其实,到这里,Activiti的定义就已经出来了。。。。。
     

    大纲:

    之前做过一些项目没有用到工作流,都是以状态控制整个流程,现在系统化的将工作流分享一下

    使用activiti-designer-5.18.0.zip

    2.创建SpringBoot工程

    ①编辑POM文件

    <!-- 继承SpringBoot官方指定的父工程 -->
    <parent>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starter-parent</artifactId>
    	<version>1.5.12.RELEASE</version>
    </parent>
    <dependencies>
    	<!-- MySQL驱动 -->
    	<dependency>
    		<groupId>mysql</groupId>
    		<artifactId>mysql-connector-java</artifactId>
    	</dependency>
    	<!-- 数据库连接池 -->
    	<dependency>
    		<groupId>com.alibaba</groupId>
    		<artifactId>druid</artifactId>
    		<version>1.0.5</version>
    	</dependency>
    	<!-- MyBatis场景启动器 -->
    	<dependency>
    		<groupId>org.mybatis.spring.boot</groupId>
    		<artifactId>mybatis-spring-boot-starter</artifactId>
    		<version>1.1.1</version>
    	</dependency>
    	<!-- Activiti场景启动器 -->
    	<dependency>
    		<groupId>org.activiti</groupId>
    		<artifactId>activiti-spring-boot-starter-basic</artifactId>
    		<version>5.21.0</version>
    	</dependency>
    	<!-- 基本场景启动器 -->
    	<dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter</artifactId>
    	</dependency>
    	<!-- SpringBoot测试支持 -->
    	<dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-test</artifactId>
    	</dependency>
    </dependencies>

    特别说明:请把mybatis-spring-boot-starter的依赖放在activiti-spring-boot-starter-basic的前面以避免jar包冲突问题。jar包冲突的表现是:java.lang.ClassNotFoundException: org.apache.ibatis.annotations.Mapper。

    依赖顺序和依赖传递的关系: mybatis-spring-boot-starter依赖mybatis-3.4.0.jar,而activiti-spring-boot-starter-basic依赖mybatis-3.3.0.jar,对于这种情况,Maven以顺序靠前的为准。现在如果导入的是mybatis-3.3.0.jar就会抛出异常,而mybatis-3.4.0.jar是正确的,所以要让mybatis-spring-boot-starter的依赖放在activiti-spring-boot-starter-basic的前面。

    ②主启动类

    @SpringBootApplication
    public class MainApplication {
    	
    	public static void main(String[] args) {
    		SpringApplication.run(MainApplication.class, args);
    	}
    
    }

    ③测试类

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class ProcessTest {
    	
    	@Autowired
    	private ProcessEngine processEngine;
    	
    	@Test
    	public void createTable() {
    		System.out.println(processEngine);
    	}
    
    }

    ④yml配置

    spring:
      datasource:
        name: mydb
        type: com.alibaba.druid.pool.DruidDataSource
        url: jdbc:mysql://127.0.0.1:3306/db_activiti
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver

    ⑤特别操作

    在src/main/java目录下创建processes目录,否则将抛出异常:java.io.FileNotFoundException: class path resource [processes/] cannot be resolved to URL because it does not exist。processes目录的作用是存放bpmn流程定义文件,并对bpmn文件进行自动部署。如果创建到src/main/resources目录下则要求processes目录下至少存在一个文件(任意)。

    三、流程操作

    1.创建第一个流程图

    2.流程部署

    ①Java代码

    注意:如果放在processes目录下会被自动部署,下面的Java代码是手动部署。

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class ProcessTest {
        @Autowired
        private RepositoryService repositoryService;
        @Test
        public void test01ProcessDefinitionDeployment() {
            //部署:将流程定义文件中流程定义信息存入数据库
            repositoryService
                .createDeployment()     //创建部署构建器对象
                .addClasspathResource("MyProcess.bpmn")   //添加要部署的流程定义文件名
                .deploy();      //执行部署
        }
    
    }

    ②数据库表分析

    [1]act_ge_bytearray表

    二进制数据表,存储了流程定义图形的XML文件和图片信息
    保存流程定义的xml信息
    保存流程定义的图片

    [2]act_re_deployment表

    部署信息表,存储了部署的相关信息(部署时间)

    [3]act_re_procdef表

    流程定义数据表,存储了当前流程图形的相关信息(id,name,版本号)

    ③解决乱码问题

    import org.activiti.spring.SpringProcessEngineConfiguration;
    import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class ActivitiConfig implements ProcessEngineConfigurationConfigurer {
    
        @Override
        public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
            processEngineConfiguration.setActivityFontName("宋体");
            processEngineConfiguration.setLabelFontName("宋体");
        }
    
    }
    

    3.流程查询

    ①第一步:创建ProcessDefinitionQuery对象

        @Test
        public void test02ProcessDefinitionQuery() {
            //1.创建流程定义查询对象
            ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
            //2.调用对应的方法执行查询
            List<ProcessDefinition> list = query.list();
            //3.遍历集合
            for (ProcessDefinition processDefinition : list) {
                String key = processDefinition.getKey();
                String name = processDefinition.getName();
                int version = processDefinition.getVersion();
                
                System.err.println("key="+key);
                System.err.println("name="+name);
                System.err.println("version="+version);
            }
        }

    注意2:创建了新的流程定义需要再次执行部署,再次启动流程。

    6.查询任务和7.完成任务

    @Test
        public void test03TaskQuery() {
            //创建任务查询对象
            TaskQuery query = taskService.createTaskQuery();
            //根据流程定义key和委托人查询待办任务
            List<Task> list = query.processDefinitionKey("MyProcess").taskAssignee("zuzu").list();
            for (Task task : list) {
                String assignee = task.getAssignee();
                String taskId = task.getId();
                String taskName = task.getName();
                //taskService需要使用@Autowired注解装配
                taskService.complete(task.getId());//完成任务,使任务进入下一步
                System.err.println("assignee="+assignee);
                System.err.println("taskId="+taskId);
                System.err.println("taskName="+taskName);
            }
        }

    8.查询流程实例历史

    //1.创建流程实例的历史查询对象,historyService使用@Autowired注解注入
    HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery();
    HistoricProcessInstance instance = 
    		query.processInstanceId("7501")	//流程实例的id
    			.finished()//调用这个方法后未完成的流程实例会返回null
    			.singleResult();
    System.out.println(instance);

    9.将任务指派给一个组

    注意1:创建的新的流程定义要指定一个新的id。
    注意2:创建了新的流程定义需要再次执行部署,再次启动流程。

    10.领取任务

        @Test
        public void test04Claim() {
            //1.创建任务查询对象
            TaskQuery taskQuery = taskService.createTaskQuery();
            //2.根据任务委托组查询任务列表
            List<Task> list = taskQuery.taskCandidateGroup("jingli").list();
            //3.遍历
            for (Task task : list) {
                String taskId = task.getId();
                String userId = "jingli";
                //3.指派任务
                taskService.claim(taskId, userId);
            }
        }

    提示:可以根据任务委托人在领取任务前和领取任务后分别查询任务,之前没有之后有即为正确。

    TaskQuery query = taskService.createTaskQuery();//创建任务查询对象
    List<Task> list = query.processDefinitionKey("MyProcess")	//指定流程定义
    			.taskAssignee("jingli")//指定委托人
    			.list();//执行查询
    for (Task task : list) {
    	System.out.println(task);
    }

    11.流程变量

    ①在创建流程定义时指定流程变量

    例如:用变量的方式指定委托人

    创建MyProcess02.bpmn

    创建后正常部署

        @Test
        public void test01ProcessDefinitionDeployment() {
            //部署:将流程定义文件中流程定义信息存入数据库
            repositoryService
                .createDeployment()     //创建部署构建器对象
                .addClasspathResource("MyProcess02.bpmn")   //添加要部署的流程定义文件名
                .deploy();      //执行部署
        }

    ②启动

        @Test
        public void test05StartProcessInstance() {
            //1.查询流程定义对象
            ProcessDefinition processDefinition = 
                    repositoryService.createProcessDefinitionQuery()
                                     .processDefinitionKey("MyProcess02")
                                     .latestVersion()
                                     .singleResult();
            //2.获取流程定义的id
            String processDefinitionId = processDefinition.getId();
            //3.使用RunTimeService根据流程定义id启动流程定义
            ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId);
            //4.打印processInstance对象
            System.err.println(processInstance);
            
        }

    带有变量的流程启动时,如果第一个任务中就存在变量,那么启动的时候就必须给出变量值。否则将抛出异常:org.activiti.engine.impl.javax.el.PropertyNotFoundException: Cannot resolve identifier 'erzi'

        @Test
        public void test06StartProcessInstanceWithVariable() {
            //1.查询流程定义对象
            ProcessDefinition processDefinition = 
                    repositoryService.createProcessDefinitionQuery()
                                     .processDefinitionKey("MyProcess02")
                                     .latestVersion()
                                     .singleResult();
            //2.获取流程定义的id
            String processDefinitionId = processDefinition.getId();
            //※为第一个任务指定流程变量
            Map<String,Object> variables = new HashMap<String, Object>();
            variables.put("erzi", "zhangsan");
            //3.使用RunTimeService根据流程定义id启动流程定义
            ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId, variables);
            //4.打印processInstance对象
            System.err.println(processInstance);
        }

    ③完成任务

    如果完成当前任务时,下一个任务中包含变量,那么此时也必须给出下一个任务的变量值

        @Test
        public void test7CompleteTaskWithVariables() {
            List<Task> list = 
                    taskService.createTaskQuery() //创建任务查询对象
                               .processDefinitionKey("MyProcess02")//指定流程定义
                               .taskAssignee("zhangsan")//指定委托人
                               .list();//执行查询
            for (Task task : list) {
                String taskId = task.getId();
                //在完成当前任务时,为下一个任务指定流程变量
                Map<String,Object> variables = new HashMap<String, Object>();
                variables.put("sunzi", "lisi");
                //完成当前任务时为下一个任务指定变量值
                taskService.complete(taskId, variables);//完成任务,使任务进入下一步
                //Unknown property used in expression: ${sunzi}
                //taskService.complete(taskId);
            }
        }

    12.排他网关

    ①创建流程定义

    部署、启动

        @Test
        public void test01ProcessDefinitionDeployment() {
            //部署:将流程定义文件中流程定义信息存入数据库
            repositoryService
                .createDeployment()     //创建部署构建器对象
                .addClasspathResource("MyProcess03.bpmn")   //添加要部署的流程定义文件名
                .deploy();      //执行部署
        }
        @Test
        public void test05StartProcessInstance() {
            //1.查询流程定义对象
            ProcessDefinition processDefinition = 
                    repositoryService.createProcessDefinitionQuery()
                                     .processDefinitionKey("MyProcess03")
                                     .latestVersion()
                                     .singleResult();
            //2.获取流程定义的id
            String processDefinitionId = processDefinition.getId();
            //3.使用RunTimeService根据流程定义id启动流程定义
            ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId);
            //4.打印processInstance对象
            System.err.println(processInstance);
            
        }

    ②完成第一个任务时为排他网关指定变量值

        @Test
        public void test7CompleteTaskWithVariables() {
            List<Task> list = 
                    taskService.createTaskQuery() //创建任务查询对象
                               .processDefinitionKey("MyProcess03")//指定流程定义
                               .taskAssignee("zhangsan")//指定委托人
                               .list();//执行查询
            for (Task task : list) {
                String taskId = task.getId();
                //在完成当前任务时,为下一个任务指定流程变量
                Map<String,Object> variables = new HashMap<String, Object>();
                variables.put("day", "5");
                //完成当前任务时为下一个任务指定变量值
                taskService.complete(taskId, variables);//完成任务,使任务进入下一步
                //Unknown property used in expression: ${sunzi}
                //taskService.complete(taskId);
            }
        }

    [3]创建流程监听器类

    import org.activiti.engine.delegate.DelegateExecution;
    import org.activiti.engine.delegate.ExecutionListener;
    
    public class YesListener implements ExecutionListener {
    
        private static final long serialVersionUID = 1L;
    
        @Override
        public void notify(DelegateExecution execution) throws Exception {
            System.err.println("YesListener触发了!!!");
        }
    
    }
    import org.activiti.engine.delegate.DelegateExecution;
    import org.activiti.engine.delegate.ExecutionListener;
    
    public class NoListener implements ExecutionListener {
    
        private static final long serialVersionUID = 1L;
    
        @Override
        public void notify(DelegateExecution execution) throws Exception {
            System.err.println("NoListener触发了!!!");
        }
    
    }

    [4]绑定监听器

    ④操作

    • 部署
    •     /**
           * 部署
           */
          @Test
          public void test01ProcessDefinitionDeployment() {
              //部署:将流程定义文件中流程定义信息存入数据库
              repositoryService
                  .createDeployment()     //创建部署构建器对象
                  .addClasspathResource("MyProcess04.bpmn")   //添加要部署的流程定义文件名
                  .deploy();      //执行部署
          }
    • 启动
    •     /**
           * 启动流程
           */
          @Test
          public void test05StartProcessInstance() {
              //1.查询流程定义对象
              ProcessDefinition processDefinition = 
                      repositoryService.createProcessDefinitionQuery()
                                       .processDefinitionKey("MyProcess04")
                                       .latestVersion()
                                       .singleResult();
              //2.获取流程定义的id
              String processDefinitionId = processDefinition.getId();
              //3.使用RunTimeService根据流程定义id启动流程定义
              ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId);
              //4.打印processInstance对象
              System.err.println(processInstance);
              
          }
    • 完成任务时为排他网关指定flag变量值
    •     /**
           * 完成任务
           */
          @Test
          public void test7CompleteTaskWithVariables() {
              List<Task> list = 
                      taskService.createTaskQuery() //创建任务查询对象
                                 .processDefinitionKey("MyProcess04")//指定流程定义
                                 .taskAssignee("zhangsan")//指定委托人
                                 .list();//执行查询
              for (Task task : list) {
                  String taskId = task.getId();
                  //在完成当前任务时,为下一个任务指定流程变量
                  Map<String,Object> variables = new HashMap<String, Object>();
                  variables.put("flag", "true");
                  //完成当前任务时为下一个任务指定变量值
                  taskService.complete(taskId, variables);//完成任务,使任务进入下一步
                  //Unknown property used in expression: ${sunzi}
                  //taskService.complete(taskId);
              }
          }
    • 观察监听器执行情况
  • 相关阅读:
    java8大排序
    如何删除oracle 的用户及其数据
    JavaScript开发者常忽略或误用的七个基础知识点
    Vim学习指南
    5个开发人员不应该错过的最好跨平台PHP编辑器
    OpenGL 简介
    web 页面内容优化管理与性能技巧
    创建高性能移动 web 站点
    近期十大优秀jQuery插件推荐
    30本世界名著浓缩成的经典话语
  • 原文地址:https://www.cnblogs.com/javawxid/p/12812040.html
Copyright © 2011-2022 走看看