1 Star 4 Fork 3

柯凯 / Flowable 工作流框架

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

工作流对接文档

[TOC]

历史版本

版本 日期 备注
1.0.0 2021/08/20 初版
1.1.0 2021/08/31 「会签」「消息通知」「功能优化」
1.2.0 2022/02/28 「框架由Activiti6.0.0变更为Flowable6.0.1」
「加入流程图自定义颜色功能」
「加入会签一票否决」
「功能优化」
1.3.0 2023/02/22 「框架由Flowable6.0.1变更为Flowable6.8.0」
「集成到通用产品框架」
「加入数据库分库功能」
「MySQL触发器改为视图」
1.4.0 2023/03/17 「添加附件上传及展示功能」
1.5.0 2023/11/13 「集成国产数据库」
开源

概述

​ 工作流,从业务角度看,就是审核流程,其表现就是控制不同的角色看到并执行不同的数据;不同的操作使得数据的流向不同,一般情况下会有申请,审核等步骤;

​ 从技术实现的角度看,就是通过控制一个业务表数据的状态字段,用户在执行过程中实现数据的状态变更。

模块特性

​ 1)基于开源Flowable 6.8.0工作流框架。

​ 2)基于BPMN图形拖拽方式定义工作流程。

​ 3)支持在流程图中静态指定各个节点任务的执行人/角色。

​ 4)支持在流程中动态指定各个节点任务的执行人/角色。

​ 5)支持会签、邮件/短信通知功能。

​ 6)代码侵入性低,集成方便。

​ 7)集成国产达梦、人大金仓数据库。

模块架构

​ 官方提供的Flowable框架提供了工作流引擎,包括流程、实例、任务等核心功能,已经能够满足业务需求。但是对于日常开发而言还不够友好,还需要解决几个问题:

​ 1、由于Flowable框架和业务系统解耦,任务的代办/已办状态在工作流引擎里面,业务系统无法直接感知代办/已办状态,需要添加额外的操作才能在业务数据里面保存状态信息。

​ 2、Flowable官网框架提供的API和业务系统不贴合,编码过程中会产生很多无用代码。如果做一层代码封装用来适应业务,并且配合代码生成器,可以减少80%的手动编码。

​ 为了解决这些问题,在基础框架之上开发了工作流SDK工具包newfiber-common-workflow。工具包使用回调方式更新业务数据状态,并且构建了一套核心类,实现了一键启动、提交、查询工作流等功能。业务系统引入工具包后,配合核心类,可以在最少编码的情况下实现工作流。

架构图

业务时序

下载

核心类设计

工作流UML

技术选型

1、系统环境

  • Java EE 8
  • Servlet 3.0
  • Apache Maven 3
  • Redis > 3
  • MySQL > 5.7
  • Node >= 12

2、主框架

  • Spring Boot 2.3.x
  • Spring Cloud Hoxton.SR9
  • Spring Framework 5.2.x
  • Spring Security 5.2.x

3、持久层

  • Apache MyBatis 3.5.x
  • Baomidou MyBatis Plus 3.5.x
  • Hibernate Validation 6.0.x
  • Alibaba Druid 1.2.x

对接流程

概述

​ 在业务模块对接过程中,主要包括前端和后端。前端主要用于BPMN流程图的绘制,后端主要用于实现业务逻辑。

​ 1)前端:前端开发人员将前端界面集成到业务模块后,绘制BPMN流程图。在极端情况下,如果业务系统无法集成前端界面,也可以通过后端接口直接导入BPMN文件,BPMN文件可以由第三方工具绘制后导出。

​ 2)后端:后端完成业务表结构设计后,在MySQL中执行视图,在代码中引入工作流模块依赖,并依照文档「后端代码对接」开始编码。

BPMN流程图

​ BPMN全称业务流程建模与标注,通过一系列的节点符号来定义一个流程图,包括开始事件、可执行节点、节点可执行的动作、结束事件等。工作流模块提供了前端页面来绘制BPMN流程图,通过拖拽节点符号,连接各个节点来绘制。如下图所示:其中定义了一个管网巡查申请流程。

image-20210818150617211

