§ 前言

工作流开发(微服务版)基于原有echain工作流改造而来,逻辑类似,使用方式略有区别

工作流开发环境依赖数据库目前支持Oracle,Mysql,Db2这三种关系型数据库开发

§ 本文目标

掌握流程图绘制,配置以及工作流的发起、提交等操作

§ 练习场景

以押品入库为例,开发押品入库、流转

前提:

  • 依赖基础微服务工程:yusp-app-oca、yusp-app-common、yusp-echain
  • RabbitMQ环境
  • 使用工作流的微服务工程

§ 初始化配置

§ 工作流引擎代码下载

链接:https://pan.baidu.com/s/1GUseg6zONVpQ9X3mKOvaQA 提取码:y1xe

§ 引入工作流相关表结构

wf_xx及wfi_xx开头的表结构,可联系统一开发平台获得初始化脚本及数据

§ 初始化数据更新

  • wf_client

  • wf_client_instu

  • wf_studio

  • wf_studio_folder

  • wf_client.clientsign字段值需与wf_client_instu.clientsign中字段值保持一致

  • wf_client_instu.instu_cde需与admin_sm_instu.instu_cde中项目组使用的机构码保持一致

  • wf_studio和wf_studio_folder,可清空,生产初始化表结构时需保留

§ 配置流程文件路径

修改echain.properties文件

echain.properties

echainstudiopath=F:\\wk\\yusp-app-framework\\yusp-app-single-starter\\echain-studio\\  #设置流程图文件夹位置
1

§ 配置流程启动文件

eChainStudio.jnlp

echain_01

§ 流程图绘制

§ 下载eChainStudio.jnlp文件

推荐使用Chrome浏览器下载

echain_02

§ 启动eChainStudio.jnlp

javaws -verbose C:\Users\figue\Desktop\eChainStudio.jnlp

echain_03

echain_04

§ 绘制流程图,见视频

https://pan.baidu.com/s/1cM5IUG8aH-quDq7BwmIHFQ

§ 绘制完流程图,重启工作流引擎[yusp-echain]

§ 流程关联业务配置

详见视频:https://pan.baidu.com/s/1cM5IUG8aH-quDq7BwmIHFQ

§ 新增流程适用业务配置

echain_05

§ 配置流程流转业务功能页面

echain_06

注:

2.0及其以上版本直接填写前端页面的路由ID,前端页面的路由ID在route.echain.js里配置,会自动关联到页面

echain_07

流程关联业务页面需要自己开发,示例见exampleInfo.html与exampleInfo.js

§ 流程关联机构配置

详见视频:https://pan.baidu.com/s/1cM5IUG8aH-quDq7BwmIHFQ

echain_08

§ 创建业务表

以押品表[WFI_DEMO_YAPIN]为例,字段最好含CUST_NAME和CUST_ID【待办会很直观】,且必须要有一个主键

echain_09

§ 前端流程发起

[示例见SampleWfInit.js、SampleWfInit.html]

流程发起核心js代码:

