E10 后端基础开发

发布于 2026-08-05

E10 后端基础开发

架构说明

| 层级 | 技术组件 | 说明 | | ------- | ------------------------------------------------- | ---------------- | | 注册/配置中心 | Nacos(支持 Zookeeper/Consul/Eureka 一键切换) | 服务注册发现、动态配置管理 | | 网关层 | Spring Cloud Gateway | 统一入口、负载均衡、熔断降级限流 | | 服务间调用 | Dubbo + OpenFeign | RPC + HTTP 双通道 | | 分布式事务 | Seata | 保障跨服务数据一致性 | | 消息队列 | RabbitMQ / ActiveMQ / RocketMQ(可一键切换) | 异步解耦 | | 缓存 | Redis(单机/哨兵/集群模式) | 高性能缓存 | | 链路追踪 | SkyWalking | 全链路性能监控 | | 日志收集 | Filebeat → Logstash → ElasticSearch → Kibana(ELK) | 集中日志分析 | 框架:使用 SpringBoot + Spring Cloud 微服务,支持单体部署和微服务部署(大多数都为单体部署) ⚠️ 注意:需要区分单体和微服务环境,这会对开发产生影响,如果是微服务环境则一些内部接口会无法调用,需要使用 RPC 接口

配置管理:配置文件 或 Nacos 最低内存要求:32G Java 版本:8

**二开服务** E10 会有一个独立的二开服务,专门用来做二次开发,它和主服务是分开的,我们写的二次开发都会部署到二开服务下。二开服务可以单独重启,不会导致主服务停止运行。

开发环境搭建

创建 Gradle 项目

E10 开发环境搭建要比 E9 复杂的多,你需要创建一个 Gradle 项目,可以使用 IDEA 进行创建,创建时 JDK 选择 1.8

创建后会下载 Gradle ,由于网络环境可能会下载失败

创建好项目之后,创建 common 子模块(你可能不需要,但为了兼容下面的配置)以及另外一个模块,你开发的代码就写在这个模块上。

然后在 build.gradle 文件覆盖粘贴下面代码:

group 'com.weaver.seconddev'  
version '1.0.0'  
description 'e10二开'  
  
// 应用到所有项目(包括根项目)  
allprojects {  
    apply plugin: 'java'  
  
    java {  
        sourceCompatibility = JavaVersion.VERSION_1_8  
        targetCompatibility = JavaVersion.VERSION_1_8  
    }  
  
    compileJava {  
        options.encoding = 'UTF-8'  
        targetCompatibility = JavaVersion.VERSION_1_8  
        sourceCompatibility = JavaVersion.VERSION_1_8  
    }  
  
  
    repositories {  
        maven { url 'https://maven.aliyun.com/repository/public/' }  
        mavenLocal()  
        mavenCentral()  
    }  
  
    // 添加 zipJar 任务,生成 build.zip 文件,可以用于上传到二开服务  
    tasks.register('zipJar', Zip) {  
        dependsOn jar  
        archiveFileName = 'build.zip'  
        destinationDirectory = layout.buildDirectory.dir("libs")  
  
        from jar.archiveFile  
    }  
  
    jar {  
        // 确保在执行jar任务之前先执行classes任务  
        dependsOn ':classes'  
        // 执行 jar 任务之后执行 zipJar 任务,生成 build.zip 文件  
        finalizedBy(zipJar)  
    }  
}  
  
