springboot2.0 整合 activiti 6.0

其实activiti被springboot整合后用起来简单很多,但还是非常推荐各位先去学习下activiti的原生基础运用,因为这样才能真正明白整合里面都干了些什么。废话就不多说了,直接来!

开发的版本: springboot 版本 2.0 + activiti 版本 6.0

开发工具:IDEA

1.引入依赖

这里用的mybatis链接数据库,还需要引入mysql的驱动(注意:mysql链接驱动的版本)

特别注意:跟 activiti6.0 匹配的mysql驱动版本不能太高!例如springboot2.0以后的默认使用的mysql驱动版本就太高了,版本不兼容会发生各种头疼且解决不了的问题。


      mysql
      mysql-connector-java
      5.1.35


      org.mybatis.spring.boot
      mybatis-spring-boot-starter
      2.0.0


      org.activiti
      activiti-spring-boot-starter-basic
      6.0.0

2.修改springboot的application.yml配置文件

数据源的信息是mybatis连接数据库的,你可以这样,配置详细的 activiti 的参数,注意 activiti 配置下的datasource 信息要一样

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    password: 123
    url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    username: root
  activiti:
    check-process-definitions: true #自动检查、部署流程定义文件
    database-schema-update: true #自动更新数据库结构
    #流程定义文件存放目录
    process-definition-location-prefix: classpath:/processes/
    #process-definition-location-suffixes: #流程文件格式
    datasource:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
      username: root
      password: 123
      initsize: 10
      maxActive: 20
      minIdle: 10
      maxWait: 120000
      poolPreparedStatements: false
      maxOpenPreparedStatements: -1
      validationQuery: select 1
      testOnborrow: true
      testOnReturn: true
      testWhileIdle: true
      timeBetweenEvictionRunsMillis: 120000

你也可以只配置 datasource 的配置,这是项目连接的数据源,springboot 整合 activiti 后默认就是去读的这个数据源

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    password: 123
    url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
    username: root

 

3.生成 activiti 所用到的所有表

直接运行下面的这个main方法,即可生成28张表(activiti6.0是28张表),每张表的作用这里就不介绍了,网上很多。

没有报错的前提是你的activiti版本跟mysql链接驱动的版本匹配,并且已经在配置文件指定数据源!

package com.liqiye.springbootdemo.test.activiti;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;

// 运行生成activiti流程依赖的表

public class ActivitiTable {

    public static void main(String[] args) {
        // 引擎配置
        ProcessEngineConfiguration pec=ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
        pec.setJdbcDriver("com.mysql.jdbc.Driver");
        pec.setJdbcUrl("jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC");
        pec.setJdbcUsername("root");
        pec.setJdbcPassword("123");
         
        /**
         * false 不能自动创建表
         * create-drop 先删除表再创建表
         * true 自动创建和更新表
         */
        pec.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);

        // 获取流程引擎对象
        ProcessEngine processEngine=pec.buildProcessEngine();

    }

}

4.画bpmn 图 

想要在IDEA 里进行 activiti的开发,必须要安装 actiBPM 插件 ,下图安装即可。

springboot2.0 整合 activiti 6.0_第1张图片

springboot 整合 activiti ,默认是启动项目后,在resources目录下的 processes 目录下读取 bpmn 流程文件,然后自动部署的,没错!不需要再自己写什么部署的方法了,项目自动帮我们完成。

注意:必须是 processes 目录,并且里面一定要有 bpmn 文件,不然项目启动报错!

在新建的processes目录下右键,new—BpmnFile ,起名leave.bpmn

springboot2.0 整合 activiti 6.0_第2张图片

然后画图 ,在界面的右边拖动流程的每一个模块,到中间组成一个流程图,点击对应的组件,在左边填写里面的id,审核人等的信息

这是我画的流程图,以及整个流程图的信息,注意:这里的id在后面开启流程的时候会用到,起名尽量规则且记住

springboot2.0 整合 activiti 6.0_第3张图片springboot2.0 整合 activiti 6.0_第4张图片

点击申请请假的绿色框,在左边填写 Assignee 的值为 ${user},记住这个标识,到后面启动流程或者审核流程需要传入参数。其实学习过activiti基础操作的同学应该明白在这里设置这个跟在xml里面设置参数是一样的。

