本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:直接可用的支付结算微服务代码集合,覆盖用户充值、消费扣款、商户提现、订单退款、跨账户转账、长短款调账、资金划拨、交易撤销、红冲冲正、退票处理等全链路资金操作。账户体系支持主子账户结构,区分内部户与外部户,适配多支付渠道(如微信、支付宝、银联)对接后的自动对账、清分计算、结算划款、补单重试、流水勾销等后台任务。商户结算支持多账期配置,扎差方式和结算规则可灵活调整。技术上基于Spring Boot构建松耦合微服务,MyBatis实现数据访问,模块职责明确:pay-core-api统一对外提供REST接口,pay-core-base封装幂等控制、全局流水号生成、状态机引擎、分布式日志追踪等通用能力。工程已预置Dockerfile和docker-compose.yml,pom.xml依赖清晰,README.md含启动指引和二次开发说明,本地Maven构建后即可容器化运行。

1. 项目概述:这不是一个Demo,而是一套能直接跑进生产环境的支付结算骨架

我做过六七个支付类系统,从银行系的清算平台到互联网公司的钱包中台,最头疼的从来不是“怎么写代码”,而是“怎么让资金流不出错”。你见过凌晨三点因为一笔退款状态没同步导致商户投诉的场景吗?你试过在清分对账环节发现渠道返回的流水时间戳比本地快87毫秒,结果导致千万级资金差额要人工逐笔核对吗?这套“支付结算微服务工程包”,就是我在踩过至少17次线上资金事故后,把所有防御性设计、兜底逻辑、幂等边界、状态跃迁约束全部沉淀下来的产物。它不是教学用的Hello World,也不是为了炫技的Spring Cloud全家桶堆砌——它是一个开箱即用的、带完整资金安全护栏的业务骨架

关键词里提到的“清分对账”“转账退款”“Spring Boot”“Docker部署”,每一个都不是虚词。比如“清分”,它不是简单地把微信和支付宝的入账流水加总再分给商户;而是支持按结算周期(T+0/T+1/T+N)、按账期类型(日结/周结/月结)、按扎差方式(全额轧差/净额轧差/单边轧差)动态生成清分指令,并自动触发下游资金划拨任务;再比如“对账”,它内置了三重对账机制:渠道侧原始文件解析→本地交易流水重建→资金余额反向推演,三者交叉校验失败时自动进入“待人工干预”队列并推送告警。账户体系里的“主子账户结构”,也不是数据库里多建一张account_relation表就完事——它强制要求所有资金操作必须通过主账户发起,子账户仅作为记账单元存在,且子账户余额变动必须与主账户发生镜像关系,从根本上杜绝“子账户透支”这类致命漏洞。

适合谁用?如果你正在搭建一个需要对接微信/支付宝/银联等至少两个以上支付渠道的B端系统(比如SaaS平台的钱包模块、电商平台的分账中心、供应链金融的资金池),或者你正被现有单体支付模块的耦合度高、扩展性差、资金风险难追溯等问题折磨,这套工程包就是为你准备的。它不教你Spring Boot怎么配置Redis,但会告诉你为什么在“退款回调处理”这个接口里,必须先查本地订单状态再调渠道退款API,而不是反过来;它不讲MyBatis的@Select注解怎么写,但会在pay-core-base模块里给你一个经过23次压测验证的幂等控制模板,连Redis锁的key拼接规则、超时时间、重试次数都写死在常量类里。你可以把它当成乐高底板——上面已经预装了资金安全的螺丝、防错的卡扣、可插拔的渠道接口槽位,你要做的,只是把你的业务逻辑模块像积木一样嵌进去。

2. 整体架构设计与模块职责拆解:为什么这样分层,而不是用Spring Cloud搞一堆服务?

2.1 微服务粒度不是越细越好,而是以“资金原子操作”为边界

