Appearance
58 财务智能报销:WF 工程与 SCF 工程架构解析及全栈开发指南
归类:Java / 微服务架构 状态:✅ 已验证
在 58 财务报销及大宗费用系统的微服务化改造中,wf 和 scf 代表了职责清晰的物理拆分。理解这两者的分工与协作,是前端开发者转型全栈开发的重要基础。
一、 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=true2. 本地 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 代码内部:
- 命令行启动 Jetty 携带调试端口参数 (5005):bash
export MAVEN_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005" mvn jetty:run -Djetty.port=5800 - 配置 IDE 远程连接:
- 在 IntelliJ IDEA 中点击
Edit Configurations。 - 新建
Remote JVM Debug配置,设置 Host 为localhost,Port 为5005。 - 在 Controller(如
MobileReimburseMcpController.java的travelExpense函数第一行)打上断点,点击 Debug 按钮启动连接。
- 在 IntelliJ IDEA 中点击
- 开始单步调试: 前端操作触发 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 Framework | Node.js 运行时环境 + 依赖管理 | 整个后端的“地基”。其核心功能是 IOC/DI (控制反反转/依赖注入)。类似于在前端使用面向对象或 DI 库(如 Angular 的 Injectable 或 NestJS 的 @Injectable()),统一在容器中实例化和管理所有的 Service、Controller 等对象,避免手动 new。 |
| Spring Boot | Vite / 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 WF | Express / Koa / Fastify | 58 自研的轻量级 Web 开发框架,在本项目中充当了 MVC 的核心路由分发器。它通过 @Path 和 @POST 来监听 HTTP 请求,处理前端发送过来的 JSON。 |
| 58 SCF | gRPC / 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 框架深度集成,成为前端与后端数据流转的结构性契约。