Skip to content

58 财务智能报销:WF 工程与 SCF 工程架构解析及全栈开发指南

归类:Java / 微服务架构 状态:✅ 已验证

在 58 财务报销及大宗费用系统的微服务化改造中,wfscf 代表了职责清晰的物理拆分。理解这两者的分工与协作,是前端开发者转型全栈开发的重要基础。


一、 WF 工程与 SCF 工程的核心定位区别

text
  [ 前端视图层 ] (Vite / Vue / React)

       ▼ (HTTP: JSON)
┌────────────────────────────────────────────────────────┐
│  erp_wf_expenseExternal (适配/工作流层)                 │
│  - 直接接受前端 HTTP 请求 (MVC)                         │
│  - 大模型 Agent 服务对接 (58ChatLing API)               │
│  - BPM 工作流状态机控制与节点回调                          │
└──────────────────────────┬─────────────────────────────┘

                           ▼ (SCF RPC / TCP 二进制)
┌────────────────────────────────────────────────────────┐
│  erp_scf_expenseExternal (底层业务服务层)               │
│  - 纯后端服务,不向浏览器暴露 HTTP                      │
│  - 负责核心预算核扣、发票真伪存储 (MySQL/Redis)           │
│  - 强并发控制与强事务一致性                              │
└────────────────────────────────────────────────────────┘

1. 核心交互边界:谁在与前端对话?

直接与前端(如移动端极速报销、PC 页面、大模型验收工作台等)交互的只有 WF 工程

  • WF (Web Front-end/Workflow):作为 HTTP Web 服务运行在 Web 容器中(如 Jetty,本地默认端口 5800),直接暴露 HTTP 接口。
  • SCF (Service Communication Framework):是 58 内部的服务协定微服务框架,通过 TCP 协议对外暴露高效的二进制 RPC 服务。前端绝对不直接调用 SCF 服务,必须通过 WF 接口做转发路由。

2. 两者的角色分工对比

维度erp_wf_expenseExternal (WF 工程)erp_scf_expenseExternal (SCF 工程)
定位业务工作流及大模型网关适配层核心业务计算与数据持久化微服务
交互协议对前端:HTTP (JSON)
对微服务:SCF RPC (TCP)
对外:不暴露 HTTP
对内:SCF RPC (TCP 二进制)
数据库读写严禁或极少直接读写核心业务数据库,所有数据操作通过 RPC 委托给 SCF 微服务。核心操作。配置有底层数据源,直接使用 MyBatis / Spring JDBC 对 MySQL 等进行读写。
大模型集成集成核心。加载提示词(PromptAssembler),发起 ChatLing/MPAI 大模型 API 调用。零耦合。保持微服务运算的确定性与独立性,不与外部 AI 网络做直接交互。

二、 业务调用时序:以“市内交通费逻辑审计”为例

以下时序展示了前端发起逻辑校验到大模型决策、本地规则核对及微服务落库的完整流程:


三、 工程项目目录与核心文件说明

1. WF 工程接口接收:MobileReimburseMcpController.java

前端发起的 Ajax POST 请求会被路由到 WF 工程的 Controller 中:

java
package com.bj58.expenseExternal.personal.controller;

import com.bj58.expenseExternal.vo.chatling.AiAuditResultVo;
import com.bj58.expenseExternal.personal.service.impl.ServiceFactory;

@Path({"reimburseMcp"})
public class MobileReimburseMcpController extends BaseController {
    
    @POST
    @Path("/travelExpense")
    public ActionResult travelExpense() {
        // 1. 从 BaseController 中提取前端 POST 的 JSON 数据
        String jsonParam = super.getJsonParameter(); 
        
        // 2. 调用业务 Service 完成逻辑审计
        AiAuditResultVo result = ServiceFactory.getMobileReimburseWebService()
                                               .doAiAuditV2(jsonParam);
        
        // 3. 返回 HTTP 响应给前端
        return getActionResult(result); 
    }
}

2. SCF 工程双模块结构

为减少服务间依赖耦合,erp_scf_expenseExternal 物理上拆分为 contract(对外契约包)和 service(后台服务包):

  • contract (契约包):定义了 DTO 数据传输对象及远程服务 Interface 接口。该包需要被打成 JAR 包发布,其他工程(如 WF 工程)通过 Maven 依赖该 JAR,从而获取 RPC 调用契约。
  • service (实现包):实现契约中定义的接口。里面含有核心事务处理和底层 DAO/Mapper 数据库读写。

四、 本地编译、部署与 Remote Debug 调试指南

1. Maven 本地依赖编译顺序