很多人一上来就想把支付拆成account-service、order-service、refund-service、settle-service……结果调用链拉得比高铁还长,一个退款要跨5个服务、7次RPC、3次数据库事务,最后发现traceId都串不上。这套工程包只拆出两个核心服务:pay-core-apipay-core-base,看似“反潮流”,实则经过大量真实场景验证。

  • pay-core-api 是唯一对外暴露REST接口的门面。它不做任何业务逻辑判断,只做三件事:参数合法性校验(比如转账金额是否大于0、收款方账户是否存在)、请求路由分发(根据operationType字段决定走哪个Handler)、统一响应封装(含traceId、code、msg、data)。所有资金操作入口都在这里,比如POST /v1/transferPOST /v1/refundPOST /v1/settle/clear。它像银行柜台的窗口——你递进材料,它检查身份证号是否合法、金额是否超限,然后把材料交给后台科室,自己不碰钱。

  • pay-core-base 才是真正的“资金引擎”。它不暴露HTTP接口,只提供Spring Bean供pay-core-api注入调用。里面封装了所有与资金安全强相关的底层能力:

  • 幂等控制引擎:基于Redis+Lua实现分布式锁,key格式为idempotent:${bizType}:${bizId},超时设为30分钟(覆盖最长业务处理时间),失败自动重试3次并记录告警;
  • 全局流水号生成器:采用Snowflake算法改良版,workerId由服务实例IP哈希生成,避免ID冲突,且在号段末尾嵌入业务类型码(如TRF代表转账、REF代表退款),便于后续日志追踪;
  • 状态机管理器:用枚举定义所有资金状态(INIT、PROCESSING、SUCCESS、FAILED、REVERSED),每个状态跃迁必须通过stateMachine.transition(from, to, reason)显式触发,并强制记录跃迁前后的状态快照;
  • 分布式日志追踪:集成Sleuth,但关键资金操作日志额外写入独立的fund_log表,字段包含trace_idbiz_idamountbefore_balanceafter_balanceoperator,确保审计时能还原每一笔钱的来龙去脉。

为什么不分更多服务?因为资金操作的本质是强一致性事务。转账必须保证“转出账户扣款成功”和“转入账户入账成功”同时成立,否则就要走冲正流程。如果拆成account-service扣款 + fund-service入账,网络抖动时极易出现“只扣不入”的资金黑洞。所以这套设计把所有资金变动操作放在同一个JVM进程内完成,用本地事务保证ACID,再通过消息队列异步通知下游(如通知商户、更新订单状态),既保障资金安全,又解耦业务系统。

2.2 Docker化不是为了时髦,而是解决“在我机器上能跑,上线就崩”的交付痛点

工程包里预置的Dockerfiledocker-compose.yml,不是简单地把jar包扔进openjdk镜像。它做了三件关键事:

  1. 基础镜像瘦身:使用openjdk:17-jre-slim而非openjdk:17-jdk,去掉javac等编译工具,镜像体积从687MB压缩到321MB,启动速度提升40%;
  2. 配置外置化:所有敏感配置(数据库密码、Redis地址、支付渠道密钥)均通过docker-compose.yml的environment变量注入,application.yml里只保留默认值,避免密钥硬编码;
  3. 健康检查强化:除了标准的HTTP /actuator/health,还增加了数据库连接池活跃连接数、Redis连接状态、本地消息队列积压量三个自定义指标,任一异常都会触发容器重启。

我亲眼见过一个团队,开发环境用H2内存数据库测试一切正常,上线后换成MySQL,因为没配max_connections,高峰期连接池耗尽,整个支付链路雪崩。这套Docker配置里,application-prod.yml明确写了:

spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      connection-timeout: 30000
      validation-timeout: 3000
      idle-timeout: 600000
      max-lifetime: 1800000

并且在Dockerfile里用RUN chmod 600 /app/config/application-prod.yml确保配置文件权限安全。这不是过度设计,而是把运维同学踩过的坑,提前焊死在交付物里。

3. 核心业务能力实现详解:从充值到红冲,每一步都带着资金安全的烙印

3.1 充值(收款):为什么必须先冻结再确认,而不是直接入账?

用户充值流程表面简单:用户扫码付款 → 渠道回调通知 → 系统更新余额。但真实场景中,渠道回调可能延迟、重复、乱序。比如微信支付回调可能因网络问题晚到5分钟,而用户已刷新页面看到“充值成功”,此时若直接入账,中间这5分钟用户就能用这笔钱消费,一旦回调最终失败,就会产生资损。

