📋 文档信息

项目说明
文档名称泛微OA-金蝶API接口通用中间件说明文档
版本v2.0
创建日期2025年11月24日
更新日期2025年12月20日
作者徐东瑞
当前功能API代理 + Token自动管理 + 前端框架 + 流程集成

🎯 变更记录

版本日期变更内容
v1.02025-10-22初始版本,包含基础API代理功能
v2.02025-11-24新增前端同步框架、流程集成、附件上传、权限控制等完整功能

🎯 项目概述

1.1 项目背景

为解决泛微E9 OA系统与金蝶云星空旗舰版ERP系统之间的数据交互需求,开发一套完整的API代理中间件。该中间件不仅提供API代理功能,还包含前端同步框架、自动Token管理、附件上传、权限控制等完整解决方案,实现安全、稳定、高效的数据同步。

1.2 已实现功能

✅ **统一接入**:提供统一的API入口,简化前端调用

✅ **Token管理**:自动管理金蝶API访问令牌,每小时自动刷新

✅ **API代理**:完整的请求转发和响应处理机制

✅ **附件上传**:支持文件流式上传到金蝶系统,避免内存溢出

✅ **权限校验**:基于角色的细粒度访问控制

✅ **前端框架**:可复用的JavaScript同步框架,支持步骤化执行,支持按条件执行步骤,支持延迟执行步骤

✅ **流程集成**:与泛微E9流程表单无缝集成

✅ **错误处理**:统一的错误解析和用户提示

✅ **进度显示**:可视化同步进度提示

🏗️ 系统架构

2.1 整体架构图

┌─────────────────────────────────────────────────────────────┐
│                    泛微E9 OA系统                            │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│  │  流程表单    │  │  Ecode后台  │  │  定时任务    │        │
│  │ (前端代码块) │  │ (框架代码)  │  │ (Token管理)  │        │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘        │
│         │                │                │                │
│         └────────────────┼────────────────┘                │
│                          │                                 │
│              ┌───────────▼───────────┐                    │
│              │  API代理中间件         │                    │
│              │  KingdeeProxyServlet  │                    │
│              └───────────┬───────────┘                    │
└──────────────────────────┼─────────────────────────────────┘
                           │
┌──────────────────────────▼─────────────────────────────────┐
│                    金蝶云星空ERP                           │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│  │   业务API    │  │  Token服务  │  │  附件服务    │        │
│  │  /v2/...    │  │ /oauth2/... │  │ /uploadFile  │        │
│  └─────────────┘  └─────────────┘  └─────────────┘        │
└─────────────────────────────────────────────────────────────┘

2.2 数据流向

  1. 流程发起:用户在OA流程表单提交数据
  2. 框架处理:前端KingdeeSync框架拦截提交事件
  3. 步骤执行:按配置步骤依次调用金蝶API
  4. 代理转发:中间件验证权限并转发请求
  5. 金蝶处理:金蝶系统处理业务逻辑
  6. 结果返回:响应逐层返回至前端界面
  7. 进度提示:用户实时查看同步进度

2.3 技术栈

层级技术选型
前端框架JavaScript ES5+、jQuery、Promise异步
中间件Java Servlet、HttpURLConnection
数据库SQL Server(泛微内置)
JSON处理FastJSON、原生JSON
文件处理流式传输、Zip解压、AES加密
权限控制泛微角色体系、基于角色的访问控制

📊 数据库设计

3.1 数据表结构

3.1.1 Token存储表 (uf\_kingdeeAPI)
CREATE TABLE [uf_kingdeeAPI] (
    [id] INT IDENTITY(1,1) PRIMARY KEY,
    [clientid] VARCHAR(50) NULL,           -- 客户端ID(固定为'weaverE9')
    [clientsecret] VARCHAR(100) NULL,      -- 客户端密钥
    [dlyhgh] VARCHAR(20) NULL,             -- 代理用户工号
    [accountid] VARCHAR(50) NULL,          -- 账户ID
    [language] VARCHAR(10) DEFAULT 'zh_CN',-- 语言
    [accesstoken] TEXT NULL,               -- 访问令牌(Base64编码)
    [tokengxsj] DATETIME NULL,             -- 令牌更新时间
  
    -- 泛微建模引擎标准字段
    [modedatamodifier] INT NULL,
    [modedatamodifydatetime] DATETIME NULL,
    [formmodeid] INT NULL,
    [modedatacreater] INT NULL,
    [modedatacreatertype] INT NULL,
    [modedatacreatedate] DATE NULL,
    [modedatacreatetime] TIME NULL,
    [form_biz_id] VARCHAR(50) NULL,
    [MODEUUID] VARCHAR(36) NULL
);

