外观
用户组织对接
AgileBPM 提供了灵活的用户组织,面向上层的调用通过接口而不关注具体实现细节。依托 Spring 框架运行时自动注入,可对底层的实现更换而不影响上层调用。面向企业已有的鉴权和用户体系,AgileBPM 提供了两种对接方案。
接口定义
枚举
com.dstz.org.api.enums.GroupType
组类型
- ORG:组织
- ROLE:角色
- POST:岗位
接口
com.dstz.org.api.UserApi
用户接口,用于获取用户相关信息
IUser getByUserId(String userId)
(可选)
根据用户 ID 获取用户信息,默认内部调用getByUserIds
实现Iterator<? extends IUser> getByUserIds(Collection<String> userIds)
用户 ID 集合获取用户IUser getByUsername(String username)
(可选)
根据用户名获取用户信息,默认内部调用getByUsernames
实现Iterator<? extends IUser> getByUsernames(Collection<String> usernames)
根据用户名集合获取用户信息Iterator<? extends IUser> getByGroupTypeAndGroupIds(String groupType, Collection<String> groupIds)
通过组类型(枚举定义:com.dstz.org.api.enums.GroupType)和组 ID 集合获取用户PageListDTO<? extends IUser> queryFilter(QueryParamDTO queryParamDTO)
(可选)
用于对接自定义对话框(userSelector: 用户选择),如自定义对话框(userSelector)选择的数据源方式可不实现
com.dstz.org.api.GroupApi
组接口,用于获取角色、岗位、组织等信息
IGroup getByGroupId(String groupType, String groupId)
(可选)
根据组类型和组 ID 获取组信息,默认内部调用getByGroupIds
实现Iterator<? extends IGroup> getByGroupIds(String groupType, Collection<String> groupIds)
根据组类型和组 ID 集合获取组信息迭代器IGroup getByGroupCode(String groupType, String groupCode)
(可选)
根据组类型和组编码获取组信息,默认内部调用getByGroupCodes
实现Iterator<? extends IGroup> getByGroupCodes(String groupType, Collection<String> groupCodes)
根据组类型和租编码集合获取组信息迭代器List<? extends IGroup> getByUserId(String userId)
(可选)
获取用户所关联组信息列表,默认将通过枚举com.dstz.org.api.enums.GroupType
调用getByGroupTypeAndUserId
获取List<? extends IGroup> getByGroupTypeAndUserId(String groupType, String userId)
根据组类型和用户 ID 获取所关联的组信息列表List<? extends IGroup> queryFilter(String groupType, QueryParamDTO queryParamDTO)
(可选)
自定义对话框(orgSelector: 组织选择、postSelector: 岗位选择、roleSelector:角色选择)的实现,如自定义对话框已选择数据源方式可不实现。
方案一:客户端对接
客户端的对接,需要您在 AgileBPM 提供的微服务项目中实现相关接口,通过编写远程调用来实现数据交换。此种方案对企业已有服务无侵入性。
会话整合
下面我们将通过一个JWT
会话标识案例来开始我们的对接。
对接步骤
- 修改
com.dstz.cloud.user.api.RequestUserSessionApiImpl
类
java
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
@Component
public class RequestUserSessionApiImpl implements UserSessionApi {
@Override
public IUserSession getSession() {
HttpServletRequest request = Objects.requireNonNull(AbRequestUtils.getHttpServletRequest());
// 从请求头中获取Token
String token = request.getHeader("access-token");
if (StrUtil.isEmpty(token)) {
return null;
}
// 解析出存储信息
Claims claims = Jwts.parser().setSigningKey("xxx").parseClaimsJws(token).getBody();
DefaultUserSession userSession = new DefaultUserSession();
// 用户相关
// 用户ID
userSession.setUserId(claims.get("userId", String.class));
// 用户名
userSession.setUsername(claims.get("username", String.class));
// 用户姓名
userSession.setFullName(claims.get("fullName", String.class));
// 当前组织相关 可选;默认从 com.dstz.org.api.GroupApi.getByGroupTypeAndUserId 获取第一条数据
// 组织ID
userSession.setOrgId(claims.get("orgId", String.class));
// 组织编码
userSession.setOrgCode(claims.get("orgCode", String.class));
// 组织名称
userSession.setOrgName(claims.get("orgName", String.class));
// 是否超级管理员 (可选,默认从从系统属性中a[admin.accounts]比对超级管理员用户名)
userSession.setSuperAdmin(claims.get("superAdmin", Boolean.class));
// 角色集合(可选,默认从 com.dstz.org.api.GroupApi.getByGroupTypeAndUserId 获取)
userSession.setAuthorities(claims.get("authorities", List.class));
return userSession;
}
}
- 修改类文件
ab-cloud/ab-cloud-common/ab-cloud-autoconfigure/src/main/java/com/dstz/cloud/autoconfigure/client/AbCloudClientConfiguration.java
移除方法abSessionInfoTransform
以及标注注解ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/session/AbCloudSessionWebConfiguration.java
移除方法requestUserSessionApiImpl
以及标注注解
移除方法userSessionApiFetch
以及标注注解
- 删除类文件
ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/feign/fallback/UserSessionApiClientFallback.java
ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/feign/client/UserSessionApiClient.java
ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/user/api/UserSessionApiFetchImpl.java
ab-cloud/ab-cloud-common/ab-cloud-autoconfigure/src/main/java/com/dstz/cloud/autoconfigure/client/AbSessionInfoTransform.java
- 配置转发 Token
ab-cloud/ab-cloud-bpm/ab-bpm-service/src/main/resources/application.yml
yaml
ab:
# 客户端信息转发
rest-client-info-transform:
headers:
- name: access-token
用户组织对接
在会话整合阶段,我们已经实现了会话信息的转发,此处无需再关注会话的传递。
1.编写 Feign 调用客户端
封装调用服务端接口的 Feign 客户端
ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/feign/client/UserApiClient.java
ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/feign/client/GroupApiClient.java
2. 转换数据
将 Feign 客户端调用返回数据转换为接口定义返回对象
ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/user/api/UserApiImpl.java
ab-cloud/ab-cloud-common/ab-cloud-user-context/src/main/java/com/dstz/cloud/user/api/GroupApiImpl.java
方案二:服务端对接
服务端对接,需要您在已有服务中引入 AgileBPM 提供的依赖,实现对应接口。
会话整合
对于网关转发的请求,BPM 会将当前会话标识请求带入到鉴权服务中,鉴权服务通过标识返回对应的用户信息
- 配置会话转发
文件:ab-cloud/ab-cloud-bpm/ab-bpm-service/src/main/resources/application.yml
yaml
ab:
rest-client-info-transform:
headers:
- name: Authorization
- 鉴权服务模块-引入依赖
xml
<dependency>
<groupId>com.dstz</groupId>
<artifactId>ab-cloud-session-endpoint</artifactId>
<version>xxx</version>
</dependency>
- 鉴权服务模块-实现接口
com.dstz.cloud.session.api.UserSessionApi
IUserSession getSession()
获取会话,您可以使用
com.dstz.cloud.session.api.model.DefaultUserSession
封装值返回
- 鉴权服务模块-注册 Bean
您可选择以下其中一种方式将 Bean 注入到 Spring 容器里
- 导入
@Import({UserSessionApiEndpoint.class})
- 包扫描
@ComponentScan(basePackages = {"com.dstz"})
- @Bean
@Bean
public UserSessionApiEndpoint userSessionApiEndpoint(UserSessionApi userSessionApi){
return new UserSessionApiEndpoint(userSessionApi);
}
用户组织
- 用户组织服务模块-引入依赖
xml
<dependency>
<groupId>com.dstz</groupId>
<artifactId>ab-cloud-usergroup-endpoint</artifactId>
<version>xxx</version>
</dependency>
- 用户组织模块-实现接口
com.dstz.org.api.UserApi
com.dstz.org.api.GroupApi
- 注册 Bean
您可选择以下其中一种方式将 Bean 注入到 Spring 容器里
- 导入
java
@Import({GroupApiEndpoint.class, UserApiEndpoint.class})
- 包扫描
java
@ComponentScan(basePackages = {"com.dstz"})
- @Bean
java
@Bean
public UserApiEndpoint userApiEndpoint(UserApi userApi) {
return new UserApiEndpoint(userApi);
}
@Bean
public GroupApiEndpoint groupApiEndpoint(GroupApi groupApi) {
return new GroupApiEndpoint(groupApi);
}
网关配置
配置网关路由,将 BPM 请求转发到 BPM 服务中
yaml
spring:
cloud:
gateway:
routes:
- id: a5-bpm-service
uri: lb://a5-bpm-service
predicates:
- Path=/ab-bpm/**
自定义对话框
您实现了上述定义的方法
com.dstz.org.api.UserApi#queryFilter
和com.dstz.org.api.GroupApi#queryFilter
,可跳过此节配置
系统页面中用到的组织对话框选择器,都利用系统的自定义对话框做了解偶,您可选择数据源的方式对组织对话框做适配。
1.删除旧纪录
数据库中执行 SQL 语句
sql
DELETE FROM biz_cust_dialog WHERE code_ IN ('userSelector', 'orgSelector', 'roleSelector', 'postSelector');
2.添加数据源
菜单:系统 > 系统数据源 > 数据源
3.配置自定义对话框
菜单:视图 > 扩展配置 > 自定义对话框
用户选择器(userSelector)
- 添加
2 设置字段参数-显示字段
点击上图设置字段参数
显示字段非固定,用于展示使用,可有多个
- 设置字段参数-条件字段
- 设置字段参数-返回字段
返回字段,有左边的字段映射到右边字段名称上
id
-用户 IDname
-用户姓名account
-用户账户
确定并保存
预览对话框
组织选择器(orgSelector)
- 添加
- 设置字段参数-显示字段
填写字段映射
- 设置字段参数-返回字段
将左侧的字段映射到规范定义返回字段
id
-组织 IDkey
-组织编码name
-组织名称
确定并保存
预览对话框
角色选择器(roleSelector)
配置上与前两选择器类似,在设置字段参数-返回字段上约定如下
id
-角色 IDkey
-角色编码name
-角色名称
岗位选择器(postSelector)
配置上与前两选择器类似,在设置字段参数-返回字段上约定如下
id
-岗位 IDkey
-岗位编码name
-岗位名称
常见问题
使用的
RestTemplate
方式调用远程接口会传递会话吗?
回答:会的,AgileBPM 实现了与 Feign 同样的拦截器,按上述配置的会话字段自动转发。自定义对话框中无法使用多表,如何配置出岗位关联?
回答:自定义对话框支持使用数据源接口方式,通过 JdbcTemplate 查询关联表并返回结果,此代码需要的 BPM 服务中编写。详细参考自定义对话框篇配置。