重要硬规则:在本地开发修改了契约层(如新增了一个 DTO 字段)后,必须先编译安装 Contract 包,否则 WF 工程在编译时会由于缓存旧的 JAR 报 Cannot find symbol 错误。

bash
# 步骤一:编译安装 SCF 的 contract 模块到本地 .m2 仓库
cd erp_scf_expenseExternal/contract
mvn clean install

# 步骤二:进入 WF 工程,重新进行整体打包构建(跳过单元测试)
cd ../../erp_wf_expenseExternal
mvn clean install -Dmaven.test.skip=true

2. 本地 Jetty 与微服务运行

  • WF 启动:直接运行内置的 Jetty 容器以进行本地开发预览。
    bash
    cd erp_wf_expenseExternal
    mvn jetty:run -Djetty.port=5800
  • SCF 启动:在 IDE(如 IntelliJ IDEA)中为 service 模块创建一个 Application 启动配置,或运行内置的 Boot 类启动本地 RPC 监听。

3. 全栈断点调试 (Remote JVM Debug)

想要从前端界面发起请求,一路 Debug 单步调试到 Java 代码内部:

  1. 命令行启动 Jetty 携带调试端口参数 (5005)
    bash
    export MAVEN_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
    mvn jetty:run -Djetty.port=5800
  2. 配置 IDE 远程连接
    • 在 IntelliJ IDEA 中点击 Edit Configurations
    • 新建 Remote JVM Debug 配置,设置 Host 为 localhost,Port 为 5005
    • 在 Controller(如 MobileReimburseMcpController.javatravelExpense 函数第一行)打上断点,点击 Debug 按钮启动连接。
  3. 开始单步调试: 前端操作触发 HTTP 请求到达本地 5800,IDE 就会瞬间捕获到该断点,接下来你就可以使用 F8(Step Over)、F7(Step Into)进行全栈级别的业务跟踪了。

五、 核心概念极速通关:Spring、Spring Boot、MVC 与前端生态全景对照

对于前端转型全栈的同学,Java 后端里满屏的配置和概念(Spring、Spring Boot、MVC、WF、SCF)很容易让人眼花缭乱。下面我们用前端同学最熟悉的技术栈来进行降维比喻。

1. 核心技术角色类比

Java 后端角色前端/Node.js 生态对照核心职责说明
Spring FrameworkNode.js 运行时环境 + 依赖管理整个后端的“地基”。其核心功能是 IOC/DI (控制反反转/依赖注入)。类似于在前端使用面向对象或 DI 库(如 Angular 的 Injectable 或 NestJS 的 @Injectable()),统一在容器中实例化和管理所有的 Service、Controller 等对象,避免手动 new
Spring BootVite / Create React App / NestJS CLI现代 Java 的“开箱即用脚手架”。传统 Spring 需要配置大量繁琐的 XML 文件;而 Spring Boot 提倡 约定大于配置,通过内置 Tomcat 服务器,支持通过 java -jar 一键把服务跑起来,完全免去了手动配置容器的烦恼。
MVC 模式前端组件化设计 (Template - Controller - State)一种软件设计思想,将工程划分为:
- Model (数据模型): 对应 Java Bean/VO (前端的数据 State/DTO)。
- View (视图): 对应 JSP 页面 (前端的 HTML/Template)。
- Controller (控制器): 对应后端 Router 路由接收方法 (前端的事件监听/请求分发处理器)。
58 WFExpress / Koa / Fastify58 自研的轻量级 Web 开发框架,在本项目中充当了 MVC 的核心路由分发器。它通过 @Path@POST 来监听 HTTP 请求,处理前端发送过来的 JSON。
58 SCFgRPC / tRPC / Node.js 间 TCP 双工通信58 自研的微服务 RPC 通信框架。它基于 TCP 自研协议,专门用来处理微服务(如 Web 前置服务与底层数据库微服务)之间高性能、低延迟的二进制数据传输,前端对此是完全无感知的。

2. 技术栈承接关系

  • Spring 提供了基础的对象依赖注入(IOC)容器支持,是所有 Java 后端开发的核心。
  • Spring Boot 在 Spring 容器的基础之上,增加了一层全自动“开箱即用”的外壳,不再需要开发者手写大量的 XML 配置文件。
  • 58 WF 框架58 SCF 框架,是 58 集团在 Spring 生态圈内为满足企业特定业务场景而研发的定制化“插件组件”。其中 WF 负责 HTTP 请求的 MVC 分发路由,SCF 负责微服务之间 TCP 级别的 RPC 通信。
  • MVC 设计模式 作为一种通用的开发思想,被 58 WF 框架深度集成,成为前端与后端数据流转的结构性契约。