-- 索引优化
CREATE INDEX idx_clientid ON uf_kingdeeAPI(clientid);
CREATE INDEX idx_tokengxsj ON uf_kingdeeAPI(tokengxsj);

3.2 数据示例

INSERT INTO [uf_kingdeeAPI] (
    [id], [clientid], [clientsecret], [dlyhgh], [accountid], 
    [language], [accesstoken], [tokengxsj], [form_biz_id], [MODEUUID]
) VALUES (
    1, 'weaverE9', '2345678910JQKAwang.', '02250', 
    '2077625015653633024', 'zh_CN', 
    'OPENAPIAUTH_MjA3NzYyNTAxNTY1MzYzMzAyNF9FSExTeVN0c0xPTnBIMEVpZDJIVnpRTHd0V0o4clFtbDFldFNLRkFubjRrb2tDODNWaWs3MzR6RlRhSGQyRmFublNCaDF2d2R3SFRKN0NWdjhjRnZlWThmVm92eGR5SnNVbUZUMDY=', 
    '2025-11-24 14:19:33', '1000799', '97ffee80-c9f1-427d-9585-fe8d7e3abdc3'
);

🔧 核心功能模块

4.1 Token自动管理模块

4.1.1 Token获取定时任务
配置项说明
类名weaver.houdedev.cron.GetKingdeeTokenCmd
执行频率0 0 0/1 * * ?(每小时执行一次)
认证地址https://ierp.houde-food.com/ierp/kapi/oauth2/getToken
请求参数client\_id、client\_secret、username、accountId、nonce、timestamp、language
响应处理解析access\_token并更新到数据库
4.1.2 Token存储管理
  • 自动获取:定时任务每小时自动刷新Token
  • 缓存机制:中间件缓存最新Token,减少数据库查询
  • 失效处理:Token过期时自动触发重新获取
  • 多应用支持:预留多金蝶应用配置扩展

4.2 API代理服务模块

4.2.1 核心Servlet
属性
类名KingdeeProxyServlet
包路径weaver.houdedev.cron
访问路径/kingdee/proxy
支持方法GET(健康检查)、POST(API代理)
编码设置全面UTF-8支持,解决中文乱码问题
4.2.2 请求处理流程

下载_副本.jpg

4.3 前端同步框架模块

4.3.1 KingdeeSync框架
特性说明
类结构面向对象设计,支持链式调用
步骤管理支持顺序、条件、延迟步骤
进度提示可视化弹窗显示执行进度
错误处理自动解析金蝶错误信息
响应处理统一的数据提取机制
4.3.2 核心方法
// 1. 创建同步实例
var sync = new KingdeeSync({
    title: "同步进度",
    showProgress: true,
    timeout: 30000
});

// 2. 添加执行步骤
sync.addStep("步骤名称", requestBuilder, dataExtractor);

// 3. 添加条件步骤
sync.addStepIf(condition, "步骤名称", requestBuilder);

// 4. 添加延迟步骤
sync.addDelayStep("等待", 5000);

// 5. 执行流程
sync.execute(callback);

4.4 附件上传模块

4.4.1 文件处理流程
  1. 文件获取:根据OA附件ID从ImageFile表获取文件信息
  2. 格式处理:支持ZIP压缩文件自动解压
  3. 加密处理:支持AES加密文件解密
  4. 流式上传:分块传输,避免大文件内存溢出
  5. 关联绑定:将附件与金蝶单据ID关联
4.4.2 关键技术
  • 多部分表单:使用multipart/form-data格式
  • 分块传输setChunkedStreamingMode(8192)
  • 内存优化:8KB缓冲区流式读写
  • 超时设置:大文件上传120秒超时

4.5 权限控制模块

4.5.1 角色权限配置
// 允许访问的角色ID列表
private static final String[] ALLOWED_ROLE_IDS = {"2", "26"};

// 允许访问的角色名称列表
private static final String[] ALLOWED_ROLE_NAMES = {"系统管理员", "ERP接口访问"};
4.5.2 权限验证流程
  1. 用户认证:通过 HrmUserVarify.getUser()获取当前用户
  2. 角色查询:查询用户关联的所有角色
  3. 权限检查:匹配角色ID或角色名称
  4. 访问控制:无权限用户返回403错误

