RuoyiOffice头像
关注
SpringBoot 企业系统集成架构:API、Webhook、MQ 与定时同步应该怎么选封面图

SpringBoot 企业系统集成架构:API、Webhook、MQ 与定时同步应该怎么选

SpringBoot 企业系统集成架构:API、Webhook、MQ 与定时同步应该怎么选

🌐 文档地址:https://ruoyioffice.com
👇👇👇 文章底部获取源码和演示地址 👇👇👇
💬 :17156169080(获取产品咨询)

企业系统集成最危险的错觉,是“接口返回 200 就算完成”。ERP 创建单据超时后到底有没有成功?支付平台把同一条回调推送三次怎么办?MQ 消费失败会不会丢数据?夜间同步漏了一页如何发现?真正可运营的集成,必须让失败可发现、重复不多写、断点能续跑、双方能对账。

企业系统集成枢纽

▲ 外部系统通过不同通信方式接入集成枢纽,再进入 OA、BPM、HRM、CRM、合同、项目和财务等内部业务域

引言:不要先问“用不用 MQ”,先问业务需要什么

常见集成需求包括:

  • OA 查询 ERP 库存;
  • 审批通过后向财务系统创建付款单;
  • 钉钉或企业微信接收待办通知;
  • 支付平台把支付结果推回来;
  • HRM 每晚同步组织和人员;
  • IoT 平台持续上报设备事件;
  • 第三方客户系统批量同步历史订单。

这些需求看起来都是“数据传输”,但实时性、方向、数据量、失败容忍度完全不同。技术选型不应该由团队最熟悉哪个中间件决定,而应该先回答五个问题:

  1. 谁发起通信;
  2. 是否必须同步得到结果;
  3. 数据是一条命令、一次状态变化,还是批量快照;
  4. 失败后业务能等待多久;
  5. 最终由哪一方负责核对一致性。

一、REST API:适合实时查询和必须立即得到结果的命令

REST API 最符合开发者直觉:调用接口,等待返回。

适合场景:

  • 查询库存、客户或合同状态;
  • 创建一张外部单据并立即拿到业务编号;
  • 校验账号、额度或权限;
  • 用户正在等待结果的操作。

它的优势是调用路径清楚、调试简单、结果及时;风险是服务依赖被直接串联。如果 OA 提交审批时同步调用 ERP,而 ERP 响应缓慢,用户会一直卡在提交页面。

开放接口至少需要两层认证

面向受控客户端,可以使用 OAuth2 Client Credentials 管理 clientId、密钥、授权类型和 Scope。

OAuth2 客户端配置

▲ 客户端配置用于确认“谁可以拿 Token、可以访问哪些 Scope、Token 多久过期”

对于需要防篡改和防重放的接口,还可以增加请求签名。框架的 @ApiSignature 定义了 appId、时间戳、随机数和签名字段:

@Inherited
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiSignature {
    int timeout() default 60;
    TimeUnit timeUnit() default TimeUnit.SECONDS;
    String appId() default "appId";
    String timestamp() default "timestamp";
    String nonce() default "nonce";
    String sign() default "sign";
}

服务端会按固定顺序拼接参数、请求体、签名头和密钥,计算 SHA-256;校验通过后把 nonce 写入 Redis,避免同一请求在有效期内被重复使用。

OAuth2 和签名解决的问题不同:OAuth2 证明客户端身份和授权范围,签名进一步证明请求没有被篡改、没有被重放。敏感开放接口可以组合使用。

API 超时不等于业务失败

调用方超时后,远端可能已经完成写入,只是响应没有回来。如果直接重试而没有幂等键,就可能创建两张付款单。

写接口建议要求调用方传入:

  • requestId 或来源单据 ID;
  • 来源系统编码;
  • 业务动作类型;
  • 必要的版本号。

服务端以“来源系统 + 请求 ID + 动作”建立唯一约束。重试时返回第一次处理结果,而不是再执行一次。

二、Webhook:适合对方掌握状态变化的主动回推

如果状态变化发生在外部平台,由我方不断轮询并不经济。例如:

  • 支付成功或退款完成;
  • 电子签章完成;
  • OnlyOffice 保存回调;
  • LiveKit 房间或通话事件;
  • 第三方审批结果变化。

Webhook 的本质是:状态拥有方在变化发生时主动通知订阅方。

它与普通 API 最大的区别是调用方向反转。开放 API 是外部系统调用我们的业务能力;Webhook 是我们提供一个回调地址,等待对方推送结果。

Webhook 必须防三类问题

第一,伪造请求。回调需要验签,不能因为来源 IP 看起来正确就直接更新业务状态。

第二,重复推送。大多数平台为了保证送达会重复发送。消费方应使用外部事件 ID、业务单号和事件类型建立幂等键。

第三,乱序到达。“支付成功”可能比“支付处理中”先到,如果只按到达顺序覆盖状态,最终状态会倒退。事件中应携带版本号、发生时间或状态机序号。

一个稳妥的处理顺序是:

