4.10 团队空间的基本CRUD

This commit is contained in:
zhangsan 2025-04-10 19:32:12 +08:00
parent 00c871f41e
commit 41760e047d
25 changed files with 782 additions and 27 deletions

View File

@ -93,4 +93,25 @@ CREATE INDEX idx_spaceId ON picture (space_id);
-- 添加新列
ALTER TABLE picture
ADD COLUMN pic_color varchar(16) null comment '图片主色调';
ADD COLUMN pic_color varchar(16) null comment '图片主色调';
-- 支持空间类型,添加新列
ALTER TABLE space
ADD COLUMN space_type int default 0 not null comment '空间类型0-私有 1-团队';
CREATE INDEX idx_spaceType ON space (space_type);
-- 空间成员表
create table if not exists space_user
(
id bigint auto_increment comment 'id' primary key,
space_id bigint not null comment '空间 id',
user_id bigint not null comment '用户 id',
space_role varchar(128) default 'viewer' null comment '空间角色viewer/editor/admin',
create_time datetime default CURRENT_TIMESTAMP not null comment '创建时间',
update_time datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
-- 索引设计
UNIQUE KEY uk_spaceId_userId (space_id, user_id), -- 唯一索引,用户在一个空间中只能有一个角色
INDEX idx_spaceId (space_id), -- 提升按空间查询的性能
INDEX idx_userId (user_id) -- 提升按用户查询的性能
) comment '空间用户关联' collate = utf8mb4_unicode_ci;

View File