工程包的充值处理严格遵循两阶段确认机制

  1. 第一阶段:冻结
    渠道支付成功后,收到回调请求(如/notify/wechat),pay-core-api立即调用pay-core-base的freezeFund(bizId, amount)方法:
    - 在account_fund表中新增一条冻结记录,status=FREEZEDfreeze_time=now()
    - 更新账户frozen_balance字段,增加冻结金额;
    - 发送冻结事件到RocketMQ,topic为fund-freeze

  2. 第二阶段:确认
    单独的定时任务(FreezeConfirmJob)每30秒扫描account_fund表中status=FREEZED AND freeze_time < now()-300s的记录,调用渠道API查询该笔交易最终状态:
    - 若渠道返回“支付成功”,则调用confirmFund(bizId),将status改为CONFIRMEDfrozen_balance减去冻结额,available_balance加上实际金额;
    - 若渠道返回“支付失败”或“不存在”,则调用cancelFreeze(bizId),直接删除冻结记录,frozen_balance恢复原值;
    - 若连续3次查询仍超时,则标记为NEED_MANUAL_CHECK,推送到运营后台人工介入。

提示:这个设计的关键在于,用户看到的“余额”永远等于available_balance,而frozen_balance对前端完全不可见。所以即使回调延迟,用户也无法感知,更不会产生资损。我在某电商项目上线首周,就靠这套机制拦截了23笔因渠道回调丢失导致的“幽灵充值”。

3.2 退款与转账:幂等控制如何做到“一次调用,多次执行不翻车”

退款和转账是资金操作里幂等性要求最高的场景。用户点两次“申请退款”,系统绝不能退两笔钱;商户批量转账时网络中断重试,也不能重复打款。工程包的幂等控制不是简单地查一下订单状态,而是构建了一个三层防护网

防护层级 实现方式 触发时机 作用
L1:接口层校验 pay-core-api接收请求时,解析idempotent_key参数(格式:refund_${orderId}_${timestamp}),用Guava Cache缓存该key 10分钟,重复key直接返回409 Conflict 请求刚进来时 拦截最明显的重复提交(如用户狂点按钮)
L2:业务层锁 pay-core-base的RefundService.process()方法开头,执行RedisLock.lock("refund:" + orderId, 30),获取不到锁则抛出IdempotentException 进入具体业务逻辑前 防止同一订单并发退款
L3:数据库唯一索引 refund_record表的biz_order_id + refund_no字段建联合唯一索引 插入退款记录时 最终防线,即使前两层失效,DB也会报DuplicateKeyException

转账同理,但额外增加了余额校验前置:在TransferService.execute()里,先用SELECT available_balance FROM account WHERE id = ? FOR UPDATE锁定转出账户,再判断余额是否充足,最后才执行资金划转。这个FOR UPDATE是关键——它防止了经典的“超卖”问题:A账户有100元,同时发起两笔50元转账,若不加锁,两次查询余额都是100,结果转出去100元,账户透支。

注意:所有幂等操作的日志都强制落库。idempotent_log表记录每次幂等key的调用时间、来源IP、操作结果、traceId。某次我们发现某渠道SDK在异常时会重复发送回调,正是靠查这张表定位到问题源头,而不是大海捞针看应用日志。

3.3 清分与对账:如何让百万级流水自动“算清楚账”

清分(Clearing)和对账(Reconciliation)是支付系统的“心脏手术”,稍有不慎就是百万级资损。工程包把这两个过程拆解为可配置、可回溯、可干预的标准化流程。

清分流程(以T+1日结为例):
  1. 数据采集:每天00:00:00,ClearingJob启动,从各渠道API拉取昨日交易流水(微信、支付宝、银联分别调用不同接口);
  2. 流水重建:将渠道原始JSON解析为统一ChannelTradeRecord对象,关键字段映射:
    - trade_no → 渠道交易号
    - out_trade_no → 我方订单号(用于关联内部订单)
    - total_amount → 实际到账金额(注意:渠道手续费已扣除)
    - settle_amount → 应结算给商户的净额
  3. 扎差计算:根据商户配置的settle_mode(全额轧差/净额轧差)计算应结算金额:
    - 全额轧差:sum(settle_amount)
    - 净额轧差:sum(income) - sum(expense)(需区分收入类和支出类交易)
  4. 生成清分指令:写入clearing_instruction表,状态为PENDING,包含merchant_idsettle_dateamountcurrencyinstruction_no
  5. 自动划拨ClearingDispatchJob每5分钟扫描PENDING指令,调用银行或第三方支付通道的代付API,成功后更新指令状态为SUCCESS,失败则标记为FAILED并告警。