​ BPMN中主要涉及到的符号包括:开始事件、人工任务、单一网关、结束事件。在绘制BPMN流程图中有相应的规范,接下来一一进行讲解。

流程图编辑器

​ 支持通用BPMN流程图编辑器。可以在Flowable Git上下载对应版本的War包,启动后可访问流程编辑器:

Release Flowable 6.0.1 release · flowable/flowable-engine · GitHub

​ 除了使用官网的War包启动设计器之外,也可以使用newfiber-workflow-design,启动后也是流程设计器。

BPMN定义

​ 点击BPMN编辑器的空白处,在下方的编辑栏编辑BPMN定义的相关信息。重点关注:

​ 1)流程唯一标识:对应后端代码中的IWorkflowDefinition.WorkflowKey

​ 2)流程名称:对应后端代码中的IWorkflowDefinition.WorkflowName

BPMN定义

开始事件

​ 开始事件用来定义一个流程的开始,任何流程都应包含该事件。按钮位置在【开始事件】-->【开始事件】。重点关注:

​ 1)ID:节点唯一编号,对应业务数据中的status字段。

​ 2)名称:节点名称。

开始事件按钮图标

开始事件定义

人工任务

​ 人工任务也就是在流程中需要人工来执行、审核的任务,例如需要用户/角色来审核。按钮位置在【活动】-->【人工任务】。重点关注:

​ 1)ID:节点唯一编号,对应业务数据中的status字段。

​ 2)名称:节点名称。

​ 3)任务派遣:指派任务到指定的执行人/角色,即只有被指派的人/角色才有任务该节点下的数据执行权限。

人工任务按钮图标

人工任务定义

​ 在人工任务中包含了数据执行权限,现包括以下两种方式指定:

​ 1)在流程图中静态指定执行人/角色。即指定固定的人/角色,任务只能由指定的人/角色执行,其他人/角色无权操作。

​ 点击【任务派遣】,在弹出的页面中选择【Identity store(身份仓库)】,在【assignment(指派)】中包括三个选项:

静态指派执行人、角色

​ ● Assigned to single user(指派给单个用户):将任务执行权限指派给单个的用户。

​ ● Candidate users(候选用户):将任务执行权限指派给一个或多个候选用户,这些用户都有可执行权限,其中任何一个用户执行则算该数据执行完成。

​ ● Candidate groups(候选组/角色):将任务执行权限指派给一个或多个候选角色,这些角色下的用户都有可执行权限,其中任何一个用户执行则算该数据执行完成。

​ 2)在流程中动态指定执行人/角色。即在流程流转过程中动态指定,可以通过上一个节点执行后来指定下一个节点的执行人/角色。

动态指派执行人、角色

​ 点击【任务派遣】,在弹出的页面中选择【Fixed value(灵活变量)】,其中包括三个输入框,输入框用于声明执行人/角色的变量,然后在程序中动态指定。注:三个输入框互斥,同时只能指定一个。

​ ● Assignee(指派给单个用户):其值固定为${approveUserId}。在流程启动或者提交时代码中动态赋值变量来指定,对应后端代码中的WorkflowStartReq.nextTaskApproveUserIdWorkflowSubmitReq.nextTaskApproveUserId。注:${approveUserId}不能改变,否则后端代码无法识别。

​ ● Candidate users(候选用户),暂未开放,后续看业务模块是否需要。

​ ● Candidate groups(候选组/角色):其值固定为${approveRoleId},在流程启动或者提交时代码中动态赋值变量来指定,对应后端代码中的WorkflowStartReq.nextTaskApproveRoleIdWorkflowSubmitReq.nextTaskApproveRoleId。注:${approveRoleId}不能改变,否则后端代码无法识别。

单一网关

​ 在用户执行任务时,会有不同的动作,比如通过、不通过等,不同的动作会指向不同的结果。BPMN提供了网关来实现这一功能,我们一般用到的是单一网关(有的也叫互斥网关)。按钮位置在【网关】-->【单一网关】。重点关注:

​ 1)网关流出的节点。详情见下方的【顺序流】。

单一网关按钮图标

单一网关定义

结束事件

