后端集成
后端集成
后端集成至少需要满足如下技术栈要求:jdk8
、springboot2.x
、mybatis / mybatis-plus
、mysql5+
、maven
1、后端代码合并
代码合并分3种情况:微服务项目
、单体单模块项目
、单体多模块项目
微服务
新建微服务模块wflow
,命名根据系统风格要求来加上 -wflow
后缀即可,将wflow相关配置及代码配置到该模块内即可
单体单模块项目
在主类同级中新建包 wflow
,将wflow代码全部复制过去即可
单体多模块项目
根据目标要求新建新maven
模块,如上和微服务差不多,注意pom依赖项
2、合并pom依赖
这个没啥说的了,把 wflow
的 pom
配置依赖都合并过去,注意和目标项目的依赖冲突,主要是mybatis依赖冲突,在mybatis-plus
中已经包含了 mybatis
的依赖,无需额外引入,flowable-spring-stater
包也包含了 mybatis
的依赖,注意需要排除
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter-actuator</artifactId>
<version>${flowable.version}</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>
如果你的项目还存在例如 pagehelper
之类的包,注意它可能也包含了mybatis
依赖,也需要排除掉,否则启动项目会出现找不到类的错误
3、合并application配置
以下几个配置项需要添加进去
spring:
#邮件发送配置,如果不需要发邮件功能这里可以不加,同时代码里面也要去除邮件功能
mail:
host: smtp.qq.com
username: smartiots@qq.com
password: fnrruelrccqaeaefx0
protocol: smtps
default-encoding: UTF-8
properties:
default-encoding: utf-8
mail:
smtp:
port: 465
auth: true
starttls:
enable: true
required: true
management:
health:
# 关闭启动时邮件配置检查
mail:
enabled: false
flowable:
async-executor-activate: true
#关闭一些不需要的功能服务
rest-api-enabled: false
idm:
enabled: false
cmmn:
enabled: false
dmn:
enabled: false
form:
enabled: false
app:
enabled: false
# wflow自带的文件上传控制配置
wflow:
file:
max-size: 20 #最大文件上传大小,MB
4、启动项目,逐步排查错误
注意
我们按上述步骤合并好代码后可能出现以下错误,需要逐步去排除
包/类路径报错
由于代码是直接复制过来的,和当前项目包和类路径不一致,需要手动批量去引入,根据开发工具的错误提示去挨个修改即可,可以使用批量替换
类冲突
wflow存在一些 config
配置类,例如 MyBatisPlusConfig
、AsyncTaskTheadPoolConfig
等,去除不需要的配置类,这个 AsyncTaskTheadPoolConfig
是用来提供线程处理异步任务的,如果大家各自项目内已经有了线程池配置,那么就不需要这个,但是要在目标项目的线程池配置里面加两个静态属性,如下:
@Configuration
public class ThreadPoolConfig {
public static ThreadPoolTaskExecutor executor;
public static ThreadPoolTaskScheduler taskScheduler;
}
在spring初始化这个类进行自动配置时,为上述两个属性赋值,taskScheduler
这个如果本身项目没有的话可以这样配置
@Bean
@Qualifier(value="applicationTaskExecutor") //这个注解下,防止线程池配置冲突
public ThreadPoolTaskScheduler threadPoolTaskScheduler(ThreadPoolTaskExecutor executor){
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
taskScheduler = threadPoolTaskScheduler;
threadPoolTaskScheduler.setThreadFactory(executor);
return threadPoolTaskScheduler;
}
5、集成组织架构及用户角色
wflow 自带了组织架构表,参见 数据库说明文档
那几张组织架构表如果是集成的话,一般目标系统都自带了,就不需要了,可以去掉它们,我们接下来就是要把查询这块全部换成目标系统的
设计方式
集成组织架构及用户角色等信息只需要实现 wflow 定义好的一个接口 com.wflow.service.OrgRepositoryService
,wflow把需要读取组织架构相关信息的地方都封装到了这个接口中,用户就可以根据自己的系统去实现对应的查询即可,返回wflow指定的实体类,这样就能适应各类系统了,甚至是从接口查组织架构数据。
事实上,wflow自带的组织架构相关表和绝大多数 RBAC 系统设计的结构大致一样,因此可以直接根据 wflow 默认实现 DefaultOrgRepositoryServiceImpl
稍作修改即可兼容到现有系统
示例
下面展示一个用户查询的集成,对应Mapper为 WflowUserMapper
public interface WflowUsersMapper extends BaseMapper<WflowUsers> {
/**
* 查询该部门下的所有用户
* @param deptId 部门ID
* @return 用户列表 type为固定值user
*/
@Select("SELECT ou.user_id id, ou.user_name `name`, 'user' AS 'type', ou.avatar FROM wflow_user_departments oud LEFT JOIN wflow_users ou ON ou.user_id = oud.user_id WHERE oud.dept_id = #{deptId}")
List<OrgTreeVo> selectUsersByDept(@Param("deptId") String deptId);
}
以集成到 ruoyi-vue
为例,那么只需要吧 BaseMapper<WflowUsers>
换成 BaseMapper<SysUser>
,然后由于若依的用户只能在一个部门下面,那么改造如下:
public interface WflowUsersMapper extends BaseMapper<SysUser> {
/**
* 查询该部门下的所有用户
* @param deptId 部门ID
* @return 用户列表 type为固定值user
*/
@Select("SELECT user_id id, nick_name `name`, 'user' AS 'type', avatar " +
"FROM sys_user WHERE del_flag = 0 AND dept_id = #{deptId}")
List<OrgTreeVo> selectUsersByDept(@Param("deptId") String deptId);
}
然后对应的 WflowUsers
都需要换成 SysUser
,其他需要修改的项为,部门
、角色
,注意有的表字段名称可能也不一样,需要修改
ID类型注意
wflow 默认的用户、部门、角色等 id类型是String,那么如果和目标系统是数值类型,那么需要在DefaultOrgRepositoryServiceImpl
内和其他地方把这个id toString()
或者 String.valueOf()
转换一下,注意有的地方id可能会是null
,用 toString()
的话需要注意空指针
还有一处查询涉及到了部门和用户关系,没有列入本接口,需要大家修改下这块
public interface WflowModelPermsMapper extends BaseMapper<WflowModelPerms> {
@Select("这段sql需要修改下部门表名称为目标系统的表名,这里默认是wflow的部门表")
List<ModelGroupVo.Form> selectByPerms(@Param("userId") String userId);
}
6、集成用户ID获取
wflow
的流程和用户身份信息相关,因此系统需要去读取 当前操作流程的人是谁,集成的话需要实现一个方法 com.wflow.utils.UserUtil.getLoginUserId()
,
public class UserUtil {
/**
* 获取当前登录用户的id
* @return 用户ID
*/
public static String getLoginUserId(){
//这里默认是用satoken实现的,需要换成各位自己的逻辑
return StpUtil.getLoginIdAsString();
}
}
例如:在 ruoyi
里面是 String.valueOf(SecurityUtils.getUserId())
8、组织架构缓存
组织架构存在深层嵌套关系,但是wflow里面有很多地方用到组织架构用户归属关系判断,例如判断张三是不是属于某个部门的人员,判断E部门是不是A部门的子部门等
我们不知道部门会有多少层级,在 wflow 中支持递归层级的,这种层级递归需要查询很频繁,那么在wflow中,系统启动的时候会直接把所有部门与用户的归属关系加载到内存中,维护2个Map,如下:
@Slf4j
@Service
public class MemoryOrgOwnershipServiceImpl implements OrgOwnershipService {
//用户ID与其所有层级所属部门ID级联映射
private static final Map<String, Set<String>> userDeptMap = new ConcurrentHashMap<>();
//部门ID与其所有父级部门ID级联关系映射
private static final Map<String, Set<String>> deptAndDeptMap = new ConcurrentHashMap<>();
}
通过这种方式,系统启动后即可通过缓存关系迅速判断这个归属关系逻辑,无需每次都递归查询数据库
通常情况下,系统的组织架构及人员数据库会变更,那么这时候缓存就要重新加载了,OrgOwnershipService
接口提供2个方法用来重载组织架构及用户归属关系缓存,直接调用即可
/**
* 重载用户与部门关系
* @param userId 用户ID
* @param isRemove 是移除还是加入
*/
void reloadUserDept(String userId, boolean isRemove);
/**
* 重载部门与部门关系
*/
void reloadDeptAndDept();
9、集成部门负责人
在wflow中存在 部门负责人
的概念,每个部门可以配置一个部门负责人,这个字段默认为leader
,如果大家要集成的系统中不存在该字段,那么可以在部门表中新增这个字段,存储作为该部门负责人的ID即可。
10、相关问题及报错
集成过程可能出现一些问题,上述过程有些章节已经有说明,当然可能补充的也不够完善,考虑不到所有的情况,欢迎大家上报给我相关问题及当时的解决方案以做补充💕