对接第三方组织架构

支持与现有的业务系统对接,支持业务系统的用户、角色和部门,本系统仅做流程处理。

# 自动登录

本系统提供一种自动登录的方式仅供参考,若不符合业务系统要求,可自行扩展

# 时序图:

  1. 业务系统跳转到本系统之前,生成一个当前登录用户的唯一token用来识别当前用户
  2. 前端将生成的token拼在本系统登录页面的url当参数传递,格式:http://pro.flyflow.cc/login?token=XXXXXXXXXXXXXXXX
  3. 本系统前端将获取的token自动传递给本系统服务器处理
  4. 本系统服务器收到前端提交的token之后,请求业务服务端进行鉴权;若鉴权成功,返回跟token对应的userId
  5. 本系统收到鉴权之后的userId之后登录系统,并将登录信息返回给本系统前端页面
  6. 本系统前端页面登录成功跳转到首页

从上面步骤可以看出,业务系统有三处需要改造:

  1. 服务端:提供生成token的接口,并将与当前登录用户关联起来
  2. web端:获取token并跳转本系统
  3. 服务端:提供鉴权接口给本系统,参数是token,返回值是userId

相关接口格式下面介绍,此处不展开了

# 注意事项

如果组织架构数据非本系统提供,则需要将role.allPermission设置为true

因为没有角色权限是不能登录系统的,而外部的用户未被设置角色,所以需要打开该配置默认所有人拥有所有的角色权限

# 服务端接口对接(Http)

  1. 所有远程调用接口皆为HTTPPOST调用
  2. 请求参数皆为JSON格式的BODY
  3. 请看代码中的HttpApi类,勿动此类
  4. 下方接口的请求地址是指完整请求的最后一段,前面部门需要一致,举例如下:
分页查询用户列表的完整url: http://www.baidu.com/aa/bb/userList
根据角色id数组获取拥有该角色的用户id数组: http://www.baidu.com/aa/bb/userIdListByRoleIdList

所有的请求地址,'http://www.baidu.com/aa/bb/'前面部分都要一致

  1. 接口全部实现之后,修改配置文件api.ori的值為http来切换实现类(默认为local),并配置http请求地址api.http.baseUrl

# 1. 分页查询用户列表

# 请求地址:/userList

# 请求参数

字段 名称 字段类型 是否必填 备注
pageNum 分页页码 int y
pageSize 每页数量 int y
deptId 部门id string n 查询部门下的人员
keywords 搜索词 string n 可以搜索手机号姓名等字段
status 用户状态 int n 1启用0禁用
name 姓名 string n 只搜索姓名
deptIdList 部门id的数组 array n 搜索多个部门下的人员

# JSON格式

{
    "deptId": "demoData",
    "keywords": "demoData",
    "status": 1,
    "name": "demoData",
    "pageNum": 1,
    "pageSize": 10,
    "deptIdList": [
        "demoData"
    ]
}

# 请求返回值

字段 名称 字段类型 是否必填 备注
total 总数量 int y
records 数据对象列表 array y
  id 用户id string y
  parentId 直属领导id string n
  name 用户姓名 string y
  avatarUrl 用户头像url string y
  deptIdList 部门id集合 array y
  deptName 部门名称 string y
  status 用户状态 int y 1启用0禁用
  phone 手机号 string n

# JSON格式

{
    "total": 12,
    "records": [
        {
            "id": "demoData",
            "parentId": "demoData",
            "name": "demoData",
            "avatarUrl": "demoData",
            "deptIdList": ["demoData"],
            "status": 1,
            "token": "demoData",
            "phone": "demoData",
            "deptName": "demoData"
        }
    ]
}

# 2. 根据角色id数组和部门id数组获取用户id数组

# 请求地址:/userIdListByRoleIdListAndDeptIdList

# 部门和角色两个参数至少传递一个,不能全部为空

# 请求参数

字段 名称 字段类型 是否必填 备注
roleIdList 角色id的数组 array n
deptIdList 部门id的数组 array n

# JSON格式

{
  "roleIdList": [
    "1"
  ],
  "deptIdList": [
    "1"
  ]
}

# 请求返回值

用户id集合

# JSON格式

["1"]

# 3. 根据用户id查询角色id数组

# 请求地址:/roleIdListByUserId

# 请求参数

字段 名称 字段类型 是否必填 备注
userId 用户id string y

# JSON格式

{
  "userId": "1"
}

# 请求返回值

角色id集合

# JSON格式

["1"]

# 4. 查询所有的角色

# 请求地址:/roleAll

# 请求参数

字段 名称 字段类型 是否必填 备注

# JSON格式

 

# 请求返回值

字段 名称 字段类型 是否必填 备注
name 角色名称 string y
id 角色id string y 唯一值
status 角色状态 int y 1启用0禁用

# JSON格式