springboot2.0 整合 activiti 6.0_第5张图片

同样的,我们在部门领导、公司领导那里也要设置审核人,那里我们就设置 ${users}

springboot2.0 整合 activiti 6.0_第6张图片

画完bpmn图了,因为idea没有给我们提供直接生成png图的功能,我们需要手动修改文件名后缀成xml,然后再右键这个leave.xml 文件 — Diagrams — Show BPMN2.0 Designer... 

springboot2.0 整合 activiti 6.0_第7张图片

然后点击下图的位置,选中项目processes目录下,生成png图片

springboot2.0 整合 activiti 6.0_第8张图片

其实springboot 整合 activiti 后,项目启动,会自动到processes目录下扫描,部署里面的bpmn文件,并且自动根据bpmn文件生成png图片的数据保存在数据库,没错,并不需要我们手动生成png图片!到时候可以直接从数据库查询并且显示流程图。

所以上面说了这么久如何生成png图片是做什么?没什么,就是学多点东西而已。

下面放上面流程图对应的xml文件,你可以直接复制到 processes 目录下,然后改后缀名为 bpmn 即可。



  
    
    
    
    
    
    
    
    
    
  
  
    
      
        
        
          
        
      
      
        
        
          
        
      
      
        
        
          
        
      
      
        
        
          
        
      
      
        
        
          
        
      
      
        
        
        
          
        
      
      
        
        
        
          
        
      
      
        
        
        
          
        
      
      
        
        
        
          
        
      
    
  

在启动项目之前,要先在springboot的启动类上面加上下面这个注解,因为activiti6.0比springboot2.0早很多,那时候还没有这个类,在启动时要排除他,不然就会报找不到该bean的错误。

springboot2.0 整合 activiti 6.0_第9张图片

@SpringBootApplication(exclude = SecurityAutoConfiguration.class)   // springboot2.0集成activiti6要加后面这个,因为6比较老版本

上面整合完 activiti 了,画完流程图,并且启动了项目,我们可以发现在之前数据库生成的 act_ge_bytearray 表中 多了两条数据,看名字就可以知道一条是部署的bpmn文件,一条是对应的png图片

4.编写 activiti 的功能接口

接下来我们编写接口来发起流程,审核流程,指定用户查看对应任务,指定发起者查看对应的流程,还有显示流程执行的图

先在controller注入要用到的 activiti 的工具

    @Autowired
    private ActivityService activityService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private IdentityService identityService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private RepositoryService repositoryService;

 

1)发起流程

注意:如果你在流程图指定了 Assignee ,这里当你启动流程时,必须要传进参数,不然报错。这里参数一般是传用户id进数据库保存

    // 发起流程
    @RequestMapping("/initiationProcess")
    @ResponseBody
    public String initiationProcess(){
        System.out.println("method startActivityDemo begin....");

        System.out.println( "调用流程存储服务,已部署流程数量:"
                + repositoryService.createDeploymentQuery().count());

        Map map = new HashMap();
        // 流程图里写的${user} ,这里传进去user
        map.put("user","liqiye");

        //流程启动
        identityService.setAuthenticatedUserId("liqiye");    // 指定流程的发起者 不指定发起者的字段就为空,注意跟审核人分开
        ExecutionEntity pi = (ExecutionEntity) runtimeService.startProcessInstanceByKey("leave",map);
        System.out.println("启动流程成功!");

        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
        System.out.println("任务ID: "+task.getId());
        System.out.println("任务的办理人: "+task.getAssignee());
        System.out.println("任务名称: "+task.getName());
        System.out.println("任务的创建时间: "+task.getCreateTime());
        System.out.println("流程实例ID: "+task.getProcessInstanceId());

        Map map2 = new HashMap();
        map2.put("users","lisi,wangwu");
        taskService.complete(task.getId(),map2);  // 开启后,环节会走到发起请假请求,要完成这个环节,才能到下一个审核环节

        System.out.println("method startActivityDemo end....");
        return "success";
    }

2)审核任务