​ 结束事件用来定义一个流程的结束,任何流程都应包含该事件。按钮位置在【结束事件】-->【结束事件】。重点关注:

​ 1)ID:节点唯一编号,其值需固定配置为「end」,对应业务数据中的status字段。

​ 2)名称:节点名称。

​ 3)执行监听器:用于监听结束事件的完成。需将其配置为com.newfiber.workflow.support.listener.WorkflowEndListener

结束事件按钮图标

结束事件定义

结束事件监听器

顺序流

​ 在BPMN流程图中,除【结束事件】,其他所有节点都会指向下一个节点,其指向的方向用顺序流表示,也就是一条实线实心箭头。每条顺序流都有其各自的跳转条件,在单一网关中,不同的执行动作就是通过顺序流的跳转条件来控制。重点关注:

​ 1)名称:顺序流对应的名称,也就是可执行的动作,对应前端界面可操作的按钮,工作流模块提供了接口供前端来查询当前节点的下一步可执行节点,接口详情见接口文档:/workflow-model/nextTasks。

​ 2)跳转条件:跳转到对应节点的条件。其值为EL表达式:${approveResult=='true'}。其中「approveResult」为变量名,不能改变;「true」为变量值,用于控制不能的跳转,可以自行制定。例如单一网关的「通过」、「不通过」可分别配置为「${approveResult=='true'}」、${approveResult=='false'}。在后端代码中对应的控制变量为WorkflowSubmitReq.approveResult。需要注意的是每条顺序流都需要指定跳转条件(「开始事件外」),否则程序无法识别。

顺序流定义

顺序流跳转条件

数据库集成

MySQL视图

​ 工作流模块有自己独立的数据库表,用于支持其自身的功能。例如:在流程图编辑的过程中,可以指定业务系统中的用户或者角色,这些数据是维护在工作流模块自身的表中的。因此需要在业务模块和工作流模块之间进行数据同步,这里提供了MySQL视图实现其数据同步功能。

​ 这里提供了对业务模块用户/角色/用户角色关系表的视图脚本,其脚本文件为:/doc/sql/workflow/view.sql。重点关注以下几张表:

​ 1)ACT_ID_USER:工作流用户表

​ 2)ACT_ID_GROUP:工作流组/角色表

​ 3)ACT_ID_MEMBERSHIP:工作流用户组/角色关系表

工作流用户视图如下:

CREATE 
    ALGORITHM = UNDEFINED 
    DEFINER = `root`@`%` 
    SQL SECURITY DEFINER
VIEW `ACT_ID_USER` AS
    SELECT 
        `newfiber_standard`.`sys_user`.`user_id` AS `ID_`,
        1 AS `REV_`,
        `newfiber_standard`.`sys_user`.`nick_name` AS `FIRST_`,
        `newfiber_standard`.`sys_user`.`nick_name` AS `LAST_`,
        `newfiber_standard`.`sys_user`.`user_name` AS `DISPLAY_NAME_`,
        `newfiber_standard`.`sys_user`.`email` AS `EMAIL_`,
        '123456' AS `PWD_`,
        NULL AS `PICTURE_ID_`,
        NULL AS `TENANT_ID_`
    FROM
        `newfiber_standard`.`sys_user`
    WHERE
        (`newfiber_standard`.`sys_user`.`del_flag` = 0)

业务表结构设计

​ 为支持业务模块的数据流转,业务表需要加入以下两个字段:

​ 1)workflow_instance_id:工作流实例编号,用于保持业务模块与工作流模块的关联关系。

​ 2)status:用户完成业务数据的状态流转

数据库分库

​ Flowable官方默认提供了47张表,如果都和业务表放在一起,那数据库就太杂乱了,之前的版本就想做分库,但是没有找到合适的方法。

​ Flowable框架暴露了接口用来自定义SpringProcessEngineConfiguration,修改里面的dataSource属性可以实现数据库分库,修改自定义flowable属性即可实现分库。

flowable:
  database-schema: newfiber_standard_workflow
  driver-class-name: com.mysql.cj.jdbc.Driver
  url: jdbc:mysql://127.0.0.1/newfiber_standard_workflow?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true
  username: root
  password: 123456

