对接第三方组织架构
支持与现有的业务系统对接,支持业务系统的用户、角色和部门,本系统仅做流程处理。
# 自动登录
本系统提供一种自动登录的方式仅供参考,若不符合业务系统要求,可自行扩展
# 时序图:
- 业务系统跳转到本系统之前,生成一个当前登录用户的唯一token用来识别当前用户
- 前端将生成的token拼在本系统登录页面的url当参数传递,格式:
http://pro.flyflow.cc/login?token=XXXXXXXXXXXXXXXX
- 本系统前端将获取的token自动传递给本系统服务器处理
- 本系统服务器收到前端提交的token之后,请求业务服务端进行鉴权;若鉴权成功,返回跟token对应的userId
- 本系统收到鉴权之后的userId之后登录系统,并将登录信息返回给本系统前端页面
- 本系统前端页面登录成功跳转到首页
从上面步骤可以看出,业务系统有三处需要改造:
- 服务端:提供生成token的接口,并将与当前登录用户关联起来
- web端:获取token并跳转本系统
- 服务端:提供鉴权接口给本系统,参数是token,返回值是userId
相关接口格式下面介绍,此处不展开了
# 注意事项
如果组织架构数据非本系统提供,则需要将role.allPermission
设置为true
因为没有角色权限是不能登录系统的,而外部的用户未被设置角色,所以需要打开该配置默认所有人拥有所有的角色权限
# 对接其他系统的组织架构
FlyFlow预留接口支持对接其他系统的组织架构,分为两种方式:
- 无需在FlyFlow写代码,其他业务系统按照接口文档(
服务端接口对接(Http)
)提供对应的接口对接即可 - 自行对接,更灵活:可以参考代码中的
NetApi
实现类,全部实现即可
以上无论何种方式对接,都记得修改配置文件中的api.ori
选项
# 服务端接口对接(Http)
- 所有远程调用接口皆为
HTTP
的POST
调用 - 请求参数皆为
JSON
格式的BODY
体 - 请看代码中的
HttpApi
类,勿动此类 - 下方接口的请求地址是指完整请求的最后一段,前面部门需要一致,举例如下:
分页查询用户列表的完整url: http://www.baidu.com/aa/bb/userList
根据角色id数组获取拥有该角色的用户id数组: http://www.baidu.com/aa/bb/userIdListByRoleIdList
所有的请求地址,'http://www.baidu.com/aa/bb/'前面部分都要一致
- 接口全部实现之后,修改配置文件
api.ori
的值為http
来切换实现类(默认为local
),并配置http请求地址api.http.baseUrl
# 1. 分页查询用户列表(若不需在FlyFlow管理用户列表,此接口可以不用对接)
# 请求地址:/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
}
]
# 16. 获取部门的顶级id
# 请求地址:/getDeptRootId
# 此处要返回的是数据库中存储的数据的顶级部门的父级部门id,比如0
# 请求参数
字段 | 名称 | 字段类型 | 是否必填 | 备注 |
---|
# JSON格式
# 请求返回值
字段 | 名称 | 字段类型 | 是否必填 | 备注 |
---|
# JSON格式
1
# 17. 根据用户id查询岗位id
# 请求地址:/postIdListByUserId
# 请求参数
字段 | 名称 | 字段类型 | 是否必填 | 备注 |
---|---|---|---|---|
userId | 用户id | string | y |
# JSON格式
{
"userId": "1"
}
# 请求返回值
岗位id集合
# JSON格式
["1"]
# 18. 根据用户id查询标签id
# 请求地址:/labelIdListByUserId
# 请求参数
字段 | 名称 | 字段类型 | 是否必填 | 备注 |
---|---|---|---|---|
userId | 用户id | string | y |
# JSON格式
{
"userId": "1"
}
# 请求返回值
标签组集合
数组第一个值是:标签组的id
数组第二个值是:标签的id
# JSON格式
[["1","1-1"]]
# 服务端接口对接(java)
- 通过实现接口
ApiStrategy
来实现三方业务系统对接 - 接口全部实现之后,修改配置文件
api.ori
来切换实现类(默认为local
)
本系统已经提供了本地和远程两种策略模式:
- 本地:直接调用本地数据库实现
- 远程:在core-app模块提供了一个测试类用来模拟业务系统服务端,可以参考
默认启用的方式是本地,若需要对接业务系统,请在core-biz
的application.yml
文件中启用:
##流程的数据api开关
api:
ori: local
此处值对应的就是ApiStrategy
实现类下的此处代码:
@Override
public void afterPropertiesSet() throws Exception {
afterPropertiesSet("local");
}
如果需要额外扩展接口,可以自行创建ApiStrategy
的实现类即可
上述接口涉及的三个对象格式如下:
- 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;
}
- 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;
}
- Role对象:
class Role {
/**
* 角色id 不能为空
*/
private String id;
/**
* 角色名字 不能为空
*/
private String name;
/**
* 角色key 例如admin:edit user:create等 不能为空
*/
private String key;
/**
* 角色状态 0 禁用 1启用
*/
private Integer status;
}
- 消息通知对象:
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;
}
- UserField对象:
class UserField {
/**
* 字段名称,唯一
*/
private String name;
/**
* 字段类型
*/
private String type;
/**
* 是否必填
*/
private Boolean required;
/**
* 配置json字符串
*/
private String props;
/**
* 字段key唯一
*/
private String key;
}
# 字段类型(type)
Number
:数字Input
:单行文本Textarea
:多行文本Date
:日期DateTime
:日期时间Time
:时间SingleSelect
:单选MultiSelect
:多选
# 配置json字符串(props)
主要是针对数字、单选和多选类型,其他类型保存:{}
{
"options": [
{
"key": "1",
"value": "男"
},
{
"key": "2",
"value": "女"
}
],
"radixNum": 4
}
- 如果是数字类型,
radixNum
:表示小数位数,最小是0,不能为空 - 如果是单选/多选类型,
options
:表示选项,不能为空;key和value都是唯一的