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 调用开放接口,调用示例都可以在开放平台接口示例中查看