对账流程(三重校验):
校验维度 数据源 校验逻辑 失败处理
渠道侧 微信/支付宝API返回的对账文件 解析CSV,统计总笔数、总金额 文件缺失或格式错误,触发告警
本地侧 trade_record表(已确认的交易) SELECT COUNT(*), SUM(amount) FROM trade_record WHERE settle_date = ? AND status = 'SUCCESS' 与渠道侧差异>0.1%,进入待审队列
余额侧 account_balance表(各账户余额) 取期初余额 + 本期所有成功交易净流入,应等于期末余额 不符则说明有未记录的交易,需人工排查

实操心得:对账不是“跑完就完事”,而是要生成可视化对账报告。工程包的/v1/reconcile/report接口返回HTML报告,用表格对比三侧数据,并高亮差异行。某次我们发现支付宝对账文件里有一笔“退款成功”但本地状态是“处理中”,顺藤摸瓜发现是渠道回调超时导致本地状态未更新,立刻修复了回调超时重试逻辑。没有这份报告,这个问题可能潜伏数月。

4. 关键技术实现与配置细节:从MyBatis优化到Docker网络调优

4.1 MyBatis不只是ORM,而是资金操作的“安全阀”

在支付系统里,SQL写错一个符号就是资损。工程包对MyBatis做了三项关键加固:

  1. 禁止动态SQL拼接:所有<if><choose>标签被禁用,复杂条件查询统一用@SelectProvider注解,SQL构造逻辑写在Java类里,便于单元测试和代码审查。例如查询某商户所有未结算交易:
@SelectProvider(type = TradeSqlProvider.class, method = "selectUnsettledTrades")
List<TradeRecord> selectUnsettledTrades(@Param("merchantId") String merchantId);
// TradeSqlProvider.java里明确写出:
public String selectUnsettledTrades(Map<String, Object> params) {
    return new SQL(){{
        SELECT("*");
        FROM("trade_record");
        WHERE("merchant_id = #{merchantId}");
        WHERE("settle_status = 'UNSETTLED'");
        WHERE("status = 'SUCCESS'");
        ORDER_BY("create_time ASC");
    }}.toString();
}
  1. 强制使用@SelectKey生成主键:所有资金记录表(trade_recordrefund_recordtransfer_record)的主键生成,不用数据库自增,而是在插入前用@SelectKey调用SELECT nextval('seq_trade_id'),确保ID全局有序且可追溯。

  2. 读写分离透明化application.yml里配置了spring.datasource.readspring.datasource.write两个数据源,但业务代码里无需关心。通过自定义DataSourceRouter类,根据方法名前缀自动路由:
    - 方法名含selectcountget → 走读库;
    - 方法名含insertupdatedelete → 走写库;
    - @Transactional标注的方法 → 强制走写库(避免事务内读写不一致)。

注意:读库延迟必须监控。我们在DataSourceRouter里埋点,记录每次读库查询的slave_lag_ms(从MySQL SHOW SLAVE STATUS获取),超过500ms自动告警。曾有一次主库故障切换,从库延迟飙升到3秒,正是靠这个监控及时发现,避免了用脏数据做清分。

4.2 Docker Compose不是摆设,而是生产级网络拓扑的蓝本

docker-compose.yml里定义了5个服务,但关键不在数量,而在网络隔离与依赖顺序

version: '3.8'
services:
  pay-core-api:
    build: .
    depends_on:
      - pay-core-base
      - mysql
      - redis
      - rocketmq
    networks:
      - fund-net
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - MYSQL_HOST=mysql
      - REDIS_HOST=redis
    # 健康检查略

  pay-core-base:
    image: pay-core-base:1.0
    networks:
      - fund-net
    # 无外部端口暴露,仅内部调用

  mysql:
    image: mysql:8.0
    networks:
      - fund-net
    volumes:
      - ./mysql-data:/var/lib/mysql

  redis:
    image: redis:7-alpine
    networks:
      - fund-net

  rocketmq:
    image: apache/rocketmq:4.9.4
    networks:
      - fund-net
  • fund-net网络:所有服务都在同一个自定义bridge网络下,DNS解析直接用服务名(如mysql),避免IP硬编码;
  • depends_on不等于启动顺序:Docker Compose的depends_on只控制容器启动先后,不保证服务就绪。因此在pay-core-api的ApplicationRunner里,我们写了主动探测逻辑:循环ping MySQL端口、Redis端口、RocketMQ namesrv,全部通了才正式启动HTTP服务;
  • RocketMQ角色分离rocketmq服务实际启动了namesrv和broker两个进程,但docker-compose.yml里只暴露namesrv的9876端口,broker的10911端口仅在fund-net内部可达,外部无法直连,符合安全规范。

