专业的编程技术博客社区

网站首页 > 博客文章 正文

记一次Java语言Spring框架对接飞书原生审批流方案

baijin 2025-04-01 15:48:43 博客文章 26 ℃ 0 评论

一、 项目背景

  • 客户集团内部的实时消息办公软件选用的是飞书全套解决方案,客户内部供应链系统需要与飞书审批系统进行集成,实现流程自动化。
  • 目标:改造现有的审批流程对接系统适配飞书相关的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());
  • 审批催办


  • 获取具体审批流中审批节点的审批信息


  • 附件单独上传飞书

  • 踩坑记录

  1. 如果在飞书审批流中定义的字段属性是必填,怎第三方调用发起审批流时 必须要有值;
  2. 业务系统中的审批流如果使用的是飞书平台的附件管理,审批流中涉及到附件传递的时候 ,需要在发起审批流时再上传一次至对应要发起的飞书审批流(可提前预处理),否则审批流端查询不到对应的附件;
  3. 自建应用嵌入飞书应用工作台后免密登录(略)

六、 总结

由于飞书开放平台还在快速迭代,及客户业务系统本身可能有新的拓展,后续也涉及到持续的迭代调优,任重而道远。



本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表