后端集成

​ 后端采用SpringBoot框架,Maven管理项目依赖,对接方式如下:

​ 1)工作流在通用工具包中newfiber-common-workflow,在pom文件中引入工作流模块依赖:

<!-- Newfiber Common Workflow -->
<dependency>
     <groupId>com.newfiber</groupId>
     <artifactId>newfiber-common-workflow</artifactId>
</dependency>

​ 2)在ApplicationStart类中引入工作流模块路径,完成依赖注入:

// 加入工作流模块路径:"com.newfiber.workflow"
@SpringBootApplication(
        scanBasePackages = {"com.newfiber.business", "com.newfiber.workflow"})
public class WorkflowParentApplication {

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

}

​ 3)开始工作流编码,主要包括以下步骤:

​ ● 创建枚举类实现IWorkflowDefinition接口,完成工作流基本信息定义。

​ ● Server层实现IWorkflowCallback接口并重写方法,完成业务回调方法实现。

​ ● Server层调用ActivitiProcessService类中的方法,完成工作流的启动,执行等操作。

​ ● 可通过WorkflowPageHelper工具类来辅助完成业务数据的分页查询操作。

IWorkflowDefinition

​ 不同的工作流有不同的定义,工作流模块提供了IWorkflowDefinition接口规范工作流的定义,接口方法签名下:

public interface IWorkflowDefinition {

    /**
     * 工作流编号
     * @return 工作流编号
     */
    String getWorkflowKey();

    /**
     * 工作流名称
     * @return 工作流名称
     */
    String getWorkflowName();

    /**
     * 业务实体表名,用于分页查询业务数据
     * @return 业务实体表名
     */
    default String getTableName() {
        return "t";
    }

    /**
     * 业务实体表主键类型,用于分页查询业务数据
     * @return 业务实体表主键类型
     */
    default Class<?> getTableIdType(){
        return String.class;
    }
}

​ 在业务系统中需要实现该接口,例如定义一个巡查申请的工作流,其代码如下:

public enum EWorkflowDefinition implements IWorkflowDefinition {
  /** */
  PatrolApply("PatrolApply", "巡查申请", "t", Integer.class);

  EWorkflowDefinition(
      String workflowKey, String workflowName, String tableName, Class<?> tableIdType) {
    this.workflowKey = workflowKey;
    this.workflowName = workflowName;
    this.tableName = tableName;
    this.tableIdType = tableIdType;
  }

  private final String workflowKey;

  private final String workflowName;

  private final String tableName;

  private final Class<?> tableIdType;

  @Override
  public String getWorkflowKey() {
    return workflowKey;
  }

  @Override
  public String getWorkflowName() {
    return workflowName;
  }

  @Override
  public String getTableName() {
    return tableName;
  }

  @Override
  public Class<?> getTableIdType() {
    return tableIdType;
  }
}

IWorkflowCallback

​ 在业务模块开始、提交工作流后,需要执行更新关联id、状态等操作,这里提供了IWorkflowCallback回调接口用来实现该功能。其方法签名如下:

public interface IWorkflowCallback<T> {

    /**
     * 业务实体类型
     * @return 业务实体类型
     */
    default Class<?> getEntityClass(){
        return ReflectionKit.getInterfaceGeneric(this);
    }

    /**
     * 工作流定义
     * @return 工作流定义
     */
    IWorkflowDefinition getWorkflowDefinition();

    /**
     * 更新业务实体的工作流实体编号
     * @param businessKey 业务实体编号
     * @param workflowInstanceId 工作流实体编号
     */
    void refreshWorkflowInstanceId(Object businessKey, String workflowInstanceId);

    /**
     * 更新业务数据状态
     * @param businessKey 业务实体编号
     * @param status 状态
     */
    void refreshStatus(Object businessKey, String status);

}

​ 业务模块的Server需要实现该接口,例如巡查申请的Server,其核心代码如下:

@Service
public class PurchaseApplyServiceImpl implements IWorkflowCallback<PurchaseApply> {

  @Override
  public IWorkflowDefinition getWorkflowDefinition() {
    return EWorkflowDefinition.PurchaseApply;
  }

