跳转到正文

工作空间重点文件与方法

重点覆盖空间、成员、邀请三个服务及 App/管理端 Controller。普通 CRUD 方法统一见 CRUD 方法参考,此处说明每个文件新增或覆盖的行为。

本页按重点文件查阅方法;表内方法名可打开源码。重载共享的约束写在表前,差异在各行说明。源码链接固定到核对版本,接入前提见快速开始

当前成员查询会阻断首次加入

WorkspaceUserServiceImpl 中名称以 query 开头的两项单条查询实际调用 getPoByWrapper。无成员或无所有者时会抛 business_not_found,不会返回 null。因此 join 中“未加入才插入”的分支在首次加入时到达不了,isAdmin/isOwner/contains 等也可能抛异常。下表按当前调用链说明,不把后续 null 分支当作有效行为。

WorkspaceService

源码:WorkspaceService;实现:WorkspaceServiceImpl

空间 CRUD 服务;扩展 initUserWorkspace 用于默认空间初始化。

方法 / 重载用途、参数与返回值注意事项
initUserWorkspace(Long userId)以 workspace:init:{userId} 加锁,查用户拥有的空间;有默认空间则返回,否则插入默认空间并尝试加入 OWNER。无覆盖两次写入的事务;首次成员加入受上方查询问题影响,可能留下未绑定的空间。

WorkspaceServiceImpl

源码:WorkspaceServiceImpl

直接声明查询构造、重名校验、删除前置和默认初始化四个方法;没有覆盖 deleteById 来调用 beforeDelete。

方法 / 重载用途、参数与返回值注意事项
lambdaQueryWrapper(WorkspaceQuery query)按名称模糊、workspaceId 等值筛选;传 userId 时限定成员空间 ID,空成员列表用 id=-1 排除所有记录。不传 userId 不限制成员范围;按创建时间降序、ID 升序。
checkBefore()返回新增/更新共用函数,检查其他记录是否同名,冲突抛 NAME_IS_EXIST。整个表范围重名检查,不按用户区分;先查后写不保证并发唯一。
beforeDelete(Long pk)查空间,默认空间则抛 DEFAULT_CANNOT_DELETE。当前普通 deleteById/deleteByIdList 不调用此 Hook,不能据此宣称默认空间已受保护。
initUserWorkspace(Long userId)锁住单用户初始化,已有默认空间时不重复创建。数据库写入和成员加入不是整体事务,锁不保证失败回滚。

WorkspaceUserService

源码:WorkspaceUserService;实现:WorkspaceUserServiceImpl

成员关系服务。除显式校验的方法外,不检查“发起调用的人”是否管理员;内部 userId 是目标用户,不一定是当前用户。

方法 / 重载用途、参数与返回值注意事项
queryPoByUserIdAndWorkspaceId(Long userId, Long workspaceId)按用户与空间返回成员 PO。当前实现为必取,缺失抛异常;不要按 query 名称期待 null。
queryPoByWorkspaceIdForOwner(Long workspaceId)按空间和 OWNER 查询单条成员 PO。缺失抛异常,多 OWNER 也可能单条查询失败。
listPoByUserIdForOwner(Long userId)查询用户作为 OWNER 的成员关系列表,创建时间升序。返回成员 PO,不是空间 PO;无匹配为空列表。
listIdByUserIdForOwner(Long userId)返回用户拥有的空间 ID 列表。返回 fkWorkspaceId,不是成员关系表主键。
listWorkspaceIdByUserId(Long userId)列出用户加入的空间 ID,按权限、创建时间排序后去重。不验证对应空间是否已删除。
join(Long workspaceId, Long userId, ConstantWorkspace.Permission permission)以 inviteCode=null 委托四参数加入。当前首次加入会被必取查询阻断;不能用它验证正常新建流程已可用。
join(Long workspaceId, Long userId, ConstantWorkspace.Permission permission, String inviteCode)锁 join:{space}:{user};已有成员抛重复异常,否则意图写关系与邀请码。缺失时实际先抛 business_not_found;方法本身也不查用户/空间有效性或操作人权限。
remove(Long workspaceId, Long userId)查成员,非 OWNER 时删除关系;OWNER 抛 CANNOT_DELETE_OWNER。方法自身不校验调用者是管理员;缺失实际抛异常。
leave(Long workspaceId, Long userId)目标用户退出,OWNER 抛 CANNOT_QUIT_OWNER。服务不证明 userId 就是调用者,App Controller 负责取当前身份;缺失抛异常。
isAdmin(Long workspaceId, Long userId)成员为 OWNER 或 ADMIN 返回 true,其他已存在成员 false。缺失因必取抛异常,不一定 false。
isOwner(Long workspaceId, Long userId)已存在成员是否 OWNER。缺失抛异常。
transferOwner(Long workspaceId, Long originUserId, Long targetUserId)锁空间,校验原主体所有者、非默认空间和目标已有成员,再旧 OWNER→ADMIN、新成员→OWNER。两次更新无覆盖事务,失败可能只完成一半;不存在成员先触发查询异常。
updatePermission(Long workspaceUserId, ConstantWorkspace.Permission permission)按成员关系主键直接更新权限。不校验 OWNER/自己/管理员限制,也不检查更新行数。
updatePermission(Long userId, Long workspaceId, ConstantWorkspace.Permission permission)按用户和空间直接更新权限。这是两个 ID 的顺序,勿写反;不执行 DTO 或更新 Hook 校验。

