一、 项目背景
- 客户集团内部的实时消息办公软件选用的是飞书全套解决方案,客户内部供应链系统需要与飞书审批系统进行集成,实现流程自动化。
- 目标:改造现有的审批流程对接系统适配飞书相关的API,实现与飞书原生审批流的对接,完成审批流程的创建、审批、查询等操作。
二、 技术选型
- 开发语言:Java
- 框架:Spring Boot、Spring MVC、VUE
- 飞书开放平台:飞书JAVA语言SDK
- 其他工具及类库:HTTP客户端(例如:RestTemplate、OkHttp)、JSON解析库(例如:Jackson、Gson)
三、 环境准备
- 飞书开发者账号注册及个人或者企业认证
- 创建飞书自建应用,获取App ID和App Secret
- 配置应用权限,申请审批流相关API权限
- Spring Boot项目搭建及依赖引入
四、 接口对接
- 4.1 获取 tenant_access_token
- 接口说明:获取调用审批流API所需的access_token
- 实现步骤:
- 使用App ID和App Secret调用飞书API获取tenant_access_token
- 缓存token,避免频繁调用接口
- 4.2 创建审批实例
- 接口说明:发起一个新的审批流程
- 实现步骤:
- 构建审批实例请求参数,包括审批定义Code、审批人、审批表单等
- 调用飞书API创建审批实例
- 处理接口返回结果,获取审批实例ID
- 4.3 查询审批实例详情
- 接口说明:根据审批实例ID查询审批流程的详细信息
- 实现步骤:
- 调用飞书API查询审批实例详情
- 解析接口返回数据,获取审批状态、审批意见等信息
- 4.4 审批操作(审批等相关动作 在飞书自己的平台完成、对接了审批历史记录及状态)
- 接口说明:对审批流程进行同意、拒绝等操作
- 实现步骤:
- 构建审批操作请求参数,包括审批实例ID、操作类型、审批意见等
- 调用飞书API进行审批操作
- 处理接口返回结果
五、 代码实现
关键代码记录
- 获取tenant_access_token的代码(后来实际在本方案中弃用、直接构建Client)
直接构建client:
Client client = Client.newBuilder(feishuConfig.getAppId(), feishuConfig.getAppSecret()).build();
- 发起审批流代码Demo
Json构建form中的数据就对应在飞书审批应用中定义的审批实例信息
- 同步飞书企业人员及部门信息
Client client = Client.newBuilder(feishuConfig.getAppId(), feishuConfig.getAppSecret()).build();
ListUserByDepartmentRequest req = new ListUserByDepartmentRequest();
req.setDepartmentId("0");
/**
* 一:部门数据同步
*/
log.info("获取远程部门数据开始");
List departments = new ArrayList<>();
try {
List remoteDepartments = DepartmentUserFinder.listDepartment(client, req);
if (!remoteDepartments.isEmpty()){
for (Department department : remoteDepartments) {
SysDepart sysDepart = getSysDepart(department);
departments.add(sysDepart);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
log.info("获取远程部门数据结束");
/**
* 二:员工数据同步
*/
log.info("获取远程员工数据开始");
List users = Lists.newArrayList();
try {
List users1 = DepartmentUserFinder.listUserByDepartmentForJob(client, req);
if (!users1.isEmpty()){
int i = 1;
for (User user : users1) {
String username = StringUtils.isNotEmpty(user.getEmployeeNo())?user.getEmployeeNo():"D0000"+i;
SysUser sysUser = new SysUser();
sysUser.setId(user.getOpenId());
sysUser.setUnionId(user.getUnionId());
sysUser.setNickname(user.getName());
sysUser.setRealname(user.getName());
sysUser.setPhone(user.getMobile());
sysUser.setEmail(StringUtils.isNotEmpty(user.getEmail())?user.getEmail():String.valueOf(i)+"@qq.com");
// sysUser.setSex(Integer.valueOf(user.getGender() == 1 ? "1" : "2"));
sysUser.setDelFlag(CommonConstant.DEL_FLAG_0);
sysUser.setStatus(Integer.valueOf("1"));
sysUser.setUsername(username);
sysUser.setUserId(user.getUserId());
sysUser.setWorkNo(username);
if (user.getDepartmentIds() != null && user.getDepartmentIds().length > 0) {
String result = Arrays.stream(user.getDepartmentIds())
.filter(Objects::nonNull)
.collect(Collectors.joining(", "));
sysUser.setDepartmentIds(result);
}
users.add(sysUser);
i++;
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
log.info("获取远程员工数据结束===远程数据量为:" + users.size());
- 审批催办
- 获取具体审批流中审批节点的审批信息
- 附件单独上传飞书
- 踩坑记录
- 如果在飞书审批流中定义的字段属性是必填,怎第三方调用发起审批流时 必须要有值;
- 业务系统中的审批流如果使用的是飞书平台的附件管理,审批流中涉及到附件传递的时候 ,需要在发起审批流时再上传一次至对应要发起的飞书审批流(可提前预处理),否则审批流端查询不到对应的附件;
- 自建应用嵌入飞书应用工作台后免密登录(略)
六、 总结
由于飞书开放平台还在快速迭代,及客户业务系统本身可能有新的拓展,后续也涉及到持续的迭代调优,任重而道远。
本文暂时没有评论,来添加一个吧(●'◡'●)