外观
工作空间重点文件与方法
重点覆盖空间、成员、邀请三个服务及 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
直接声明查询构造、重名校验、删除前置和默认初始化四个方法;没有覆盖 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
实现上方全部服务方法,并覆盖 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
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
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。 | 不存在抛业务异常。 |
使用前核对
先按快速开始完成依赖和数据库准备。当前新成员加入存在上述实现阻断,页面中的创建→邀请→加入流程用于说明接口顺序,不能据此宣称已能成功联调。正常路径及失败分支需在实现修正后重新验证;权限和事务差异也不能由配置开关自动补齐。