// 应用到子模块  
subprojects { subproject ->  
    // 除 common 模块外,其它子模块都引入 common 模块的源码  
    if (subproject.name != 'common') {  
        dependencies {  
            implementation project(':common')  
        }  
    }  
  
    // 打包配置  
    if (subproject.name != 'common') {  
        jar {  
            archiveBaseName = "secondev-hnweaver-" + subproject.name  
        }  
    }  
  
    sourceSets {  
        main {  
            resources {  
                exclude '**'  
            }  
        }    }  
    jar {  
        manifest {  
            attributes 'weaver-ecode-seconddev-id': 'hnweaver-' + rootProject.version,  
                    'Implementation-Version': rootProject.version,  
                    'Implementation-Vendor-Id': rootProject.group,  
                    'Implementation-Title': rootProject.name  
        }  
        // 将源码打进jar包  
        from(subproject.sourceSets.main.java)  
    }  
  
    // 添加公共的依赖  
    dependencies {  
        compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.30'  
        annotationProcessor 'org.projectlombok:lombok:1.18.30'  
        testImplementation("org.junit.jupiter:junit-jupiter-api:5.13.3")  
        testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.13.3")  
        testImplementation("org.junit.platform:junit-platform-launcher:1.13.3")  
        testImplementation("org.mockito:mockito-core:5.18.0")  
        testImplementation("org.mockito:mockito-junit-jupiter:5.18.0")  
  
        // 添加二开服务拉取的清单依赖  
        def includeType = ['**/*.jar', '**/*.class']  
        implementation fileTree(dir: rootProject.projectDir.getPath() + '/secDevLib', includes: includeType)  
        // 项目二开自定义依赖  
        implementation fileTree(dir: subproject.projectDir.getPath() + "/out-dep", includes: includeType)  
  
    }  
  
    test {  
        useJUnitPlatform()  
    }  
}

该 Gradle 包含了以下配置:

  • java 版本为 1.8
  • E10 的依赖都放在 `secDevLib` 此目录下
  • 第三方依赖都放在 `out-dep` 目录下
  • 所有模块都依赖 common 模块(放公共代码)
  • 执行 jar 任务时打成符合 E10 部署要求的压缩包
  • 添加测试依赖:包含 junit5 和 mockito

build.gradle 文件中的 hnweaver 为组织名称,你可以改为你的组织名称

拉取开发依赖

按照官方说明文档,在你的 E10 服务器中拉取依赖到你的电脑中,文档:e10平台定制开发指引

将所有依赖都拷贝到项目的 `secDevLib` 目录中,然后重新加载 gradle 项目。

开发环境项目模板

使用此项目模板可免除上面复杂的配置,里面开发环境都帮你搭好了 模板下载:

注意:模板里面的开发依赖比较旧,需要去除里面的依赖,到服务器拉取开发依赖到 `secDevLib` 目录中

你的第一个接口

在你的开发环境项目上创建一个接口,如果你使用的是我给的开发环境模板,那么就有这个接口了

package com.weaver.seconddev.hnweaver.demo.api;

import com.weaver.common.authority.annotation.WeaPermission;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 姚礼林
 * @desc 测试接口
 * @date 2024/4/1
 */
@RestController
@RequestMapping({"/api/secondev/hnweaver/workflow/demo","/papi/secondev/hnweaver/workflow/demo"})
@WeaPermission(publicPermission = true)
@Slf4j
public class ApiDemoController {

    @GetMapping("/hello")
    public String hello() {

        return "hello world";
    }
}

E10 后端 WEB 接口的开发与 SpringBoot 中是相同的。

接口必需包含的注解:

  • @RestController:表示此接口只返回数据,而不是视图
  • @WeaPermission:不加则访问不了
  • @RequestMapping:接口路径,/api 开头表示需要认证才能访问,/papi 开头表示此接口是公共暴露的,不需要进行认证就能访问(相当于 E9 的白名单接口)

打包与部署

执行你的模块中的 gradle 的 jar 任务,生成部署的压缩包

在当前模块的 /build/libs 目录下,找到 build.zip 文件,等会需要将此压缩包上传到系统进行部署

打开你的 E10 系统,进入 /ecode 页面,然后点击此图标进入监控管理平台(必需是系统管理员账号)

选择部署 jar,选择二开服务,上传 build.zip 文件夹,此时会进行文件校验,过程比较久需要耐心等待。之后会让你填写开发说明,以及各个类的说明。

然后进行 jar 包审核,审核通过之后到运维平台重启二开服务

重启之后在系统链接地址上输入 `/api/secondev/hnweaver/workflow/demo/hello` 进行访问,看是否会返回 hello world

团队 jar 包部署

对于团队开发,可以在项目中为每个团队成员创建一个模块,例如 yllDev,在部署时打包当前模块的 jar 包,这样每个人打包的 jar 包就不会冲突。

