java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Flowable整合SpringBoot

Flowable整合SpringBoot实现的示例代码

作者:C和弦与炊烟

本文详细介绍了如何在SpringBoot项目中整合Flowable进行工作流管理,包括依赖引入、流程部署与启动、表结构、流程挂起和激活以及任务分配等关键操作,具有一定的参考价值,感兴趣的可以了解一下

一、SringBoot整合Flowable

1.引入依赖

SpringBoot使用2.7.1,亲测3.3.0不能用,JDK使用1.8

建议slf4j版本如下,不会报错,太高了报错

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
 
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter</artifactId>
            <version>6.7.2</version>
            <!--关闭自带的权限认证-->
             <exclusions>
                <exclusion>
                    <groupId>org.flowable</groupId>
                    <artifactId>flowable-spring-security</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
<!--        日志-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>2.0.0</version>
        </dependency>

2.安装流程图绘制插件

Flowable BPMN visualizer

3.yml配置

server:
  port: 8080

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    #nullCatalogMeansCurrent=true 设置为只查当前连接的schema库
    url: jdbc:mysql://localhost:3306/flowable?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
    username: root
    password: root
flowable:
  #关闭定时任务
  async-executor-activate: true
  #数据库表与flowable最新表不一致会进行更新
  database-schema-update: true
logging:
  level:
    org:
      flowable: debug

二、Spring环境下的应用

1.流程部署与启动

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

    @Test
    void deployFlow(){
        //流程引擎的配置对象,关联相关数据源
        Deployment deploy = repositoryService.createDeployment()
                //一次部署所有processes文件夹内的流程
                .name("第一次部署")
                .deploy();
        System.out.println("deploy.getId()="+deploy.getId());
    }

    /**
     * 启动流程实例
     * 在流程定义表中动态维护 act_re_procdef
     */
    @Test
    void startFlow(){
        String processId="ask_for_leave.bpmn20:1:4";
        String processKey="ask_for_leave.bpmn20";
        //1.根据流程定义di启动流程实例
        runtimeService.startProcessInstanceById(processId);
        //2.根据流程定义key启动流程实例
        //runtimeService.startProcessInstanceByKey(processKey);
    }
	/**
     * 任务的审批
     * 需要数据:任务id
     */
    @Test
    void compeleteTask(){
        taskService.complete("2506");
    }

流程定义:相当于Java中的类

流程实例:相当于java中的对象

注意:在Spring环境下,Spring会自动扫描processes文件夹,若不指定文件路径,则一次把所有bpmn流程全部部署,也就是一次创建所有流程定义。一个部署对应多个流程定义

 @Test
    void deployFlow(){
        Deployment deploy = repositoryService.createDeployment()
            	//如果再添加部署文件,会部署两次,导致流程定义中出现新版本的流程定义
                .addClasspathResource("processes/ask_for_leave.bpmn20.xml")
                .name("部署名称")
                .deploy();
        System.out.println("deploy.getId()="+deploy.getId());
    }

常用:1.通过bpmn部署。2.通过zip压缩包部署。3.自己创建model模型,然后保存到数据库中,再通过模型部署。

创建好model之后保存到act_re_model表中(上图仅仅是举个3的例子)。部署也是先从表中获取model部署。

2.表结构

act_ge_bytearray(重要),存放了流程定义的png图片。

3.流程挂起和激活

 /**
     * 流程定义的挂起和激活
     *act_re_procdef
     */
    @Test
    void suspendedActivity(){
        String processDefinitionId="ask_for_leave.bpmn20:1:4";
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(processDefinitionId)
                .singleResult();
        //获取当前流程定义的状态
        boolean suspended = processDefinition.isSuspended();
        if (suspended) {
            //挂起-->激活
            System.out.println("激活流程");
            repositoryService.activateProcessDefinitionById(processDefinitionId);
        }else {
            //激活-->挂起
            System.out.println("挂起流程");
            repositoryService.suspendProcessDefinitionById(processDefinitionId);
        }
    }