把上面打印出来的taskId 记下来,然后发起下面的接口链接,即可审核任务

    // 根据 taskid 审核任务
    @RequestMapping("/audit")
    @ResponseBody
    public String audit(String taskId){

        Map map = new HashMap();
        // 流程图里写的${users} ,这里传进去users
        map.put("users","lisi,wangwu");

        taskService.complete(taskId,map);
        return "success";
    }

3)指定用户查看对应任务

    // 通过用户名查询该用户的所有任务
    @RequestMapping("/checkByUser")
    @ResponseBody
    public String checkByUser(String user){
        List tasks = taskService//与任务相关的Service
                .createTaskQuery()//创建一个任务查询对象
                .taskAssignee(user)
                .list();
        if(tasks !=null && tasks.size()>0){
            for(Task task:tasks){
                System.out.println("任务ID:"+task.getId());
                System.out.println("任务的办理人:"+task.getAssignee());
                System.out.println("任务名称:"+task.getName());
                System.out.println("任务的创建时间:"+task.getCreateTime());
                System.out.println("流程实例ID:"+task.getProcessInstanceId());
            }
        }
        return "success";
    }

4)指定发起者查看对应的流程

    // 通过发起者查询该用户发起的所有任务
    @RequestMapping("/checkByInitiator")
    @ResponseBody
    public String checkByInitiator(String user){
        List list = runtimeService.createProcessInstanceQuery().startedBy(user).list();  //获取该用户发起的所有流程实例
        // System.out.println(list.toString());
        for (ProcessInstance processInstance : list) {
            List tasks = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
            if(tasks !=null && tasks.size()>0){
                for(Task task:tasks){
                    System.out.println("任务ID:"+task.getId());
                    System.out.println("任务的办理人:"+task.getAssignee());
                    System.out.println("任务名称:"+task.getName());
                    System.out.println("任务的创建时间:"+task.getCreateTime());
                    System.out.println("流程实例ID:"+task.getProcessInstanceId());
                }
            }
        }
        return "success";
    }

5)显示流程执行的图

直接发起这个接口就可以显示对应的流程图

    /**
     * 获取流程图 执行到哪里高亮显示
     * @param procDefId 部署的流程id  在 act_re_procdef 这张表里
     * @param execId  要查询的流程执行的id(开启了一个流程就会生成一条执行的数据)  在 act_ru_execution 这张表里(该表下PROC_DEF_ID_字段可以判断哪个流程)
     * @param response
     * @throws Exception
     */
    @RequestMapping("/getActPic/{procDefId}/{execId}")
    public void  getActPic(@PathVariable("procDefId") String procDefId,
                           @PathVariable("execId") String execId, HttpServletResponse response)throws Exception {
        InputStream imageStream = activityService.tracePhoto(procDefId, execId);
        // 输出资源内容到相应对象
        byte[] b = new byte[1024];
        int len;
        while ((len = imageStream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }

ActivitiService 里的方法

        // 获取流程图 执行到哪里红色显示
	public InputStream tracePhoto(String processDefinitionId, String executionId) {
		// ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(executionId).singleResult();
		BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

		List activeActivityIds = new ArrayList();
		if (runtimeService.createExecutionQuery().executionId(executionId).count() > 0){
			activeActivityIds = runtimeService.getActiveActivityIds(executionId);
		}

		// 不使用spring请使用下面的两行代码
		// ProcessEngineImpl defaultProcessEngine = (ProcessEngineImpl)ProcessEngines.getDefaultProcessEngine();
		// Context.setProcessEngineConfiguration(defaultProcessEngine.getProcessEngineConfiguration());

		// 使用spring注入引擎请使用下面的这行代码
		Context.setProcessEngineConfiguration(processEngineFactory.getProcessEngineConfiguration());
		// return ProcessDiagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds);
		return processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator()
				.generateDiagram(bpmnModel, "png", activeActivityIds);
	}

 

我这里只是测试了一个非常简单的流程,当然,实际开发中基本会在流程图里用到互斥网关,或者并行网关什么的,开发起来也差不多,无非是复杂点,这里就不一一介绍了。

你可能感兴趣的:(springboot,springboot)