大家好,我是隐墨星辰,前几天发布了AVA版低代码报文网关,只需要手写几个配置文件,就可以快速接入一个渠道。接入效果和详情请看《百图解码支付系统设计与实现》专栏中的文章《开源发布:JAVA版低代码报文网关-通过简单配置快速对接银行渠道》。
今天讲解报文的源码,分享设计如何落地。项目代码写得很简洁精炼,稍微有点绕的是内联函数的实现,没有写过相关代码的同学可以重点看一下,看懂后就会觉得:嗯,原来这么简单。
补一个直观的效果,一个渠道的支付接口就是一个配置文件:
1. 原理介绍
说明:
- 处理器引擎服务:串起全部业务处理。
- 引擎上下文:保存接口配置、请求参数、返回参数、加解密加验签临时变量、内联函数等。
- 处理器责任链工厂:组装并管理内部发外部,外部发内部责任链。
- 处理器责任链:处理业务数据。包括解析、参数转换、签名验签、发送等处理。
- 缓存服务:缓存渠道配置,密钥配置等。
详细设计参考《百图解码支付系统设计与实现》专栏文章:
《图解支付报文网关:一种低代码报文网关的设计思路与核心代码实现》
《图解支付渠道网关(一):不只是对接渠道的接口》
《图解支付渠道网关(二):不只是对接渠道的接口》
2. 工程目录说明
如下图所示。
3. 入口服务定义与实现
入口服务只有一个,是通用服务,无论支付、退款、支付查询、退款查询等全部都是这个接口。
上游根据实际需求,定义一些强类型,比如支付请求模型,退款请求模型,然后使用JSON.toString序列化后传下来。返回后再反序列化强模型做内部处理。
com.demo.gateway.api.GatewayService
com.demo.gateway.api.response.GatewayResponse
com.demo.gateway.api.response.GatewayResponse
com.demo.gateway.service.GatewayServiceImpl
4. 流程引擎
流程引擎服务是最核心的服务,全部处理由流程引擎串起来。
4.1. 流程引擎服务定义与实现
流程引擎核心只做了3件事:
- 初始上下文。
- 从处理器工厂找到处理器责任链。
- 依次执行处理器。
4.2. 处理器工厂
处理器工厂核心能力:
- 定义内部到外部,外部到内部的处理责任链。
- 初始化责任链。
- 根据方向(内部发外部,或外部发内部)返回指定的责任链。
定义责任链:
4.3. 各类型处理器
各种各样的处理器,每个处理器都非常简单,只做一件事,组合起来就是强大的网关。
4.3.1. 处理器基类
4.3.2. 参数转换
4.3.3. 签名验签名
以RSA签名示例。非RSA可以自行扩展。
4.3.4. 报文组装
4.3.5. 发送
4.3.6. 其它处理器
其它加解密等略过,主体结构都差不多。
5. 内联函数
5.1. 使用场景
大部分的参数是一一映射的,比如内部参数叫:orderNo,外部渠道参数叫merchantOrderNo,都是比较容易映射的,如下:
但是一些特殊的处理,就需要使用内联函数来解决,比如内部传的日期是时间戳,类似:1715509833656,但是外部渠道要求格式为:"yyyy-MM-dd HH:mm:ss",就不能直接做映射。
还一些情况下,比如组装复杂的结构体,或者发送前需要调用内部应用先获取一些数据,都可以使用内联函数实现。
5.2. 实现原理
主要是借助Groovy的模板引擎来实现。
先定义一个基类,方便Spring自动加载。
时间处理函数:
JSON格式化函数:
Money转换函数
先把内联函数缓存起来备用。
每次请求进来,都会初始化引荐上下文,这时把内联函数放到引擎上下文中。
com.demo.gateway.engine.impl.HandlerEngineServiceImpl#initContext
再以function开头放到runtimeContext中,这样配置文件就可以使用"${function.funcationname.method(param)}的方式调用。
com.demo.gateway.engine.context.HandlerEngineContext#initRuntimeContext
调用示例:
6. Groovy模板引擎
参数映射和内联函数的运算,依赖Groovy模板引擎。
com.demo.gateway.groovy.GroovyUtil
调用,就会把转换变量。
比如配置文件:
kotlin
{
"requestTime": "${function.Datetime.formatDateString(requestData.requestTime, 'yyyy-MM-dd HH:mm:ss')}"
}
转换后的报文:
json
{
"requestTime": "2024-05-12 18:30:33"
}
7. 配置模型
就是把渠道接口抽象出不同的配置类型,然后组装起来。
8. 配置数据
- 生产上可以考虑放数据库中。
- 生产参数和线下联调环境参数要区分开。部分敏感数据,比如apiKey建议加密后存储,提高安全性。
- 生产密钥保存到密钥平台,提高安全性。
9. 测试与验证
9.1. 测试代码
com.demo.gateway.DemoTest#run()
如果需要验证http外发能力,先运行:com.demo.gateway.GatewayApplication#main
com.demo.gateway.web.DemoChannelMockController#mockChannel是web服务,模拟外部渠道的http服务。
9.2. 运行日志参考
只截取了部分日志。详细输出参考:《百图解码支付系统设计与实现》专栏中的文章《开源发布:JAVA版低代码报文网关-通过简单配置快速对接银行渠道》。
- 内部应用调用网关的完整请求参数 (GatewayRequest) :
- 转换后返回内部应用的参数(GatewayResponse):
10. 如何获取源码
11. 小结
项目代码写得很简洁精炼,如果有同学所在公司的网关想升级或准备重构,可以拿回去参考一下。说不定能为上半年的好绩效做点贡献。
这是《百图解码支付系统设计与实现》专栏系列文章中的第(33)篇。 欢迎和我一起深入解码支付系统的方方面面。
专栏系列文章PDF合集,以及电子书《图解支付系统设计与实现》(已写9万字左右)不定时更新,欢迎关注我的公众号获取:隐墨星辰。
有个小群不定时解答一些问题或知识点,有兴趣的同学可先加微信(yinmon_sc)后进入,添加微信请备注:666。