flowable_flowable 条件 - CSDN
精华内容
参与话题
  • Flowable 快速入门教程:SpringBoot 集成 Flowable + Flowable Modeler 流程配置可视化(超详细)版本加依赖内部日志初始化 ProcessEngine代码初始化flowable.cfg.xml 初始化我的初始化示例 版本 这里选择的版本为...

    版本

    这里选择的版本为 6.4.1

    Flowable 6.4.1 release

    中文版用户手册:Flowable BPMN 用户手册

    如果需要集成 Flowable Modeler 的请下载源码

    PS:不要选择 6.4.2 版本,这个版本有发版问题

    加依赖

    由于是 spring-boot 集成,因此直接选择 flowable-spring-boot-starter,里面提供了齐全的 REST API

    <!-- Flowable spring-boot 版套餐 -->
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-spring-boot-starter</artifactId>
        <version>6.4.1</version>
    </dependency>
    

    其他的也可以直接选择 flowable-engine

    <!-- flowable-engine -->
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-engine</artifactId>
        <version>6.4.1</version>
    </dependency>
    
    

    加配置

    # flowable 配置
    flowable:
      # 关闭异步,不关闭历史数据的插入就是异步的,会在同一个事物里面,无法回滚
      # 开发可开启会提高些效率,上线需要关闭
      async-executor-activate: false
    

    内部日志

    Flowable 使用 SLF4J 作为内部日志框架。在这个例子中,我们使用 log4j 作为 SLF4J 的实现。

    加依赖

    <!-- Flowable 内部日志采用 SLF4J -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.21</version>
    </dependency>
    

    resource 目录下新建文件 log4j.properties

    log4j.rootLogger=DEBUG, CA
    log4j.appender.CA=org.apache.log4j.ConsoleAppender
    log4j.appender.CA.layout=org.apache.log4j.PatternLayout
    log4j.appender.CA.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n
    

    初始化 ProcessEngine

    代码初始化

    // 流程引擎配置
    ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
                        .setJdbcUrl(url)
                        .setJdbcUsername(username)
                        .setJdbcPassword(password)
                        .setJdbcDriver(driverClassName)
                        // 初始化基础表,不需要的可以改为 DB_SCHEMA_UPDATE_FALSE
                        .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
    // 初始化流程引擎对象
    ProcessEngine processEngine = cfg.buildProcessEngine();
    

    flowable.cfg.xml 初始化

    代码部分

    // 流程引擎配置
    ProcessEngineConfiguration cfg = ProcessEngineConfiguration
    	// 根据文件名获取配置文件
            //.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
            // 获取默认配置文件,默认的就是 activiti.cfg.xml
            .createProcessEngineConfigurationFromResourceDefault()
            // 初始化基础表,不需要的可以改为 DB_SCHEMA_UPDATE_FALSE
            .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
    // 初始化流程引擎对象
    ProcessEngine processEngine = cfg.buildProcessEngine();
    

    新建 flowable.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="processEngineConfiguration" class="org.flowable.engine.impl.cfg.StandaloneProcessEngineConfiguration">
            <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/test"/>
            <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
            <property name="jdbcUsername" value="root"/>
            <property name="jdbcPassword" value="123456"/>
            <property name="databaseSchemaUpdate" value="true"/>
        </bean>
    </beans>
    

    我的初始化示例

    我的配置文件 ProcessEngineConfig.java

    依赖

    • spring-boot-configuration-processor 加载配置文件
    • lomok 简化 java 代码
    <!-- 配置文件处理器 -->
    <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-configuration-processor</artifactId>
     </dependency>
     <!-- lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.0</version>
        <scope>provided</scope>
    </dependency>
    
    /**
     * 流程引擎配置文件
     * @author: linjinp
     * @create: 2019-10-21 16:49
     **/
    @Configuration
    @ConfigurationProperties(prefix = "spring.datasource")
    @Data
    public class ProcessEngineConfig {
    
        private Logger logger = LoggerFactory.getLogger(ProcessEngineConfig.class);
    
        @Value("${spring.datasource.url}")
        private String url;
    
        @Value("${spring.datasource.driver-class-name}")
        private String driverClassName;
    
        @Value("${spring.datasource.username}")
        private String username;
    
        @Value("${spring.datasource.password}")
        private String password;
    
        @Value("${spring.datasource.publicKey}")
        private String publicKey;
    
        /**
         * 初始化流程引擎
         * @return
         */
        @Primary
        @Bean(name = "processEngine")
        public ProcessEngine initProcessEngine() {
            logger.info("=============================ProcessEngineBegin=============================");
    
            // 流程引擎配置
            ProcessEngineConfiguration cfg = null;
    
            try {
                cfg = new StandaloneProcessEngineConfiguration()
                        .setJdbcUrl(url)
                        .setJdbcUsername(username)
                        .setJdbcPassword(ConfigTools.decrypt(publicKey, password))
                        .setJdbcDriver(driverClassName)
                        // 初始化基础表,不需要的可以改为 DB_SCHEMA_UPDATE_FALSE
                        .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE)
                        // 默认邮箱配置
                        // 发邮件的主机地址,先用 QQ 邮箱
                        .setMailServerHost("smtp.qq.com")
                        // POP3/SMTP服务的授权码
                        .setMailServerPassword("xxxxxxx")
                        // 默认发件人
                        .setMailServerDefaultFrom("836369078@qq.com")
                        // 设置发件人用户名
                        .setMailServerUsername("管理员")
                        // 解决流程图乱码
                        .setActivityFontName("宋体")
                        .setLabelFontName("宋体")
                        .setAnnotationFontName("宋体");
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 初始化流程引擎对象
            ProcessEngine processEngine = cfg.buildProcessEngine();
            logger.info("=============================ProcessEngineEnd=============================");
            return processEngine;
        }
    }
    

    PS:这里没有单独对流程引擎中的 8 个核心服务做初始化,是因为使用 flowable-spring-boot-starter 依赖,会自动帮忙注册好,不需要自己再注册,直接使用即可

    如果你使用的依赖是 flowable-engine,你可能还需要

    //八大接口
    // 业务流程的定义相关服务
    @Bean
    public RepositoryService repositoryService(ProcessEngine processEngine){
        return processEngine.getRepositoryService();
    }
    
    // 流程对象实例相关服务
    @Bean
    public RuntimeService runtimeService(ProcessEngine processEngine){
        return processEngine.getRuntimeService();
    }
    
    // 流程任务节点相关服务
    @Bean
    public TaskService taskService(ProcessEngine processEngine){
        return processEngine.getTaskService();
    }
    
    // 流程历史信息相关服务
    @Bean
    public HistoryService historyService(ProcessEngine processEngine){
        return processEngine.getHistoryService();
    }
    
    // 表单引擎相关服务
    @Bean
    public FormService formService(ProcessEngine processEngine){
        return processEngine.getFormService();
    }
    
    // 用户以及组管理相关服务
    @Bean
    public IdentityService identityService(ProcessEngine processEngine){
        return processEngine.getIdentityService();
    }
    
    // 管理和维护相关服务
    @Bean
    public ManagementService managementService(ProcessEngine processEngine){
        return processEngine.getManagementService();
    }
    
    // 动态流程服务
    @Bean
    public DynamicBpmnService dynamicBpmnService(ProcessEngine processEngine){
        return processEngine.getDynamicBpmnService();
    }
    //八大接口 end
    

    集成 Flowable Modeler

    下载源码

    版本为 6.4.1,不多说了,看文章开头下载源码

    文件位置

    打开文件夹 flowable-ui-modeler

    路径:flowable-engine-flowable-6.4.1\modules\flowable-ui-modeler

    • flowable-ui-modeler-app:主要为前端界面,文件在 resource/static
    • flowable-ui-modeler-conf:主要为一些配置文件 Configuration
    • flowable-ui-modeler-logic:主要为一些业务逻辑还有 SQL
    • flowable-ui-modeler-rest:主要为 rest 接口

    这些都是需要用到的

    新增依赖

    使用 rest,logic,conf 的依赖

    <!-- flowable 集成依赖 rest,logic,conf -->
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-ui-modeler-rest</artifactId>
        <version>6.4.1</version>
    </dependency>
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-ui-modeler-logic</artifactId>
        <version>6.4.1</version>
    </dependency>
    <dependency>
        <groupId>org.flowable</groupId>
        <artifactId>flowable-ui-modeler-conf</artifactId>
        <version>6.4.1</version>
    </dependency>
    

    代码集成

    前端代码集成

    在项目中的 resource 文件夹下新建一个 static 文件夹

    SpringBoot 能自动读取 static 目录下的静态文件,因此文件夹名称不可随意更改

    复制 flowable-ui-modeler-app 包中 resources\static 下所有文件,复制到新建的 static

    路径:flowable-engine-flowable-6.4.1\modules\flowable-ui-modeler\flowable-ui-modeler-app\src\main\resources\static

    在这里插入图片描述

    后端代码集成

    复制以下文件到自己的项目中

    ApplicationConfiguration.java

    路径:flowable-engine-flowable-6.4.1\modules\flowable-ui-modeler\flowable-ui-modeler-conf\src\main\java\org\flowable\ui\modeler\conf

    原因:这个文件是启动中必要的配置文件,需要做修改,详细的可以看下 app 中启动类,文件路径随意

    AppDispatcherServletConfiguration.java

    路径:flowable-engine-flowable-6.4.1\modules\flowable-ui-modeler\flowable-ui-modeler-conf\src\main\java\org\flowable\ui\modeler\servlet

    原因:这个文件是启动中必要的配置文件,需要做修改,详细的可以看下 app 中启动类,文件路径随意

    StencilSetResource.java

    路径:flowable-engine-flowable-6.4.1\modules\flowable-ui-modeler\flowable-ui-modeler-rest\src\main\java\org\flowable\ui\modeler\rest\app

    同时在 resource 下新建一个 stencilset 文件夹用来放汉化文件,可以直接下载我上传的

    原因:国际化配置加载,为了使用我们自己的汉化文件因此把文件拿出来并修改,文件路径随意

    PS:复制出来后要对这个文件进行重命名,否则会与 Jar 包里的文件产生 Bean 存在的冲突

    我这重命名后叫 FlowableStencilSetResource.java

    SecurityUtils

    路径:flowable-engine-flowable-6.4.1\modules\flowable-ui-common\src\main\java\org\flowable\ui\common\security

    原因:流程模型加载需要调用的工具类,文件路径需要与原路径保持一致

    也就是包路径必须是 org.flowable.ui.common.security 这样在 Jar 中的方法在调用时会覆盖原 Jar 里的工具类

    结构

    在这里插入图片描述

    代码修改

    ApplicationConfiguration 修改

    此文件不需要过多说明,主要移除 IDM 方面的配置

    注意 conf 目录不要引入,里面也包含和 IDM 相关的配置

    @Configuration
    @EnableConfigurationProperties(FlowableModelerAppProperties.class)
    @ComponentScan(basePackages = {
    //        "org.flowable.ui.modeler.conf", // 不引入 conf
            "org.flowable.ui.modeler.repository",
            "org.flowable.ui.modeler.service",
    //        "org.flowable.ui.modeler.security", //授权方面的都不需要
    //        "org.flowable.ui.common.conf", // flowable 开发环境内置的数据库连接
    //        "org.flowable.ui.common.filter", // IDM 方面的过滤器
            "org.flowable.ui.common.service",
            "org.flowable.ui.common.repository",
            //
    //        "org.flowable.ui.common.security",//授权方面的都不需要
            "org.flowable.ui.common.tenant" },excludeFilters = {
            // 移除 RemoteIdmService
            @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = RemoteIdmService.class)
        }
    )
    public class ApplicationConfiguration {
    
        @Bean
        public ServletRegistrationBean modelerApiServlet(ApplicationContext applicationContext) {
            AnnotationConfigWebApplicationContext dispatcherServletConfiguration = new AnnotationConfigWebApplicationContext();
            dispatcherServletConfiguration.setParent(applicationContext);
            dispatcherServletConfiguration.register(ApiDispatcherServletConfiguration.class);
            DispatcherServlet servlet = new DispatcherServlet(dispatcherServletConfiguration);
            ServletRegistrationBean registrationBean = new ServletRegistrationBean(servlet, "/api/*");
            registrationBean.setName("Flowable Modeler App API Servlet");
            registrationBean.setLoadOnStartup(1);
            registrationBean.setAsyncSupported(true);
            return registrationBean;
        }
    }
    

    AppDispatcherServletConfiguration 修改

    同理,为了不引入 IDM 的配置

    @Configuration
    @ComponentScan(value = { "org.flowable.ui.modeler.rest.app",
            // 不加载 rest,因为 getAccount 接口需要我们自己实现
    //        "org.flowable.ui.common.rest"
        },excludeFilters = {
            // 移除 EditorUsersResource 与 EditorGroupsResource,因为不使用 IDM 部分
            @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = EditorUsersResource.class),
            @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = EditorGroupsResource.class),
            // 配置文件用自己的
            @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = StencilSetResource.class),
        }
    )
    @EnableAsync
    public class AppDispatcherServletConfiguration implements WebMvcRegistrations {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(AppDispatcherServletConfiguration.class);
    
        @Bean
        public SessionLocaleResolver localeResolver() {
            return new SessionLocaleResolver();
        }
    
        @Bean
        public LocaleChangeInterceptor localeChangeInterceptor() {
            LOGGER.debug("Configuring localeChangeInterceptor");
            LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
            localeChangeInterceptor.setParamName("language");
            return localeChangeInterceptor;
        }
    
        @Override
        public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
            LOGGER.debug("Creating requestMappingHandlerMapping");
            RequestMappingHandlerMapping requestMappingHandlerMapping = new RequestMappingHandlerMapping();
            requestMappingHandlerMapping.setUseSuffixPatternMatch(false);
            requestMappingHandlerMapping.setRemoveSemicolonContent(false);
            Object[] interceptors = { localeChangeInterceptor() };
            requestMappingHandlerMapping.setInterceptors(interceptors);
            return requestMappingHandlerMapping;
        }
    }
    

    SecurityUtils 修改

    这个主要保存时候会调这里的接口

    getCurrentUserObject 方法进行修改,让他获取默认的 admin

    /**
     * @return the {@link User} object associated with the current logged in user.
     */
    public static User getCurrentUserObject() {
        if (assumeUser != null) {
            return assumeUser;
        }
    
        RemoteUser user = new RemoteUser();
        user.setId("admin");
        user.setDisplayName("Administrator");
        user.setFirstName("Administrator");
        user.setLastName("Administrator");
        user.setEmail("admin@flowable.com");
        user.setPassword("123456");
        List<String> pris = new ArrayList<>();
        pris.add(DefaultPrivileges.ACCESS_MODELER);
        pris.add(DefaultPrivileges.ACCESS_IDM);
        pris.add(DefaultPrivileges.ACCESS_ADMIN);
        pris.add(DefaultPrivileges.ACCESS_TASK);
        pris.add(DefaultPrivileges.ACCESS_REST_API);
        user.setPrivileges(pris);
        return user;
    }
    

    新增 getAccount 接口

    新建文件 FlowableController,自己随意

    在加载页面时候会调用这个接口获取用户信息,由于我们绕过了登陆,因此给个默认的用户 admin

    为了不和原文件冲突,所以 @RequestMapping("/login")

    /**
     * Flowable 相关接口
     * @author linjinp
     * @date 2019/10/31 10:55
     */
    @RestController
    @RequestMapping("/login")
    public class FlowableController {
    
        /**
         * 获取默认的管理员信息
         * @return
         */
        @RequestMapping(value = "/rest/account", method = RequestMethod.GET, produces = "application/json")
        public UserRepresentation getAccount() {
            UserRepresentation userRepresentation = new UserRepresentation();
            userRepresentation.setId("admin");
            userRepresentation.setEmail("admin@flowable.org");
            userRepresentation.setFullName("Administrator");
    //        userRepresentation.setLastName("Administrator");
            userRepresentation.setFirstName("Administrator");
            List<String> privileges = new ArrayList<>();
            privileges.add(DefaultPrivileges.ACCESS_MODELER);
            privileges.add(DefaultPrivileges.ACCESS_IDM);
            privileges.add(DefaultPrivileges.ACCESS_ADMIN);
            privileges.add(DefaultPrivileges.ACCESS_TASK);
            privileges.add(DefaultPrivileges.ACCESS_REST_API);
            userRepresentation.setPrivileges(privileges);
            return userRepresentation;
        }
    }
    

    url-config.js 修改

    路径:resource\static\scripts\configuration\url-conf.js

    getAccountUrl 的路径改为上面自己的 getAccount 接口的路径
    在这里插入图片描述

    StencilSetResource汉化

    记得重命名,我这重命名后叫 FlowableStencilSetResource

    把配置文件路径改为我们自己目录下的路径

    stencilset/stencilset_bpmn.jsonstencilset/stencilset_cmmn.json

    在这里插入图片描述

    启动器修改

    主要修改三个

    1. 引入 自己目录 下的 ApplicationConfigurationAppDispatcherServletConfiguration,可参考 app 的启动器
    2. 引入 Jar 包 里的 DatabaseConfiguration,这个文件是对表进行更新的,由于 conf 目录不引入,因此我们只能单独引入,具体内容可以自己看下这个文件
    3. 移除 Security 自动配置
      1. Spring Cloud 为 Finchley 版本:@SpringBootApplication(exclude={SecurityAutoConfiguration.class})
      2. Spring Cloud 为 Greenwich 版本:@SpringBootApplication(exclude={SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class, SecurityFilterAutoConfiguration.class})
    //启用全局异常拦截器
    @Import(value={
            // 引入修改的配置
            ApplicationConfiguration.class,
            AppDispatcherServletConfiguration.class,
            // 引入 DatabaseConfiguration 表更新转换
            DatabaseConfiguration.class})
    // Eureka 客户端
    @EnableDiscoveryClient
    @ComponentScan(basePackages = {"com.springcloud.*"})
    @MapperScan("com.springcloud.*.dao")
    // 移除 Security 自动配置
    // Spring Cloud 为 Finchley 版本
    // @SpringBootApplication(exclude={SecurityAutoConfiguration.class})
    // Spring Cloud 为 Greenwich 版本
    @SpringBootApplication(exclude={SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class, SecurityFilterAutoConfiguration.class})
    public class FlowableApplication {
        public static void main(String[] args) {
            SpringApplication.run(FlowableApplication.class, args);
        }
    }
    

    访问页面

    https://localhost:8087/

    自动跳转

    在这里插入图片描述

    关闭数据库自动更新

    在这里插入图片描述
    创建完数据库后,关闭自动更新。原因是更新的标准并非是你引入的流程引擎的版本,而是官方发布的版本,所以如果一直开启,以后重启之类的可能导致提示版本升级失败,毕竟你的依赖版本并没有升级。

    Factory method 'initProcessEngine' threw exception; nested exception is
    org.flowable.common.engine.api.FlowableException: 
    Could not update Flowable database schema: unknown version from database: '6.5.0.1'
    

    因此除非你确实要提高你的引擎版本到最新,否则不要开启

    假如你出现了上述问题,可尝试:
    1.删掉所有表重建
    这样会创建你当前版本的数据库,这种肯定可以,但是基本上数据是没了,除非你有耐心迁移下。

    2.直接修改当前数据库版本
    就是这张 ACT_GE_PROPERTY 的数据,如果出问题了,这里的版本就会变成更新的版本,如:6.5.0.1,状态从创建变为更新,手动直接修正所有参数。本人没尝试过这种方式,应该可行。
    在这里插入图片描述

    自身 XML 扫描不到的问题

    首页不建议将业务代码和流程引擎混在一个项目中

    如果一定要这样,遇到自己的 XML 总扫描不到,转下面的文章

    SpringBoot 集成 Flowable + Flowable Modeler 导致自身 XML 扫描不到解决方案

    结尾

    文章如果存在什么问题,请及时留言反馈

    集成后的代码:https://gitee.com/linjinp-spring-cloud/linjinp-spring-cloud
    代码在 flowable-demo 包,IDEA Active profiles 配置为 sit 测试分支,单独启动即可

    展开全文
  • 采用springboot+flowable快速实现工作流

    万次阅读 多人点赞 2019-04-09 20:34:44
    前言 工作流框架大家一定不陌生,各种OA系统里我们常常用到。 对于JAVA领域来说一说起工作流框架第一浮现我在脑海中的便是大名鼎鼎的Activiti了。很久以前学习Activiti框架时我也曾记录过一篇文章。...

    前言    

        工作流框架大家一定不陌生,各种OA系统里我们常常用到。    

        对于JAVA领域来说一说起工作流框架第一浮现我在脑海中的便是大名鼎鼎的Activiti了。很久以前学习Activiti框架时我也曾记录过一篇文章。见链接:工作流框架Activiti常用功能初探  尽管当时只是学习了一下在之后的相关工作和项目中并没有用到,通过学习后了解了下, 仅对于知识广度进行了扩宽。

    最近在一个开源项目里见到有使用另一个工做流框架:flowable 。简单用了下感觉还是挺方便的,于是乎决定还是要来使用下并在此做下记录,便于后面用到时可以“拿来主义”,哈哈!

    什么是flowable?

    对于flowable是什么以及关于此框架的具体信息可以参看此项目的官方文档:https://www.flowable.org/docs/userguide/index.html

    官网对于此项目如何使用有非常详细的描述,只是目前还没有对应的中文文档。

    Flowable is a light-weight business process engine written in Java.这是官网文档对此框架的完美解释:Flowable是一个用java语言写的轻量级工作流引擎。

    在简单了解flowable后与activiti框架相比的第一感觉就是开发方便快速,易与springBoot等各种框架快速整合。如果项目中需要快速实现一些工作流的相关功能那么用此框架是一个不错的选择。

    使用版本

        用测试方便,这里都使用springBoot和flowable最新的稳定版本

        springBoot版本:2.0.1.RELEASE

         flowable版本:6.3.0

    Flowable与springBoot项目整合

    添加依赖

    将flowable的依赖加入到POM中即可,flowable使用需要一个数据库,这里为了方便我选择mysql

    <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--flowable工作流依赖-->
            <dependency>
                <groupId>org.flowable</groupId>
                <artifactId>flowable-spring-boot-starter</artifactId>
                <version>6.3.0</version>
            </dependency>
            <!--mysql依赖-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.45</version>
            </dependency>
        </dependencies>        <dependency>
                <groupId>org.flowable</groupId>
                <artifactId>flowable-spring-boot-starter</artifactId>
                <version>6.3.0</version>
            </dependency>
            <!--mysql依赖-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.45</version>
            </dependency>
        </dependencies>

    flowable配置

    测试方便flowable配置为默认的即可。为了测试时方便看日志信息,我这里将flowable的定时job功能暂时关闭,其他的都用默认的

    当然记得要添加一个数据源,我这里添加的mysql,并且记得建好对应的mysql库,如果没有建就自己建一个吧

    like this:

    CREATE DATABASE  `flowable-spring-boot` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

     

    spring:
      datasource:
        url: jdbc:mysql://127.0.0.1:3306/flowable-spring-boot?characterEncoding=UTF-8
        username: root
        password: root
    flowable:
    #关闭定时任务JOB
      async-executor-activate: false

    这样操作后,flowable与springBoot的整个就完成了! 个人非常方便!

    然后就可以运行了,初次运行时flowable会将自动执行flowable中的初始化脚本完成工作流所需要的数据表的建立,如果指定的数据库中还未创建过flowable的相关数据表的话。

    定义流程文件

    上面已经完成了flowable与springboot的整合了,接下来就可以使用此框架进行流程需要开发了!

    同样在flowable官方文档中对于流程文件它有这样的建议:

    The Flowable engine expects processes to be defined in the BPMN 2.0 format, which is an XML standard that is widely accepted in the industry. 

    flowable建议采用业界标准BPMN2.0的XML来描述需要定义的工作流。

    那么BPMN这个流程文件应该怎么写呢?

    Typically, such a process definition is modeled with a visual modeling tool, such as the Flowable Designer (Eclipse) or the Flowable Modeler (web application).

    上官方文档中有看到这样的描述后即便我不会写也不怕了。通常都是通过专门的流程建模工具来画出来的,可以用Eclipse里的流程插件来画。同时Flowable也提供了对应的web管理台可以对流程文件进行创建。详见: Flowable UI applications

    为了方便测试,这里采用一个开源项目中的流程文件,其描述如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
                 xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
                 typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath"
                 targetNamespace="http://www.flowable.org/processdef">
        <process id="Expense" name="ExpenseProcess" isExecutable="true">
            <documentation>报销流程</documentation>
            <startEvent id="start" name="开始"></startEvent>
            <userTask id="fillTask" name="出差报销" flowable:assignee="${taskUser}">
                <extensionElements>
                    <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler">
                        <![CDATA[false]]></modeler:initiator-can-complete>
                </extensionElements>
            </userTask>
            <exclusiveGateway id="judgeTask"></exclusiveGateway>
            <userTask id="directorTak" name="经理审批">
                <extensionElements>
                    <flowable:taskListener event="create"
                                           class="com.haiyang.flowable.listener.ManagerTaskHandler"></flowable:taskListener>
                </extensionElements>
            </userTask>
            <userTask id="bossTask" name="老板审批">
                <extensionElements>
                    <flowable:taskListener event="create"
                                           class="com.haiyang.flowable.listener.BossTaskHandler"></flowable:taskListener>
                </extensionElements>
            </userTask>
            <endEvent id="end" name="结束"></endEvent>
            <sequenceFlow id="directorNotPassFlow" name="驳回" sourceRef="directorTak" targetRef="fillTask">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
            </sequenceFlow>
            <sequenceFlow id="bossNotPassFlow" name="驳回" sourceRef="bossTask" targetRef="fillTask">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='驳回'}]]></conditionExpression>
            </sequenceFlow>
            <sequenceFlow id="flow1" sourceRef="start" targetRef="fillTask"></sequenceFlow>
            <sequenceFlow id="flow2" sourceRef="fillTask" targetRef="judgeTask"></sequenceFlow>
            <sequenceFlow id="judgeMore" name="大于500元" sourceRef="judgeTask" targetRef="bossTask">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${money > 500}]]></conditionExpression>
            </sequenceFlow>
            <sequenceFlow id="bossPassFlow" name="通过" sourceRef="bossTask" targetRef="end">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
            </sequenceFlow>
            <sequenceFlow id="directorPassFlow" name="通过" sourceRef="directorTak" targetRef="end">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=='通过'}]]></conditionExpression>
            </sequenceFlow>
            <sequenceFlow id="judgeLess" name="小于500元" sourceRef="judgeTask" targetRef="directorTak">
                <conditionExpression xsi:type="tFormalExpression"><![CDATA[${money <= 500}]]></conditionExpression>
            </sequenceFlow>
        </process>
        <bpmndi:BPMNDiagram id="BPMNDiagram_Expense">
            <bpmndi:BPMNPlane bpmnElement="Expense" id="BPMNPlane_Expense">
                <bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
                    <omgdc:Bounds height="30.0" width="30.0" x="285.0" y="135.0"></omgdc:Bounds>
                </bpmndi:BPMNShape>
                <bpmndi:BPMNShape bpmnElement="fillTask" id="BPMNShape_fillTask">
                    <omgdc:Bounds height="80.0" width="100.0" x="405.0" y="110.0"></omgdc:Bounds>
                </bpmndi:BPMNShape>
                <bpmndi:BPMNShape bpmnElement="judgeTask" id="BPMNShape_judgeTask">
                    <omgdc:Bounds height="40.0" width="40.0" x="585.0" y="130.0"></omgdc:Bounds>
                </bpmndi:BPMNShape>
                <bpmndi:BPMNShape bpmnElement="directorTak" id="BPMNShape_directorTak">
                    <omgdc:Bounds height="80.0" width="100.0" x="735.0" y="110.0"></omgdc:Bounds>
                </bpmndi:BPMNShape>
                <bpmndi:BPMNShape bpmnElement="bossTask" id="BPMNShape_bossTask">
                    <omgdc:Bounds height="80.0" width="100.0" x="555.0" y="255.0"></omgdc:Bounds>
                </bpmndi:BPMNShape>
                <bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
                    <omgdc:Bounds height="28.0" width="28.0" x="771.0" y="281.0"></omgdc:Bounds>
                </bpmndi:BPMNShape>
                <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
                    <omgdi:waypoint x="315.0" y="150.0"></omgdi:waypoint>
                    <omgdi:waypoint x="405.0" y="150.0"></omgdi:waypoint>
                </bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
                    <omgdi:waypoint x="505.0" y="150.16611295681062"></omgdi:waypoint>
                    <omgdi:waypoint x="585.4333333333333" y="150.43333333333334"></omgdi:waypoint>
                </bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="judgeLess" id="BPMNEdge_judgeLess">
                    <omgdi:waypoint x="624.5530726256983" y="150.44692737430168"></omgdi:waypoint>
                    <omgdi:waypoint x="735.0" y="150.1392757660167"></omgdi:waypoint>
                </bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="directorNotPassFlow" id="BPMNEdge_directorNotPassFlow">
                    <omgdi:waypoint x="785.0" y="110.0"></omgdi:waypoint>
                    <omgdi:waypoint x="785.0" y="37.0"></omgdi:waypoint>
                    <omgdi:waypoint x="455.0" y="37.0"></omgdi:waypoint>
                    <omgdi:waypoint x="455.0" y="110.0"></omgdi:waypoint>
                </bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="bossPassFlow" id="BPMNEdge_bossPassFlow">
                    <omgdi:waypoint x="655.0" y="295.0"></omgdi:waypoint>
                    <omgdi:waypoint x="771.0" y="295.0"></omgdi:waypoint>
                </bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="judgeMore" id="BPMNEdge_judgeMore">
                    <omgdi:waypoint x="605.4340277777778" y="169.56597222222223"></omgdi:waypoint>
                    <omgdi:waypoint x="605.1384083044983" y="255.0"></omgdi:waypoint>
                </bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="directorPassFlow" id="BPMNEdge_directorPassFlow">
                    <omgdi:waypoint x="785.0" y="190.0"></omgdi:waypoint>
                    <omgdi:waypoint x="785.0" y="281.0"></omgdi:waypoint>
                </bpmndi:BPMNEdge>
                <bpmndi:BPMNEdge bpmnElement="bossNotPassFlow" id="BPMNEdge_bossNotPassFlow">
                    <omgdi:waypoint x="555.0" y="295.0"></omgdi:waypoint>
                    <omgdi:waypoint x="455.0" y="295.0"></omgdi:waypoint>
                    <omgdi:waypoint x="455.0" y="190.0"></omgdi:waypoint>
                </bpmndi:BPMNEdge>
            </bpmndi:BPMNPlane>
        </bpmndi:BPMNDiagram>
    </definitions>

    其中的两个代理类为:

    import org.flowable.engine.delegate.TaskListener;
    import org.flowable.task.service.delegate.DelegateTask;
    
    public class ManagerTaskHandler implements TaskListener {
    
        @Override
        public void notify(DelegateTask delegateTask) {
            delegateTask.setAssignee("经理");
        }
    
    }
    public class BossTaskHandler implements TaskListener {
    
        @Override
        public void notify(DelegateTask delegateTask) {
            delegateTask.setAssignee("老板");
        }
    
    }

    为了方便,也可以去掉这两个JAVA类,将其对应的task改写为如下的形式:

    <userTask id="holidayApprovedTask" name="Holiday approved" flowable:assignee="${employee}"/>

    尽管上面的BPMN文件很长,但放心,毕竟那是通过相关的工具生成出来的,对于核心的逻辑部分也很少(主要在process 标签内) ,如需要详细了解的可自行学习下BPMN的标签即可!当然,在flowable的使用文档中也有相关的描述,详见:Creating a ProcessEngine

    如上定义好一个流程文件后,将其命令为ExpenseProcess.bpmn20.xml并将其放于项目中的resource目录下的processes(如此目录不存在自行创建)目录下就可以了。

    like this:

    这样当此框架启动的时候它会默认加载resource目录下的processes时就可以将此流程配置加载到数据库进行持久化了

    测试controller

    为了方便这里通过一个controller来完成此DEMO的快速编写

    @Controller
    @RequestMapping(value = "expense")
    public class ExpenseController {
        @Autowired
        private RuntimeService runtimeService;
        @Autowired
        private TaskService taskService;
        @Autowired
        private RepositoryService repositoryService;
        @Autowired
        private ProcessEngine processEngine;
    
    /***************此处为业务代码******************/
    }

    写一个controller,并注入由flowable框架启动时自动注册的几个bean,下面的功能将会用到!

    开始流程

        /**
         * 添加报销
         *
         * @param userId    用户Id
         * @param money     报销金额
         * @param descption 描述
         */
        @RequestMapping(value = "add")
        @ResponseBody
        public String addExpense(String userId, Integer money, String descption) {
            //启动流程
            HashMap<String, Object> map = new HashMap<>();
            map.put("taskUser", userId);
            map.put("money", money);
            ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Expense", map);
            return "提交成功.流程Id为:" + processInstance.getId();
        }

    上面的代码通过接收用户的一个请求传入用户的ID和金额以及描述信息来开启一个报销流程,并返回给用户这个流程的Id

    查询流程列表,待办列表

        /**
         * 获取审批管理列表
         */
        @RequestMapping(value = "/list")
        @ResponseBody
        public Object list(String userId) {
            List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();
            for (Task task : tasks) {
                System.out.println(task.toString());
            }
            return tasks.toArray().toString();
        }

    通过上面的代码获取出此用户需要处理的流程

    批准,同意

        /**
         * 批准
         *
         * @param taskId 任务ID
         */
        @RequestMapping(value = "apply")
        @ResponseBody
        public String apply(String taskId) {
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (task == null) {
                throw new RuntimeException("流程不存在");
            }
            //通过审核
            HashMap<String, Object> map = new HashMap<>();
            map.put("outcome", "通过");
            taskService.complete(taskId, map);
            return "processed ok!";
        }

    通过前端传入的任务ID来对此流程进行同意处理

    拒绝,不同意

        /**
         * 拒绝
         */
        @ResponseBody
        @RequestMapping(value = "reject")
        public String reject(String taskId) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("outcome", "驳回");
            taskService.complete(taskId, map);
            return "reject";
        } 

    生成当前流程图表

        /**
         * 生成流程图
         *
         * @param processId 任务ID
         */
        @RequestMapping(value = "processDiagram")
        public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
    
            //流程走完的不显示图
            if (pi == null) {
                return;
            }
            Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
            //使用流程实例ID,查询正在执行的执行对象表,返回流程实例对象
            String InstanceId = task.getProcessInstanceId();
            List<Execution> executions = runtimeService
                    .createExecutionQuery()
                    .processInstanceId(InstanceId)
                    .list();
    
            //得到正在执行的Activity的Id
            List<String> activityIds = new ArrayList<>();
            List<String> flows = new ArrayList<>();
            for (Execution exe : executions) {
                List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
                activityIds.addAll(ids);
            }
    
            //获取流程图
            BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
            ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
            ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
            InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0);
            OutputStream out = null;
            byte[] buf = new byte[1024];
            int legth = 0;
            try {
                out = httpServletResponse.getOutputStream();
                while ((legth = in.read(buf)) != -1) {
                    out.write(buf, 0, legth);
                }
            } finally {
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.close();
                }
            }
        } 

    通过传入流程ID生成当前流程的流程图给前端,如果流程中使用到中文且生成的图片是乱码的,则需要进配置下字体:

    /**
     * @author haiyangp
     * date:  2018/4/7
     * desc: flowable配置----为放置生成的流程图中中文乱码
     */
    @Configuration
    public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
    
    
        @Override
        public void configure(SpringProcessEngineConfiguration engineConfiguration) {
            engineConfiguration.setActivityFontName("宋体");
            engineConfiguration.setLabelFontName("宋体");
            engineConfiguration.setAnnotationFontName("宋体");
        }
    }

    整体演示

    上面的代码写好后就可以演示下整体流程了

    1.先启动好此项目,然后创建一个流程:

    访问:http://localhost:8080/expense/add?userId=123&money=123321

    返回:提交成功.流程Id为:2501

     

    2.查询待办列表:

    访问:http://localhost:8080/expense/list?userId=123

    输出:Task[id=2507, name=出差报销]

     

    3.同意:

    访问:http://localhost:8080/expense/apply?taskId=2507

    返回:processed ok!

     

    4.生成流程图:

    访问:http://localhost:8080/expense/processDiagram?processId=2501

    返回如下图片:

    整体流程截图如下:

    总结

    通过springBoot与flowable的整合体验到了工作流的开发原来如此简单方便。

    给此框架点赞,向巨人们致敬!

     

    本文源码地址:https://github.com/puhaiyang/flowable-springboot

    文末推荐一个关于flowable的QQ群!

    QQ群:242771252

    点击链接加入群【flowable学习交流】:https://jq.qq.com/?_wv=1027&k=5DKcjgU

    展开全文
  • Flowable深入浅出-1 Flowable简介

    万次阅读 多人点赞 2018-12-24 20:43:58
    1 Flowable简介什么是BPMN什么是FlowableFlowable官网、开源社区Flowable流程示例 什么是BPMN 先来看下百度百科的定义: 由BPMI(The Business Process Management Initiative)开发了一套标准叫业务流程建模符号(BPMN...

    什么是BPMN

    先来看下百度百科的定义:
    由BPMI(The Business Process Management Initiative)开发了一套标准叫业务流程建模符号(BPMN - Business Process Modeling Notation)。在 BPMI Notation Working Group超过2年的努力,于2004年5月对外发布了BPMN 1.0 规范。后BPMI并入到OMG组织,OMG于2011年推出BPMN2.0标准,对BPMN进行了重新定义**(Business Process Model and Notation**)。BPMN的主要目标是提供一些被所有业务用户容易理解的符号,从创建流程轮廓的业务分析到这些流程的实现,直到最终用户的管理监控。BPMN也支持提供一个内部的模型可以生成可执行的BPEL4WS。因此BPMN的出现,弥补了从业务流程设计到流程开发的间隙。
    BPMN定义了一个业务流程图(Business Process Diagram),该业务流程图基于一个流程图(flowcharting),该流程图被设计用于创建业务流程操作的图形化模型。而一个业务流程模型(Business Process Model),指一个由图形对象(graphical objects)组成的网状图,图形对象包括活动(activities)和用于定义这些活动执行顺序的流程控制器(flow controls)。
    大白话理解:
    BPMN是一套符号的标准,这些符号描述了如果做一个业务,并且这个业务在做的过程中被人监控和控制。业务人员和开发人员通过这套图形可以很好的完成协作。

    什么是Flowable

    官方描述如下:
    Flowable提供了一个组高效的核心开源业务流程引擎,为开发人员,系统管理员和业务用户提供工作流和业务流程管理(BPM)平台。全部用Java编写,并且基于Apache 2.0许可的开源,代码在社区维护。其核心是一个快速,经过试验和测试的动态BPMN流程引擎,附带DMN决策表和CMMN Case管理引擎.
    大白话理解:
    Flowable是BPMN的一个基于java的软件实现,不过Flowable不仅仅包括BPMN,还有DMN决策表和CMMN Case管理引擎,并且有自己的用户管理、微服务API等一系列功能,是一个服务平台。

    Flowable官网、开源社区

    Flowable官方网站:
    https://www.flowable.org/
    Flowable开源代码仓库:
    https://github.com/flowable/flowable-engine
    Flowable 最新版本(V6.4.0)截止目前下载地址:
    Tomcat 版本安装包:
    https://download.csdn.net/download/houyj1986/10871025
    https://github.com/flowable/flowable-engine/releases/download/flowable-6.4.0/tomcat-flowable-6.4.0.zip
    EAR版本版本安装包:
    https://download.csdn.net/download/houyj1986/10871018
    https://github.com/flowable/flowable-engine/releases/download/flowable-6.4.0/flowable-6.4.0.zip
    Flowable源代码(V6.4.0)下载地址:
    https://download.csdn.net/download/houyj1986/10871014

    Flowable流程示例

    一个简单度假申请流程主要过程如下:
    1、员工提交请假信息,如工号,请假天数
    2、经理点击审批通过或者拒绝
    3、如果拒绝直接进入系统发邮件服务通知员工
    4、如果通过系统记录该员工的请假天数,减少可用天数
    5、员工看到自己请假审批通过,点击完成请假。
    Flowable的BPMN流程图: 员工度假申请流程图

    流程图的BMPN文件如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef">
      <process id="holidayRequest" name="Holiday Request" isExecutable="true">
        <startEvent id="startEvent"></startEvent>
        <sequenceFlow id="sequenceFlow-3fa7af74-df9a-4d3a-b0eb-10b20e7dc202" sourceRef="startEvent" targetRef="approveTask"></sequenceFlow>
        <userTask id="approveTask" name="经理通过或驳回申请"></userTask>
        <sequenceFlow id="sequenceFlow-d9127dc0-158f-4169-b61b-99226ffe8494" sourceRef="approveTask" targetRef="decision"></sequenceFlow>
        <exclusiveGateway id="decision"></exclusiveGateway>
        <serviceTask id="externalSystemCall" name="系统记录申请天数" flowable:class="org.flowable.CallExternalSystemDelegate"></serviceTask>
        <sequenceFlow id="sequenceFlow-6232f578-3975-4d7e-81f2-43b242d33ebd" sourceRef="externalSystemCall" targetRef="holidayApprovedTask"></sequenceFlow>
        <userTask id="holidayApprovedTask" name="员工查看申请通过"></userTask>
        <sequenceFlow id="sequenceFlow-29fd3375-9bcb-42f2-bb6f-63ae1f98813a" sourceRef="holidayApprovedTask" targetRef="approveEnd"></sequenceFlow>
        <serviceTask id="sendRejectionMail" name="发送驳回邮件" flowable:class="org.flowable.SendRejectionMail"></serviceTask>
        <sequenceFlow id="sequenceFlow-b390b442-2411-44a9-96eb-3c129d4c8408" sourceRef="sendRejectionMail" targetRef="rejectEnd"></sequenceFlow>
        <endEvent id="approveEnd"></endEvent>
        <endEvent id="rejectEnd"></endEvent>
        <sequenceFlow id="sequenceFlow-6f21d3e2-2e49-4b00-9aae-0b71d861a177" name="驳回" sourceRef="decision" targetRef="sendRejectionMail">
          <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!approved}]]></conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="sequenceFlow-2470619b-fa36-440b-a231-b7bd226c23bb" name="通过" sourceRef="decision" targetRef="externalSystemCall">
          <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approved}]]></conditionExpression>
        </sequenceFlow>
      </process>
      <bpmndi:BPMNDiagram id="BPMNDiagram_holidayRequest">
        <bpmndi:BPMNPlane bpmnElement="holidayRequest" id="BPMNPlane_holidayRequest">
          <bpmndi:BPMNShape bpmnElement="startEvent" id="BPMNShape_startEvent">
            <omgdc:Bounds height="30.0" width="30.0" x="0.0" y="95.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNShape bpmnElement="approveTask" id="BPMNShape_approveTask">
            <omgdc:Bounds height="60.0" width="100.0" x="80.0" y="80.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNShape bpmnElement="decision" id="BPMNShape_decision">
            <omgdc:Bounds height="40.0" width="40.0" x="230.0" y="90.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNShape bpmnElement="externalSystemCall" id="BPMNShape_externalSystemCall">
            <omgdc:Bounds height="60.0" width="100.0" x="320.0" y="1.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNShape bpmnElement="holidayApprovedTask" id="BPMNShape_holidayApprovedTask">
            <omgdc:Bounds height="60.0" width="100.0" x="470.0" y="1.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNShape bpmnElement="sendRejectionMail" id="BPMNShape_sendRejectionMail">
            <omgdc:Bounds height="60.0" width="100.0" x="320.0" y="160.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNShape bpmnElement="approveEnd" id="BPMNShape_approveEnd">
            <omgdc:Bounds height="28.0" width="28.0" x="620.0" y="16.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNShape bpmnElement="rejectEnd" id="BPMNShape_rejectEnd">
            <omgdc:Bounds height="28.0" width="28.0" x="505.0" y="175.0"></omgdc:Bounds>
          </bpmndi:BPMNShape>
          <bpmndi:BPMNEdge bpmnElement="sequenceFlow-2470619b-fa36-440b-a231-b7bd226c23bb" id="BPMNEdge_sequenceFlow-2470619b-fa36-440b-a231-b7bd226c23bb">
            <omgdi:waypoint x="250.0" y="90.0"></omgdi:waypoint>
            <omgdi:waypoint x="250.0" y="31.0"></omgdi:waypoint>
            <omgdi:waypoint x="319.99999999999284" y="31.0"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge bpmnElement="sequenceFlow-3fa7af74-df9a-4d3a-b0eb-10b20e7dc202" id="BPMNEdge_sequenceFlow-3fa7af74-df9a-4d3a-b0eb-10b20e7dc202">
            <omgdi:waypoint x="29.949998618355412" y="110.0"></omgdi:waypoint>
            <omgdi:waypoint x="80.0" y="110.0"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge bpmnElement="sequenceFlow-6232f578-3975-4d7e-81f2-43b242d33ebd" id="BPMNEdge_sequenceFlow-6232f578-3975-4d7e-81f2-43b242d33ebd">
            <omgdi:waypoint x="419.95000000000005" y="31.0"></omgdi:waypoint>
            <omgdi:waypoint x="470.0" y="31.0"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge bpmnElement="sequenceFlow-b390b442-2411-44a9-96eb-3c129d4c8408" id="BPMNEdge_sequenceFlow-b390b442-2411-44a9-96eb-3c129d4c8408">
            <omgdi:waypoint x="419.949999999997" y="189.66442953020135"></omgdi:waypoint>
            <omgdi:waypoint x="505.00030595247523" y="189.0936221647077"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge bpmnElement="sequenceFlow-d9127dc0-158f-4169-b61b-99226ffe8494" id="BPMNEdge_sequenceFlow-d9127dc0-158f-4169-b61b-99226ffe8494">
            <omgdi:waypoint x="179.9499999999898" y="110.0"></omgdi:waypoint>
            <omgdi:waypoint x="230.0" y="110.0"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge bpmnElement="sequenceFlow-29fd3375-9bcb-42f2-bb6f-63ae1f98813a" id="BPMNEdge_sequenceFlow-29fd3375-9bcb-42f2-bb6f-63ae1f98813a">
            <omgdi:waypoint x="569.9499999999988" y="31.0"></omgdi:waypoint>
            <omgdi:waypoint x="582.0" y="31.0"></omgdi:waypoint>
            <omgdi:waypoint x="582.0" y="31.0"></omgdi:waypoint>
            <omgdi:waypoint x="620.0025321198765" y="30.268220825690175"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
          <bpmndi:BPMNEdge bpmnElement="sequenceFlow-6f21d3e2-2e49-4b00-9aae-0b71d861a177" id="BPMNEdge_sequenceFlow-6f21d3e2-2e49-4b00-9aae-0b71d861a177">
            <omgdi:waypoint x="250.0" y="129.9375468164794"></omgdi:waypoint>
            <omgdi:waypoint x="250.0" y="190.0"></omgdi:waypoint>
            <omgdi:waypoint x="319.99999999997794" y="190.0"></omgdi:waypoint>
          </bpmndi:BPMNEdge>
        </bpmndi:BPMNPlane>
      </bpmndi:BPMNDiagram>
    </definitions>
    

    文件名为Holiday_Request.bpmn20.xml,flowable支持以BPMN和bpmn20.xml结尾的流程文件。上面的xml看起来非常恐怖,不用担心,后面我会介绍Flowable的专门的流程绘制软件。
    以上主要让大家对Flowable有个简单的了解,下一节介绍如何启动Flowable,并且介绍Flowable的启动包的相关内容。

    版权

    转载请联系作者,谢谢。由书山登峰人创作。

    展开全文
  • flowable 6.2版本官方文档汉化版本,适合flowable初学者阅读、使用。
  • activiti与flowable的区别

    万次阅读 多人点赞 2020-03-13 20:39:11
    《Activiti6视频教程全家桶》《Flowable系列优惠套餐》《Flowable全家桶》《Camunda教程》《Drool7从入门到精通》 在详细说明activiti与flowable的细节区别之前,我们需要说明一下这两个框架的发展史。 我在写...

     

     

    在详细说明activiti与flowable的细节区别之前,我们需要说明一下这两个框架的发展史。

    我在写Activiti权威指南的时候,大概是2016年7月份左右。给清华大学出版社交稿的时候大概在2017年3月份左右、最终出版是2017年5月份左右。其实在2016.7~2017.5期间activiti团队内部已经产生了重大的分歧。关于新的activiti新团队与原有的团队重要开发人员我们罗列一下,细节如下:

    上图是Tijs Rademakers,算是activiti5以及6比较核心的leader了。现在是flowable框架的leader。

    Joram Barrez  算是activiti5以及6比较核心的leader了。目前从事flowable框架开发。

    Salaboy Activiti Cloud BPM leader(Activiti Cloud BPM 也就是目前的activiti7框架)

    Tijs Rademakers以及Salaboy目前是两个框架的leader。

        特此强调一点:activiti5以及activiti6、flowable是Tijs Rademakers团队开发的。

    Activiti7是 Salaboy团队开发的。activiti6以及activiti5代码目前有 Salaboy团队进行维护。因为Tijs Rademakers团队去开发flowable框架了,所以activiti6以及activiti5代码已经交接给了 Salaboy团队(可以理解为离职之前工作交接)。目前的activiti5以及activiti6代码还是原Tijs Rademakers原有团队开发的。Salaboy团队目前在开发activiti7框架。对于activiti6以及activiti5的代码官方已经宣称暂停维护了。activiti7就是噱头 内核使用的还是activiti6。并没有为引擎注入更多的新特性,只是在activiti之外的上层封装了一些应用。

        注意:activiti6的很多框架bug在flowable框架中已经修复的差不多了。

    我们不妨看一下这两个框架的github分支情况,侧民印证下我上面说的结论。

    Activiti框架情况

    activiti的github地址;https://github.com/Activiti/Activiti

     

    通过上面的一系列图,可以看出来。activiti5以及ativiti6的核心开发团队是Tijs Rademakers团队。activiti6最终版本由Salaboy团队发布的。

    可能很多人有疑惑,activiti6核心代码是Tijs Rademakers团队开发的,为何是Salaboy团队发布的呢?很简单,因为这个时候Tijs Rademakers团队已经去开发flowable去了。flowable是基于activiti-6.0.0.Beta4 分支开发的。下面我们截图一些flowable的发展。

    Flowable框架情况

    flowable的github地址:https://github.com/flowable/flowable-engine

     

    关于更多的Activiti6视频地址:https://ke.qq.com/course/package/11402?tuin=84de321b

    关于更多的Flowable视频地址:https://ke.qq.com/course/package/11431?tuin=84de321b

     

    目前Flowable已经修复了activiti6很多的bug,可以实现零成本从activiti迁移到flowable。

    flowable目前已经支持加签、动态增加实例中的节点、支持cmmn、dmn规范。这些都是activiti6目前版本没有的。

    1、flowable已经支持所有的历史数据使用mongdb存储,activiti没有。

    2、flowable支持事务子流程,activiti没有。

    3、flowable支持多实例加签、减签,activiti没有。

    4、flowable支持httpTask等新的类型节点,activiti没有。

    5、flowable支持在流程中动态添加任务节点,activiti没有。

    6、flowable支持历史任务数据通过消息中间件发送,activiti没有。

    7、flowable支持java11,activiti没有。

    8、flowable支持动态脚本,,activiti没有。

    9、flowable支持条件表达式中自定义juel函数,activiti没有。

    10、flowable支持cmmn规范,activiti没有。

    11、flowable修复了dmn规范设计器,activit用的dmn设计器还是旧的框架,bug太多。

    12、flowable屏蔽了pvm,activiti6也屏蔽了pvm(因为6版本官方提供了加签功能,发现pvm设计的过于臃肿,索性直接移除,这样加签实现起来更简洁、事实确实如此,如果需要获取节点、连线等信息可以使用bpmnmodel替代)。

    13、flowable与activiti提供了新的事务监听器。activiti5版本只有事件监听器、任务监听器、执行监听器。

    14、flowable对activiti的代码大量的进行了重构。

    15、activiti以及flowable支持的数据库有h2、hsql、mysql、oracle、postgres、mssql、db2。其他数据库不支持的。使用国产数据库的可能有点失望了,需要修改源码了。

    16、flowable支持jms、rabbitmq、mongodb方式处理历史数据,activiti没有。

    几个框架前景对比

    1、2019年6月中旬 salboy已从alfresco公司离职。activiti7/8开发动向不明确。

    2、flowable以6.4.1版本为分水岭,大力发展其商业版产品。开源版本维护不及时。部分功能已经不再开源版发布,比如表单生成器(表单引擎)、历史数据同步至其他数据源、es等等。dmn目前是个半成品,没有camunda稳定和好用,对于dmn规范支持薄弱。部分商业版的组件被商业化,因此开源版不再维护。Mongdb目前也放到商业产品中了,开源版的几乎不能用。

    其他的后续再来总结、上述的新特性在我们的系列课程在基本都给大家讲解了。

     

    展开全文
  • flowable简介

    2019-08-17 14:38:21
    flowable 2017发布,主创人员来自Activiti团队,目前支持BPMN和CMMN、DMN规范、它的主要含有五个引擎和一个官方自带的Modeler流程设计器,以及一套数据库表,以及发布版本(5个war)/源代码等: (一)五大引擎: ...
  • Flowable是什么?

    2020-02-27 16:59:04
    Flowable是什么? Flowable是一个使用Java编写的轻量级业务流程引擎。Flowable流程引擎可用于部署BPMN 2.0流程定义(用于定义流程的行业XML标准), 创建这些流程定义的流程实例,进行查询,访问运行中或历史的流程...
  • flowable工作流入门(一)

    万次阅读 2019-08-14 17:40:34
    flowable工作流入门 Flowable下载 使用spring boot flowble生成所需表 <dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter</artifactId>...
  • Flowable实战系列文章

    万次阅读 2020-01-06 17:15:46
    flowable modler为任务节点增加自定义属性 Flowable cmmn结构以及bpmn与cmmn的区别 flowable6.3中新增的功能以及亮点,包括Flowable bpmn,flowable dmn,flowable cmmn等模块 Flowable决策任务(decision task) ...
  • flowable 简介以及中文文档

    万次阅读 2018-11-28 14:50:17
    Flowable是什么 Flowable是一个使用Java编写的轻量级业务流程引擎。Flowable流程引擎可用于部署BPMN 2.0流程定义(用于定义流程的行业XML标准), 创建这些流程定义的流程实例,进行查询,访问运行中或历史的流程...
  • springboot + flowable + idm 在线编辑器

    万次阅读 2019-07-24 10:40:16
    我的码云上的代码, ,可供下载互相学习 https://gitee.com/heiyueGit/springboot-flowable
  • flowable设计器插件安装

    万次阅读 2020-01-06 17:16:30
    工欲善其事必先利其器,要想使用flowable,必须搭建一套环境,本文以Eclipse中安装flowable插件为例详细说明整个安装过程。 首先,打开Eclipse,HelpàInstall New Software.然后输入一下信息: ·Name:Flowable ...
  • Flowable深入浅出-3 Flowable-IDM详述

    千次阅读 2018-12-25 22:06:46
    3 Flowable-IDM简介Flowable-IDM功能Flowable-IDM登录地址Flowable-IDM登录用户和页面Flowable-IDM用户管理页面Flowable-IDM用户组管理页面Flowable-IDM用户权限管理页面Flowable-IDM用户权限管理页面 Flowable-IDM...
  • 快速搭建flowable

    万次阅读 2019-02-26 16:48:32
    工作流存在的重要意义,Activity与Flowable的区别,三分钟搭建flowable应用,审批流API的Demo
  • Flowable学习(一)flowable插件

    千次阅读 2018-10-10 14:26:36
    项目采用 spring+flowable,其中flowable的版本用的是6.2.1 创建BPMN文件可以选用 flowable插件来完成 例如SpringToolSuite(sts),Help-&gt;Install new software 点击完成后,在file -》new 可以看到 ...
  • Flowable BPMN 用户手册 (v 6.3.0)

    千次阅读 2019-06-27 17:11:13
    小编本来想学习 activity但是被同事强烈推荐学习Flowable。百度了一下发现Flowable是activity的一个升级。 第一步找学习资料:找到一个分享给大家:https://tkjohn.github.io/flowable-userguide/#_getting_started ...
  • flowable实现流程回退功能

    万次阅读 2017-08-30 17:06:35
    flowable利用Command实现流程回退功能
  • Flowable实战7-Flowable Modeler集成

    万次阅读 2020-01-06 19:33:28
    Flowable完整源码编译 解压源代码,结果如下 启动idea,配置好maven的路径。单击File->Open,选择上面的根目录打开工程,结果如下: 打开后,按下快捷键Alt+F12,启动Terminal终端,输入命令mvn clean ...
  • Flowable深入浅出-2 Flowable启动

    千次阅读 2018-12-30 11:50:47
    2 Flowable启动Flowable部署包分析Flowable部署包启动版权 Flowable部署包分析 tomcat版本 在上一节我们下载了Flowable的部署安装包,tomcat版本解压后如下: 核心的代码在webapps下面,其中flowable的相关的代码...
  • 最近在写Flowable实战一书,刚好写到了在userTask上加任务监听器,然而通常情况下实现类注入的bean一直为null,解决方案如下: 1、流程定义xml中的任务监听器,使用delegateExpression表达式将所使用的任务监听器...
1 2 3 4 5 ... 20
收藏数 4,621
精华内容 1,848
关键字:

flowable