Browse Source

fix(tenant): 修复租户同步中tenantId类型错误及健壮性问题

- 将OnlCgreportHead和OnlFormHead的tenantId字段类型从String改为Long
- 修正同步处理中错误使用transId作为tenantId的问题,改为从消息体正确获取
- 新增parseRelativeFormCodes方法安全解析widgetJson,避免非法JSON抛异常
- 对in查询的空集合做防护,避免MyBatis-Plus传入空列表导致SQL异常
- 消息体中显式传递tenantId字段确保同步端可正确识别租户
- 角色查询中过滤null的roleId并使用LinkedHashSet去重
- 组织未配置角色时新增fallback机制回退到用户自身角色
- 表单元数据同步查询条件增加tenantId过滤确保租户隔离
feature/tenant-sync-online
chenchuchuan 2 days ago
parent
commit
937bdddea6
  1. 47
      application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/tenant/service/impl/OnlineFormTenantSyncServiceImpl.java
  2. 70
      application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/tenant/service/impl/SysTenantRoleServiceImpl.java
  3. 28
      application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/service/impl/SysUserServiceImpl.java
  4. 39
      application-tenant/tenant-sync/src/main/java/apelet/tenantsync/online/service/SysTenantOnlCgreporHeadServiceImpl.java
  5. 50
      application-tenant/tenant-sync/src/main/java/apelet/tenantsync/online/service/SysTenantOnlFormHeadServiceImpl.java
  6. 4
      common/common-generator/src/main/java/apelet/common/generator/model/OnlCgreportHead.java
  7. 3
      common/common-generator/src/main/java/apelet/common/generator/model/OnlFormHead.java

47
application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/tenant/service/impl/OnlineFormTenantSyncServiceImpl.java