  @Override
  public void refreshWorkflowInstanceId(Object businessKey, String workflowInstanceId) {
    PurchaseApply condition = new PurchaseApply();
    condition.setId(Integer.parseInt(businessKey.toString()));
    condition.setWorkflowInstanceId(workflowInstanceId);
    updateById(condition);
  }

  @Override
  public void refreshStatus(Object businessKey, String status) {
    PurchaseApply condition = new PurchaseApply();
    condition.setId(Integer.parseInt(businessKey.toString()));
    condition.setStatus(status);
    updateById(condition);
  }
}

ActivitiProcessService

ActivitiProcessService提供了工作流程中涉及到的核心方法,包括工作流开始、提交等方法,其核心方法签名如下:

    /**
     * 启动工作流
     * @param workflowCallback 回调接口
     * @param businessKey 业务编号
     * @param startReq 启动参数
     * @return 工作流实体编号
     */
    String startWorkflow(IWorkflowCallback<?> workflowCallback, Object businessKey, WorkflowStartReq startReq);

    /**
     * 提交工作流
     * @param callback 回调接口
     * @param businessKey 业务编号
     * @param submitReq 提交结果
     * @return 业务编号
     */
    String submitWorkflow(IWorkflowCallback<?> callback, Object businessKey, WorkflowSubmitReq submitReq);

​ 业务模块的Server需要注入该接口,并调用其启动和提交方法完成工作流的数据流转,例如巡查申请的Server,其核心代码如下:

@Service
public class PatrolApplyServiceImpl implements PatrolApplyService, IWorkflowCallback<PatrolApply> {

  @Resource 
  private ActivitiProcessService activitiProcessService;

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void create(PatrolApplyCreateReq req) {
    PatrolApply patrolApply = new PatrolApply();
    BeanUtils.copyProperties(req, patrolApply);
    this.save(patrolApply);

    // 启动工作流
    activitiProcessService.startWorkflow(this, patrolApply.getId(), req);
  }

  @Override
  public void approve(PatrolApplyApproveReq req) {
    // 提交工作流
    activitiProcessService.submitWorkflow(this, req.getId(), req);
  }
}

WorkflowPageHelper

​ 在业务数据查询过程中,会涉及到数据查询权限的问题,其中的权限包括两个部分:

​ 1)数据状态权限:用户只能查看到处于某一状态下的数据。

​ 2)数据执行权限:用户只能查看属于自己的可执行的数据。

​ 对于第一种数据权限,可以通过业务表的status字段控制,业务系统实现起来较为简单。而第二种权限实现起来则较为复杂,这是因为业务模块和工作流模块都只相互存放了对方的数据ID,导致业务模块必须先调用工作流模块查询用户可执行的数据ID,然后才能执行业务查询操作,其调用时序图如下所示:

数据权限查询时序图

​ 为解决业务模块调用方法繁琐的问题,这里提供了WorkflowPageHelper工具类。可以实现在分页查询业务数据时,自动加入用户权限数据查询的功能。其核心方法签名如下:

		/**
     * 开始分页
     * @param pageNum 开始页数
     * @param pageSize 每页数量
     * @param orderBy 排序字段
     * @param userId 用户编号
     * @param taskKey 任务编号,对应相应的状态节点
     * @param workflowCallback 回调接口
     * @return 分页参数实体
     */
    public static <E> Page<E> startPage(int pageNum, int pageSize, String orderBy, Object userId, String taskKey, IWorkflowCallback<?> workflowCallback)

    /**
     * 开始分页
     * @param workflowPageReq 分页接口参数
     * @param workflowCallback 回调接口
     * @return 分页参数实体
     */
    public static <E> Page<E> startPage(WorkflowPageReq workflowPageReq, IWorkflowCallback<?> workflowCallback)

​ 其也是基于开源工具PageHelper,用法类似。例如巡查申请分页查询,其核心代码如下:

@Override
  public PageInfo<PatrolApply> page(PatrolApplyPageReq req) {
    PatrolApply condition = new PatrolApply();
    BeanUtils.copyProperties(req, condition);
    
    // 执行分页操作
    WorkflowPageHelper.startPage(req, this);

    List<PatrolApply> list = patrolApplyDao.selectByCondition(condition);
    return new PageInfo<>(list);
  }

