Spring Boot 调用泛微 E9 Token 认证 + 创建流程完整教程

Spring Boot 调用泛微 E9 Token 认证 + 创建流程完整教程

本文基于 Spring Boot 项目结构,完整串联 APPID 注册 → Token 认证 → userid 加密 → 调用流程创建接口 的全过程,适合作为

  • 企业内部标准示例工程
  • 对接泛微 E9 的统一技术模板
  • 二次开发 / 联调排障参考

一、整体架构说明(Spring Boot 视角)

复制代码
E9-workflow-springboot/
├── pom.xml
├── src/main/java
│   └── com/company/e9
│       ├── E9Application.java
│       ├── config
│       │   └── E9Properties.java
│       ├── security
│       │   ├── RsaUtil.java
│       │   └── TokenClient.java
│       ├── workflow
│       │   ├── WorkflowClient.java
│       │   └── WorkflowRequestBuilder.java
│       └── controller
│           └── TestController.java
└── src/main/resources
    └── application.yml

职责划分原则

  • config:OA 地址、appid、userid 等配置
  • security:RSA、注册、token 获取
  • workflow:流程请求体构建与提交流程
  • controller:对外测试入口(可选)

二、基础依赖(pom.xml)

xml 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- hutool:RSA + HTTP -->
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.22</version>
    </dependency>

    <!-- fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.83</version>
    </dependency>
</dependencies>

三、统一配置(application.yml)

yaml 复制代码
e9:
  base-url: http://xx.xx.xx.xx:8081
  appid: EEAA5436-7577-4BE0-8C6C-89E9D88805EA
  userid: XXXXX
  token-expire: 1800
java 复制代码
@ConfigurationProperties(prefix = "e9")
@Component
@Data
public class E9Properties {
    private String baseUrl;
    private String appid;
    private String userid;
    private Integer tokenExpire;
}

四、Token 认证全过程(核心)

4.1 第一步:注册(只调用一次)

java 复制代码
public void registIfNeeded() {
    if (serverPublicKey != null && serverSecret != null) {
        return;
    }

    RSA rsa = new RSA();
    localPrivateKey = rsa.getPrivateKeyBase64();
    localPublicKey = rsa.getPublicKeyBase64();

    String resp = HttpRequest.post(baseUrl + "/api/ec/dev/auth/regist")
            .header("appid", appid)
            .header("cpk", localPublicKey)
            .disableCookie()
            .execute().body();

    JSONObject json = JSON.parseObject(resp);
    serverPublicKey = json.getString("spk");
    serverSecret = json.getString("secrit");
}

⚠️ 注意

  • 该步骤只能执行一次
  • serverPublicKey / serverSecret 必须持久化(DB / 配置中心)

4.2 第二步:获取 Token

java 复制代码
public String fetchToken() {
    registIfNeeded();

    RSA rsa = new RSA(null, serverPublicKey);
    String encryptSecret = rsa.encryptBase64(serverSecret, KeyType.PublicKey);

    String resp = HttpRequest.post(baseUrl + "/api/ec/dev/auth/applytoken")
            .header("appid", appid)
            .header("secret", encryptSecret)
            .header("time", tokenExpire.toString())
            .disableCookie()
            .execute().body();

    return JSON.parseObject(resp).getString("token");
}

4.3 第三步:userid 加密

java 复制代码
public String encryptUserid() {
    RSA rsa = new RSA(null, serverPublicKey);
    return rsa.encryptBase64(userid, KeyType.PublicKey);
}

五、流程创建(WorkflowService / REST)

5.1 构建流程请求体

java 复制代码
public JSONObject buildRequest() {
    JSONObject main = new JSONObject();
    main.put("field1", "测试标题");
    main.put("field2", "2026-01-01");

    JSONArray details = new JSONArray();
    JSONObject row = new JSONObject();
    row.put("detail_field1", "明细A");
    row.put("detail_field2", "100");
    details.add(row);

    JSONObject req = new JSONObject();
    req.put("mainData", main);
    req.put("detailData", details);
    return req;
}

5.2 调用流程创建接口

