1 Star 4 Fork 3

柯凯 / Flowable 工作流框架

Create your Gitee Account
Explore and code with more than 12 million developers,Free private repositories !:)
Sign up
This repository doesn't specify license. Please pay attention to the specific project description and its upstream code dependency when using it.
Clone or Download
contribute
Sync branch
Cancel
Notice: Creating folder will generate an empty file .keep, because not support in Git
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

Empty file

About

基于Flowable的工作流框架。支持BPMN流程图,提供低侵入性、低开发量、快速集成、高复用的工作流组件。实现了一键启动、提交、查询工作流等功能。 expand collapse
Java and 2 more languages
Cancel

Releases

No release

Contributors

All

Activities

Load More
can not load any more
Java
1
https://gitee.com/silverconx/newfiber-workflow-release.git
git@gitee.com:silverconx/newfiber-workflow-release.git
silverconx
newfiber-workflow-release
Flowable 工作流框架
main

Search

53164aa7 5694891 3bd8fe86 5694891