⚠️ 注意:jar 包之间不能包含相同的文件,否则无法通过部署校验,如果团队中共享了公共模块的代码,需将公共模块进行独立打包部署,各成员的 jar 包不含公共模块代码

WEB 接口开发

接口开与 SpringBoot 的接口开发一致

强制要求: 接口统一返回 `WeaResult` 对象

接口开发示例:

Controller:

package com.weaver.seconddev.hnweaver.demo.api;

import com.weaver.common.authority.annotation.WeaPermission;
import com.weaver.common.base.entity.result.WeaResult;
import com.weaver.seconddev.hnweaver.demo.domain.param.HelloParam;
import com.weaver.seconddev.hnweaver.demo.service.HelloService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

/**
 * @author 姚礼林
 * @desc 测试接口
 * @date 2024/4/1
 */
@RestController
@RequestMapping({"/api/secondev/hnweaver/workflow/demo","/papi/secondev/hnweaver/workflow/demo"})
@WeaPermission(publicPermission = true)
@Slf4j
@RequiredArgsConstructor
public class ApiDemoController {

    private final HelloService helloService;

    @GetMapping("/hello")
    public WeaResult<String> hello(@RequestParam("name") String name) {

        return WeaResult.success("hello world");
    }

    @PostMapping("/hello")
    public WeaResult<String> posetHello(@RequestBody HelloParam param) {
        if (param == null || param.getName() == null) {
            return WeaResult.fail("name 不能为空");
        }
        if (helloService.hello(param)) {
            return WeaResult.success("hello world");
        }
        return WeaResult.fail("执行错误");
    }
}

请求参数对象:

package com.weaver.seconddev.hnweaver.demo.domain.param;  
  
import lombok.Data;  
  
/**  
 * @author 姚礼林  
 * @desc 请求参数  
 * @date 2026/6/16  
 **/@Data  
public class HelloParam {  
    private String name;  
    private Integer age;  
}

业务接口:

package com.weaver.seconddev.hnweaver.demo.service;  
  
import com.weaver.seconddev.hnweaver.demo.domain.param.HelloParam;  
  
/**  
 * @author 姚礼林  
 * @desc 测试业务接口  
 * @date 2026/6/16  
 **/
 public interface HelloService {  
  
    boolean hello(HelloParam param);  
}

业务实现类:

package com.weaver.seconddev.hnweaver.demo.service.impl;

import com.weaver.seconddev.hnweaver.demo.domain.param.HelloParam;
import com.weaver.seconddev.hnweaver.demo.service.HelloService;

/**
 * @author 姚礼林
 * @desc 测试业务类
 * @date 2026/6/16
 **/
public class HelloServiceImpl implements HelloService {

    @Override
    public boolean hello(HelloParam param) {
        return true;
    }
}

全局异常处理器

如果接口发生异常,则会使用系统默认的对象进行返回,提示服务器错误,可以创建全局异常处理器,让发生异常时也返回 `WeaResult` ,这样前端能统一按 `WeaResult` 处理。

package com.weaver.seconddev.hnweaver.common.handler;

import com.weaver.common.base.entity.result.WeaResult;
import com.weaver.seconddev.hnweaver.common.exception.ApiExceptionMsgInterface;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理器,仅作用于 com.weaver.seconddev.hnweaver 包下的 Controller
 */
@RestControllerAdvice(basePackages = "com.weaver.seconddev.hnweaver")
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public WeaResult<String> handleException(Exception ex) {
        log.error("接口发生异常:{}",ex.getMessage(), ex);
        if (ex instanceof ApiExceptionMsgInterface) {
            return WeaResult.fail("系统异常:" + ex.getMessage());
        } else if (ex instanceof MissingServletRequestParameterException) {
            return WeaResult.fail("缺少参数:" + ex.getMessage());
        }

        return WeaResult.fail("系统发生异常");
    }
}

第三方系统调用二开接口

需要将二开接口在开放平台中进行发布,就能使用开放平台的认证机制,让第三方系统获取 token ,将 token 添加到二开接口参数中进行调用。

在开放平台中发布接口

进入开放平台管理中心进行审核接口