接收请求 → 验签 → 保存原始事件 → 幂等检查
→ 校验状态迁移 → 更新业务 → 记录处理结果 → 快速响应

不要在 Webhook 请求线程中执行大量报表、通知和跨系统调用。先可靠落库,再通过事件或任务异步扩散。

当前代码库存在 OnlyOffice、LiveKit 等具体回调实现,但还没有一套覆盖所有业务的通用 Webhook 注册、投递和重试中心。文章将其作为推荐架构,而不是宣称平台已经有一个万能 Webhook 菜单。

三、MQ:适合异步解耦、削峰和一件事触发多件后续动作

审批通过后可能同时需要:

  • 更新业务台账;
  • 发送站内信;
  • 推送企业微信;
  • 写审计日志;
  • 更新统计数据;
  • 通知外部系统。

如果全部同步串行执行,一个通知失败就可能拖垮主业务。MQ 更适合表达“某件业务事实已经发生”,让不同消费者分别处理后续动作。

RuoYi Office 的基础设施支持 Redis、RocketMQ、RabbitMQ、Kafka 等多种消息发送方式,WebSocket 广播也可以按部署形态选择本地或消息中间件。

多 MQ 可插拔架构

▲ 业务层依赖消息抽象,具体部署可以按环境选择 RocketMQ、Kafka、RabbitMQ 或 Redis

多租户消息必须携带租户上下文

HTTP 请求进入系统时可以从 Header 获取租户 ID,异步消息离开请求线程后,这个上下文不会自动存在。RocketMQ 发送 Hook 会把当前租户写入消息属性:

public void sendMessageBefore(SendMessageContext context) {
    Long tenantId = TenantContextHolder.getTenantId();
    if (tenantId == null) {
        return;
    }
    context.getMessage().putUserProperty(
            HEADER_TENANT_ID, tenantId.toString());
}

消费侧再恢复租户上下文。缺少这一层,消息消费者可能查不到数据,或者更严重地落到错误租户。

MQ 不保证业务天然只执行一次

大多数企业消息系统提供的是“至少一次”投递语义。消费者必须假设同一消息会出现两次:

  • 使用稳定的 messageId
  • 业务表建立来源唯一键;
  • 消费成功后记录处理状态;
  • 失败按次数重试;
  • 超过阈值进入死信或人工补偿;
  • 不要把日志打印成功当作业务处理成功。

“MQ 发出去了”也不等于事务已经可靠。数据库事务提交前发送消息,随后事务回滚,会产生幽灵事件;事务提交后发送,又可能在发送前进程宕机。生产级方案通常需要 Outbox、本地消息表或事务消息。

当前框架提供多 MQ 适配和租户透传,但统一 Outbox 与业务级死信补偿仍应按场景建设。

四、定时同步:适合批量主数据、历史数据和最终对账

定时同步常被认为“不够先进”,实际上它是企业集成不可替代的兜底方式。

适合场景:

  • 每晚同步组织、人员和客商;
  • 每小时拉取外部订单状态;
  • 首次上线迁移历史数据;
  • 对 API、Webhook 或 MQ 结果进行补偿对账;
  • 清理过期日志和中间数据。

XXL-Job 负责调度、执行记录和失败查看。例如访问日志清理任务会分批删除超过保留期的数据:

@XxlJob("accessLogCleanJob")
@TenantIgnore
@JobDesc("物理清理超过 14 天的接口访问日志")
public void execute() {
    Integer count = apiAccessLogService.cleanAccessLog(14, 100);
    log.info("[execute][清理访问日志数量 ({}) 个]", count);
}

XXL-Job 调度架构

▲ 调度中心决定何时执行,业务执行器负责分页处理、记录水位和报告结果

真正的数据同步任务不能只有一个 Cron 表达式,还要有:

  • 增量游标或更新时间水位;
  • 分页大小和批次号;
  • 单条失败与整批失败策略;
  • 上次成功位置;
  • 重跑是否会重复写入;
  • 源端与目标端数量、金额或哈希对账。

时间窗口建议使用左闭右开,例如 [lastSuccessTime, currentEndTime),并允许少量重叠,通过幂等消除重复。这样可以降低数据库时间精度、网络延迟和时钟差导致的漏数风险。

五、四种方式如何组合,而不是四选一

一个可靠的付款集成可以这样设计:

  1. OA 通过 REST API 向财务系统创建付款申请;
  2. API 使用来源单据 ID 保证幂等;
  3. 财务系统异步处理后,通过 Webhook 回推付款结果;
  4. 我方保存回调事件并发布 MQ 消息;
  5. 消费者更新合同、项目、通知和统计;
  6. 夜间定时任务按付款单号对账,补齐漏回调状态。

这时四种通信方式各司其职:

方式负责什么
REST API发起必须立即确认接收的业务命令
Webhook外部系统主动回推后续状态
MQ在内部异步扩散业务事件
定时同步补偿漏数、同步批量数据、完成最终对账

