跳转到正文

空间管理

当前实现限制

WorkspaceUserServiceImpl.queryPoByUserIdAndWorkspaceIdqueryPoByWorkspaceIdForOwner 实际调用必取接口,无结果会抛异常。因此首次加入成员会在检查阶段失败,创建空间或默认初始化可能已先写入空间记录。本文的创建、邀请、加入步骤说明接口顺序;需先修正并验证该调用链才能跑通新成员流程。isAdminisOwnercontains 的缺失成员情况也可能抛异常,不能统一当作 false。详见重点文件与方法

App 端用于用户创建和查看参与的空间,管理端用于后台维护。首次接入先完成快速开始,再按本页选择入口。

接口约定

接口前缀为 /api/app//api/admin/,如应用配置了 context path,需在此前追加。标有请求体的接口使用 JSON;表中的返回值均位于 ResultModel<T>.data

内容约定
响应包装codemessagetsuccesstraceIddata;正常成功码为 00000
无数据操作R.success() 不赋值 data;接口声明 Boolean 也不代表返回 true
分页page 默认 1,rows 默认 10,最多 100;结果为 pagerowstotallistisLastPage
IDJava 类型 Long,数据库为 bigint;框架默认 MVC 序列化为字符串,前端应按字符串保存
时间LocalDateTime,默认 JSON 格式 yyyy-MM-dd HH:mm:ss,不携带时区偏移
角色接口使用 OWNERADMINMEMBER;数据库保存枚举 code,见成员与角色

空间、成员和邀请都使用逻辑删除字段 is_deleted(0 存在、1 删除)。删除接口不会物理清空记录,也不自动处理关联数据。

接口业务错误按 codemessage 处理;当前响应包装及二次确认处理可能仍将 success 置为 true,不能只判断这一字段。应用若自定义响应或序列化规则,以其实际配置为准。

公共响应、异常转换和 Long/日期格式的完整说明见 Base 使用与配置;分页和审计模型属于 Base Business,不由 Base 自动装配。

用户管理自己的空间

以下路径统一加前缀 /api/app/workspace

方法与路径请求体返回数据当前行为
POST /allWorkspaceQueryWorkspaceVo[]userId 覆盖为当前用户,只查已加入空间;没有成员关系时返回空列表
POST /WorkspaceDtoWorkspaceVo创建普通空间,另行将当前用户加入为所有者
GET /id/{workspaceId}WorkspaceVo按 ID 获取;当前没有成员身份校验
PUT /id/{workspaceId}WorkspaceDtoWorkspaceVo修改入口;当前没有成员身份校验,且存在下述 DTO 更新限制
DELETE /id/{workspaceId}无业务数据检查当前用户是该空间所有者,并执行二次确认

WorkspaceDto 接受 namecover。名称不能为空,服务按名称做全局重名检查,不是仅在当前用户的空间内查重;数据库未提供名称唯一索引。字段容量以表结构为准:名称 50、封面 300 字符,DTO 没有对应长度校验。

WorkspaceQuery 支持 name 模糊匹配、workspaceId 精确匹配、userId 对应的成员关系过滤。App 端覆盖客户端 userId;管理端保留传入的筛选条件。空间按创建时间倒序、ID 升序排列。虽然继承了 keywords,当前服务未配置该字段的搜索列,按名称搜索请使用 name

WorkspaceVo 提供 idnamecoverisDefault 及基础审计信息。当前空间查询没有填充其中预留的 userIdpermissionuserInfo,判断当前角色应查询成员关系。

修改与删除的当前边界

按 ID 读取、修改空间前,应用需要补充成员身份及角色校验,不能仅依赖 /api/app/ 路径。

当前通用更新链路 updateByDto → dto.toPo(oldPo) 会在 BaseEntityDto.toPo(entity, supplier) 中回调子类转换方法,工作空间 DTO 对非空旧对象会递归调用。因此现有空间修改接口不能视为可用的更新流程,应先修复转换逻辑,参见 DTO 转换边界。转换代码还会将 isDefault 设为 0,修复时需同时明确默认标记的保留规则。

删除只操作工作空间表,没有实现成员、邀请或应用业务数据的级联清理。默认空间删除检查虽然写在 beforeDelete 中,但当前基础服务的 deleteByIddeleteByIdList 直接调用 Mapper,没有执行该 Hook;不能依靠它保护默认空间。应用开放删除前应补充这些业务约束。

删除时的二次确认

App 空间删除和管理端空间、成员删除均标注了二次确认。组件默认启用,首次请求可能返回确认挑战,而没有执行删除。前端应展示响应 message,用户确认后,将响应 data.key 作为请求头名、data.token 作为值,原样重发相同请求,再按业务响应码判断结果。

管理后台维护空间

引入 springboot-business-workspace-controller-admin,路径统一加前缀 /api/admin/workspace

方法与路径请求体返回数据
POST /allWorkspaceQueryWorkspaceVo[]
POST /pageWorkspaceQueryPageModel<WorkspaceVo>
POST /mapWorkspaceQueryWorkspaceMapVo[],仅含 ID、名称、封面、默认标记
GET /id/{id}WorkspaceVo
POST /WorkspaceDtoWorkspaceVo
PUT /id/{id}WorkspaceDtoWorkspaceVo,受上述更新限制影响
DELETE /id/{id}无业务数据
DELETE /ids{"ids":["10001","10002"]}无业务数据

管理端使用 WORKSPACE 模块的操作权限注解,查询、详情、新增、修改、删除分别声明相应操作权限;/map 没有方法级操作权限注解。具体放行由应用认证与权限组件处理,管理端不自动限制为当前用户参与的空间。

管理端创建只写空间记录,不会像 App 创建那样自动绑定当前用户为所有者。需要可协作空间时,应由应用显式建立所有者关系,并保证整个操作的事务一致性。

初始化默认空间

默认空间通过 WorkspaceService.initUserWorkspace(userId) 显式初始化,没有对应 HTTP 接口,也没有在当前登录、注册流程中自动调用。可在应用自己的用户初始化服务中调用,例如:

java
import com.own.business.workspace.business.service.WorkspaceService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserWorkspaceInitializer {
    private final WorkspaceService workspaceService;

    public UserWorkspaceInitializer(WorkspaceService workspaceService) {
        this.workspaceService = workspaceService;
    }

    @Transactional(rollbackFor = Exception.class)
    public void initialize(Long userId) {
        workspaceService.initUserWorkspace(userId);
    }
}

将该类放入应用扫描范围,用户创建成功后通过 Spring 注入的 UserWorkspaceInitializer 调用 initialize(userId),传入实际系统用户 ID;不要通过同类自调用绕过事务代理。

初始化以用户 ID 加锁,检查用户拥有的空间中是否已有默认空间;已有则返回,否则创建名称为“默认工作空间”、isDefault=1 的空间,并将该用户加入为所有者。它直接插入数据,不经过普通创建的名称查重,因此不同用户可以各有同名默认空间。

默认空间的所有权转让会被拒绝;所有者退出也会被拒绝。其他成员的退出没有检查默认标记。默认空间删除及修改的限制见上文,不能将其描述为完全受保护的系统空间。