接口发布后,调用接口时要加上开放平台接口的前缀 `/papi/openapi/` , 完整接口地址为 :`/papi/openapi/{发布接口路由}` , 比如二开接口的路由为:`/sapi/secondev/hnweaver/test/log` , 则在第三方调用时地址为:`/papi/openapi/sapi/secondev/hnweaver/test/log` , 还需要加上 `access_token` 参数到地址中进行认证,比如:`api_url?access_token={token}`

配置获取

配置文件路径:`E10部署路径\weaver-secondev-service\webapps\ROOT\WEB-INF\classes\weaver\config\config-center\weaver-secondev-service.properties`

读取示例:

@Data
@Configuration
@RefreshScope
public class TwoHaoHrProperty {
    @Value("${2HaoHr.appId}")
    private String appId;
    @Value("${2HaoHr.appKey}")
    private String appKey;
    @Value("${oaAddress}")
    private String oaAddress;
    @Value("${2HaoHr.ssoUrl:https://h5.2haohr.com/browser/authorize.html}")
    private String ssoUrl;
}

**读取其它配置文件:**

使用 `PropertySource` 指定配置文件

⚠️ 注意:如果配置文件不存在会导致服务无法启动

@PropertySource("classpath:/weaver/config/config-center/seconddev-demo-openapi.properties")
@Configuration
@Data
public class DemoProperties {
    @Value("${openapi.serverAddress}")
    private String serverAddress;
    @Value("${openapi.cropid}")
    private String cropid;
    @Value("${openapi.appKey}")
    private String appKey;
    @Value("${openapi.appSecret}")
    private String appSecret;
}

日志

E10 默认日志级别为 error,如果需要输出 info 或 debug 级别日志,需要修改配置文件配置日志级别,修改后只能临时生效,过段时间会自动恢复日志级别为 error。

**配置日志级别方法:** 修改 `E10部署路径\weaver-secondev-service\webapps\ROOT\WEB-INF\classes\weaver\config\config-center\weaver-secondev-service.properties` 配置文件,在配置文件加上:

logging.level.com.weaver.seconddev=[日志级别]

**日志输出:** 在类中使用 `@Slf4j` 注解

示例:

package com.weaver.seconddev.hnweaver.demo.api;

import com.weaver.common.authority.annotation.WeaPermission;
import com.weaver.common.base.entity.result.WeaResult;
import com.weaver.seconddev.hnweaver.demo.domain.param.HelloParam;
import com.weaver.seconddev.hnweaver.demo.service.HelloService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

/**
 * @author 姚礼林
 * @desc 测试接口
 * @date 2024/4/1
 */
@RestController
@RequestMapping({"/api/secondev/hnweaver/workflow/demo","/papi/secondev/hnweaver/workflow/demo"})
@WeaPermission(publicPermission = true)
@Slf4j
@RequiredArgsConstructor
public class ApiDemoController {

    private final HelloService helloService;

    @GetMapping("/hello")
    public WeaResult<String> hello(@RequestParam("name") String name) {
        log.info("这是一条日志,参数name={}", name);
        return WeaResult.success("hello world");
    }
}

**日志获取:** 在运维平台中获取日志

数据库操作

参见:e10平台定制开发指引

E10 执行数据库 SQL 要比 E9 更加复杂

需要先创建 `ExecuteSqlEntity` 对象,用来存放 SQL 语句以及其它的一些信息

  • Sql :必需使用 Base64 编码
  • GroupId :数据库表对应的服务,可以通过这个接口查到每个模块的 GroupId :/api/datasource/ds/group?sourceType=LOGIC,目前没有方法知道哪个表对应哪个服务,所以只能凭感觉查找,比如说这是一个流程相关的表,那么你就选流程的模块
  • SourceType :固定为 SourceType.LOGIC

此方法不支持使用占位符注入参数,只能使用字符串拼接参数

ExecuteSqlEntity sqlEntity = new ExecuteSqlEntity();
String sql = "select person_name,age from uf_personrecord";
sqlEntity.setSql(Base64.encode(sql));
sqlEntity.setGroupId("weaver-ebuilder-form-service");
sqlEntity.setSourceType(SourceType.LOGIC);