WorkspaceUserServiceImpl

源码:WorkspaceUserServiceImpl

实现上方全部服务方法,并覆盖 Query 与列表补全。服务方法的参数、结果及异常逐项见上表,源码文件可查看锁内完整过程。

方法 / 重载用途、参数与返回值注意事项
lambdaQueryWrapper(WorkspaceUserQuery query)添加 userId/workspaceId 等值,创建时间及 ID 倒序。未传相应字段则不限制,不从 SessionUserUtil 自动补值。
afterList(List<WorkspaceUserVo> list)批量查空间和用户资料,回填 workspace/userInfo。仅对调用 afterList 的 Query/分页路径生效;Wrapper VO 列表不自动补全。

WorkspaceUserInviteService

源码:WorkspaceUserInviteService;实现:WorkspaceUserInviteServiceImpl

邀请码可复用的邀请服务;邀请码有效性与管理员操作校验分开。

方法 / 重载用途、参数与返回值注意事项
create(Long userId, Long workspaceId, ConstantWorkspace.Permission permission, LocalDateTime expiredTime)检查调用用户为管理员,生成 UUID 邀请码,enabled=1,写入 PO 并返回。直接调用不运行 DTO 校验;需保证到期时间非 null、权限允许邀请、空间有效。
queryPoByInviteCode(String inviteCode)按邀请码 queryPoByExtractor,缺失 null。不检查启用/到期,也不是消费邀请码。
join(Long userId, String inviteCode)查邀请;不存在、停用、已过期分别抛对应错误,再按邀请权限调用成员 join。成功后不禁用邀请码;null 到期时间会失败;首次成员加入目前仍受上方阻断问题影响。

WorkspaceUserInviteServiceImpl

源码:WorkspaceUserInviteServiceImpl

实现三项邀请方法,另覆盖以下 Query/VO 扩展。

方法 / 重载用途、参数与返回值注意事项
lambdaQueryWrapper(WorkspaceUserInviteQuery query)按邀请码和空间 ID 筛选,创建时间与 ID 倒序。不自动排除过期或停用邀请。
afterList(List<WorkspaceUserInviteVo> list)批量查询空间并回填 workspace。已删除空间可能没有映射对象。
afterGetVo(WorkspaceUserInviteVo vo)必取 VO 后补充对应空间,空 VO 返回 null。queryVoById 走 afterQueryVo,不自动使用此 Hook。

App Controller

下列方法统一返回 ResultModel;返回类型声明为 Boolean 的多个方法实际使用 R.success(),其 data 未赋值,不应期待 true。路径中的 ID 用 Long,调用前需完整接入登录与确认组件。

AppWorkspaceController

源码:AppWorkspaceController

HTTP 前缀 /api/app/workspace。列表限定当前用户,但更新和详情没有同等的成员范围校验。

方法 / 重载用途、参数与返回值注意事项
all(WorkspaceQuery query)POST /all,覆盖 query.userId 为当前用户,返回 VO 列表。query 必须非 null。
add(WorkspaceDto dto)POST /,验证 DTO,创建空间再将当前用户加入 OWNER。首次加入当前会失败,先建空间不回滚。
updateById(Long workspaceId, WorkspaceDto dto)PUT /id/{workspaceId},验证 DTO 后通用更新。当前未验证调用者是否该空间管理员/成员,应用开放前补齐范围限制。
deleteById(Long workspaceId)DELETE /id/{workspaceId},检查当前用户为 OWNER 后删除。有二次确认;beforeDelete 默认空间保护并未被服务默认删除调用。
getById(Long workspaceId)GET /id/{workspaceId},必取 VO。当前没有成员过滤。

AppWorkspaceUserController

源码:AppWorkspaceUserController

HTTP 前缀 /api/app/workspace/user。管理动作中有显式权限校验,成员分页则未先校验当前用户是否有该空间访问权。