争论“API 和 MQ 哪个更好”没有意义。一个面向用户的完整业务链,往往同时需要两到四种方式。

六、可靠性底座比通信协议更重要

无论使用哪种方式,都要统一考虑下面几层。

1. 身份与授权

  • OAuth2 管理客户端身份和 Scope;
  • API 签名防篡改、防重放;
  • 内网服务也不能默认互相信任;
  • 密钥必须支持轮换和失效。

OAuth2 Token 台账

▲ Token 台账提供客户端、用户、Scope、过期时间和撤销状态,便于定位接入问题

2. 幂等

不同通道都可能重复:API 超时重试、Webhook 重推、MQ 重投、定时任务重跑。幂等键必须进入业务表或独立处理表,而不是只放在短期内存缓存里。

3. 重试和补偿

瞬时网络故障可以自动重试,业务校验失败不应无限重试。系统需要区分:

  • 可恢复技术异常;
  • 不可恢复参数错误;
  • 需要人工判断的业务冲突。

4. 观察与审计

至少记录来源系统、目标系统、请求 ID、业务单号、耗时、状态、错误摘要和重试次数。

API 访问日志详情

▲ 访问日志能回答谁在什么时候调用了什么接口、耗时多久、结果如何

API 访问日志列表

▲ 列表适合按应用、接口、时间和异常状态筛选,详情用于恢复上下文

当前通用访问日志主要围绕用户、接口和耗时展开。面向机器到机器集成时,还应补充 clientId、来源系统、请求 ID 和外部业务单号,才能形成真正的集成审计链。

5. 对账

对账不是等客户投诉后查日志,而是定期比较:

  • 数量是否一致;
  • 金额合计是否一致;
  • 业务编号集合是否一致;
  • 状态是否一致;
  • 是否存在单边数据。

接口成功率只能说明网络和程序运行情况,不能证明业务数据最终一致。

七、集成数据模型建议保留哪些字段

如果企业集成较多,建议建立统一请求或事件台账,至少包含:

integration_code     集成场景编码
source_system        来源系统
target_system        目标系统
request_id           全链路请求 ID
business_type        业务类型
business_id/code     内部业务标识
external_id/code     外部业务标识
payload_hash         请求内容摘要
status               待处理/成功/失败/待人工
retry_count          重试次数
next_retry_time      下次重试时间
last_error           最近错误
occurred_time        业务发生时间
processed_time       处理完成时间
tenant_id            租户边界

这张台账不是用来替代业务表,而是负责连接、追踪、重试和对账。

八、常见错误:接口越多,系统反而越脆

错误一:在 Controller 里直接调用五个外部系统

任何一个系统超时都会拖住用户请求。应把必须同步的动作与可异步动作拆开。

错误二:用定时任务轮询所有实时状态

延迟高、压力大,还难以区分没有变化和漏同步。外部平台支持 Webhook 时,应以推送为主、定时对账为辅。

错误三:认为 MQ 可以自动解决一致性

MQ 解决传输与解耦,不替你完成业务幂等、数据库事务和补偿。

错误四:只记录 HTTP 200,不记录业务结果

对方可能返回 200,但响应体表示业务失败。日志和台账必须区分通信成功与业务成功。

错误五:把外部编号当数据库主键

不同系统的编号规则可能冲突。内部主键、业务编号和外部编号应分别保存。

九、落地企业集成平台的推荐顺序

  1. 先梳理系统清单、数据所有权和业务主责;
  2. 为每条链路确定方向、实时性和最终对账方;
  3. 建立 OAuth2、签名、密钥轮换和权限范围;
  4. 统一请求 ID、幂等键和错误分类;
  5. 接入访问日志和业务处理台账;
  6. 再按场景引入 Webhook、MQ 和定时任务;
  7. 最后建设重试、死信、补偿、告警和自动对账。

先建立治理规则,再增加通道数量。否则接入系统越多,故障时越难确定哪一方应该负责。

结语

REST API、Webhook、MQ 和定时同步不是四套相互竞争的技术,而是企业集成工具箱里的四种基本动作:请求、回推、广播和补偿。

真正决定系统能否长期运行的,不是用了哪个中间件,而是有没有把认证、租户、幂等、重试、死信、补偿、日志和对账设计成共同底座。

RuoYi Office 已具备 OAuth2、API 签名、访问日志、多 MQ 适配、租户消息透传和 XXL-Job 等基础设施。面向更复杂的企业集成,下一步应重点补齐统一 Webhook、Outbox、死信补偿和集成对账台账,让接口从“能调通”走向“可运营”。

如果这篇对你有用,点个「在看」或收藏。

🌐 演示地址:https://ruoyioffice.com/web
📦 GitHub 源码:https://github.com/yuqing2026/ruoyi-office
📦 Gitee 源码:https://gitee.com/yqzy1688/ruoyi-office
💬 微信:17156169080(获取产品咨询)

RuoYi Office 企业管理一体化平台

打开演示地址直接查看系统。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/zhouzhongyan/article/details/166142219

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--