@ -0,0 +1,136 @@
package edu.whut.smilepicturebackend.controller;
import cn.hutool.core.util.ObjectUtil;
import edu.whut.smilepicturebackend.common.BaseResponse;
import edu.whut.smilepicturebackend.common.DeleteRequest;
import edu.whut.smilepicturebackend.common.ResultUtils;
import edu.whut.smilepicturebackend.exception.BusinessException;
import edu.whut.smilepicturebackend.exception.ErrorCode;
import edu.whut.smilepicturebackend.exception.ThrowUtils;
import edu.whut.smilepicturebackend.model.dto.spaceuser.SpaceUserAddRequest;
import edu.whut.smilepicturebackend.model.dto.spaceuser.SpaceUserEditRequest;
import edu.whut.smilepicturebackend.model.dto.spaceuser.SpaceUserQueryRequest;
import edu.whut.smilepicturebackend.model.entity.SpaceUser;
import edu.whut.smilepicturebackend.model.entity.User;
import edu.whut.smilepicturebackend.model.vo.SpaceUserVO;
import edu.whut.smilepicturebackend.service.SpaceUserService;
import edu.whut.smilepicturebackend.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* 空间成员管理
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/spaceUser")
@Slf4j
public class SpaceUserController {
private final SpaceUserService spaceUserService;
private final UserService userService;
/**
* 添加成员到空间
*/
@PostMapping("/add")
public BaseResponse<Long> addSpaceUser(@RequestBody SpaceUserAddRequest spaceUserAddRequest, HttpServletRequest request) {
ThrowUtils.throwIf(spaceUserAddRequest == null, ErrorCode.PARAMS_ERROR);
long id = spaceUserService.addSpaceUser(spaceUserAddRequest);
return ResultUtils.success(id);
}
/**
* 从空间移除成员
*/
@PostMapping("/delete")
public BaseResponse<Boolean> deleteSpaceUser(@RequestBody DeleteRequest deleteRequest,
HttpServletRequest request) {
if (deleteRequest == null || deleteRequest.getId() <= 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
long id = deleteRequest.getId();
// 判断是否存在
SpaceUser oldSpaceUser = spaceUserService.getById(id);
ThrowUtils.throwIf(oldSpaceUser == null, ErrorCode.NOT_FOUND_ERROR);
// 操作数据库
boolean result = spaceUserService.removeById(id);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
return ResultUtils.success(true);
}
/**
* 查询某个成员在某个空间的信息
*/
@PostMapping("/get")
public BaseResponse<SpaceUser> getSpaceUser(@RequestBody SpaceUserQueryRequest spaceUserQueryRequest) {
// 参数校验
ThrowUtils.throwIf(spaceUserQueryRequest == null, ErrorCode.PARAMS_ERROR);
Long spaceId = spaceUserQueryRequest.getSpaceId();
Long userId = spaceUserQueryRequest.getUserId();
ThrowUtils.throwIf(ObjectUtil.hasEmpty(spaceId, userId), ErrorCode.PARAMS_ERROR);
// 查询数据库
SpaceUser spaceUser = spaceUserService.getOne(spaceUserService.getQueryWrapper(spaceUserQueryRequest));
ThrowUtils.throwIf(spaceUser == null, ErrorCode.NOT_FOUND_ERROR);
return ResultUtils.success(spaceUser);
}
/**
* 查询成员信息列表
*/
@PostMapping("/list")
public BaseResponse<List<SpaceUserVO>> listSpaceUser(@RequestBody SpaceUserQueryRequest spaceUserQueryRequest,
HttpServletRequest request) {
ThrowUtils.throwIf(spaceUserQueryRequest == null, ErrorCode.PARAMS_ERROR);
List<SpaceUser> spaceUserList = spaceUserService.list(
spaceUserService.getQueryWrapper(spaceUserQueryRequest)
);
return ResultUtils.success(spaceUserService.getSpaceUserVOList(spaceUserList));
}
/**
* 编辑成员信息设置权限
*/
@PostMapping("/edit")
public BaseResponse<Boolean> editSpaceUser(@RequestBody SpaceUserEditRequest spaceUserEditRequest,
HttpServletRequest request) {
if (spaceUserEditRequest == null || spaceUserEditRequest.getId() <= 0) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
// 将实体类和 DTO 进行转换
SpaceUser spaceUser = new SpaceUser();
BeanUtils.copyProperties(spaceUserEditRequest, spaceUser);
// 数据校验
spaceUserService.validSpaceUser(spaceUser, false);
// 判断是否存在
long id = spaceUserEditRequest.getId();
SpaceUser oldSpaceUser = spaceUserService.getById(id);
ThrowUtils.throwIf(oldSpaceUser == null, ErrorCode.NOT_FOUND_ERROR);
// 操作数据库
boolean result = spaceUserService.updateById(spaceUser);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
return ResultUtils.success(true);
}
/**
* 查询我加入的团队空间列表
*/
@PostMapping("/list/my")
public BaseResponse<List<SpaceUserVO>> listMyTeamSpace(HttpServletRequest request) {
User loginUser = userService.getLoginUser(request);
SpaceUserQueryRequest spaceUserQueryRequest = new SpaceUserQueryRequest();
spaceUserQueryRequest.setUserId(loginUser.getId());
List<SpaceUser> spaceUserList = spaceUserService.list(
spaceUserService.getQueryWrapper(spaceUserQueryRequest)
);
return ResultUtils.success(spaceUserService.getSpaceUserVOList(spaceUserList));
}
}

View File

@ -6,7 +6,6 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @author 张三
* @description 针对表picture(图片)的数据库操作Mapper
* @createDate 2025-06-11 11:23:11
* @Entity edu.whut.smilepicturebackend.model.entity.Picture
*/
public interface PictureMapper extends BaseMapper<Picture> {

View File

@ -5,7 +5,6 @@ import edu.whut.smilepicturebackend.model.entity.Space;
/**
* @author 张三
* @description 针对表space(空间)的数据库操作Mapper
* @createDate 2025-06-16 16:49:09
* @Entity generator.domain.Space
*/
public interface SpaceMapper extends BaseMapper<Space> {

View File

@ -0,0 +1,17 @@
package edu.whut.smilepicturebackend.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import edu.whut.smilepicturebackend.model.entity.SpaceUser;
/**
* @author 张三
* @description 针对表space_user(空间用户关联)的数据库操作Mapper
* @Entity generator.domain.SpaceUser
*/
public interface SpaceUserMapper extends BaseMapper<SpaceUser> {
}

View File

@ -6,7 +6,6 @@ import edu.whut.smilepicturebackend.model.entity.User;
/**
* @author 张三
* @description 针对表user(用户)的数据库操作Mapper
* @createDate 2025-06-05 17:43:52
*/
public interface UserMapper extends BaseMapper<User> {

View File

@ -0,0 +1,29 @@
package edu.whut.smilepicturebackend.model.dto.spaceuser;
import lombok.Data;
import java.io.Serializable;
/**
* 创建空间成员请求
*/
@Data
public class SpaceUserAddRequest implements Serializable {
/**
* 空间 ID
*/
private Long spaceId;
/**
* 用户 ID
*/
private Long userId;
/**
* 空间角色viewer/editor/admin
*/
private String spaceRole;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,24 @@
package edu.whut.smilepicturebackend.model.dto.spaceuser;
import lombok.Data;
import java.io.Serializable;
/**
* 编辑空间成员请求
*/
@Data
public class SpaceUserEditRequest implements Serializable {
/**
* id
*/
private Long id;
/**
* 空间角色viewer/editor/admin
*/
private String spaceRole;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,34 @@
package edu.whut.smilepicturebackend.model.dto.spaceuser;
import lombok.Data;
import java.io.Serializable;
/**
* 空间用户查询请求
*/
@Data
public class SpaceUserQueryRequest implements Serializable {
/**
* ID
*/
private Long id;
/**
* 空间 ID
*/
private Long spaceId;
/**
* 用户 ID
*/
private Long userId;
/**
* 空间角色viewer/editor/admin
*/
private String spaceRole;
private static final long serialVersionUID = 1L;
}

View File

@ -29,6 +29,11 @@ public class Space implements Serializable {
*/
private Integer spaceLevel;
/**
* 空间类型0-私有 1-团队
*/
private Integer spaceType;
/**
* 空间图片的最大总大小
*/

View File

@ -0,0 +1,52 @@
package edu.whut.smilepicturebackend.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 空间用户关联
* @TableName space_user
*/
@TableName(value ="space_user")
@Data
public class SpaceUser implements Serializable {
/**
* id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 空间 id
*/
private Long spaceId;
/**
* 用户 id
*/
private Long userId;
/**
* 空间角色viewer/editor/admin
*/
private String spaceRole;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,68 @@
package edu.whut.smilepicturebackend.model.enums;
import cn.hutool.core.util.ObjUtil;
import lombok.Getter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 空间角色枚举
*/
@Getter
public enum SpaceRoleEnum {
VIEWER("浏览者", "viewer"),
EDITOR("编辑者", "editor"),
ADMIN("管理员", "admin");
private final String text;
private final String value;
SpaceRoleEnum(String text, String value) {
this.text = text;
this.value = value;
}
/**
* 根据 value 获取枚举
*
* @param value 枚举值的 value
* @return 枚举值
*/
public static SpaceRoleEnum getEnumByValue(String value) {
if (ObjUtil.isEmpty(value)) {
return null;
}
for (SpaceRoleEnum anEnum : SpaceRoleEnum.values()) {
if (anEnum.value.equals(value)) {
return anEnum;
}
}
return null;
}
/**
* 获取所有枚举的文本列表
*
* @return 文本列表
*/
public static List<String> getAllTexts() {
return Arrays.stream(SpaceRoleEnum.values())
.map(SpaceRoleEnum::getText)
.collect(Collectors.toList());
}
/**
* 获取所有枚举的值列表
*
* @return 值列表
*/
public static List<String> getAllValues() {
return Arrays.stream(SpaceRoleEnum.values())
.map(SpaceRoleEnum::getValue)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,38 @@
package edu.whut.smilepicturebackend.model.enums;
import cn.hutool.core.util.ObjUtil;
import lombok.Getter;
/**
* 空间类型枚举类
*/
@Getter
public enum SpaceTypeEnum {
PRIVATE("私有空间", 0),
TEAM("团队空间", 1);
private final String text;
private final int value;
SpaceTypeEnum(String text, int value) {
this.text = text;
this.value = value;
}
/**
* 根据 value 获取枚举
*/
public static SpaceTypeEnum getEnumByValue(Integer value) {
if (ObjUtil.isEmpty(value)) {
return null;
}
for (SpaceTypeEnum spaceTypeEnum : SpaceTypeEnum.values()) {
if (spaceTypeEnum.value == value) {
return spaceTypeEnum;
}
}
return null;
}
}

View File

@ -0,0 +1,86 @@
package edu.whut.smilepicturebackend.model.vo;
import edu.whut.smilepicturebackend.model.entity.SpaceUser;
import lombok.Data;
import org.springframework.beans.BeanUtils;
import java.io.Serializable;
import java.util.Date;
/**
* 空间成员响应类
*/
@Data
public class SpaceUserVO implements Serializable {
/**
* id
*/
private Long id;
/**
* 空间 id
*/
private Long spaceId;
/**
* 用户 id
*/
private Long userId;
/**
* 空间角色viewer/editor/admin
*/
private String spaceRole;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 用户信息
*/
private UserVO user;
/**
* 空间信息
*/
private SpaceVO space;
private static final long serialVersionUID = 1L;
/**
* 封装类转对象
*
* @param spaceUserVO
* @return
*/
public static SpaceUser voToObj(SpaceUserVO spaceUserVO) {
if (spaceUserVO == null) {
return null;
}
SpaceUser spaceUser = new SpaceUser();
BeanUtils.copyProperties(spaceUserVO, spaceUser);
return spaceUser;
}
/**
* 对象转封装类
*
* @param spaceUser
* @return
*/
public static SpaceUserVO objToVo(SpaceUser spaceUser) {
if (spaceUser == null) {
return null;
}
SpaceUserVO spaceUserVO = new SpaceUserVO();
BeanUtils.copyProperties(spaceUser, spaceUserVO);
return spaceUserVO;
}
}

View File

@ -19,7 +19,6 @@ import java.util.List;
/**
* @author 张三
* @description 针对表picture(图片)的数据库操作Service
* @createDate 2025-06-11 11:23:11
*/
public interface PictureService extends IService<Picture> {
/**

View File

@ -3,15 +3,10 @@ import com.baomidou.mybatisplus.extension.service.IService;
import edu.whut.smilepicturebackend.model.dto.space.analyze.*;
import edu.whut.smilepicturebackend.model.entity.Space;
import edu.whut.smilepicturebackend.model.entity.User;
import edu.whut.smilepicturebackend.model.vo.analyze.*;
import edu.whut.smilepicturebackend.model.vo.space.analyze.*;
import java.util.List;
/**
* @author 李鱼皮
* @createDate 2024-12-18 19:53:34
*/
public interface SpaceAnalyzeService extends IService<Space> {
/**

View File

@ -15,7 +15,6 @@ import javax.servlet.http.HttpServletRequest;
/**
* @author 张三
* @description 针对表space(空间)的数据库操作Service
* @createDate 2025-06-16 16:49:09
*/
public interface SpaceService extends IService<Space> {
/**

View File

@ -0,0 +1,59 @@
package edu.whut.smilepicturebackend.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import edu.whut.smilepicturebackend.model.dto.spaceuser.SpaceUserAddRequest;
import edu.whut.smilepicturebackend.model.dto.spaceuser.SpaceUserQueryRequest;
import edu.whut.smilepicturebackend.model.entity.SpaceUser;
import edu.whut.smilepicturebackend.model.vo.SpaceUserVO;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* @author 张三
* @description 针对表space_user(空间用户关联)的数据库操作Service
*/
public interface SpaceUserService extends IService<SpaceUser> {
/**
* 创建空间成员
*
* @param spaceUserAddRequest
* @return
*/
long addSpaceUser(SpaceUserAddRequest spaceUserAddRequest);
/**
* 校验空间成员
*
* @param spaceUser
* @param add 是否为创建时检验
*/
void validSpaceUser(SpaceUser spaceUser, boolean add);
/**
* 获取空间成员包装类单条
*
* @param spaceUser
* @param request
* @return
*/
SpaceUserVO getSpaceUserVO(SpaceUser spaceUser, HttpServletRequest request);
/**
* 获取空间成员包装类列表
*
* @param spaceUserList
* @return
*/
List<SpaceUserVO> getSpaceUserVOList(List<SpaceUser> spaceUserList);
/**
* 获取查询对象
*
* @param spaceUserQueryRequest
* @return
*/
LambdaQueryWrapper<SpaceUser> getQueryWrapper(SpaceUserQueryRequest spaceUserQueryRequest);
}

View File

@ -15,7 +15,6 @@ import java.util.List;
/**
* @author 张三
* @description 针对表user(用户)的数据库操作Service
* @createDate 2025-06-05 17:43:52
*/
public interface UserService extends IService<User> {
/**

View File

@ -13,7 +13,6 @@ import edu.whut.smilepicturebackend.model.dto.space.analyze.*;
import edu.whut.smilepicturebackend.model.entity.Picture;
import edu.whut.smilepicturebackend.model.entity.Space;
import edu.whut.smilepicturebackend.model.entity.User;
import edu.whut.smilepicturebackend.model.vo.analyze.*;
import edu.whut.smilepicturebackend.model.vo.space.analyze.*;
import edu.whut.smilepicturebackend.service.PictureService;
import edu.whut.smilepicturebackend.service.SpaceAnalyzeService;
@ -28,8 +27,7 @@ import java.util.Map;
import java.util.stream.Collectors;
/**
* @author 李鱼皮
* @createDate 2024-12-18 19:53:34
* @author 张三
*/
@Service
@RequiredArgsConstructor

View File

@ -16,11 +16,15 @@ import edu.whut.smilepicturebackend.mapper.SpaceMapper;
import edu.whut.smilepicturebackend.model.dto.space.SpaceAddRequest;
import edu.whut.smilepicturebackend.model.dto.space.SpaceQueryRequest;
import edu.whut.smilepicturebackend.model.entity.Space;
import edu.whut.smilepicturebackend.model.entity.SpaceUser;
import edu.whut.smilepicturebackend.model.entity.User;
import edu.whut.smilepicturebackend.model.enums.SpaceLevelEnum;
import edu.whut.smilepicturebackend.model.enums.SpaceRoleEnum;
import edu.whut.smilepicturebackend.model.enums.SpaceTypeEnum;
import edu.whut.smilepicturebackend.model.vo.SpaceVO;
import edu.whut.smilepicturebackend.model.vo.UserVO;
import edu.whut.smilepicturebackend.service.SpaceService;
import edu.whut.smilepicturebackend.service.SpaceUserService;
import edu.whut.smilepicturebackend.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
@ -39,7 +43,6 @@ import java.util.stream.Collectors;
/**
* @author 张三
* @description 针对表space(空间)的数据库操作Service实现
* @createDate 2025-06-16 16:49:09
*/
@Service
@RequiredArgsConstructor
@ -48,13 +51,9 @@ public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space>
private final UserService userService;
// 静态锁表JVM 级别共享
private static final ConcurrentHashMap<Long, Object> USER_LOCKS = new ConcurrentHashMap<>();
private final SpaceUserService spaceUserService;
private final TransactionTemplate transactionTemplate;
// 为了方便部署注释掉分表
// @Resource
// @Lazy
// private DynamicShardingManager dynamicShardingManager;
/**
* 创建空间 加锁和事务
*
@ -74,6 +73,9 @@ public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space>
if (space.getSpaceLevel() == null) {
space.setSpaceLevel(SpaceLevelEnum.COMMON.getValue());
}
if (space.getSpaceType() == null) {
space.setSpaceType(SpaceTypeEnum.PRIVATE.getValue());
}
// 填充容量和大小
this.fillSpaceBySpaceLevel(space);
// 2. 校验参数
@ -93,12 +95,21 @@ public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space>
Long newSpaceId = transactionTemplate.execute(status -> {
boolean exists = this.lambdaQuery()
.eq(Space::getUserId, userId)
.eq(Space::getSpaceType, space.getSpaceType())
.exists();
ThrowUtils.throwIf(exists, ErrorCode.OPERATION_ERROR, "每个用户每类空间只能创建一个");
boolean result = this.save(space);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "保存空间到数据库失败");
// 创建成功后如果是团队空间默认将创建人加入团队且视为管理员
if (SpaceTypeEnum.TEAM.getValue() == space.getSpaceType()) {
SpaceUser spaceUser = new SpaceUser();
spaceUser.setSpaceId(space.getId());
spaceUser.setUserId(userId);
spaceUser.setSpaceRole(SpaceRoleEnum.ADMIN.getValue());
result = spaceUserService.save(spaceUser);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "创建团队成员记录失败");
}
return space.getId();
});
return Optional.ofNullable(newSpaceId).orElse(-1L);
@ -116,6 +127,8 @@ public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space>
String spaceName = space.getSpaceName();
Integer spaceLevel = space.getSpaceLevel();
SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(spaceLevel);
Integer spaceType = space.getSpaceType();
SpaceTypeEnum spaceTypeEnum = SpaceTypeEnum.getEnumByValue(spaceType);
// 创建时校验
if (add) {
@ -125,6 +138,9 @@ public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space>
if (spaceLevel == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间级别不能为空");
}
if (spaceType == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间类别不能为空");
}
}
// 修改数据时空间名称进行校验
if (StrUtil.isNotBlank(spaceName) && spaceName.length() > 30) {
@ -134,6 +150,10 @@ public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space>
if (spaceLevel != null && spaceLevelEnum == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间级别不存在");
}
// 修改数据时空间类别进行校验
if (spaceType != null && spaceTypeEnum == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间类别不存在");
}
}
@Override
@ -190,10 +210,11 @@ public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space>
LambdaQueryWrapper<Space> qw = Wrappers.lambdaQuery(Space.class);
// 基本等值与模糊匹配
qw.eq(ObjUtil.isNotNull(req.getId()), Space::getId, req.getId())
.eq(ObjUtil.isNotNull(req.getUserId()), Space::getUserId, req.getUserId())
qw.eq(ObjUtil.isNotEmpty(req.getId()), Space::getId, req.getId())
.eq(ObjUtil.isNotEmpty(req.getUserId()), Space::getUserId, req.getUserId())
.like(StrUtil.isNotBlank(req.getSpaceName()), Space::getSpaceName, req.getSpaceName())
.eq(ObjUtil.isNotNull(req.getSpaceLevel()), Space::getSpaceLevel, req.getSpaceLevel());
.eq(ObjUtil.isNotEmpty(req.getSpaceLevel()), Space::getSpaceLevel, req.getSpaceLevel())
.eq(ObjUtil.isNotEmpty(req.getSpaceType()), Space::getSpaceType,req.getSpaceType());
// 动态排序将驼峰字段转成下划线再拼到 SQL ORDER BY
if (StrUtil.isNotBlank(req.getSortField())) {

View File

@ -0,0 +1,158 @@
package edu.whut.smilepicturebackend.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import edu.whut.smilepicturebackend.exception.BusinessException;
import edu.whut.smilepicturebackend.exception.ErrorCode;
import edu.whut.smilepicturebackend.exception.ThrowUtils;
import edu.whut.smilepicturebackend.mapper.SpaceUserMapper;
import edu.whut.smilepicturebackend.model.dto.spaceuser.SpaceUserAddRequest;
import edu.whut.smilepicturebackend.model.dto.spaceuser.SpaceUserQueryRequest;
import edu.whut.smilepicturebackend.model.entity.Space;
import edu.whut.smilepicturebackend.model.entity.SpaceUser;
import edu.whut.smilepicturebackend.model.entity.User;
import edu.whut.smilepicturebackend.model.enums.SpaceRoleEnum;
import edu.whut.smilepicturebackend.model.vo.SpaceUserVO;
import edu.whut.smilepicturebackend.model.vo.SpaceVO;
import edu.whut.smilepicturebackend.model.vo.UserVO;
import edu.whut.smilepicturebackend.service.SpaceService;
import edu.whut.smilepicturebackend.service.SpaceUserService;
import edu.whut.smilepicturebackend.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author 张三
* @description 针对表space_user(空间用户关联)的数据库操作Service实现
*/
@Service
@RequiredArgsConstructor
public class SpaceUserServiceImpl extends ServiceImpl<SpaceUserMapper, SpaceUser>
implements SpaceUserService {
private final UserService userService;
@Lazy
private final SpaceService spaceService;
@Override
public long addSpaceUser(SpaceUserAddRequest spaceUserAddRequest) {
// 参数校验
ThrowUtils.throwIf(spaceUserAddRequest == null, ErrorCode.PARAMS_ERROR);
SpaceUser spaceUser = new SpaceUser();
BeanUtils.copyProperties(spaceUserAddRequest, spaceUser);
validSpaceUser(spaceUser, true);
// 数据库操作
boolean result = this.save(spaceUser);
ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
return spaceUser.getId();
}
@Override
public void validSpaceUser(SpaceUser spaceUser, boolean add) {
ThrowUtils.throwIf(spaceUser == null, ErrorCode.PARAMS_ERROR);
// 创建时空间 id 和用户 id 必填
Long spaceId = spaceUser.getSpaceId();
Long userId = spaceUser.getUserId();
if (add) {
ThrowUtils.throwIf(ObjectUtil.hasEmpty(spaceId, userId), ErrorCode.PARAMS_ERROR);
User user = userService.getById(userId);
ThrowUtils.throwIf(user == null, ErrorCode.NOT_FOUND_ERROR, "用户不存在");
Space space = spaceService.getById(spaceId);
ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
}
// 校验空间角色
String spaceRole = spaceUser.getSpaceRole();
SpaceRoleEnum spaceRoleEnum = SpaceRoleEnum.getEnumByValue(spaceRole);
if (spaceRole != null && spaceRoleEnum == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间角色不存在");
}
}
@Override
public SpaceUserVO getSpaceUserVO(SpaceUser spaceUser, HttpServletRequest request) {
// 对象转封装类
SpaceUserVO spaceUserVO = SpaceUserVO.objToVo(spaceUser);
// 关联查询用户信息
Long userId = spaceUser.getUserId();
if (userId != null && userId > 0) {
User user = userService.getById(userId);
UserVO userVO = userService.getUserVO(user);
spaceUserVO.setUser(userVO);
}
// 关联查询空间信息
Long spaceId = spaceUser.getSpaceId();
if (spaceId != null && spaceId > 0) {
Space space = spaceService.getById(spaceId);
SpaceVO spaceVO = spaceService.getSpaceVO(space, request);
spaceUserVO.setSpace(spaceVO);
}
return spaceUserVO;
}
@Override
public List<SpaceUserVO> getSpaceUserVOList(List<SpaceUser> spaceUserList) {
// 判断输入列表是否为空
if (CollUtil.isEmpty(spaceUserList)) {
return Collections.emptyList();
}
// 对象列表 => 封装对象列表
List<SpaceUserVO> spaceUserVOList = spaceUserList.stream().map(SpaceUserVO::objToVo).collect(Collectors.toList());
// 1. 收集需要关联查询的用户 ID 和空间 ID
Set<Long> userIdSet = spaceUserList.stream().map(SpaceUser::getUserId).collect(Collectors.toSet());
Set<Long> spaceIdSet = spaceUserList.stream().map(SpaceUser::getSpaceId).collect(Collectors.toSet());
// 2. 批量查询用户和空间
Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
.collect(Collectors.groupingBy(User::getId));
Map<Long, List<Space>> spaceIdSpaceListMap = spaceService.listByIds(spaceIdSet).stream()
.collect(Collectors.groupingBy(Space::getId));
// 3. 填充 SpaceUserVO 的用户和空间信息
spaceUserVOList.forEach(spaceUserVO -> {
Long userId = spaceUserVO.getUserId();
Long spaceId = spaceUserVO.getSpaceId();
// 填充用户信息
User user = null;
if (userIdUserListMap.containsKey(userId)) {
user = userIdUserListMap.get(userId).get(0);
}
spaceUserVO.setUser(userService.getUserVO(user));
// 填充空间信息
Space space = null;
if (spaceIdSpaceListMap.containsKey(spaceId)) {
space = spaceIdSpaceListMap.get(spaceId).get(0);
}
spaceUserVO.setSpace(SpaceVO.objToVo(space));
});
return spaceUserVOList;
}
@Override
public LambdaQueryWrapper<SpaceUser> getQueryWrapper(SpaceUserQueryRequest req) {
if (req == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "请求参数为空");
}
LambdaQueryWrapper<SpaceUser> qw = Wrappers.lambdaQuery(SpaceUser.class);
qw.eq(ObjUtil.isNotEmpty(req.getId()), SpaceUser::getId, req.getId())
.eq(ObjUtil.isNotEmpty(req.getSpaceId()), SpaceUser::getSpaceId, req.getSpaceId())
.eq(ObjUtil.isNotEmpty(req.getUserId()), SpaceUser::getUserId, req.getUserId())
.eq(ObjUtil.isNotEmpty(req.getSpaceRole()),SpaceUser::getSpaceRole, req.getSpaceRole());
return qw;
}
}

View File

@ -37,7 +37,6 @@ import java.util.stream.Collectors;
/**
* @author 张三
* @description 针对表user(用户)的数据库操作Service实现
* @createDate 2025-06-05 17:43:52
*/
@Service
@Slf4j

View File

@ -8,6 +8,7 @@
<id property="id" column="id" jdbcType="BIGINT"/>
<result property="spaceName" column="space_name" jdbcType="VARCHAR"/>
<result property="spaceLevel" column="space_level" jdbcType="INTEGER"/>
<result property="spaceType" column="space_type" jdbcType="INTEGER"/>
<result property="maxSize" column="max_size" jdbcType="BIGINT"/>
<result property="maxCount" column="max_count" jdbcType="BIGINT"/>
<result property="totalSize" column="total_size" jdbcType="BIGINT"/>
@ -20,7 +21,7 @@
</resultMap>
<sql id="Base_Column_List">
id,space_name,space_level,
id,space_name,space_level,space_type,
max_size,max_count,total_size,
total_count,user_id,create_time,
edit_time,update_time,is_delete

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="edu.whut.smilepicturebackend.mapper.SpaceUserMapper">
<resultMap id="BaseResultMap" type="edu.whut.smilepicturebackend.model.entity.SpaceUser">
<id property="id" column="id" jdbcType="BIGINT"/>
<result property="spaceId" column="space_id" jdbcType="BIGINT"/>
<result property="userId" column="user_id" jdbcType="BIGINT"/>
<result property="spaceRole" column="space_role" jdbcType="VARCHAR"/>
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
id,space_id,user_id,
space_role,create_time,update_time
</sql>
</mapper>