[
  {
    "name": "demoData",
    "id": "demoData",
    "status": 1
  }
]

# 5. 根据登录token获取用户id

# 请求地址:/userIdByToken

# 请求参数

字段 名称 字段类型 是否必填 备注
token 登录token string y

# JSON格式

 {
  "token":  "1"
}

# 请求返回值

用户id

# JSON格式

 "1"

# 6. 根据父级id获取所有的部门对象,若父级id为空 则获取所有的部门

# 请求地址:/deptListByParentDeptId

# 请求参数

字段 名称 字段类型 是否必填 备注
parentDeptId 部门id string n id为空 则获取所有的部门

# JSON格式

 {
  "parentDeptId":  "1"
}

# 请求返回值

字段 名称 字段类型 是否必填 备注
id 部门id string y
name 部门名称 string y
parentId 上级部门id string y 若是最顶层的部门id则是0
leaderUserIdList 部门领导的userId array y 若没有部门领导,请设置为空数组[]
status 部门状态 int y 1启用0禁用
srot 部门排序 int y

# JSON格式

[
  {
    "id": "demoData",
    "name": "demoData",
    "parentId": "demoData",
    "leaderUserIdList": [
      "demoData"
    ],
    "status": 1,
    "sort": 1
  }
]

# 7. 根据部门id获取部门下的所有用户

# 请求地址:/userListByDeptId

# 请求参数

字段 名称 字段类型 是否必填 备注
deptId 部门id string y

# JSON格式

 {
  "deptId":  "1"
}

# 请求返回值

字段 名称 字段类型 是否必填 备注
id 用户id string y
parentId 直属领导id string n
name 用户姓名 string y
avatarUrl 用户头像url string y
deptIdList 部门id数组 array y
deptName 部门名称 string y
status 用户状态 int y 1启用0禁用
phone 手机号 string n

# JSON格式

[
  {
    "id": "demoData",
    "parentId": "demoData",
    "name": "demoData",
    "avatarUrl": "demoData",
    "deptIdList": ["demoData"],
    "status": 1,
    "token": "demoData",
    "phone": "demoData",
    "deptName": "demoData"
  }
]

# 8. 根据用户id查询用户对象

# 请求地址:/userById

# 请求参数

字段 名称 字段类型 是否必填 备注
userId 用户id string y

# JSON格式

 {
  "userId":  "1"
}

# 请求返回值

字段 名称 字段类型 是否必填 备注
id 用户id string y
parentId 直属领导id string n
name 用户姓名 string y
avatarUrl 用户头像url string y
deptIdList 部门id 数组 array y
deptName 部门名称 string y
status 用户状态 int y 1启用0禁用
phone 手机号 string n

# JSON格式


  {
    "id": "demoData",
    "parentId": "demoData",
    "name": "demoData",
    "avatarUrl": "demoData",
    "deptIdList": ["demoData"],
    "status": 1,
    "token": "demoData",
    "phone": "demoData",
    "deptName": "demoData"
  }

# 9. 发送通知

# 请求地址:/messageNotify

# 请求参数

字段 名称 字段类型 是否必填 备注
userId 消息接收人id string y
type 消息类型 string y TodoTask:待办任务 ,UrgeTask:催办任务,ExpiredTask:超时提醒任务
bizUniqueId 业务唯一id string y 根据不同类型,此字段含义不同,现在都表示任务id
content 消息体 string y
title 标题 string y
flowId 流程id string y
processInstanceId 流程实例id string y
tenantId 租户id string y
startUserId 发起人id string y
groupName 流程组名称 string y
flowName 流程名称 string y
{
    "type": "type_e7bf441a6100",
    "userId": "userId_97aa8bef3a49",
    "bizUniqueId": "bizUniqueId_4dc04cef7485",
    "content": "content_5c5762384252",
    "title": "title_4fab9b3af67d",
    "flowId": "flowId_b245576d0299",
    "processInstanceId": "processInstanceId_ee4ad2f3719b",
    "tenantId": "tenantId_086853ee65c5",
    "startUserId": "startUserId_70cd553fbaa7",
    "groupName": "groupName_08c2494e5979",
    "flowName": "flowName_753ec0d2c383"
}

# 请求返回值

# 10. 根据姓名搜索用户

# 请求地址:/userByName

# 请求参数

字段 名称 字段类型 是否必填 备注
name 用户姓名 string y 模糊匹配

# JSON格式

 {
  "name":  "1"
}

# 请求返回值

字段 名称 字段类型 是否必填 备注
id 用户id string y
parentId 直属领导id string n
name 用户姓名 string y
avatarUrl 用户头像url string y
deptIdList 部门id 数组 array y
deptName 部门名称 string y
status 用户状态 int y 1启用0禁用
phone 手机号 string n

# JSON格式