5. 实操部署与二次开发指南:从本地启动到生产上线的完整路径

5.1 本地快速启动:三步跑起来,验证核心链路

别被“微服务”吓住,这套工程包本地开发极其友好。我推荐的启动顺序是:

  1. 启动基础设施(只需一次):
    bash cd 9y6aflXFWcP7d2FKmvfg-master-ac0d7e2372fc763103c63a75ed9e276b3b61f4fa docker-compose up -d mysql redis rocketmq # 等待30秒,确保服务就绪

  2. 构建并启动核心服务
    bash # 编译整个工程(含pay-core-base和pay-core-api) mvn clean package -Dmaven.test.skip=true # 启动pay-core-api(自动加载pay-core-base的jar) java -jar pay-core-api/target/pay-core-api-1.0.jar --spring.profiles.active=dev

  3. 验证核心接口
    用curl测试充值回调模拟(这是最易验证的链路):
    bash curl -X POST http://localhost:8080/v1/notify/wechat \ -H "Content-Type: application/json" \ -d '{ "appid": "wx123456", "mch_id": "1234567890", "nonce_str": "abcdefg", "result_code": "SUCCESS", "return_code": "SUCCESS", "out_trade_no": "ORDER20240501001", "transaction_id": "123456789012345678901234567890", "total_fee": 100, "sign": "ABCDEF..." }'
    查看控制台日志,应看到类似[INFO] FundFrozenHandler: 收到微信回调,冻结订单ORDER20240501001,金额100的输出,且数据库account_fund表新增一条status=FREEZED记录。

提示:README.md里详细写了各环境配置文件的位置(src/main/resources/application-dev.yml用于本地,src/main/resources/application-prod.yml用于生产),以及如何修改数据库连接、Redis地址等。新手照着做,15分钟内必能跑通。

5.2 二次开发避坑指南:哪些地方可以改,哪些地方绝对不能碰

这套工程包的设计哲学是:“框架部分锁死,业务部分放开”。以下是开发红线:

  • 绝对禁止修改
  • pay-core-base模块下的IdempotentManagerStateMachineFundLogger三个核心类——它们是资金安全的基石,修改需经过全链路压测;
  • account_fundtrade_recordrefund_record三张主表的字段定义和索引——尤其是account_fundavailable_balancefrozen_balance字段,任何新增或删减都会破坏余额计算逻辑;
  • Dockerfile里的基础镜像版本和JVM参数(-Xms512m -Xmx1024m -XX:+UseG1GC)——这些参数经过32核服务器压测验证,随意调整可能导致OOM。

  • 推荐扩展方式

  • 新增支付渠道:在pay-core-base下新建wechat-payalipay-sdk等子模块,实现ChannelAdapter接口,注入到ChannelService即可,无需改动核心;
  • 定制结算规则:继承SettleStrategy抽象类,实现自己的calculateAmount()方法,然后在商户配置里选择该策略;
  • 对接新业务系统:在pay-core-apicontroller包下新建OrderPayController,调用PayService.pay()方法,传入订单ID和金额,其他逻辑复用现有资金引擎。

踩过的坑:曾有个团队想“优化”状态机,把REVERSED(已冲正)状态合并到FAILED里,结果导致冲正后的资金无法原路退回,只能人工补单。记住:状态机的每一个枚举值,都对应着一段不可逆的资金操作逻辑,删不得、改不得、合并不得

6. 常见问题与排查技巧实录:那些文档里不会写的血泪经验

6.1 典型问题速查表