startWorkFlow: function () {
    var _self = this;
    this.$confirm('发起流程?', '提示', {
        confirmButtonText: '同意',
        cancelButtonText: '取消',
        type: 'success',
        center: true
     }).then(function(){
            
        var comitData = {};
       comitData.bizSeqNo = '修改为业务主键';
            comitData.wfSign = '修改为流程标识';
        comitData.applType = '修改为流程申请类型';// 有了流程标识就不再需要申请类型
        comitData.custId='客户ID';
        comitData.custName='客户名称';
        comitData.paramMap={};//自定义流程参数,此处comitData.paramMap={"bxje":"xxxx"},路由脚本里可以拿到String bxje=(String)obj.paramMap.get("bxje");
        _self.$refs.yufpWfInit.wfInit(comitData);
    })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

核心html代码:

yufp-wf-init ref="yufpWfInit" @afterinit="onAfterInit" @afterclose="onAfterClose" :common-params="wfCommonParams" />
1

注意:

需要引入js (./custom/widgets/js/YufpWfInit.js)

echain_10

§ 业务微服务做后业务处理

集成开发无需依赖RabbitMQ及相关配置

§ pom.xml引入依赖jar包

务微服务的后业务处理,通过mq的监听实现,业务微服务引用工作流客户端jar包

pom.xml

<dependency>
     <groupId>cn.com.yusys.yusp</groupId>
     <artifactId>yusp-echain-client</artifactId>
     <version>2.1.1-SNAPSHOT</version>
</dependency>
<dependency>
     <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9

§ RabbitMQ中添加queue

rabbmitMQ安装(步骤略)

2.0及以上版本队列名称为【echain.流程标识】,队列在mq中手动添加

echain_11

修改springboot配置文件中mq的地址

spring:     
    # rabbitmq配置
    rabbitmq:
        host: localhost #MQ地址
        port: 5672 #MQ端口
        username: username #MQ用户名
        password: password #MQ密码
1
2
3
4
5
6
7

复制如下代码到业务微服务工程中

package cn.com.yusys.yusp.echain.server.clientdemo;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import cn.com.yusys.yusp.echain.client.consts.Consts;
import cn.com.yusys.yusp.echain.client.message.InstanceMessageProcessor;
import cn.com.yusys.yusp.echain.client.message.InstanceMessageProcessorFactory;
@Component
public class InstanceMessageListeners {
    private final Logger log = LoggerFactory.getLogger(InstanceMessageListeners.class);
    @Autowired
    private InstanceMessageProcessorFactory processorFactory;
    @RabbitListener(queues = {"RabbitMQ中queue名称"})// 队列名称,多个时以逗号隔开;2.0及以上版本队列名称为【echain.流程标识】,队列在mq中手动添加
    @RabbitHandler
    public void receiveQueue(String message) {
        List<InstanceMessageProcessor> processors = processorFactory.getProcessors(message);
        for (InstanceMessageProcessor processor : processors) {
            try {
                processor.process(message);
            } catch (Exception e) {
                log.error(e.toString(), e);
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

§ 后业务逻辑操作

继承InstanceMessageProcessor.java,完成发起,提交,退回,打回等

示例代码如下:

import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.com.yusys.yusp.echain.client.consts.Consts;
import cn.com.yusys.yusp.echain.client.message.InstanceMessage;
import cn.com.yusys.yusp.echain.client.message.InstanceMessageProcessor;
/**
 * 后业务处理示例
 */
@Component
public class BizInstanceMessageProcessorDemo implements InstanceMessageProcessor {
 private final Logger log = LoggerFactory.getLogger(this.getClass());
 private ObjectMapper objectMapper = new ObjectMapper();
 @Override
 public boolean should(String message) {
  try {
   InstanceMessage instanceMessage = objectMapper.readValue(message, InstanceMessage.class);// 字符串转为对象
   String wfSign = instanceMessage.getInstanceInfo().getWfSign();
   if ("修改为流程标".equals(wfSign)) {// 根据流程标识,决定此流程是否走此后业务处理
    log.debug("后业务处理类命中:" + this.getClass());
    return true;
   }
  } catch (IOException e) {
   e.printStackTrace();
  }
  return false;
 }
 @Override
 public int order() {
  return 0;
 }
 @Override
 public void process(String message) throws Exception {
  // instanceMessage 对象中包含业务表主键等信息,便于后业务处理
  InstanceMessage instanceMessage = objectMapper.readValue(message, InstanceMessage.class);
  String messageType = instanceMessage.getType();
  try {
   if (Consts.MESSAGE_TYPE_INIT.equals(messageType)) {
    log.debug("初始化操作:" + message);
   } else if (Consts.MESSAGE_TYPE_SUBMIT.equals(messageType)) {
    log.debug("提交操作:" + message);
   } else if (Consts.MESSAGE_TYPE_SIGNIN.equals(messageType)) {
    log.debug("签收操作:" + message);
   } else if (Consts.MESSAGE_TYPE_SIGNOFF.equals(messageType)) {
    log.debug("签收取消操作:" + message);
   } else if (Consts.MESSAGE_TYPE_CHANGE.equals(messageType)) {
    log.debug("转办操作:" + message);
  } else if (Consts.MESSAGE_TYPE_JUMP.equals(messageType)) {
    log.debug("跳转操作:" + message);
   } else if (Consts.MESSAGE_TYPE_END.equals(messageType)) {
    log.debug("结束操作:" + message);
   } else if (Consts.MESSAGE_TYPE_RETURNBACK.equals(messageType)) {
    log.debug("退回操作:" + message);
   } else if (Consts.MESSAGE_TYPE_CALLBACK.equals(messageType)) {
    log.debug("打回操作:" + message);
   } else if (Consts.MESSAGE_TYPE_TAKEBACK.equals(messageType)) {
    log.debug("拿回操作:" + message);
   } else if (Consts.MESSAGE_TYPE_CANCEL.equals(messageType)) {
    log.debug("撤销操作:" + message);
   } else if (Consts.MESSAGE_TYPE_HANG.equals(messageType)) {
    log.debug("挂起操作:" + message);
   } else if (Consts.MESSAGE_TYPE_WAKE.equals(messageType)) {
    log.debug("唤醒操作:" + message);
   }  else if (Consts.MESSAGE_TYPE_REFUSE.equals(messageType)) {
    log.debug("否决操作:" + message);
   } else {
    log.warn("未知操作:" + message);
   }
  } catch (Exception e) {
   e.printStackTrace();
  log.error("后业务处理失败"+e.toString());
   // 后业务处理失败时,将 message保存到自己的异常表中,调用bizInstanceMessageProcessorDemo.process(String message)进行手动重试
  }
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

§ 统一待办处理

echain_12

echain_13

§ 流程发起视频演示

视频链接:https://pan.baidu.com/s/1cM5IUG8aH-quDq7BwmIHFQ

§ FAQ

http://192.168.251.151:8090/pages/viewpage.action?pageId=1114467

最后更新于: 4/28/2022, 5:10:13 PM