🚀 接口详细设计

5.1 API代理接口

请求方式请求地址
postOA地址/kingdee/proxy

功能:代理调用任意金蝶API接口

请求头

Content-Type: application/json;charset=UTF-8
Cookie: JSESSIONID=... (泛微会话Cookie)

请求体

{
    "apiUrl": "/v2/basedata/bd_supplier/addSup",
    "apiResultData": {
        "data": [
            {
                "name": "供应商名称",
                "number": "GYS2025001",
                ...
            }
        ]
    },
    "fileId": [123, 456],
    "attachmentUploadFileArgs": {
        "entityNumber": "bd_supplier",
        "controlKey": "d8b9_attachmentpanelap",
        "billPkId": "供应商单据ID"
    }
}

参数说明

参数名类型必填说明
apiUrlString金蝶API路径(不包含基础URL)
apiResultDataObject金蝶API要求的完整参数格式
fileIdArrayOA附件文件ID列表
attachmentUploadFileArgsObject附件上传参数,包含单据关联信息

响应

{
    "status": true,
    "data": {
        "金蝶API返回的原始数据"
    },
    "message": "请求成功",
    "attachmentResults": {
        "file_123": {
            "status": true,
            "message": "上传完成",
            "billId": "单据ID"
        }
    }
}

5.2 健康检查接口

请求方式请求地址
getOA地址/kingdee/proxy

功能:服务健康状态检查

响应

{
    "status": true,
    "message": "服务正常,当前有 1 个有效token",
    "currentUser": "admin",
    "userRoles": "系统管理员(2), ERP接口访问(26)"
}

5.3 错误码定义

错误码说明处理建议
400请求参数错误检查apiUrl和apiResultData参数格式
401用户未登录或Token无效重新登录或检查Token获取任务
403权限不足为用户分配系统管理员或ERP接口访问角色
404接口路径不存在检查金蝶API路径是否正确
500服务器内部错误查看服务器日志,联系管理员
502网络连接失败检查到金蝶系统的网络连通性
504请求超时适当增加timeout参数值

🔧 核心代码实现

6.1 KingdeeProxyServlet 核心方法

6.1.1 主请求处理
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
    // 1. 设置UTF-8编码(必须最先执行)
    request.setCharacterEncoding("UTF-8");
    response.setContentEncoding("UTF-8");
  
    // 2. 用户身份验证和权限校验
    User user = HrmUserVarify.getUser(request, response);
    if (!checkUserRolePermission(user)) {
        returnError(response, 403, "权限不足");
        return;
    }
  
    // 3. 读取并解析请求体
    String requestBody = readRequestBody(request);
    JSONObject params = JSON.parseObject(requestBody);
  
    // 4. 获取最新Token
    String accessToken = getLatestTokenFromDB();
  
    // 5. 调用金蝶API
    String apiResponse = sendPostRequest(fullUrl, jsonBody, accessToken);
  
    // 6. 处理附件上传(如果存在)
    if (hasAttachments(params) && isSuccess(apiResponse)) {
        uploadAttachments(fileIds, attachmentArgs, accessToken, billId);
    }
  
    // 7. 返回响应
    returnSuccess(response, apiResponse);
}
6.1.2 流式附件上传
private String sendStreamingMultipartPostRequest(String url, JSONObject args, 
                                                 InputStream fileStream, 
                                                 String fileName, 
                                                 String accessToken) {
    // 1. 设置分块传输模式
    connection.setChunkedStreamingMode(8192);
  
    // 2. 构建多部分表单边界
    String boundary = "----WebKitFormBoundary" + UUID.randomUUID();
  
    // 3. 流式写入表单数据
    try (OutputStream os = connection.getOutputStream()) {
        // 写入JSON参数部分
        writeFormField(os, boundary, "attachmentUploadFileArgs", 
                      args.toJSONString(), "application/json");
  
        // 写入文件部分
        writeFileField(os, boundary, "file", fileName, fileStream);
  
        // 写入结束边界
        writeBoundaryEnd(os, boundary);
    }
  
    // 4. 读取响应
    return readResponse(connection);
}

6.2 前端同步框架核心(ecode)

6.2.1 KingdeeSync类结构
function KingdeeSync(options) {
    this.options = options || {};
    this.steps = [];           // 执行步骤数组
    this.stepResults = [];     // 步骤结果存储
    this.currentStep = 0;      // 当前步骤索引
    this.progressModal = null; // 进度弹窗引用
}