之后使用 `dataSetService` 执行 ,获取返回结果,返回的 `HashMap` 键为字段名,值为字段的值

Map<String, Object> result = dataSetService.executeSql(sqlEntity);
// records 可能为null,注意判断
List<HashMap<String ,Object>> records = (List<HashMap<String, Object>>) result.get("records");
for (HashMap<String, Object> row : records) {
     row.forEach((k,v) -> log.info("column:"+k+",value:"+v));
}

更多详细使用请查看官方说明文档

使用工具类执行 SQL

为了简化 SQL 的执行,我创建了一个工具类,让它和 E9 的 `RecordSet` 一样简单。

  • 操作简单
  • 支持使用占位符注入参数

你需要将此公共类库放入你的项目,开源地址:weaver-e10-second-dev-common: 泛微 E10 二次开发公共类库,提供工具类和通用组件,可在任何 E10 二开项目中使用。

使用示例:

String sql = "SELECT " + fieldName + " FROM " + tableName + " WHERE id = ?";
SqlExecuteResult result = sqlExecuteClient.executeSql(groupType, sql, dataId);
if (!result.isSuccess()) {
    log.error("查询字段值失败,sql:{},错误信息:{}", sql, result.getMessage());
    throw new SqlExecuteException("查询字段值失败,sql:" + sql + ",错误信息:" + result.getMessage());
}
// 获取查询数据
List<Map<String, Object>> records = result.getRecords();

`executeSql()` :

SqlExecuteResult executeSql(DatasourceGroupType groupType, String sql, SqlParam... params)
  • groupType:数据库表所属模块
  • sql:需要执行的sql,不区分查询和更新
  • params:传入 sql 中的参数,如果没有则不需要传

可通过返回结果的 `SqlExecuteResult.isSuccess` 判断是否执行成功

⚠️ 注意:返回结果的字段名可能会为大写,获取时需要注意,你可以使用 `SqlExecuteClient.getFieldValueIgnoreCase()` 方法忽略字段名大小写来获取字段值

缓存

通过 `BaseCache` 来操作缓存,参考:e10平台定制开发指引

示例:

@RestController
@RequestMapping({"/api/secondev/workflow/demo","/papi/secondev/workflow/demo"})
@Slf4j
public class ApiDemoController {
    
    // 默认读weaver-secondev-service\webapps\ROOT\WEB-INF\classes\weaver\config\config-center\weaver-secondev-service.properties文件
    @Value("${spring.datasource.username}")
    private String name;
    @Autowired
    private BaseCache baseCache;
    
    @GetMapping("/hello")
    public String hello() {
        log.info("hello,=> {}",name);
        // 写入缓存并设置时间
        baseCache.set("dev", "age", 18,60*60);
        log.info("age = {}", baseCache.get("dev", "age"));
        baseCache.del("dev", "age");
        log.info("age = {}", baseCache.get("dev", "age"));
        return "hello world";
    }
}

消息队列

官方文档说明:e10平台定制开发指引

定时任务

官方文档说明:E10自定义定时任务开发文档

定时任务有两个方法: 1. 通过动作流实现 2. 通过 @ESchedulerHandler 注解实现

@ESchedulerHandler 注解实现示例:

package com.weaver.seconddev.demo.escheduler;

import com.weaver.common.escheduler.context.ESchedulerJobHelper;
import com.weaver.common.escheduler.handler.annotation.ESchedulerHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class DemoEscheduler {

    private static final Logger log = LoggerFactory.getLogger(DemoEscheduler.class);

    /**
     * value: 业务方法的执行名称
     * cron: cron表达式自定义执行时间
     * @throws Exception
     */
    @ESchedulerHandler(value = "demoJobHandler", cron = "0/10 * * * * ?")
    public void demoJobHandler() throws Exception {
        log.info("demoJobHandler runnint");
        try {
            // todo
            // 获取页面上配置的任务参数
            final String jobParam = ESchedulerJobHelper.getJobParam();

        } catch (Exception e) {
            e.printStackTrace();
            log.error("demoJobHandler runnint error");
        }
        ESchedulerJobHelper.log("ESchedulerHandler, Hello World.");
    }
}