[
  {
    "id": "demoData",
    "parentId": "demoData",
    "name": "demoData",
    "avatarUrl": "demoData",
    "deptIdList": ["demoData"],
    "status": 1,
    "phone": "demoData",
    "deptName": "demoData"
  }
]

# 11. 账号密码登录

# 请求地址:/login

# 请求参数

字段 名称 字段类型 是否必填 备注
account 账号 string y
password 密码 string y

# JSON格式

 {
  "account":  "1",
  "password":  "1"
}

# 请求返回值

如果成功了返回用户id,否则返回null或者空字符串都可以

# JSON格式

 "1"

# 12. 获取配置的自定义用户字段

# 请求地址:/userFieldList

# 请求参数

字段 名称 字段类型 是否必填 备注

# 请求返回值

字段 名称 字段类型 是否必填 备注
name 字段名称 string y
type 字段类型 string y 参考下方备注: 字段类型(type)
required 是否必须 boolean y 用来控制编辑用户或者新增用户是否是必输项
props 字段属性配置 string y 参考下方备注:配置json字符串(props)
key 字段唯一key string y

# JSON格式

[
  {
    "name": "name_f32ec0a9ad64",
    "type": "type_458657fc0931",
    "required": false,
    "props": "props_48b520d1f05f",
    "key": "key_5c92fcb1fc37"
  }
]

# 13. 查询用户的自定义字段值

# 请求地址:/userFieldData

# 请求参数

字段 名称 字段类型 是否必填 备注
userId 用户id string y

# 请求返回值

字典类型:key是接口获取配置的自定义用户字段定义的key,value是值

具体值格式请参考各个类型的表单定义格式

若没有自定义字段,返回{}即可

# JSON格式

 {
  "key_5c92fcb1fc37": 123
}

# 14. 根据用户id批量查询用户

# 请求地址:/userByIdList

# 请求参数

字段 名称 字段类型 是否必填 备注
userIdList 用户id集合 array y

# JSON格式

 {
  "userIdList":  ["1"]
}

# 请求返回值

返回值字典类型,key是用户id,value是用户对象

字段 名称 字段类型 是否必填 备注
id 用户id string y
parentId 直属领导id string n
name 用户姓名 string y
avatarUrl 用户头像url string y
deptIdList 部门id数组 array y
deptName 部门名称 string y
status 用户状态 int y 1启用0禁用
phone 手机号 string n

# JSON格式

{
  "1": {
    "id": "demoData",
    "parentId": "demoData",
    "name": "demoData",
    "avatarUrl": "demoData",
    "deptIdList": ["demoData"],
    "status": 1,
    "token": "demoData",
    "phone": "demoData",
    "deptName": "demoData"
  }
}

# 15. 查询所有的岗位

# 请求地址:/postAll

# 请求参数

字段 名称 字段类型 是否必填 备注

# JSON格式

 

# 请求返回值

字段 名称 字段类型 是否必填 备注
name 角色名称 string y
id 角色id string y 唯一值
status 角色状态 int y 1启用0禁用

# JSON格式

[
  {
    "name": "demoData",
    "id": "demoData",
    "status": 1
  }
]

# 服务端接口对接(java)

  1. 通过实现接口ApiStrategy来实现三方业务系统对接
  2. 接口全部实现之后,修改配置文件api.ori来切换实现类(默认为local)
 
/**
 * API接口
 * 用来扩展数据:对接已存在的组织架构、角色等数据
 */
public interface ApiStrategy {

 

    /**
     * 根据角色id集合获取拥有该角色的用户id集合
     *
     * @param roleIdList 角色id集合
     * @return
     */
    List<String> loadUserIdListByRoleIdList(List<String> roleIdList);

    /**
     * 根据用户id查询角色id集合
     * @param userId
     * @return
     */
    List<String> loadRoleIdListByUserId(String userId);


    /**
     * 获取所有的角色
     *
     * @return
     */
    List<RoleDto> loadAllRole();

    /**
     * 根据部门id集合获取该部门下的用户id集合
     * 注意:直属部门,不包括子级及以下部门
     *
     * @param deptIdList 部门id集合
     * @return
     */
    List<String> loadUserIdListByDeptIdList(List<String> deptIdList);

    /**
     * 根据父级id获取所有的部门
     * 若父级id为空 则获取所有的部门
     *
     * @param parentDeptId 父级id
     * @return
     */
    List<DeptDto> loadAllDept(String parentDeptId);

    /**
     * 根据部门获取部门下的用户集合
     *
     * @param deptId 部门id
     * @return
     */
    List<UserDto> loadUserByDept(String deptId);

    /**
     * 根据用户id获取用户
     *
     * @param userId
     * @return
     */
    UserDto getUser(String userId);

    /**
     * 获取部门数据
     * @param deptId
     * @return
     */
    DeptDto getDept(String deptId);