// 添加执行步骤
KingdeeSync.prototype.addStep = function(name, requestBuilder, dataExtractor) {
    this.steps.push({
        name: name,
        requestBuilder: requestBuilder,
        dataExtractor: dataExtractor || function(response) {
            return { rawData: response.data };
        }
    });
    return this; // 支持链式调用
};

// 执行步骤
KingdeeSync.prototype.executeStep = function(stepIndex, callback) {
    var step = this.steps[stepIndex];
    var self = this;
  
    // 更新进度显示
    this.updateProgress(step.name);
  
    // 构建请求数据
    var requestData = step.requestBuilder(this.stepResults);
  
    // 调用API
    this.callKingdeeAPI(requestData).then(function(response) {
        if (response.status && response.data.status) {
            // 成功:提取数据并继续下一步
            var extractedData = step.dataExtractor(response, self.stepResults);
            self.stepResults.push(extractedData);
            self.currentStep++;
            self.executeStep(stepIndex + 1, callback);
        } else {
            // 失败:解析错误信息
            var errorDetails = self.parseKingdeeError(response);
            self.handleStepError(step.name, new Error(errorDetails));
        }
    }).catch(function(error) {
        self.handleStepError(step.name, error);
    });
};

🛠️ 部署指南

7.1 环境要求

组件要求
操作系统Windows Server 2012+ / Linux CentOS 7+
Java环境JDK 1.8+
应用服务器泛微E9自带Resin服务器
数据库SQL Server 2012+ / Oracle 11g+ / MySQL 5.7+
网络OA服务器可访问金蝶云星空API
泛微版本E9 9.0及以上

7.2 部署步骤

7.2.1 数据库准备
  1. 创建数据表:通过建模引擎创建uf\_kingdeeAPI表并添加字段
  2. 初始化配置:插入金蝶API认证信息
  3. 权限配置:确保OA数据库用户有读写权限
7.2.2 文件部署
  1. 部署class文件

    /ecology/WEB-INF/classes/weaver/houdedev/cron/
    ├── GetKingdeeTokenCmd.class
    ├── KingdeeProxyServlet.class
    └── ...
  2. 配置web.xml
<servlet>
    <servlet-name>KingdeeProxyServlet</servlet-name>
    <servlet-class>weaver.houdedev.cron.KingdeeProxyServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>KingdeeProxyServlet</servlet-name>
    <url-pattern>/kingdee/proxy</url-pattern>
</servlet-mapping>
  1. 部署前端代码

    1. 将ecode代码上传到泛微ecode后台
    2. 配置为全局可用的JavaScript模块
7.2.3 定时任务配置
  1. 登录泛微E9管理后台
  2. 进入“集成中心” → “功能集成”→ “计划任务”
  3. 点击“新建”按钮
  4. 配置任务参数:
参数项
任务名称金蝶Token自动获取
类名weaver.houdedev.cron.GetKingdeeTokenCmd
执行频率0 0 0/1 * * ?
状态启用
描述每小时获取金蝶API访问令牌

7.3 权限配置

  1. 角色分配

    1. OA后台进入 组织权限中心 → 权限管理 → 角色设置
    2. 为需要调用金蝶接口的用户分配“系统管理员”或“ERP接口访问”角色

🔍 使用示例

8.1 前端调用示例

8.1.1 基本API调用
// 供应商查询示例
jQuery.ajax({
    url: '/kingdee/proxy',
    type: 'POST',
    contentType: 'application/json;charset=UTF-8',
    data: JSON.stringify({
        "apiUrl": "/v2/basedata/bd_supplier/query",
        "apiResultData": {
            "data": {
                "start_createtime": "2025-01-24 15:51:43",
                "end_createtime": "2025-03-25 15:55:45",
                "status": ["B", "C"]
            },
            "pageSize": 10,
            "pageNo": 1
        }
    }),
    success: function(response) {
        if (response.status) {
            console.log('查询成功:', response.data);
        } else {
            console.error('查询失败:', response.message);
        }
    }
});
8.1.2 流程集成示例
// 流程表单前端代码块
jQuery(document).ready(function() {
    // 1. 注册当前流程
    KingdeeSyncUtils.registerWorkflow(1595);
  
    // 2. 创建同步实例
    var kingdeeSync = new KingdeeSync({
        title: "供应商数据同步",
        showProgress: true,
        timeout: 30000
    });
  
    // 3. 定义执行步骤
    kingdeeSync
        .addStep("新增供应商", buildSupplierCreateRequest, extractSupplierId)
        .addStep("提交审核", buildSubmitRequest)
        .addDelayStepIf(needAssign, "等待分配", 3000)
        .addStepIf(needAssign, "组织分配", buildAssignRequest);
  
    // 4. 注册提交事件
    WfForm.registerCheckEvent(WfForm.OPER_SUBMIT, function(callback) {
        if (KingdeeSyncUtils.isEnabled()) {
            kingdeeSync.execute(callback);
        } else {
            callback();
        }
    });
});

