相比于从零开始构建全套信息化系统,基于成熟的ERP等行业软件做二次开发是更多中大型企业应对个性化软件需求的首选方案。如何在二开模块中,可靠地对成品软件的数据库进行读写操作,以满足单据自动创建、元数据自动同步等系统集成要求,是摆在开发者面前的难题。今天,我们基于活字格低代码平台的技术支持工作中较为常见SAP HANA为例,为您介绍几种典型的路线。
方案1:通过ODBC直连HANA,操作原始数据
SAP HANA的客户端程序中提供了ODBC的数据源,这就使得开发团队可以直接通过ODBC连接HANA数据库,并通过SQL语句对数据库中的原始数据进行读写操作。
文章图片
(通过ODBC操作HANA)
首先,我们需要在开发环境、测试环境和生产环境的服务器上,配置SAP提供的ODBC数据源。在安装有SAP Client(推荐x64)之后,打开系统的odbc数据源管理程序(注意区分64为和32位,需要和SAP Client保持一致)。在"系统DSN"选项卡中点击"添加",选择HDBODBC,之后按照界面提示输入数据源的名称,如"HANA-测试库"、服务器IP地址、用户名和密码就可以了。
文章图片
(创建到HANA的ODBC数据源)
配置完成后,我们就可以像操作其他数据库一样,对 SAP HANA的数据进行读写了。回到活字格里面,我们使用"连接到外联表"功能,引入HANA中需要操作的所有数据表。之后就可以用拖拽的方式完成数据绑定,或者在服务端拼接和执行SQL语句了。
文章图片
(在活字格低代码平台中引入ODBC数据源)
如果仅仅是读取元数据或者一些简单的单据,这种方案确实是一个简单的办法。但是,SAP的数据表结构复杂,且缺乏有效的数据库脚本跟踪能力,我们很难确定一个单据创建过程需要操作哪几张表的哪些字段。所以,在涉及到稍微复杂一点的应用场景时,通过ODBC直接操作原始数据的做法的风险较高。
文章图片
(纯代码,通过ODBC操作HANA的数据表)
基于多年的技术支持经验,我们通常不会推荐客户采用这个方案。
方案2:调用NetWeaver API,操作业务对象
SAP显然也清楚开发者直连HANA,操作原始数据带来的可靠性风险。所以,SAP推出了NetWeaver集成平台,给开发者提供了一个原厂级二开解决方案,"尽量"确保写入的数据不会对SAP系统运行造成威胁。然而,这个平台的开发成本依然不如人意,以至于大多数开发者在二开项目之初就放弃了这个方案。不过,NetWeaver中对数据表中原始数据的操作封装成对业务对象的操作,并加入了一些必要的校验逻辑,这一点对于二开来说还是非常有意义的。更重要的是,这些封装的接口是开放的,即便我们采用了其他的二开方案,依然可以通过RFC协议,调用NetWeaver提供的HANA操作能力,从而避免直接读写原始数据带来的风险。
引入NetWeaver后,二开模块可以不再直接操作HANA数据库,而是通过位于二开服务器上的RFC桥(如果对可维护性要求不高,也可直接集成到二开模块中)和位于SAP集群中的NetWeaver来完成。二开模块通过HTTP等协议调用RFC桥,RFC桥则通过RFC协议转调NetWeaver,NetWeaver则负责在HANA上直接对应的SQL语句。
之所以我们将RFC调用部分抽象成一个专门的RFC桥模块,主要是考虑到这部分采用了一个第三方组件库(SAP原厂的.NET SDK口碑不佳),将其与二开模块进行隔离,可有效降低维护风险。因为客户采用的是低代码的开发方式,这个RFC桥的实现方式为基于活字格服务端编程接口开发的自定义WebAPI。对于纯代码开发者来说,RFC桥通常是一个ASP.NET MVC或Java SpringBoot的Web服务。在实现逻辑和架构原理上,低代码与纯代码大同小异,都需要通过写代码的方式完成。
文章图片
(通过RFC + NetWeaver操作HANA)
步骤一:使用C#开发调用NetWeaver的RFC桥
在这一步中,我们需要使用到Visual Studio(截屏是VS2021)、活字格服务端编程接口(截屏是活字格V7.0 Update1)、SAP NetWeaver RFC SDK(截屏是7.5)和开源项目SapNwRfc(https://github.com/huysentruitw/SapNwRfc)。其中SAP的SDK需要客户使用SAP账号,从SAP官网下载。
首先,我们在VS2021中创建.NET 4.7.2的类库工程,引用RFC SDK中lib文件夹的sapnwrfc.dll;然后通过nuget查找并安装SapNwRfc包和Microsoft.AspNetCore.Http.Abstractions包(活字格服务端编程接口需要依赖这个包);最后引用活字格服务器程序安装目录中的GrapeCity.Forguncy.ServerApi.dll。为了确保RFC SDK的正常运行,简化部署操作,我们更建议将RFC SDK的文件直接拷贝到系统盘下的某个目录,并且在系统的PATH变量中追加这个目录下面的lib文件夹,以确保运行时可以准确找到所引用的sapnwrfc.dll。
文章图片
(Nuget中的SapNwRfc包)
然后,我们需要根据SAP的文档说明,创建RFC的传入和传出参数所对应的类。SAP为每一个NetWeaver接口准备一个Excel文件,记录了方法名,传入参数和传出参数的类型和结构。我们只需要找到所需调用的那个接口对应的Excel文件,根据文档要求创建入参和出参对应的class即可。需要注意的是,属性的名称、SapName标签的值需要和文档中的参数名严格保持一致。以创建供应商为例,我们需要创建传入参数类:CreateVendorParameters和传出参数类:createVendorParametersObj。
文章图片
(NetWeaver中创建供应商的接口所对应的参数结构)
然后,我们在工程中创建WebAPI,一个继承自ForguncyApi的类GetSAPInfo,然后创建POST请求的响应方法CallRFCFunction(方法名和类名组成了URL的Path部分)。在代码中,我们从请求中读取连接字符串、需要使用的方法和参数,调用SapConnection类的对应方法进行处理,最后把结果序列化后返回给该WebAPI的调用者。和属性名称一样,调用SapConnection时传入的方法名也需要和文档中的文字严格保持一致,如创建供应商的方法名为ZLIFNR\_CREATE。
文章图片
(RFC桥的WebAPI实现)
根据既往经验,为了降低调用RFC桥的开发者的学习门槛,让他们也可以参照SAP提供的文档直接进行操作,我们推荐将所有用到的接口统合到一个WebAPI中,在代码中通过SAP的方法名进行switch分支。
如需使用这些示例代码,可以从码云获取:https://gitee.com/GrapeCity/lowcode\_extention\_demo\_hana\_via\_sap\_rfc
步骤二:在活字格中调用RFC桥
使用活字格服务端编程接口开发出的WebAPI与纯代码开发出的WebAPI的使用方法完全一致。在使用活字格开发业务系统的时候,都可以通过"发送HTTP请求"命令来调用。
首先,开发和测试的环境下,我们通常会连接不同的SAP数据库,所以,我们需要将连接NetWeaver所需的必要信息存储到数据库中,随程序一同发布,而不是写死在代码或全局配置文件中。
文章图片
(存储在数据库中的NetWeaver连接信息)
在需要操作SAP的数据时,我们需要先使用"设置变量命令",从数据库中读取当前环境所使用的HANA数据库的参数,拼接成连接字符串;然后使用"发送HTTP请求命令",通过调用RFC桥的WebAPI。
按照步骤一中RFC桥的实现,其URL地址是customapi/{类名}/{方法名}。我们还需要在HEAD中设置连接字符串和方法名(来自SAP提供的Excel文档,如ZLIFNR\_CREATE)。
文章图片
(配置NetWeaver的连接字符串和方法名)
而具体的请求参数则需要在BODY中进行设置,将二开系统的业务数据作为参数传递给HANA,执行对应的数据操作,最终达到系统集成的效果,如这里举例的创建供应商档案。
文章图片
(配置传递给NetWeaver的业务数据)
下面是我们帮助客户进行技术评估时,快速构建的活字格与SAP NetWeaver集成的Demo。如需使用这个工程,可以从码云获取:https://gitee.com/GrapeCity/lowcode\_demo\_hana\_via\_sap\_rfc
文章图片
(使用活字格集成SAP HANA的效果)
讨论
为了帮助开发者做二次开发,SAP和用友等主流厂商大多提供了直连数据库和封装业务接口两种开发模式。在纯代码开发方式下,两种模式最大的差异在于前者性能上限更高,后者可靠性更强。
【还在写SQL做SAP二开(通过RFC调用NetWeaver,让HANA数据库操作更可靠)】进入低代码时代后,封装业务接口的模式体现出了更强的竞争优势。比如今天的例子中,在RFC桥的帮助下,业务应用的开发者能通过可视化配置,轻松实现对HANA数据库的读取和写入操作,而这一切,无需掌握任何一门编程语言。专业程序员借助平台的编程接口扩展平台能力,非专业程序员通过使用这些能力,可视化完成系统开发,这种"混合模式"正在成为低代码开发的主流。
推荐阅读
- fetch简单封装request.js
- JavaScript的事件循环机制浅析
- js 数组去重的方式
- JavaScript 数组方法filter和reduce
- 关于promise学习
- 【JS30-Wes Bos】30天原生JS挑战——总结
- 【JS30-Wes Bos】自定义视频播放器 11
- Day 33/100 JavaScript 创建对象的四种方式
- 【JS30-Wes Bos】HTML5 画板 06