你可以通过 ` /info/dispatch/escheduler/report` 页面来查看这些计划任务

动作流介绍

动作流是 E10 的一个强大的功能,它内置了很多功能,比如表单数据修改、接口连接器调用、消息提醒等,可以通过多种形式触发动作流,可在动作流内使用条件进行分叉,控制动作走向。

可进入系统后台,在这个页面管理所有动作流,地址:/info/esb/application

动作流功能包括:

  • 内置多种标准组件,比如消息提醒,表单数据修改,数据计算(变量修改)等
  • 可添加条件,实现组件根据条件进行流转
  • 每个组件都可以获取前面组件的数据
  • 可对参数进行动态赋值,例如使用函数计算(可执行js),获取表单字段值(流程中使用)

函数

在动作流中可以创建自定义函数,来进行参数赋值

函数可以在动态赋值对话框中创建,也可以在 ESB 中心的函数列表中创建:`/info/esb/setting/function`

**创建函数**

params 参数可以有多个参数,例如:

function test(param1,param2){

}

示例:

function convertGenderToNum(value){
	return value === 'male'? 1: 2;
}

注意:创建函数时要先选择结果类型,因为函数创建之后结果类型就不能更改,你只能删了函数重新创建。 js 中不能包含注释

连接器

连接器可作为动作流中的组件,是一个非常常用的功能,可用于进行接口调用,例如流程归档之后调用第三方系统接口反馈状态。

入口:ESB 中心> 连接器 创建连接器时配置接口地址以及请求参数、返回参数即可,连接器发布后可在动作流中调用此连接器,实现接口调用。

自定义 Action 接口

可在动作流中配置自定义 Action 接口,通过 Action 来进行处理

**应用场景:** 在流程节点后操作添加动作流,在动作流内配置 Action,通过 Action 来实现功能,这个有点像 E9 的流程 Action,不过 E10 的 Action 是通用的,不止是在流程上

Action 具有输入和输出参数,在输入参数中可通过动态赋值,来获取表单字段值或者流程系统参数。输出参数可在动作流后面进行获取,比如说输出参数返回的是成功还是失败,在动作流进行流转控制,或者是在动作流获取输出参数中的结果。

输入参数:

输出参数:

创建 Action

在类中实现 `EsbServerlessRpcRemoteInterface` 接口 需要使用 `@Service` 注解,并且配置名称,名称和类名一样即可,如果不一样则可能无法识别该 Action。

execute() 方法的参数对应动作流中 Action 的输入参数,方法返回的 `WeaResult` 中的类型对象,对应动作流中 Action 的输出参数

示例:

package com.weaver.seconddev.hnweaver.demo.action;  
  
import com.weaver.common.base.entity.result.WeaResult;  
import com.weaver.esb.api.rpc.EsbServerlessRpcRemoteInterface;  
import org.springframework.stereotype.Service;  
  
import java.util.HashMap;  
import java.util.Map;  
  
/**  
 * @author 姚礼林  
 * @desc 测试 Action  
 * @date 2024/5/6  
 */
@Service("TestAction")  
public class TestAction implements EsbServerlessRpcRemoteInterface {  
  
    @Override  
    public WeaResult<Map<String, Object>> execute(Map<String, Object> params) {  
        WeaResult<Map<String, Object>> result;  
        if (params.get("name") == null || "1".equals(params.get("name"))) {  
            result =  WeaResult.fail("流程出错啦,name 参数不正确");  
            return result;  
        }  
        Map<String, Object> data = new HashMap<>();  
        result = WeaResult.success(data);  
        return result;  
    }  
}

**在 xml 配置文件上配置 Action**

上传后端 jar 包后, 需要在 `/ecode/monitor/loom/deploy/jar` 页面编辑配置文件,配置刚才创建的 Action,注意如果 Action 不存在则会导致二开服务无法启动。

需要在 xml 文件内的 `beans` 标签内添加: 以刚才创建的 Action 为示例

<dubbo:service ref="TestAction"
               interface="com.weaver.esb.api.rpc.EsbServerlessRpcRemoteInterface"
               group="TestAction" />
  • ref: Action 中的 @Service 注解中的名称,不可与其它名称重复
  • interface: 固定为 `com.weaver.esb.api.rpc.EsbServerlessRpcRemoteInterface`
  • group : 与 ref 一致