4.任务分配表达式Assignee

Assignee也可以写表达式

/**
     * 任务的审批
     * 需要数据:任务id,hashMap  "assign1","lisi"
     * 把当前任务分给lisi审批,运行后lisi可以查到待办
     */
    @Test
    void compeleteAssign1(){
        HashMap<String, Object> variables = new HashMap<>();
        variables.put("assign1","lisi");
        //完成任务审批,根据任务id绑定对应表达式的值
        taskService.complete("taskId",variables);
    }

(act_ru_actinst)出现了lisi

  @Test
    void findFlow(){
        //任务实例通过TaskService来实现
        TaskService taskService = getEngine().getTaskService();
        //获取到 act_ru_task中 assignee是lisi的记录
        List<Task> tasks = taskService.createTaskQuery()
                .taskAssignee("lisi")
                .list();
        tasks.forEach(System.out::println);
        //Task[id=15004, name=second]
    }

得到结果Task[id=15004, name=second],此时还需要审批。

------ 方法表达式${ myBean.getAssignee() } -------

//MyBean加入容器
@Component
public class MyBean {
    public String getAssignee(){
        System.out.println("getAssignee执行...");
        return "王五";
    }
}
​
    @Test
    void compeleteAssign1(){
        TaskService taskService = getEngine().getTaskService();
        //再执行审批时,会去MyBean中执行该方法
        taskService.complete("15004");
    }

拿到id后再执行审批。

5.流程变量

输出{var3=test3, var2=test2, var1=test1}

6.候选人

可以指定多个候选人,在启动流程时进行赋值就好。

	/**
     * 根据候选人查询任务
     * 候选人需要拾取任务才能变成审批人
     *只有一个人能变为审批人,审批人还可以归还,变成候选人
     */
    @Test
    void claimTask(){
        //act_ru_task中
        List<Task> tasks = taskService.createTaskQuery()
                //这里有改变
                .taskCandidateUser("张三")
                .list();
        for (Task task : tasks) {
            //拾取
            taskService.claim(task.getId(),"张三");
            //归还unclaim(task.getId(),"张三")
            //指派taskService.setAssignee(task.getId(),"xxx")
        }
    }

   @Test
    void findFlow(){
        //act_ru_task中
        List<Task> tasks = taskService.createTaskQuery()
                //这里有改变
                .taskCandidateUser("张三")
                .list();
        tasks.forEach(System.out::println);
    }

7.候选人组

	//先创建用户
	@Test
    void createUser(){
        User user = identityService.newUser("zhangsan");
        user.setEmail("zhansgan@qq.com");
        user.setFirstName("zhang");
        user.setLastName("san");
        user.setPassword("123456");
        identityService.saveUser(user);
    }

/**
     * 用户组
     */
    @Test
    void createGroup(){
        Group group = identityService.newGroup("xsb");
        group.setName("销售部");
        group.setType("type1");
        identityService.saveGroup(group);
    }
/**
     * 用户与用户组的关系
     */
    @Test
    void createMemberShip(){
        Group group = identityService.createGroupQuery().groupId("xsb").singleResult();
        List<User> users = identityService.createUserQuery().list();
        users.forEach(user -> {identityService.createMembership(user.getId(), group.getId());});
    }

act_id_group

act_id_membership

直接部署后启动,act_ru_identitylink中就会出现候选组信息。

 /**
     * 当前登录用户根据候选人组查询任务
     */
    @Test
    void findGroupTask(){
        //先查询当前所在的组 如查张三
        Group group = identityService.createGroupQuery()
                .groupMember("zhangsan").singleResult();
        System.out.println("当前用户所在组的id为:"+group.getId());
        List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup(group.getId()).list();
        for (Task task : tasks) {
            //拾取任务
            taskService.claim(task.getId(),"zhangsan");
        }
    }
    
    /**
     * 任务的审批
     */
    @Test
    void compeleteTask(){
        Map<String,Object> variables =new HashMap<>();
        taskService.complete("ae543ec1-1d5f-11ef-a409-005056c00008");
    }