方法 / 重载用途、参数与返回值注意事项
contains(Long workspaceId)POST /contains/workspace/id/{workspaceId},查询当前用户成员关系。不存在当前抛异常,不返回 data=false。
page(Long workspaceId, WorkspaceUserQuery query)POST /page/workspace/id/{workspaceId},覆盖 query.workspaceId,返回分页。没有校验当前用户属于该空间。
leave(Long workspaceId)DELETE /leave/workspace/id/{workspaceId},当前用户退出。OWNER 不可退出;缺失成员查询抛异常。
removeUser(Long workspaceId, Long userId)DELETE /remove/workspace/id/{workspaceId}/user/{userId},禁止移除自己,要求当前用户管理员。服务进一步禁止移除 OWNER。
transferOwner(Long workspaceId, Long userId)PUT /transfer/workspace/id/{workspaceId}/user/{userId},以当前用户为 origin 转让。使用服务校验,但多步更新无整体事务。
updatePermission(Long workspaceUserId, ConstantWorkspace.Permission permission)POST /update/id/{workspaceUserId}/permission/{permission},拒绝授 OWNER、修改 OWNER 或自己,再检查管理员。服务直接调用没有这些限制。

AppWorkspaceUserInviteController

源码:AppWorkspaceUserInviteController

HTTP 前缀 /api/app/workspace/user/invite。读取邀请不等于验证其仍可加入;创建和删除才显式检查管理员。

方法 / 重载用途、参数与返回值注意事项
page(Long workspaceId, WorkspaceUserInviteQuery query)POST /page/{workspaceId},按空间分页返回邀请 VO。没有先校验调用者为本空间成员或管理员。
add(WorkspaceUserInviteDto dto)POST /,验证 DTO、当前管理员身份后 create。返回新 VO,不返回可自动投递的邀请消息。
join(String inviteCode)POST /join/{inviteCode},以当前用户加入。存在当前成员查询阻断问题;邀请码不会自动销毁。
deleteById(Long id)DELETE /id/{id},必取邀请并按其空间校验管理员,再删除。不是仅凭知道 ID 就删除。
getById(Long id)GET /id/{id},必取邀请 VO。未校验当前用户的空间归属。
get(String inviteCode)GET /code/{inviteCode},查邀请并补充空间;缺失报错。不检查到期/启用,不能作为“可以加入”的判断。

AdminWorkspaceController

源码:AdminWorkspaceController

HTTP 前缀 /api/admin/workspace。使用管理端权限注解,不强制当前用户数据范围;空间成员的通用 CRUD 也不会自动运行 join/remove 的专用约束。

方法 / 重载用途、参数与返回值注意事项
all(WorkspaceQuery query)POST /all;返回完整 VO 列表。不是分页;按提交的查询范围读取。
page(WorkspaceQuery query)POST /page;返回 PageModel<VO>。Query 非 null;权限注解生效需已接入安全组件。
map(WorkspaceQuery query)POST /map;返回简要 MAP 列表。没有方法级 PermissionOperation,不能仅凭 admin 路径推断严格访问控制。
add(WorkspaceDto dto)POST /;验证 DTO 后新增。不自动建立空间 OWNER。
updateById(Long id, WorkspaceDto dto)PUT /id/{id};验证 DTO 后更新。不复用 App 的 OWNER/自己等约束。
deleteById(Long id)DELETE /id/{id};确认后按 ID 删除。不自动清理全部关联资料。
deleteByIds(IdsModel model)DELETE /ids;校验 ID 列表后批量删除。不逐条调用业务单条删除规则。
getById(Long id)GET /id/{id};必取详情 VO。不存在抛业务异常。

AdminWorkspaceUserController

源码:AdminWorkspaceUserController

HTTP 前缀 /api/admin/workspace/user。使用管理端权限注解,不强制当前用户数据范围;空间成员的通用 CRUD 也不会自动运行 join/remove 的专用约束。

方法 / 重载用途、参数与返回值注意事项
all(WorkspaceUserQuery query)POST /all;返回完整 VO 列表。不是分页;按提交的查询范围读取。
page(WorkspaceUserQuery query)POST /page;返回 PageModel<VO>。Query 非 null;权限注解生效需已接入安全组件。
map(WorkspaceUserQuery query)POST /map;返回简要 MAP 列表。没有方法级 PermissionOperation,不能仅凭 admin 路径推断严格访问控制。
add(WorkspaceUserDto dto)POST /;验证 DTO 后新增。不经过 join 的防重锁及成员检查。
updateById(Long id, WorkspaceUserDto dto)PUT /id/{id};验证 DTO 后更新。不复用 App 的 OWNER/自己等约束。
deleteById(Long id)DELETE /id/{id};确认后按 ID 删除。不自动清理全部关联资料。
deleteByIds(IdsModel model)DELETE /ids;校验 ID 列表后批量删除。不逐条调用业务单条删除规则。
getById(Long id)GET /id/{id};必取详情 VO。不存在抛业务异常。

使用前核对

先按快速开始完成依赖和数据库准备。当前新成员加入存在上述实现阻断,页面中的创建→邀请→加入流程用于说明接口顺序,不能据此宣称已能成功联调。正常路径及失败分支需在实现修正后重新验证;权限和事务差异也不能由配置开关自动补齐。