配置之后重启二开服务生效

**在动作流上配置 Action**

在动作流中添加操作,选择 serverless/Action

分组标识填写刚才在配置文件上配的 `group`

之后填写输入和输出参数

获取全部表单数据

在 Action 参数中通过动态赋值传入表单对象(Action 参数类型需要为文本),在后端中就可以获取到表单的全部数据,结构为 JSON 字符串,JSON 示例:

{
     "1211482743793795074": "2324",
     "1211482743793795074_name": "xxx项目",
     "1152361200519618679": [],
     "creator": 7515108099660413000,
     "1245873242740899841": [],
     "createTime": "2026-08-03 15:52:29",
     "1248495328915374080": [],
     "1211483482519781377": "42444",
     "1234764971354963969": []
}

json 中的字段数据的 key 为字段id,`字段id_name` 为字段值的显示名(如下拉框的显示名,浏览框的显示名)。

开放平台

开放平台介绍

开放平台入口:后台中心 -> 开放平台 开放平台接口文档:/sp/opendoc

**什么是开放平台** 开放平台内有许多公开的接口,可以供第三方或者OA系统内部进行调用,也就是这些接口就用来给别人调的

开放平台使用

新建应用和完善开发者资料

需要先新建应用和完善开发者资料才可以调用开放平台接口,可以在开放平台文档查看如何操作:`/sp/opendoc`

在后端中调用开放平台接口

**获取 SDK** 从此处下载 SDK,然后在此页面 `/ecode/monitor/loom/thirdJar` 将 SDK 作为第三方依赖上传到二开服务中,如提示文件格式不对,需要打包成 build.zip 文件进行上传

**获取 Token** 需要 token 才能调用接口,也就是先要进行认证

编写一个 Token 获取工具类,用于获取 Token

package com.weaver.seconddev.hnweaver.common.sdk.util;

import com.weaver.openapi.pojo.auth.params.AccessTokenParam;
import com.weaver.openapi.pojo.auth.params.CodeParam;
import com.weaver.openapi.pojo.auth.res.AccessToken;
import com.weaver.openapi.pojo.auth.res.Code;
import com.weaver.openapi.service.AuthService;
import lombok.experimental.UtilityClass;

/**
 * @author 姚礼林
 * @desc 开放接口 token 获取工具类
 * @date 2025/7/5
 **/
@UtilityClass
public class OpenApiTokenUtil {

    /**
     * 获取开放平台接口 Token
     *
     * @param appKey        应用 Key
     * @param appSecret     应用 Secret
     * @param cropid        企业 cropid,可在开发者资料中查看 corpId
     * @param state         重定向后会带上state参数,企业可以填写a-zA-Z0-9的参数值,长度不可超过128个字节
     * @param serverAddress OA 地址
     * @return 开放平台接口 Token
     */
    public static String getToken(String appKey, String appSecret, String cropid, String state, String serverAddress) {
        AccessTokenParam tokenParam = new AccessTokenParam(appKey, appSecret,
                "authorization_code", fetchCode(cropid, state, serverAddress));
        AccessToken token = AuthService.getAuthAccessToken(tokenParam,
                serverAddress + "/papi/openapi", null);
        return token.getAccessToken();
    }

    private static String fetchCode(String cropid, String state, String serverAddress) {
        CodeParam codeParam = new CodeParam(cropid, "code", state);
        Code code = AuthService.getAuthCode(codeParam, serverAddress + "/papi/openapi", null);
        return code.getCode();
    }
}

getToken() 参数说明:

  • appKey :可在开放平台的应用中查看
  • appSecret:可在开放平台的应用中查看
  • cropid:可在开放平台的开发者资料中查看 corpId
  • state:随便填
  • serverAddress:E10 地址,如 http://127.0.0.1:20600

使用示例:

package com.weaver.seconddev.hnweaver.common.request;

import com.weaver.seconddev.hnweaver.common.sdk.util.OpenApiTokenUtil;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

/**
 * @author 姚礼林
 * @desc todo
 * @date 2025/9/26
 **/