java 复制代码
public String submitWorkflow(JSONObject body) {
    String token = tokenClient.fetchToken();

    return HttpRequest.post(baseUrl + "/api/workflow/create")
            .header("appid", appid)
            .header("token", token)
            .header("userid", tokenClient.encryptUserid())
            .header("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
            .disableCookie()
            .body(body.toJSONString())
            .execute().body();
}

六、返回结果判定

json 复制代码
{
  "code": 0,
  "status": true,
  "workflowid": "215021"
}

判定规则:

  • code == 0 && status == true → 成功
  • 否则记录错误日志并回滚

七、常见问题(Spring Boot 场景)

问题 解决方案
解密失败 检查是否重复 regist、jar 冲突
userid 不生效 禁止 Cookie
token 很快过期 本地缓存 + DB 兜底
500 错误 检查 KB 版本 / session 失效

八、最佳实践总结

  1. regist 永远只执行一次
  2. token 单例缓存 + 自动刷新
  3. RSA / Token 与业务代码解耦
  4. 所有请求统一 disableCookie
  5. 先 Postman,再 Spring Boot

✅ 本文档可直接作为 Spring Boot + 泛微 E9 接口认证与流程创建的标准模板


九、可直接运行的 Demo 项目说明(补充)

9.1 项目结构(完整)

复制代码
E9-workflow-springboot-demo/
├── pom.xml
├── README.md
├── src/main/java/com/company/e9
│   ├── E9Application.java
│   ├── config
│   │   └── E9Properties.java
│   ├── security
│   │   ├── RsaUtil.java
│   │   └── TokenClient.java
│   ├── workflow
│   │   ├── WorkflowClient.java
│   │   └── WorkflowRequestBuilder.java
│   └── controller
│       └── WorkflowTestController.java
└── src/main/resources
    └── application.yml

9.2 启动类

java 复制代码
@SpringBootApplication
@EnableConfigurationProperties(E9Properties.class)
public class E9Application {
    public static void main(String[] args) {
        SpringApplication.run(E9Application.class, args);
    }
}

9.3 Controller(一键提交流程)

java 复制代码
@RestController
@RequestMapping("/test/workflow")
@RequiredArgsConstructor
public class WorkflowTestController {

    private final WorkflowClient workflowClient;
    private final WorkflowRequestBuilder requestBuilder;

    @PostMapping("/submit")
    public String submit() {
        return workflowClient.submitWorkflow(
                requestBuilder.buildDemoRequest()
        );
    }
}

访问地址:

复制代码
POST http://localhost:8080/test/workflow/submit

9.4 WorkflowClient(核心提交流程)

java 复制代码
@Component
@RequiredArgsConstructor
public class WorkflowClient {

    private final TokenClient tokenClient;
    private final E9Properties props;

    public String submitWorkflow(JSONObject body) {
        String token = tokenClient.fetchToken();

        return HttpRequest.post(props.getBaseUrl() + "/api/workflow/create")
                .header("appid", props.getAppid())
                .header("token", token)
                .header("userid", tokenClient.encryptUserid())
                .header("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
                .disableCookie()
                .body(body.toJSONString())
                .execute().body();
    }
}

9.5 WorkflowRequestBuilder(示例表单数据)

java 复制代码
@Component
public class WorkflowRequestBuilder {

    public JSONObject buildDemoRequest() {
        JSONObject main = new JSONObject();
        main.put("title", "SpringBoot 提交流程测试");
        main.put("apply_date", "2026-01-22");

        JSONArray details = new JSONArray();
        JSONObject row = new JSONObject();
        row.put("fee_type", "差旅费");
        row.put("amount", "1000");
        details.add(row);

        JSONObject req = new JSONObject();
        req.put("mainData", main);
        req.put("detailData", details);
        return req;
    }
}

9.6 TokenClient(完整示例)

java 复制代码
@Component
@RequiredArgsConstructor
public class TokenClient {

    private final E9Properties props;

    private String serverPublicKey;
    private String serverSecret;
    private String token;

    public synchronized String fetchToken() {
        if (StrUtil.isNotBlank(token)) {
            return token;
        }
        registIfNeeded();

        RSA rsa = new RSA(null, serverPublicKey);
        String encryptSecret = rsa.encryptBase64(serverSecret, KeyType.PublicKey);

        String resp = HttpRequest.post(props.getBaseUrl() + "/api/ec/dev/auth/applytoken")
                .header("appid", props.getAppid())
                .header("secret", encryptSecret)
                .header("time", props.getTokenExpire().toString())
                .disableCookie()
                .execute().body();

        token = JSON.parseObject(resp).getString("token");
        return token;
    }

    private void registIfNeeded() {
        if (serverPublicKey != null && serverSecret != null) {
            return;
        }
        RSA rsa = new RSA();
        String publicKey = rsa.getPublicKeyBase64();

        String resp = HttpRequest.post(props.getBaseUrl() + "/api/ec/dev/auth/regist")
                .header("appid", props.getAppid())
                .header("cpk", publicKey)
                .disableCookie()
                .execute().body();

        JSONObject json = JSON.parseObject(resp);
        serverPublicKey = json.getString("spk");
        serverSecret = json.getString("secrit");
    }

    public String encryptUserid() {
        RSA rsa = new RSA(null, serverPublicKey);
        return rsa.encryptBase64(props.getUserid(), KeyType.PublicKey);
    }
}

9.7 使用方式总结

  1. 修改 application.yml 中 OA 地址、appid、userid
  2. 启动 Spring Boot
  3. 调用 /test/workflow/submit
  4. OA 中查看流程是否创建成功

✅ 至此,你已拥有一套 可直接运行的 Spring Boot + 泛微 E9 Token 认证 + 提交流程 Demo 项目

相关推荐
Sheep Shaun1 小时前
深入理解红黑树:从概念到完整C++实现详解
java·开发语言·数据结构·c++·b树·算法
wb043072011 小时前
一次jvm配置问题导致的数据库连接异常
服务器·jvm·数据库·后端
楼田莉子1 小时前
CMake学习:入门及其下载配置
开发语言·c++·vscode·后端·学习
苦逼的老王2 小时前
《java-使用kkview+libreoffice 实现在线预览ppt、xls、doc、pdf..》
java·pdf·powerpoint
智源研究院官方账号2 小时前
技术详解 | 众智FlagOS1.6:一套系统,打通多框架与多芯片上下适配
人工智能·驱动开发·后端·架构·硬件架构·硬件工程·harmonyos
invicinble2 小时前
对于进行报表的经验思考
后端
没有bug.的程序员2 小时前
Spring Boot 启动原理:从 @SpringBootApplication 到自动配置深度解析
java·spring boot·后端·python·springboot·application
jiaguangqingpanda2 小时前
Day26-20260122
java·算法·排序算法
Ahtacca2 小时前
拒绝重复造轮子:利用自定义注解封装POI,实现Java通用Excel解析
java·javascript·vue·excel