功能特性

会签

​ 在流程业务管理中,任务通常都是由一个人去处理的。而多个人同时处理一个任务,根据多个人的审核结果来确定流程的走向,这种任务我们称之为会签任务。

​ 在绘制BPMN流程图时,添加将【人工任务】配置为会签节点,重点关注:

​ 1)多实例类型:选择「Parallel」。

​ 2)集合(多实例):配置为approveUserIdList。会签节点的审核人列表,对应代码中的WorkflowStartReq.nextTaskApproveUserIdListWorkflowSubmitReq.nextTaskApproveUserIdList

​ 3)元素的变量(多实例):集合的变量,会签节点的审核人,需要和「任务派遣」定义的审核人对应。

​ 4)任务派遣:会签节点的审核人。

会签节点配置

​ 配置完成后,当执行到该节点时,会为每个会签人员分配一个任务,所有人通过才会通过。

一票否决

​ 会签实现多个人同时审批,任意一个人不同意时,会签任务结束。

​ 1)在完成条件(多实例)中添加以下配置,当满足表达式的条件时,会签节点结束,进入下一个节点:${(approveResult=='false')||(nrOfCompletedInstances/nrOfInstances==1)}

​ ●approveResult=='false':「approveResult」为「false」时会签结束,即一票否决。

​ ●nrOfCompletedInstances/nrOfInstances==1:框架中维护了两个变量「nrOfCompletedInstances」--Number Of Completed Instances(已完成实例数)和「nrOfInstances」--Number Of Instances(实例数),当两者相同时会签节点结束。

消息通知监听器节点

消息通知

​ 在工作流执行到流程中的某个节点时,可以向节点的执行人发送邮件/短信通知。现支持三种方式:

​ 1)使用工作流默认的邮件通知

​ 2)使用自定义消息模板发送通知

​ 3)使用代码调用的方式发送通知

在配置文件中添加以下配置:

spring:
    mail:
        host: smtp.exmail.qq.com
        username: xiongkai@chinhangroup.com
        password: 123456
        properties:
            mail:
                smtp:
                    auth: true

在需要发送消息的【人工任务】中配置消息通知监听器com.newfiber.workflow.support.listener.WorkflowNotificationListener

消息通知监听器节点

消息通知监听器

默认邮件通知

​ 在需要进行消息通知的任务中添加监听器,当执行到该任务时,会自动向该任务的执行人发送一封邮件,邮件内容为 [%workflowKey]您有一条待办任务:[%businessKey]。如果需要自定义发送的内容,或者需要发送短信,可以参照下文的「自定义消息模板」和「方法调用」。

自定义消息模板

​ 如果不想使用默认的消息模板,可以自定义消息模板。这里提供了接口来实现自定义消息模板:IWorkflowEmailNotification用于定义邮件模板,IWorkflowSmsNotification用于定义短信模板,其方法签名如下。其中短信模板现仅支持腾讯云短信,需要在腾讯云中申请短信签名及短信模板后再使用。(注:任务需要配置WorkflowNotificationListener监听器)

IWorkflowEmailNotification
public interface IWorkflowEmailNotification extends IWorkflowNotification{

    /**
     * 通知模板
     * @return 通知模板
     */
    String getNotificationTemplate();

}
IWorkflowSmsNotification
public interface IWorkflowSmsNotification extends IWorkflowNotification{

    /**
     * 短信签名
     * @return 短信签名
     */
    default String getSmsSign(){
        return null;
    }

    /**
     * 短信模板编号
     * @return 短信模板编号
     */
    default String getSmsTemplateCode(){
        return null;
    }
}

​ 使用时,首先需要在业务代码中创建枚举实现以上接口。这里以同时发送邮件和短信为例:分别配置了邮件模板和短信模板。

public enum ECountersignNotification implements IWorkflowEmailNotification, IWorkflowSmsNotification {
    /**
     *
     */
    AfterApprove("AfterApprove", "[%s]您有一条待办任务:[%s],请在[%s]前完成", 
                 "新钜物联","10945341");