    /**
     * 根据手机号获取用户
     * @param phone
     * @return
     */
    UserDto getUserByPhone(String phone);

    /**
     * 根据名字搜索用户
     *
     * @param name
     * @return
     */
    List<UserDto> searchUser(String name);

    /**
     * 根据token获取用户id
     * 处理登录接口请求的
     *
     * @param token
     * @return
     */
    String getUserIdByToken(String token);

    /**
     * 查询自定义用户字段
     *
     * @return
     */
    List<UserFieldDto> queryUserFieldList();

    /**
     * 查询自定义用户字段值
     *
     * @return
     */
    Map<String, String> queryUserFieldData(String userId);
   

    /**
     * 重新拉取数据
     * 现在用来钉钉同步数据使用 其他业务视情况决定是否启用
     */
    void loadRemoteData();

    /**
     * 获取登录地址
     *
     * @return
     */
    LoginUrlDto getLoginUrl();

    /**
     * 获取登录参数
     * 钉钉扫码登录使用
     * 其他业务视情况决定是否启用
     * @return
     */
    Object getLoginParam();

    /**
     * 发送消息
     *  业务行对接消息
     * @param messageDto
     */
    void sendMsg(MessageDto messageDto);
}


本系统已经提供了本地和远程两种策略模式:

  1. 本地:直接调用本地数据库实现
  2. 远程:在core-app模块提供了一个测试类用来模拟业务系统服务端,可以参考

默认启用的方式是本地,若需要对接业务系统,请在core-bizapplication.yml文件中启用:

##流程的数据api开关
api:
  ori: local

此处值对应的就是ApiStrategy实现类下的此处代码:

    @Override
    public void afterPropertiesSet() throws Exception {
        afterPropertiesSet("local");
    }

如果需要额外扩展接口,可以自行创建ApiStrategy的实现类即可

上述接口涉及的三个对象格式如下:

  1. User对象:
   class User {
        /**
         * 用户id 不能为空
         */
        private String id;
        /**
        * 直属领导id
        */
        private String parentId;
        /**
         * 用户姓名 不能为空
         */
        private String name;
        /**
         * 用户头像 不能为空
         */
        private String avatarUrl;
        /**
         * 用户所属部门id 可以为空
         */
        private String deptId;
        /**
         * 用户状态 0禁用 1启用
         */
        private Integer status;
    }

  1. Dept对象:
 
@Data
@Builder
public class DeptDto {
    /**
     * 部门id 不能为空
     */
    private String id;
    /**
     * 部门名字 不能为空
     */
    private String name;
    /**
     * 部门上级id 不能为空 若为顶级 则是0
     */
    private String parentId;
    /**
     * 部门主管的userId 可以为空 支持多个
     */
    private List<String> leaderUserIdList;
    /**
     * 部门状态 0 禁用 1启用
     */
    private Integer status;


}

  1. Role对象:
  class Role {
        /**
         * 角色id 不能为空
         */
        private String id;
        /**
         * 角色名字 不能为空
         */
        private String name;
        /**
         * 角色key  例如admin:edit user:create等 不能为空
         */
        private String key;
        /**
         * 角色状态 0 禁用 1启用
         */
        private Integer status;
    }

  1. 消息通知对象:



public class MessageDto    {


    /**
     * 类型
     * {@link MessageTypeEnum}
     */
    private String type;

    /**
     * 是否已读
     */
    private Boolean readed;

    /**
     * 用户id
     */
    private String userId;

    /**
     * 唯一id
     */
    private String uniqueId;

    /**
     * 消息参数
     */
    private String param;

    /**
     * 消息内容
     */
    private String content;

    /**
     * 消息头
     */
    private String title;
    /**
     * 流程id
     */
    private String flowId;
    /**
     *  流程实例id
     */
    private String processInstanceId;
}



  1. UserField对象:
  class UserField {

        /**
         * 字段名称,唯一
          */
        private String name;
    
    
        /**
         * 字段类型
         */
        private String type;
    
        /**
         * 是否必填
         */
        private Boolean required;
    
        /**
         * 配置json字符串
         */
        private String props;
    
        /**
         * 字段key唯一 
         */
        private String key; 
    }

# 字段类型(type)

  1. Number:数字
  2. Input:单行文本
  3. Textarea:多行文本
  4. Date:日期
  5. DateTime:日期时间
  6. Time:时间
  7. SingleSelect:单选
  8. MultiSelect:多选

# 配置json字符串(props)

主要是针对数字、单选和多选类型,其他类型保存:{}

{
  "options": [
    {
      "key": "1",
      "value": "男"
    },
    {
      "key": "2",
      "value": "女"
    }
  ],
  "radixNum": 4
}
  1. 如果是数字类型,radixNum:表示小数位数,最小是0,不能为空
  2. 如果是单选/多选类型,options:表示选项,不能为空;key和value都是唯一的