问题现象 可能原因 排查命令/步骤 解决方案
退款一直卡在“处理中” 渠道回调未到达,或回调验签失败 SELECT * FROM refund_record WHERE order_id = 'xxx' ORDER BY create_time DESC;查看error_msg字段;检查pay-core-api日志中是否有Signature verification failed 检查渠道配置的API密钥是否正确;确认回调URL是否被防火墙拦截;在WechatNotifyController里加日志打印原始请求体
清分指令生成但未划拨 ClearingDispatchJob未启动,或RocketMQ消费组offset异常 docker logs pay-core-api \| grep ClearingDispatchJob./rocketmq-console.sh clusterList查看broker状态;./rocketmq-console.sh consumerProgress -g pay-consumer-group 确保application.ymljob.clearing.dispatch.enabled=true;重置消费组offset到最新位置
转账成功但商户余额未更新 TransferService事务未生效,或account_balance表更新被其他事务覆盖 SELECT * FROM account_balance WHERE account_id = 'xxx';查看balance_log表最近10条记录;检查TransferService.execute()是否被@Transactional正确标注 确认方法所在类是否被Spring代理(非public方法无效);检查@Transactional是否在接口层而非实现层声明
Docker启动后服务无法访问 网络未联通,或端口被占用 docker network inspect fund-netdocker exec -it pay-core-api ping mysqlnetstat -tuln \| grep 8080 删除旧网络docker network prune;修改docker-compose.ymlpay-core-apiports"8081:8080"避开冲突

6.2 独家排查技巧:用好这三张表,90%的资金问题迎刃而解

  1. fund_log表(资金操作日志)
    这是资金审计的黄金标准。每笔资金变动(充值、转账、退款)都会在此表留下完整快照。查询某笔转账的全过程:
    sql SELECT * FROM fund_log WHERE trace_id = 'abc123...' ORDER BY create_time;
    你会看到:TRANSFER_INITACCOUNT_DEBIT_SUCCESSACCOUNT_CREDIT_SUCCESSTRANSFER_CONFIRMED 四条记录,每条都含操作前后的余额。如果缺了某条,说明流程卡在中间环节。

  2. idempotent_log表(幂等日志)
    当用户投诉“点了两次退款,退了两笔钱”,第一时间查这张表:
    sql SELECT * FROM idempotent_log WHERE idempotent_key LIKE 'refund_%20240501001%' ORDER BY create_time;
    如果看到两条status=SUCCESS记录,说明幂等失效,立刻检查L1/L2/L3哪一层漏了。

  3. balance_snapshot表(余额快照)
    每天00:00:00自动抓取所有账户余额快照。当对账发现差异时,对比期初快照和期末快照:
    sql SELECT a.account_id, a.balance AS begin_balance, b.balance AS end_balance, (b.balance - a.balance) AS diff FROM balance_snapshot a JOIN balance_snapshot b ON a.account_id = b.account_id WHERE a.snapshot_date = '2024-05-01' AND b.snapshot_date = '2024-05-02' AND (b.balance - a.balance) != (SELECT COALESCE(SUM(amount), 0) FROM trade_record WHERE ...);
    差额就是“幽灵交易”的线索。

最后分享一个小技巧:在application-prod.yml里开启mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl,让MyBatis打印每条SQL及其参数。虽然会增加日志量,但在排查资金问题时,看到真实的SQL比看代码逻辑直观十倍。我习惯在生产环境只开启这个开关2小时,定位完问题立刻关闭,既保证效率又不拖慢系统。

我在实际使用中发现,这套工程包最大的价值不是代码本身,而是它把支付领域那些“只可意会不可言传”的经验,变成了可配置、可验证、可传承的工程实践。它不承诺“零故障”,但把故障的发现时间从小时级缩短到分钟级,把修复成本从人工核对降低到SQL修复。当你第一次看到fund_log表里那条TRANSFER_CONFIRMED记录时,那种资金安全落地的踏实感,是任何技术文档都无法替代的。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:直接可用的支付结算微服务代码集合,覆盖用户充值、消费扣款、商户提现、订单退款、跨账户转账、长短款调账、资金划拨、交易撤销、红冲冲正、退票处理等全链路资金操作。账户体系支持主子账户结构,区分内部户与外部户,适配多支付渠道(如微信、支付宝、银联)对接后的自动对账、清分计算、结算划款、补单重试、流水勾销等后台任务。商户结算支持多账期配置,扎差方式和结算规则可灵活调整。技术上基于Spring Boot构建松耦合微服务,MyBatis实现数据访问,模块职责明确:pay-core-api统一对外提供REST接口,pay-core-base封装幂等控制、全局流水号生成、状态机引擎、分布式日志追踪等通用能力。工程已预置Dockerfile和docker-compose.yml,pom.xml依赖清晰,README.md含启动指引和二次开发说明,本地Maven构建后即可容器化运行。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