    private final String notificationTask;

    private final String notificationTemplate;

    private final String smsSign;

    private final String smsTemplateCode;

    ECountersignNotification(String notificationTask, String notificationTemplate, String smsSign, String smsTemplateCode) {
        this.notificationTask = notificationTask;
        this.notificationTemplate = notificationTemplate;
        this.smsSign = smsSign;
        this.smsTemplateCode = smsTemplateCode;
    }

    @Override
    public String getNotificationTask() {
        return notificationTask;
    }

    @Override
    public String getNotificationTemplate() {
        return notificationTemplate;
    }

    @Override
    public String getSmsSign() {
        return smsSign;
    }

    @Override
    public String getSmsTemplateCode() {
        return smsTemplateCode;
    }

}

​ 然后业务模块的Server需要实现*IWorkflowCallback接口的getWorkflowNotification()*方法,并返回模板定义类。例如会签申请的Server,其核心代码如下:

public interface IWorkflowCallback<T> {

    /**
     * 工作流通知
     * @return 工作流通知
     */
    default IWorkflowNotification[] getWorkflowNotification(){
        return null;
    }
}
public class CountersignServiceImpl implements IWorkflowCallback<Countersign> {

    @Override
    public IWorkflowNotification[] getWorkflowNotification() {
        return ECountersignNotification.values();
    }
}

​ 在发送通知时,可以动态指定消息模板的参数。参数内容通过WorkflowStartReq.notificationTemplateArgs或者WorkflowSubmitReq.notificationTemplateArgs传入。

方法调用

​ 如果不想使用默认邮件通知和自定义消息模板,也可以直接通过代码调用的方式发送通知。方法签名如下:

public interface ActivitiProcessService {
    /**
     * 发送邮件通知
     * @param email 邮箱
     * @param content 内容
     * @return 是否成功
     */
    boolean sendEmailNotification(String email, String content);

    /**
     * 发送短信通知
     * @param mobile 手机号
     * @param smsSign 短信签名
     * @param smsTemplateCode 短息模板编号
     * @param templateArgs 模板参数
     * @return 是否成功
     */
    boolean sendSmsNotification(String mobile, String smsSign, String smsTemplateCode, List<String> templateArgs);
}

文件上传及查询

上传

​ 工作流框架集成到通用产品框架后,节点附件上传走的通用文件上传,文件数据通过「refType」+「refField」和业务数据关联。

​ ● refType:关联类型/业务类型;例如巡查任务:patrolTask

​ ●refField:关联字段;可同时区分节点和文件类型,例如开始图片:start.picture,结束视频:finish.video

查询

​ 在「列表查询历史活动记录」接口*/workflow-process/list-history-activity*中,需要返回文件数据,由于涉及到依赖关系问题,工作流模块无法直接调用系统文件模块查询。所以现在的方案是通过AOP切面实现文件查询功能,涉及到的关键类:

​ 1、com.newfiber.common.core.annotation.WorkflowFileWrapper:文件包装注解

​ 2、com.newfiber.common.security.aspect.WorkflowFileAspect:文件包装AOP

​ 对于每个节点的文件,默认会以refField.startsWith(节点状态)过滤(即每个节点只能查询自身上传的文件)。同时查询条件中暴露了字段fileRefFieldPattern 查询关联文件匹配符(例查询refField like '%picture%', 则传picture),用于定制化查询。

集成国产数据库

​ 修改newfiber-common-datasource包的POM依赖,切换数据库组件。

    <dependencies>

        <!-- Mysql Connector -->
<!--        <dependency>-->
<!--            <groupId>mysql</groupId>-->
<!--            <artifactId>mysql-connector-java</artifactId>-->
<!--        </dependency>-->

        <!-- Druid -->
<!--        <dependency>-->
<!--            <groupId>com.alibaba</groupId>-->
<!--            <artifactId>druid-spring-boot-starter</artifactId>-->
<!--        </dependency>-->

        <!-- Kingbase Connector -->
        <dependency>
            <groupId>cn.com.kingbase</groupId>
            <artifactId>kingbase8</artifactId>
        </dependency>

      <!--    DM Connector  -->