@ -16,6 +16,7 @@ import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.JsonPath;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.redisson.api.RBucket; import org.redisson.api.RBucket;
@ -99,17 +100,24 @@ public class OnlineFormTenantSyncServiceImpl implements OnlineFormTenantSyncServ
} }
// 根据表单json中的relativeFormCode获取到对应的查询数据源数据 // 根据表单json中的relativeFormCode获取到对应的查询数据源数据
String widgetJson = onlineForm.getWidgetJson(); String widgetJson = onlineForm.getWidgetJson();
List<String> relativeFormCodeList = JsonPath.read(widgetJson, "$..relativeFormCode"); List<String> relativeFormCodeList = parseRelativeFormCodes(widgetJson);
List<OnlCgreportHead> onlCgreportHeadList = iOnlCgreportHeadService.list(new LambdaQueryWrapper<OnlCgreportHead>() List<OnlCgreportHead> onlCgreportHeadList = relativeFormCodeList.isEmpty()
.in(OnlCgreportHead::getCode, relativeFormCodeList)); ? Collections.emptyList()
: iOnlCgreportHeadService.list(new LambdaQueryWrapper<OnlCgreportHead>()
.in(OnlCgreportHead::getCode, relativeFormCodeList));
List<String> onlCgreportHeadIdList = onlCgreportHeadList.stream().map(OnlCgreportHead::getId).collect(Collectors.toList()); List<String> onlCgreportHeadIdList = onlCgreportHeadList.stream().map(OnlCgreportHead::getId).collect(Collectors.toList());
List<OnlCgreportItem> onlCgreportItemList = iOnlCgreportItemService.list(new LambdaQueryWrapper<OnlCgreportItem>() List<OnlCgreportItem> onlCgreportItemList = onlCgreportHeadIdList.isEmpty()
.in(OnlCgreportItem::getCgrheadId, onlCgreportHeadIdList)); ? Collections.emptyList()
List<OnlCgreportParam> onlCgreportParamList = iOnlCgreportParamService.list(new LambdaQueryWrapper<OnlCgreportParam>() : iOnlCgreportItemService.list(new LambdaQueryWrapper<OnlCgreportItem>()
.in(OnlCgreportParam::getCgrheadId, onlCgreportHeadIdList)); .in(OnlCgreportItem::getCgrheadId, onlCgreportHeadIdList));
List<OnlCgreportParam> onlCgreportParamList = onlCgreportHeadIdList.isEmpty()
? Collections.emptyList()
: iOnlCgreportParamService.list(new LambdaQueryWrapper<OnlCgreportParam>()
.in(OnlCgreportParam::getCgrheadId, onlCgreportHeadIdList));
for (Long tenantId : tenantIdSet) { for (Long tenantId : tenantIdSet) {
// 表单更新同步通知 // 表单更新同步通知
JSONObject formMsgJsonData = new JSONObject(); JSONObject formMsgJsonData = new JSONObject();
formMsgJsonData.put("tenantId", tenantId);
formMsgJsonData.put("adminOnlineForm", onlineForm); formMsgJsonData.put("adminOnlineForm", onlineForm);
formMsgJsonData.put("originalOnlineForm", lastUpdateOnlineForm); formMsgJsonData.put("originalOnlineForm", lastUpdateOnlineForm);
formMsgJsonData.put("datasourceIdSet", datasourceIdSet); formMsgJsonData.put("datasourceIdSet", datasourceIdSet);
@ -122,6 +130,7 @@ public class OnlineFormTenantSyncServiceImpl implements OnlineFormTenantSyncServ
TenantConstant.MESSAGE_QUEUE_SELECTOR_KEY); TenantConstant.MESSAGE_QUEUE_SELECTOR_KEY);
//表单数据源更新同步新增 //表单数据源更新同步新增
JSONObject onlCgreportHeadMsgJsonData = new JSONObject(); JSONObject onlCgreportHeadMsgJsonData = new JSONObject();
onlCgreportHeadMsgJsonData.put("tenantId", tenantId);
onlCgreportHeadMsgJsonData.put("onlCgreportHeadList", onlCgreportHeadList); onlCgreportHeadMsgJsonData.put("onlCgreportHeadList", onlCgreportHeadList);
onlCgreportHeadMsgJsonData.put("onlCgreportItemList", onlCgreportItemList); onlCgreportHeadMsgJsonData.put("onlCgreportItemList", onlCgreportItemList);
onlCgreportHeadMsgJsonData.put("onlCgreportParamList", onlCgreportParamList); onlCgreportHeadMsgJsonData.put("onlCgreportParamList", onlCgreportParamList);
@ -146,6 +155,7 @@ public class OnlineFormTenantSyncServiceImpl implements OnlineFormTenantSyncServ
// 表单元数据通知更新新增 // 表单元数据通知更新新增
for(Long tenantId : tenantIdSet){ for(Long tenantId : tenantIdSet){
JSONObject messageJsonData = new JSONObject(); JSONObject messageJsonData = new JSONObject();
messageJsonData.put("tenantId", tenantId);
messageJsonData.put("onlFormHeadList", headList); messageJsonData.put("onlFormHeadList", headList);
messageJsonData.put("onlFormFindList", findList); messageJsonData.put("onlFormFindList", findList);
messageJsonData.put("onlFormFieldList", fieldList); messageJsonData.put("onlFormFieldList", fieldList);
@ -165,8 +175,27 @@ public class OnlineFormTenantSyncServiceImpl implements OnlineFormTenantSyncServ
return true; return true;
} }
private static @NotNull String getOnlFormHeadByPageIdSQL(Long pageId) { /**
String placeholders = pageId.toString(); * 从 widgetJson 中提取所有的 relativeFormCode(查询数据源编码)。
* widgetJson 为空、非法 JSON 或没有该节点时返回空集合,不抛异常。
*/
private List<String> parseRelativeFormCodes(String widgetJson) {
if (StrUtil.isBlank(widgetJson)) {
return Collections.emptyList();
}
try {
List<String> codes = JsonPath.read(widgetJson, "$..relativeFormCode");
if (codes == null) {
return Collections.emptyList();
}
return codes.stream().filter(StrUtil::isNotBlank).distinct().collect(Collectors.toList());
} catch (Exception e) {
log.warn("解析 widgetJson 的 relativeFormCode 失败,按无查询数据源处理:{}", e.getMessage());
return Collections.emptyList();
}
}
private static @NotNull String getOnlFormHeadByPageIdSQL(Long pageId) { String placeholders = pageId.toString();
String sql = "WITH RECURSIVE form_tree AS (" + String sql = "WITH RECURSIVE form_tree AS (" +
"SELECT fh.* FROM onl_form_head fh " + "SELECT fh.* FROM onl_form_head fh " +
"LEFT JOIN zz_online_page p ON p.master_table_id = fh.id " + "LEFT JOIN zz_online_page p ON p.master_table_id = fh.id " +

70
application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/tenant/service/impl/SysTenantRoleServiceImpl.java

@ -532,27 +532,34 @@ public class SysTenantRoleServiceImpl extends BaseService<SysTenantRole, Long> i
for (OnlineForm onlineForm : onlineFormListByPageIds) { for (OnlineForm onlineForm : onlineFormListByPageIds) {
// 根据表单json中的relativeFormCode获取到对应的查询数据源数据 // 根据表单json中的relativeFormCode获取到对应的查询数据源数据
String widgetJson = onlineForm.getWidgetJson(); String widgetJson = onlineForm.getWidgetJson();
List<String> relativeFormCodeList = JsonPath.read(widgetJson, "$..relativeFormCode"); List<String> relativeFormCodeList = parseRelativeFormCodes(widgetJson);
List<OnlCgreportHead> onlCgreportHeadList = iOnlCgreportHeadService.list(new LambdaQueryWrapper<OnlCgreportHead>() if (!relativeFormCodeList.isEmpty()) {
.in(OnlCgreportHead::getCode, relativeFormCodeList)); List<OnlCgreportHead> onlCgreportHeadList = iOnlCgreportHeadService.list(new LambdaQueryWrapper<OnlCgreportHead>()
List<String> onlCgreportHeadIdList = onlCgreportHeadList.stream().map(OnlCgreportHead::getId).collect(Collectors.toList()); .in(OnlCgreportHead::getCode, relativeFormCodeList));
List<OnlCgreportItem> onlCgreportItemList = iOnlCgreportItemService.list(new LambdaQueryWrapper<OnlCgreportItem>() List<String> onlCgreportHeadIdList = onlCgreportHeadList.stream().map(OnlCgreportHead::getId).collect(Collectors.toList());
.in(OnlCgreportItem::getCgrheadId, onlCgreportHeadIdList)); List<OnlCgreportItem> onlCgreportItemList = onlCgreportHeadIdList.isEmpty()
List<OnlCgreportParam> onlCgreportParamList = iOnlCgreportParamService.list(new LambdaQueryWrapper<OnlCgreportParam>() ? Collections.emptyList()
.in(OnlCgreportParam::getCgrheadId, onlCgreportHeadIdList)); : iOnlCgreportItemService.list(new LambdaQueryWrapper<OnlCgreportItem>()
for (Long tenantId : tenantIds) { .in(OnlCgreportItem::getCgrheadId, onlCgreportHeadIdList));
//表单数据源更新同步新增 List<OnlCgreportParam> onlCgreportParamList = onlCgreportHeadIdList.isEmpty()
JSONObject onlCgreportHeadMsgJsonData = new JSONObject(); ? Collections.emptyList()
onlCgreportHeadMsgJsonData.put("onlCgreportHeadList", onlCgreportHeadList); : iOnlCgreportParamService.list(new LambdaQueryWrapper<OnlCgreportParam>()
onlCgreportHeadMsgJsonData.put("onlCgreportItemList", onlCgreportItemList); .in(OnlCgreportParam::getCgrheadId, onlCgreportHeadIdList));
onlCgreportHeadMsgJsonData.put("onlCgreportParamList", onlCgreportParamList); for (Long tenantId : tenantIds) {
dataSyncProducer.sendOrderly( //表单数据源更新同步新增
tenantId, JSONObject onlCgreportHeadMsgJsonData = new JSONObject();
applicationConfig.getTenantSyncTopic(), onlCgreportHeadMsgJsonData.put("tenantId", tenantId);
OnlCgreportHead.class.getSimpleName(), onlCgreportHeadMsgJsonData.put("onlCgreportHeadList", onlCgreportHeadList);
TenantConstant.INSERT_TENANT_ONL_CGREPORT_HEAD_COMMAND, onlCgreportHeadMsgJsonData.put("onlCgreportItemList", onlCgreportItemList);
onlCgreportHeadMsgJsonData.toJSONString(), onlCgreportHeadMsgJsonData.put("onlCgreportParamList", onlCgreportParamList);
TenantConstant.MESSAGE_QUEUE_SELECTOR_KEY); dataSyncProducer.sendOrderly(
tenantId,
applicationConfig.getTenantSyncTopic(),
OnlCgreportHead.class.getSimpleName(),
TenantConstant.INSERT_TENANT_ONL_CGREPORT_HEAD_COMMAND,
onlCgreportHeadMsgJsonData.toJSONString(),
TenantConstant.MESSAGE_QUEUE_SELECTOR_KEY);
}
} }
} }
//根据页面ID获取表单元数据列表 //根据页面ID获取表单元数据列表
@ -567,6 +574,7 @@ public class SysTenantRoleServiceImpl extends BaseService<SysTenantRole, Long> i
// 表单元数据通知更新新增 // 表单元数据通知更新新增
for(Long tenantId : tenantIds){ for(Long tenantId : tenantIds){
JSONObject messageJsonData1 = new JSONObject(); JSONObject messageJsonData1 = new JSONObject();
messageJsonData1.put("tenantId", tenantId);
messageJsonData1.put("onlFormHeadList", headList); messageJsonData1.put("onlFormHeadList", headList);
messageJsonData1.put("onlFormFindList", findList); messageJsonData1.put("onlFormFindList", findList);
messageJsonData1.put("onlFormFieldList", fieldList); messageJsonData1.put("onlFormFieldList", fieldList);
@ -744,6 +752,26 @@ public class SysTenantRoleServiceImpl extends BaseService<SysTenantRole, Long> i
return resultMenuIdSet; return resultMenuIdSet;
} }
/**
* 从 widgetJson 中提取所有的 relativeFormCode(查询数据源编码)。
* widgetJson 为空、非法 JSON 或没有该节点时返回空集合,不抛异常。
*/
private List<String> parseRelativeFormCodes(String widgetJson) {
if (StrUtil.isBlank(widgetJson)) {
return Collections.emptyList();
}
try {
List<String> codes = JsonPath.read(widgetJson, "$..relativeFormCode");
if (codes == null) {
return Collections.emptyList();
}
return codes.stream().filter(StrUtil::isNotBlank).distinct().collect(Collectors.toList());
} catch (Exception e) {
log.warn("解析 widgetJson 的 relativeFormCode 失败,按无查询数据源处理:{}", e.getMessage());
return Collections.emptyList();
}
}
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor

28
application-tenant/tenant-admin/src/main/java/apelet/tenantadmin/upms/service/impl/SysUserServiceImpl.java

@ -806,22 +806,25 @@ public class SysUserServiceImpl extends BaseService<SysUser, Long> implements Sy
} }
// 2. 查询当前用户的角色记录(含deptId) // 2. 查询当前用户的角色记录(含deptId)
List<SysUserRole> userRoleList = sysUserRoleMapper.selectList(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId)); List<SysUserRole> userRoleList = sysUserRoleMapper.selectList(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
Set<Long> userRoleIdSet = userRoleList.stream().map(SysUserRole::getRoleId).collect(Collectors.toSet()); Set<Long> userRoleIdSet = userRoleList.stream().map(SysUserRole::getRoleId).filter(Objects::nonNull).collect(Collectors.toCollection(LinkedHashSet::new));
Set<Long> userDeptIdSet = userRoleList.stream().map(SysUserRole::getDeptId).filter(Objects::nonNull).collect(Collectors.toSet()); Set<Long> userDeptIdSet = userRoleList.stream().map(SysUserRole::getDeptId).filter(Objects::nonNull).collect(Collectors.toSet());
// 3. 批量查询所有组织的角色关联(通过SysUserRole.deptId) // 3. 批量查询所有组织的角色关联(通过SysUserRole.deptId),同一组织内按roleId去重
List<Long> allDeptIds = allDepts.stream().map(SysDept::getDeptId).collect(Collectors.toList()); List<Long> allDeptIds = allDepts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
LambdaQueryWrapper<SysUserRole> roleDeptQuery = new LambdaQueryWrapper<>(); LambdaQueryWrapper<SysUserRole> roleDeptQuery = new LambdaQueryWrapper<>();
roleDeptQuery.in(SysUserRole::getDeptId, allDeptIds); roleDeptQuery.in(SysUserRole::getDeptId, allDeptIds);
List<SysUserRole> allRoleDeptList = sysUserRoleMapper.selectList(roleDeptQuery); List<SysUserRole> allRoleDeptList = sysUserRoleMapper.selectList(roleDeptQuery);
Map<Long, List<Long>> deptRoleMap = new HashMap<>(); Map<Long, Set<Long>> deptRoleMap = new HashMap<>();
Set<Long> allRoleIdSet = new HashSet<>();
if (CollUtil.isNotEmpty(allRoleDeptList)) { if (CollUtil.isNotEmpty(allRoleDeptList)) {
for (SysUserRole ur : allRoleDeptList) { for (SysUserRole ur : allRoleDeptList) {
deptRoleMap.computeIfAbsent(ur.getDeptId(), k -> new ArrayList<>()).add(ur.getRoleId()); if (ur.getRoleId() == null) {
allRoleIdSet.add(ur.getRoleId()); continue;
}
deptRoleMap.computeIfAbsent(ur.getDeptId(), k -> new LinkedHashSet<>()).add(ur.getRoleId());
} }
} }
// 4. 批量查询所有角色 // 4. 批量查询所有角色,兜底角色一并查出来
Set<Long> allRoleIdSet = new HashSet<>(userRoleIdSet);
deptRoleMap.values().forEach(allRoleIdSet::addAll);
Map<Long, SysRole> roleMap = Collections.emptyMap(); Map<Long, SysRole> roleMap = Collections.emptyMap();
if (CollUtil.isNotEmpty(allRoleIdSet)) { if (CollUtil.isNotEmpty(allRoleIdSet)) {
List<SysRole> allRoleList = sysRoleMapper.selectBatchIds(allRoleIdSet); List<SysRole> allRoleList = sysRoleMapper.selectBatchIds(allRoleIdSet);
@ -835,8 +838,13 @@ public class SysUserServiceImpl extends BaseService<SysUser, Long> implements Sy
deptInfo.put("deptId", dept.getDeptId()); deptInfo.put("deptId", dept.getDeptId());
deptInfo.put("deptName", dept.getDeptName()); deptInfo.put("deptName", dept.getDeptName());
item.put("deptinfo", deptInfo); item.put("deptinfo", deptInfo);
List<Long> roleIds = deptRoleMap.getOrDefault(dept.getDeptId(), Collections.emptyList()); // 该组织尚未配置任何角色时,回退到用户自身的角色,打破"没配置就选不到角色"的死循环
boolean deptCheck = userDeptIdSet.contains(dept.getDeptId()) || roleIds.stream().anyMatch(userRoleIdSet::contains); Set<Long> roleIds = deptRoleMap.get(dept.getDeptId());
boolean fallback = CollUtil.isEmpty(roleIds);
if (fallback) {
roleIds = userRoleIdSet;
}
boolean deptCheck = userDeptIdSet.contains(dept.getDeptId()) || (!fallback && roleIds.stream().anyMatch(userRoleIdSet::contains));
deptInfo.put("check", deptCheck); deptInfo.put("check", deptCheck);
List<Map<String, Object>> roleInfoList = new ArrayList<>(); List<Map<String, Object>> roleInfoList = new ArrayList<>();
for (Long roleId : roleIds) { for (Long roleId : roleIds) {
@ -845,7 +853,7 @@ public class SysUserServiceImpl extends BaseService<SysUser, Long> implements Sy
Map<String, Object> roleInfo = new HashMap<>(); Map<String, Object> roleInfo = new HashMap<>();
roleInfo.put("roleId", role.getRoleId()); roleInfo.put("roleId", role.getRoleId());
roleInfo.put("roleName", role.getRoleName()); roleInfo.put("roleName", role.getRoleName());
roleInfo.put("check", userRoleIdSet.contains(roleId)); roleInfo.put("check", fallback || userRoleIdSet.contains(roleId));
roleInfoList.add(roleInfo); roleInfoList.add(roleInfo);
} }
} }

39
application-tenant/tenant-sync/src/main/java/apelet/tenantsync/online/service/SysTenantOnlCgreporHeadServiceImpl.java

@ -33,20 +33,29 @@ public class SysTenantOnlCgreporHeadServiceImpl implements BaseDataSyncConsumerS
@Override @Override
public void doHandle(String transId, String messageCommand, JSONObject messageJsonData) { public void doHandle(String transId, String messageCommand, JSONObject messageJsonData) {
if (StrUtil.equals(messageCommand, TenantConstant.INSERT_TENANT_ONL_FORM_HEAD_COMMAND)) { if (StrUtil.equals(messageCommand, TenantConstant.INSERT_TENANT_ONL_CGREPORT_HEAD_COMMAND)) {
List<OnlCgreportHead> onlCgreportHeadList = messageJsonData.getJSONArray("onlCgreportHeadList").toJavaList(OnlCgreportHead.class); // transId 是消息流水号,不是租户Id,必须从消息体取
List<OnlCgreportItem> onlCgreportItemList = messageJsonData.getJSONArray("onlCgreportItemList").toJavaList(OnlCgreportItem.class); Long tenantId = messageJsonData.getLong("tenantId");
List<OnlCgreportParam> onlCgreportParamList = messageJsonData.getJSONArray("onlCgreportParamList").toJavaList(OnlCgreportParam.class); if (tenantId == null) {
log.warn("查询数据源同步缺少 tenantId,已跳过。transId={}", transId);
return;
}
List<OnlCgreportHead> onlCgreportHeadList = toList(messageJsonData, "onlCgreportHeadList", OnlCgreportHead.class);
List<OnlCgreportItem> onlCgreportItemList = toList(messageJsonData, "onlCgreportItemList", OnlCgreportItem.class);
List<OnlCgreportParam> onlCgreportParamList = toList(messageJsonData, "onlCgreportParamList", OnlCgreportParam.class);
if (onlCgreportHeadList.isEmpty()) {
log.warn("查询数据源同步内容为空,已跳过。transId={}, tenantId={}", transId, tenantId);
return;
}
//对需要同步的查询数据源数据进行多租户处理 //对需要同步的查询数据源数据进行多租户处理
onlCgreportHeadList.stream().map(onlCgreportHead -> { for (OnlCgreportHead onlCgreportHead : onlCgreportHeadList) {
onlCgreportHead.setTenantId(transId); onlCgreportHead.setTenantId(tenantId);
return onlCgreportHead; }
}).collect(Collectors.toList());
for (OnlCgreportHead onlCgreportHead : onlCgreportHeadList) { for (OnlCgreportHead onlCgreportHead : onlCgreportHeadList) {
//判断对应租户是否已经存在相同名称的查询数据源 //判断对应租户是否已经存在相同名称的查询数据源
OnlCgreportHead one = iOnlCgreportHeadService.getOne(new LambdaQueryWrapper<OnlCgreportHead>() OnlCgreportHead one = iOnlCgreportHeadService.getOne(new LambdaQueryWrapper<OnlCgreportHead>()
.eq(OnlCgreportHead::getCode, onlCgreportHead.getCode()) .eq(OnlCgreportHead::getCode, onlCgreportHead.getCode())
.eq(OnlCgreportHead::getTenantId, transId)); .eq(OnlCgreportHead::getTenantId, tenantId));
if (one == null) { if (one == null) {
// 把onlCgreportItemList、onlCgreportParamList中headId和onlCgreportHead的id匹配的数据过滤出来 // 把onlCgreportItemList、onlCgreportParamList中headId和onlCgreportHead的id匹配的数据过滤出来
List<OnlCgreportItem> matchedItemList = onlCgreportItemList.stream() List<OnlCgreportItem> matchedItemList = onlCgreportItemList.stream()
@ -72,11 +81,19 @@ public class SysTenantOnlCgreporHeadServiceImpl implements BaseDataSyncConsumerS
iOnlCgreportParamService.saveBatch(matchedParamList); iOnlCgreportParamService.saveBatch(matchedParamList);
} }
} }
} else if (StrUtil.equals(messageCommand, TenantConstant.DELETE_TENANT_ONL_FORM_HEAD_COMMAND)) { } else if (StrUtil.equals(messageCommand, TenantConstant.DELETE_TENANT_ONL_CGREPORT_HEAD_COMMAND)) {
// 保留骨架:管理端查询数据源 tab 不再建设,本期不实现删除同步。
} }
} }
/**
* 安全地取集合字段:字段缺失或为空时返回空集合,避免 NPE。
*/
private <T> List<T> toList(JSONObject messageJsonData, String key, Class<T> clazz) {
com.alibaba.fastjson.JSONArray array = messageJsonData.getJSONArray(key);
return array == null ? java.util.Collections.emptyList() : array.toJavaList(clazz);
}
@Override @Override
public String handleMessageType() { public String handleMessageType() {
return OnlCgreportHead.class.getSimpleName(); return OnlCgreportHead.class.getSimpleName();

50
application-tenant/tenant-sync/src/main/java/apelet/tenantsync/online/service/SysTenantOnlFormHeadServiceImpl.java

@ -39,23 +39,33 @@ public class SysTenantOnlFormHeadServiceImpl implements BaseDataSyncConsumerServ
@Override @Override
public void doHandle(String transId, String messageCommand, JSONObject messageJsonData) { public void doHandle(String transId, String messageCommand, JSONObject messageJsonData) {
if (StrUtil.equals(messageCommand, TenantConstant.INSERT_TENANT_ONL_FORM_HEAD_COMMAND)) { if (StrUtil.equals(messageCommand, TenantConstant.INSERT_TENANT_ONL_FORM_HEAD_COMMAND)) {
List<OnlFormHead> onlFormHeadList = messageJsonData.getJSONArray("onlFormHeadList").toJavaList(OnlFormHead.class); // transId 是消息流水号(形如 "100-1234-OnlFormHead-INSERT-1761700000000"),不是租户Id,必须从消息体取
List<OnlFormFind> onlFormFindList = messageJsonData.getJSONArray("onlFormFindList").toJavaList(OnlFormFind.class); Long tenantId = messageJsonData.getLong("tenantId");
List<OnlFormField> onlFormFieldList = messageJsonData.getJSONArray("onlFormFieldList").toJavaList(OnlFormField.class); if (tenantId == null) {
List<OnlFormCheck> onlFormCheckList = messageJsonData.getJSONArray("onlFormCheckList").toJavaList(OnlFormCheck.class); log.warn("表单元数据同步缺少 tenantId,已跳过。transId={}", transId);
List<OnlFormIndex> onlFormIndexList = messageJsonData.getJSONArray("onlFormIndexList").toJavaList(OnlFormIndex.class); return;
List<OnlFormKey> onlFormKeyList = messageJsonData.getJSONArray("onlFormKeyList").toJavaList(OnlFormKey.class); }
List<OnlFormPage> onlFormPageList = messageJsonData.getJSONArray("onlFormPageList").toJavaList(OnlFormPage.class); List<OnlFormHead> onlFormHeadList = toList(messageJsonData, "onlFormHeadList", OnlFormHead.class);
List<OnlFormFind> onlFormFindList = toList(messageJsonData, "onlFormFindList", OnlFormFind.class);
List<OnlFormField> onlFormFieldList = toList(messageJsonData, "onlFormFieldList", OnlFormField.class);
List<OnlFormCheck> onlFormCheckList = toList(messageJsonData, "onlFormCheckList", OnlFormCheck.class);
List<OnlFormIndex> onlFormIndexList = toList(messageJsonData, "onlFormIndexList", OnlFormIndex.class);
List<OnlFormKey> onlFormKeyList = toList(messageJsonData, "onlFormKeyList", OnlFormKey.class);
List<OnlFormPage> onlFormPageList = toList(messageJsonData, "onlFormPageList", OnlFormPage.class);
if (onlFormHeadList.isEmpty()) {
log.warn("表单元数据同步内容为空,已跳过。transId={}, tenantId={}", transId, tenantId);
return;
}
//对需要同步的表单元数据进行多租户处理 //对需要同步的表单元数据进行多租户处理
onlFormHeadList.stream().map(onlFormHead -> { for (OnlFormHead onlFormHead : onlFormHeadList) {
onlFormHead.setTenantId(transId); onlFormHead.setTenantId(tenantId);
onlFormHead.setTableName(onlFormHead.getTableName() + "_" + transId); onlFormHead.setTableName(onlFormHead.getTableName() + "_" + tenantId);
return onlFormHead; }
}).collect(Collectors.toList());
for (OnlFormHead onlFormHead : onlFormHeadList) { for (OnlFormHead onlFormHead : onlFormHeadList) {
//判断对应租户是否已经存在相同名称的表单元数据 //判断对应租户是否已经存在相同名称的表单元数据
OnlFormHead one = onlFormHeadService.getOne(new LambdaQueryWrapper<OnlFormHead>() OnlFormHead one = onlFormHeadService.getOne(new LambdaQueryWrapper<OnlFormHead>()
.eq(OnlFormHead::getTableName, onlFormHead.getTableName())); .eq(OnlFormHead::getTableName, onlFormHead.getTableName())
.eq(OnlFormHead::getTenantId, tenantId));
if (one == null) { if (one == null) {
// 把onlFormFindList、onlFormFieldList、onlFormCheckList、onlFormIndexList、onlFormKeyList、onlFormPageList // 把onlFormFindList、onlFormFieldList、onlFormCheckList、onlFormIndexList、onlFormKeyList、onlFormPageList
// 中headId和onlFormHead的id匹配的数据过滤出来 // 中headId和onlFormHead的id匹配的数据过滤出来
@ -114,13 +124,25 @@ public class SysTenantOnlFormHeadServiceImpl implements BaseDataSyncConsumerServ
onlFormPageService.saveBatch(matchedPageList); onlFormPageService.saveBatch(matchedPageList);
//表单元数据同步 //表单元数据同步
onlFormHeadService.syncDB(onlFormHead, 0L); onlFormHeadService.syncDB(onlFormHead, 0L);
} else {
// TODO 去重同步策略待定:当前表已存在则整段跳过,
// 导致管理端后续新增的字段无法下发到租户,未来需改为字段级 diff + ALTER TABLE ADD COLUMN。
log.info("表单元数据已存在,跳过同步。tenantId={}, tableName={}", tenantId, onlFormHead.getTableName());
} }
} }
} else if (StrUtil.equals(messageCommand, TenantConstant.DELETE_TENANT_ONL_FORM_HEAD_COMMAND)) { } else if (StrUtil.equals(messageCommand, TenantConstant.DELETE_TENANT_ONL_FORM_HEAD_COMMAND)) {
// 保留骨架:管理端表单元数据 tab 不再建设,本期不实现删除同步。
} }
} }
/**
* 安全地取集合字段:字段缺失或为空时返回空集合,避免 NPE。
*/
private <T> List<T> toList(JSONObject messageJsonData, String key, Class<T> clazz) {
com.alibaba.fastjson.JSONArray array = messageJsonData.getJSONArray(key);
return array == null ? java.util.Collections.emptyList() : array.toJavaList(clazz);
}
@Override @Override
public String handleMessageType() { public String handleMessageType() {
return OnlFormHead.class.getSimpleName(); return OnlFormHead.class.getSimpleName();

4
common/common-generator/src/main/java/apelet/common/generator/model/OnlCgreportHead.java

@ -1,6 +1,7 @@
package apelet.common.generator.model; package apelet.common.generator.model;
import apelet.common.core.base.model.BaseModel; import apelet.common.core.base.model.BaseModel;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@ -52,5 +53,6 @@ public class OnlCgreportHead extends BaseModel implements Serializable {
private Integer deletedFlag; private Integer deletedFlag;
@Schema(description = "租户id") @Schema(description = "租户id")
private String tenantId; @TableField(value = "tenant_id")
private Long tenantId;
} }

3
common/common-generator/src/main/java/apelet/common/generator/model/OnlFormHead.java

@ -115,7 +115,8 @@ public class OnlFormHead extends BaseModel implements Serializable {
private String metaTable; private String metaTable;
@Schema(description = "租户id") @Schema(description = "租户id")
private String tenantId; @TableField(value = "tenant_id")
private Long tenantId;
@Schema(description = "数据库属性分录") @Schema(description = "数据库属性分录")
@TableField(exist = false) @TableField(exist = false)

Loading…
Cancel
Save