class OpenApiTokenUtilTest {

    @Test
    void getToken() {
        String token = OpenApiTokenUtil.getToken("301dcdc2a74ba068d687e9359325af44",
                "d1abb71bs77ec2h0d4ddf4461b11e4f", "7701caaehg185d19c3je87ad0c4642fa",
                "dev", "http://127.0.0.1:20600");
        System.out.println(token);
        assertFalse(token.isEmpty());
    }
}

为了在后端中方便调用,可以创建一个管理 Token 获取的类,将 appKey、appSecret 这些信息配置在配置文件里

示例: 可将 Token 存放到缓存

package com.weaver.seconddev.hnweaver.common.request;

import com.weaver.common.cache.base.BaseCache;
import com.weaver.openapi.pojo.auth.params.AccessTokenParam;
import com.weaver.openapi.pojo.auth.params.CodeParam;
import com.weaver.openapi.pojo.auth.res.AccessToken;
import com.weaver.openapi.pojo.auth.res.Code;
import com.weaver.openapi.service.AuthService;
import com.weaver.seconddev.hnweaver.common.config.OpenApiProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @author 姚礼林
 * @desc 获取开放接口 token
 * @date 2024/5/30
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class OpenApiTokenManger {
    private static final String STATE = "dev";
    private static final String MODULE_KEY = "seconddev";
    private static final String TOKEN_CACHE_KEY = "openApiAccessToken";
    private final BaseCache baseCache;
    private final OpenApiProperties properties;

    public String fetchAccessToken() {
        Object tokenCache = baseCache.get(MODULE_KEY, TOKEN_CACHE_KEY);
        if (tokenCache != null) {
            return (String) tokenCache;
        }
        AccessTokenParam tokenParam = new AccessTokenParam(properties.getAppKey(), properties.getAppSecret(),
                "authorization_code", fetchCode());
        AccessToken token = AuthService.getAuthAccessToken(tokenParam,
                properties.getServerAddress()+"/papi/openapi", null);
        baseCache.set(MODULE_KEY, TOKEN_CACHE_KEY,token.getAccessToken(),token.getExpiresIn());
        return token.getAccessToken();
    }

    public String getApiUrlPrefix() {
        return properties.getServerAddress() + "/papi/openapi";
    }

    private  String fetchCode() {
        CodeParam codeParam = new CodeParam(properties.getCropid(), "code", STATE);
        Code code = AuthService.getAuthCode(codeParam, properties.getServerAddress()+"/papi/openapi", null);
        return code.getCode();
    }

}

配置类,存放用于调用开放平台的一些信息。 需要在配置类上配置属性,都以 openapi. 开头,例如:openapi.serverAddress 、openapi.cropid

package com.weaver.seconddev.hnweaver.common.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * @author 姚礼林
 * @desc 开放接口配置属性
 * @date 2024/5/31
 */
@Configuration
@ConfigurationProperties(prefix = "openapi")
@Data
public class OpenApiProperties {
    private String serverAddress;
    private String cropid;
    private String appKey;
    private String appSecret;
}

**调用 Open API 接口**

该示例使用 SDK 调用部门列表接口

/**
 * @author 姚礼林
 * @desc TODO
 * @date 2024/5/30
 */
@RestController
@WeaPermission(publicPermission = true)
@RequestMapping("/api/secondev/hnweaver/demo/openapi")
public class OpenApiTestController {
    @Autowired
    private  OpenApiTokenManger tokenManger;
    @Autowired
    private OpenApiProperties properties;

    @GetMapping("/departments")
    public WeaResult<DeptList> queryDepartmentList() {
        DeptListParam deptListParam = new DeptListParam(tokenManger.fetchAccessToken(),null,null,null);
        DeptList deptList = DeptService.listDeptV2(deptListParam, properties.getServerAddress()+"/papi/openapi", null);

        return WeaResult.success(deptList);
    }
}

如果想用 HTTP 请求接口进行调用,在接口参数中添加 `access_token` 参数,传入获取的 token 即可

使用 SDK 进行调用

建议使用 SDK 调用开放接口,调用示例都可以在开放平台接口示例中查看