<!--        <dependency>-->
<!--            <groupId>com.dameng</groupId>-->
<!--            <artifactId>DmJdbcDriver18</artifactId>-->
<!--        </dependency>-->
      
    </dependencies>

人大金仓

链接配置

spring:
  datasource:
    driver-class-name: com.kingbase8.Driver
    url: jdbc:kingbase8://192.168.30.91:54321/newfiber_standard
    username: system
    password: system2023

达梦

链接配置

datasource:
 	driver-class-name: dm.jdbc.driver.DmDriver
  url: jdbc:dm://192.168.30.93:5236/newfiber_standard?schema=newfiber_standard
  username: SYSDBA
  password: SYSDBA

工作流框架适配

​ 由于达梦不同于人大金仓,数据库不支持原生的隐式数据类型转换,会导致工作流在启动初始化时报错,所以对工作流源码进行了改造用以适配。

​ 项目模块如果引用了工作流,需要用/resources/liquibase-core-4.9.1.jar包替换掉本地maven仓库对应的包才可正常启动。

总结

​ 总的来看,对接工作流模块需要完成以下步骤:

​ 1)画符合规范的BPMN流程图。

​ 2)编写符合业务模块的MySQL视图并执行。

​ 3)设计业务表。

​ 4)完成后端代码编码。

问题及补充

BPMN绘制规范

​ 在工作流开发过程中,BPMN绘制占很重要的部分,可以由懂业务的项目经理或者开发人员来绘制。在绘制过程中要特别注意上文「BPMN流程图」中提到的「重点关注」事项,其中的绘制规范涉及到和后端代码的交互,如果不遵守会导致后端代码无法识别。重点关注:

​ ● BPMN流程图要指定「流程唯一标识」和「名称」

​ ● 各个节点要指定「ID」和「名称」

​ ● 人工任务节点可指定用户/角色权限,对于变量名的指定要符合文档规范

​ ● 结束事件的ID固定为「end」,并且要指定「执行监听器」

​ ● 每条顺序流都要指定「跳转条件」(「开始事件外」)

相关SQL

已办

SELECT RES.* from ACT_HI_TASKINST RES WHERE RES.END_TIME_ is not null and 
( EXISTS(select LINK.ID_ from ACT_HI_IDENTITYLINK LINK where LINK.USER_ID_ = 1 and LINK.TASK_ID_ = RES.ID_) 
or RES.ASSIGNEE_ = 1 or RES.OWNER_ = 1 ) 
and exists ( select 1 from ACT_RE_PROCDEF D 
WHERE RES.PROC_DEF_ID_ = D.ID_ and D.KEY_ like 'PatrolCase' ) order by RES.ID_ asc;

SELECT RES.* from ACT_HI_TASKINST RES 
left join ACT_RE_PROCDEF D on RES.PROC_DEF_ID_ = D.ID_
where D.KEY_ = 'PatrolCase'

代办

SELECT RES.* from ACT_RU_TASK RES WHERE exists ( select 1 from ACT_RE_PROCDEF D 
WHERE RES.PROC_DEF_ID_ = D.ID_ and D.KEY_ = 'projectQualityReformRecord' ) 
and (RES.ASSIGNEE_ = 1 or ( RES.ASSIGNEE_ is null and 
exists(select LINK.ID_ from ACT_RU_IDENTITYLINK LINK 
where LINK.TASK_ID_ = RES.ID_ and LINK.TYPE_ = 'candidate' 
and (LINK.USER_ID_ = 1 or ( LINK.GROUP_ID_ IN ( 89010001 ) ) )))) order by RES.ID_ asc

空文件

简介

基于Flowable的工作流框架。支持BPMN流程图,提供低侵入性、低开发量、快速集成、高复用的工作流组件。实现了一键启动、提交、查询工作流等功能。 展开 收起
Java 等 2 种语言
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/silverconx/newfiber-workflow-release.git
git@gitee.com:silverconx/newfiber-workflow-release.git
silverconx
newfiber-workflow-release
Flowable 工作流框架
main

搜索帮助

53164aa7 5694891 3bd8fe86 5694891