8.2 健康检查示例

// 定期检查服务状态
function checkServiceHealth() {
    fetch('/kingdee/proxy')
        .then(response => response.json())
        .then(data => {
            if (data.status) {
                console.log('✅ 金蝶接口服务正常:', data.message);
            } else {
                console.error('❌ 金蝶接口服务异常:', data.message);
            }
        })
        .catch(error => {
            console.error('❌ 服务连接失败:', error);
        });
}

// 每5分钟检查一次
setInterval(checkServiceHealth, 5 * 60 * 1000);

8.3 错误处理示例

// 自定义错误处理
kingdeeSync.handleStepError = function(stepName, error) {
    // 记录错误日志
    console.error('步骤"' + stepName + '"执行失败:', error);
  
    // 显示用户友好的错误信息
    var userMessage = "同步失败,请联系管理员";
  
    if (error.message.includes("权限不足")) {
        userMessage = "您没有操作权限,请联系系统管理员";
    } else if (error.message.includes("网络连接")) {
        userMessage = "网络连接失败,请检查网络设置";
    } else if (error.message.includes("超时")) {
        userMessage = "请求超时,请稍后重试";
    }
  
    // 显示错误提示
    WfForm.showMessage(userMessage, 2, 5);
  
    // 停止后续步骤
    this.stopExecution();
};

📈 监控与维护

9.1 系统监控

监控项监控方法告警阈值
Token状态检查uf\_kingdeeAPI.tokengxsj更新时间超过55分钟
服务可用性GET /kingdee/proxy 健康检查响应时间>3秒或状态非200

9.2 故障排查

常见问题及解决方案

问题现象可能原因解决方案
Token无效错误1. 定时任务未执行2. 金蝶认证信息变更3. Token过期未刷新1. 检查计划任务状态2. 检查数据库缓存表配置3. 手动执行Token获取定时任务
附件上传失败1. 文件路径不存在2. ZIP文件损坏3. 网络超时1. 检查ImageFile表记录2. 验证文件完整性3. 增加超时时间
中文乱码1. 编码设置不一致2. 数据库编码问题3. 金蝶API编码限制1. 统一使用UTF-82. 检查数据库连接字符串3. 排查金蝶API配置
权限拒绝1. 用户角色未配置2. 角色配置错误3. 会话过期1. 分配正确角色2. 检查角色ID/名称3. 重新登录OA系统
性能缓慢1. 网络延迟2. 大文件处理3. 数据库查询慢1. 网络优化2. 分块传输大文件3. 添加数据库索引

9.4 备份与恢复

备份策略

  1. 配置文件备份

    # 备份web.xml配置
    cp /ecology/WEB-INF/web.xml /backup/web.xml.$(date +%Y%m%d)
    
    # 备份数据库配置
    sqlcmd -S localhost -d ecology -Q "SELECT * FROM uf_kingdeeAPI" -o /backup/kingdee_config.sql
  2. 代码备份

    # 备份Java类文件
    tar -czf /backup/kingdee_classes_$(date +%Y%m%d).tar.gz \
         /ecology/WEB-INF/classes/weaver/houdedev/cron/
  3. 恢复步骤

    1. 停止Resin服务
    2. 恢复配置文件
    3. 恢复class文件
    4. 重启服务并验证

📋 参考资料

1. 金蝶API接口清单

请登录金蝶旗舰版,进入菜单 开放服务云-OpenAPI-API开发,到API列表中查看地址及请求方式

2. 泛微前端开发文档

3. 已应用流程

流程名称实现功能
HD-供应商新增流程1. 供应商新增1. 供应商自动分配至其他组织1. 流程附件同步至金蝶供应商附件中

文档签署

角色姓名签字日期
编写人徐东瑞 2025-12-20
审核人
批准人

文档状态:✅ 正式发布

保密级别:内部机密

分发范围:系统管理员、开发人员、实施顾问

最后修改:2026 年 01 月 04 日
如果觉得我的文章对你有用,请随意赞赏