8.网关

排他网关

在审批的时候加入day天数就能完成请假步骤,从而转向不同的审批人。

   @Test
    void compeleteTask(){
        Map<String,Object> variables =new HashMap<>();
        variables.put("day",3);
        taskService.complete("fae74a9a-1d6c-11ef-9a09-005056c00008");
    }

注意:条件尽量包含所有情况,否则报错。

并行网关

提交申请之后,task表中将会出现两条审批,分别是zhangsan和lisi。

包含网关

可以看成并行和排他的结合体

如num=2走三条,num=5走两条,num=8走三条

Tips

与Activiti7的区别

1.Activiti默认不开启数据库的历史记录,flowable默认开启

2.Activiti23张表,flowable79张表。

3.Flowable是Activiti的继任者,因此Flowable包含了Activiti的所有功能,并且在原有功能的基础上进行了进一步的改进和优化。

4.支持 CMMN 和 DMN 标准

三、SpringBoot项目中引入flowable

1.配置flowable独立数据源

flowable:
  async-executor-activate: false
  #第一次生成后关闭
  database-schema-update: true
  #保存历史数据级别
  history-level: full
  #解决乱码
  activity-font-name: "宋体"
  annotation-font-name: "宋体"
  label-font-name: "宋体"
  
#配置flowable数据源
flow:
  username: root
  password: root
  url: jdbc:mysql://localhost:3306/flowable2?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
  driver-class-name: com.mysql.cj.jdbc.Driver
  maxPoolSize: 30

2.创建配置类

import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.app.spring.SpringAppEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
​
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
​
/**
 * 一共有两个配置类,一个是ProcessEngineConfiguration,一个是SpringAppEngineConfiguration
 * 他们里面都需要重写configure方法来进行配置
 * 配置数据源应该在SpringAppEngineConfiguration中设定
 * 前者是配置ProcessEngine的,如自动生成表,设置中文,在yml文件中配置的属性便是在此类中读取
 */
@Configuration
@PropertySource("classpath:application-dev.yml")
@Slf4j
​
public class FlowableConfig implements EngineConfigurationConfigurer<SpringAppEngineConfiguration> {
​
    //读取配置
    @Value("${flow.username}")
    private String user;
    @Value("${flow.password}")
    String password;
    @Value("${flow.url}")
    String jdbcUrl;
    @Value("${flow.driver-class-name}")
    String driverClass;
    @Value("${flow.maxPoolSize}")
    int maxPoolSize;
​
//    @Bean(name = "processEngine")
//    public ProcessEngine processEngineConfiguration() throws PropertyVetoException {
//        ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration();
//        cfg.setDataSource(dataSource2());
//        cfg.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE);
//        cfg.setActivityFontName("宋体");
//        cfg.setLabelFontName("宋体");
//        cfg.setAnnotationFontName("宋体");
//        cfg.setAsyncExecutorActivate(false);
//        return cfg.buildProcessEngine();
//    }
​
    //配置数据源
    public DataSource dataSource2() throws PropertyVetoException {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        dataSource.setUrl(jdbcUrl);
        dataSource.setDriverClassName(driverClass);
        dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolSize);
        return dataSource;
    }
​
    @Override
    public void configure(SpringAppEngineConfiguration engineConfiguration) {
        try {
            //把数据源设置进来
            engineConfiguration.setDataSource(dataSource2());
            log.info("配置flowable数据源成功");
        } catch (PropertyVetoException e) {
            throw new RuntimeException(e);
        }
    }
}

注意这里配置的是SpringAppEngineConfiguration,而不是ProcessEngine,否则将出现报错,或者设置单独的数据源失败。

项目启动成功就可以看到自动创建的79张表了。然后把表的自动更新关闭,否则会影响性能。

到此这篇关于Flowable整合SpringBoot实现的示例代码的文章就介绍到这了,更多相关Flowable整合SpringBoot内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文