You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3.9 KiB
3.9 KiB
04 · 值对象与上下文按模块化:DataVisibility / DataScopeLevel / DataVisibilityContext
Type: grilling Status: resolved Blocked by: 01
Question
DataVisibility(现承载单一 level + 部门集合)、DataScopeLevel、DataVisibilityContext
(ThreadLocal 放一份 DataVisibility)如何改造成「按模块」的结构?
要定的点:
- 上下文形态:ThreadLocal 从「一份 DataVisibility」变成「module → DataVisibility 的 map」? 还是「一份持有各模块档位的聚合对象」?
- 部门集合、expandedDeptIds(子树展开)是否可跨模块共享(同一用户部门集合不随模块变,仅档位变)—— 这决定改造能否只在「档位」维度分模块、而部门集合仍算一次。
DataVisibility的不可变/整体装入契约(ADR-0006「不存在设了一半」)如何在多模块下保持。DataScopeLevel枚举本身是否需要动(大概率不动,仅其"每模块一份")。currentScope()/currentOwnership()的签名如何变(读侧需按模块问 scope)。
依赖 01(模块标识)。与 05(拦截器)互相牵连,但结构决策在此先定。
Answer
方案 A:一个 DataVisibility 持有 Map<String, DataScopeLevel>
1. DataVisibility 结构变化
把单个 level 字段替换为 Map<String, DataScopeLevel> moduleLevels(key = module code,value = 档位)。
身份数据不变,只存一份:
public final class DataVisibility {
private final Long userId; // 不变
private final Long primaryDeptId; // 不变
private final List<Long> deptIds; // 不变
private final List<Long> expandedDeptIds; // 不变
private final Map<String, DataScopeLevel> moduleLevels; // 新:替代单个 level
}
Map.copyOf(moduleLevels)封装,不可变。- 空构造校验:
userId必填;moduleLevels必填但允许空 Map(空 = 所有模块走默认 SELF)。 expandedDeptIds校验放宽:只要任一模块的 level 是 DEPT_AND_CHILDREN 就要求非 null(空 List 可以,表示一律不可见)。
2. 方法签名变化
// 读侧:按模块取档位 → 折算 VisibilityScope
public VisibilityScope visibilityScope(String moduleCode) {
DataScopeLevel level = moduleLevels.getOrDefault(moduleCode, DataScopeLevel.SELF);
return switch (level) {
case SELF -> VisibilityScope.ownedBy(userId);
case DEPT -> departmentsOrNone(deptIds);
case DEPT_AND_CHILDREN -> departmentsOrNone(expandedDeptIds);
case ALL -> VisibilityScope.allVisible();
};
}
// 写侧:不变
public DataOwnership dataOwnership() { ... } // 完全不动
3. DataVisibilityContext 变化
ThreadLocal 仍持有一份 DataVisibility,但 currentScope() 加参数:
public static VisibilityScope currentScope(String moduleCode) {
DataVisibility visibility = CURRENT.get();
return visibility != null
? visibility.visibilityScope(moduleCode)
: VisibilityScope.allVisible();
}
// currentOwnership() 完全不变
public static Optional<DataOwnership> currentOwnership() { ... }
4. 部门集合只算一次
deptIds / expandedDeptIds 是用户级的(主部门 + 兼职并集 + 子树展开),与模块无关。
PermissionResolver 算一次,存入 DataVisibility。各模块的档位决定用不用这组部门 ID,不需要重算。
5. DataScopeLevel 枚举不动
四个值(SELF/DEPT/DEPT_AND_CHILDREN/ALL)不变,每模块各选一个。枚举本身无需改。
6. ADR-0006(不存在设了一半)保持
DataVisibility 仍不可变、构造成功即完整。Map 用 Map.copyOf 封装。空 Map 是合法状态(所有模块走 SELF)。不存在「设了一半」——要么整个上下文没有(无登录),要么整个上下文有(带完整的 moduleLevels map)。