4.8 图库空间使用分析:私人和公共

This commit is contained in:
zhangsan 2025-04-08 19:51:38 +08:00
parent e40c4a975b
commit 00c871f41e
15 changed files with 798 additions and 0 deletions

View File

@ -0,0 +1,134 @@
package edu.whut.smilepicturebackend.controller;
import edu.whut.smilepicturebackend.common.BaseResponse;
import edu.whut.smilepicturebackend.common.ResultUtils;
import edu.whut.smilepicturebackend.exception.ErrorCode;
import edu.whut.smilepicturebackend.exception.ThrowUtils;
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 edu.whut.smilepicturebackend.service.SpaceAnalyzeService;
import edu.whut.smilepicturebackend.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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;
/**
* @author 程序员鱼皮 <a href="https://www.codefather.cn">编程导航原创项目</a>
*/
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/space/analyze")
public class SpaceAnalyzeController {
private final UserService userService;
private final SpaceAnalyzeService spaceAnalyzeService;
/**
* 获取空间的使用状态
*
* @param spaceUsageAnalyzeRequest
* @param request
* @return
*/
@PostMapping("/usage")
public BaseResponse<SpaceUsageAnalyzeResponse> getSpaceUsageAnalyze(
@RequestBody SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest,
HttpServletRequest request) {
ThrowUtils.throwIf(spaceUsageAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
User loginUser = userService.getLoginUser(request);
SpaceUsageAnalyzeResponse spaceUsageAnalyze = spaceAnalyzeService.getSpaceUsageAnalyze(spaceUsageAnalyzeRequest, loginUser);
return ResultUtils.success(spaceUsageAnalyze);
}
/**
* 获取空间图片分类分析
*
* @param spaceCategoryAnalyzeRequest
* @param request
* @return
*/
@PostMapping("/category")
public BaseResponse<List<SpaceCategoryAnalyzeResponse>> getSpaceCategoryAnalyze(
@RequestBody SpaceCategoryAnalyzeRequest spaceCategoryAnalyzeRequest,
HttpServletRequest request) {
ThrowUtils.throwIf(spaceCategoryAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
User loginUser = userService.getLoginUser(request);
List<SpaceCategoryAnalyzeResponse> spaceCategoryAnalyze = spaceAnalyzeService.getSpaceCategoryAnalyze(spaceCategoryAnalyzeRequest, loginUser);
return ResultUtils.success(spaceCategoryAnalyze);
}
/**
* 获取空间图片标签分析
*
* @param spaceTagAnalyzeRequest
* @param request
* @return
*/
@PostMapping("/tag")
public BaseResponse<List<SpaceTagAnalyzeResponse>> getSpaceTagAnalyze(
@RequestBody SpaceTagAnalyzeRequest spaceTagAnalyzeRequest,
HttpServletRequest request) {
ThrowUtils.throwIf(spaceTagAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
User loginUser = userService.getLoginUser(request);
List<SpaceTagAnalyzeResponse> spaceTagAnalyze = spaceAnalyzeService.getSpaceTagAnalyze(spaceTagAnalyzeRequest, loginUser);
return ResultUtils.success(spaceTagAnalyze);
}
/**
* 获取空间图片大小分析
*
* @param spaceSizeAnalyzeRequest
* @param request
* @return
*/
@PostMapping("/size")
public BaseResponse<List<SpaceSizeAnalyzeResponse>> getSpaceSizeAnalyze(@RequestBody SpaceSizeAnalyzeRequest spaceSizeAnalyzeRequest,
HttpServletRequest request) {
ThrowUtils.throwIf(spaceSizeAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
User loginUser = userService.getLoginUser(request);
List<SpaceSizeAnalyzeResponse> resultList = spaceAnalyzeService.getSpaceSizeAnalyze(spaceSizeAnalyzeRequest, loginUser);
return ResultUtils.success(resultList);
}
/**
* 获取空间用户行为分析
*
* @param spaceUserAnalyzeRequest
* @param request
* @return
*/
@PostMapping("/user")
public BaseResponse<List<SpaceUserAnalyzeResponse>> getSpaceUserAnalyze(@RequestBody SpaceUserAnalyzeRequest spaceUserAnalyzeRequest,
HttpServletRequest request) {
ThrowUtils.throwIf(spaceUserAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
User loginUser = userService.getLoginUser(request);
List<SpaceUserAnalyzeResponse> resultList = spaceAnalyzeService.getSpaceUserAnalyze(spaceUserAnalyzeRequest, loginUser);
return ResultUtils.success(resultList);
}
/**
* 获取空间使用排行分析
*
* @param spaceRankAnalyzeRequest
* @param request
* @return
*/
@PostMapping("/rank")
public BaseResponse<List<Space>> getSpaceRankAnalyze(@RequestBody SpaceRankAnalyzeRequest spaceRankAnalyzeRequest,
HttpServletRequest request) {
ThrowUtils.throwIf(spaceRankAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
User loginUser = userService.getLoginUser(request);
List<Space> resultList = spaceAnalyzeService.getSpaceRankAnalyze(spaceRankAnalyzeRequest, loginUser);
return ResultUtils.success(resultList);
}
}

View File

@ -0,0 +1,30 @@
package edu.whut.smilepicturebackend.model.dto.space.analyze;
import lombok.Data;
import java.io.Serializable;
/**
* 通用空间分析请求
* queryAll ->查全空间仅管理员 querypublic:查公共图库仅管理员 spaceId,仅queryAll和querypublic都false时启用查私人空间
*/
@Data
public class SpaceAnalyzeRequest implements Serializable {
/**
* 空间 ID
*/
private Long spaceId;
/**
* 是否查询公共图库
*/
private boolean queryPublic;
/**
* 全空间分析
*/
private boolean queryAll;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,13 @@
package edu.whut.smilepicturebackend.model.dto.space.analyze;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 空间图片分类分析请求
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class SpaceCategoryAnalyzeRequest extends SpaceAnalyzeRequest {
}

View File

@ -0,0 +1,19 @@
package edu.whut.smilepicturebackend.model.dto.space.analyze;
import lombok.Data;
import java.io.Serializable;
/**
* 空间使用排行分析请求仅管理员
*/
@Data
public class SpaceRankAnalyzeRequest implements Serializable {
/**
* 排名前 N 的空间
*/
private Integer topN = 10;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,13 @@
package edu.whut.smilepicturebackend.model.dto.space.analyze;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 空间图片大小分析请求
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class SpaceSizeAnalyzeRequest extends SpaceAnalyzeRequest {
}

View File

@ -0,0 +1,13 @@
package edu.whut.smilepicturebackend.model.dto.space.analyze;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 空间图片标签分析请求
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class SpaceTagAnalyzeRequest extends SpaceAnalyzeRequest {
}

View File

@ -0,0 +1,13 @@
package edu.whut.smilepicturebackend.model.dto.space.analyze;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 空间资源使用分析请求封装类
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class SpaceUsageAnalyzeRequest extends SpaceAnalyzeRequest {
}

View File

@ -0,0 +1,22 @@
package edu.whut.smilepicturebackend.model.dto.space.analyze;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 空间用户上传行为分析请求
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class SpaceUserAnalyzeRequest extends SpaceAnalyzeRequest {
/**
* 用户 ID
*/
private Long userId;
/**
* 时间维度day / week / month
*/
private String timeDimension;
}

View File

@ -0,0 +1,33 @@
package edu.whut.smilepicturebackend.model.vo.space.analyze;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 空间图片分类分析响应
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SpaceCategoryAnalyzeResponse implements Serializable {
/**
* 图片分类
*/
private String category;
/**
* 图片数量
*/
private Long count;
/**
* 分类图片总大小
*/
private Long totalSize;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,28 @@
package edu.whut.smilepicturebackend.model.vo.space.analyze;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 空间图片大小分析响应
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SpaceSizeAnalyzeResponse implements Serializable {
/**
* 图片大小范围
*/
private String sizeRange;
/**
* 图片数量
*/
private Long count;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,28 @@
package edu.whut.smilepicturebackend.model.vo.space.analyze;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 空间图片标签分析响应
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SpaceTagAnalyzeResponse implements Serializable {
/**
* 标签名称
*/
private String tag;
/**
* 使用次数
*/
private Long count;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,44 @@
package edu.whut.smilepicturebackend.model.vo.space.analyze;
import lombok.Data;
import java.io.Serializable;
/**
* 空间资源使用分析响应类
*/
@Data
public class SpaceUsageAnalyzeResponse implements Serializable {
/**
* 已使用大小
*/
private Long usedSize;
/**
* 总大小
*/
private Long maxSize;
/**
* 空间使用比例
*/
private Double sizeUsageRatio;
/**
* 当前图片数量
*/
private Long usedCount;
/**
* 最大图片数量
*/
private Long maxCount;
/**
* 图片数量占比
*/
private Double countUsageRatio;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,28 @@
package edu.whut.smilepicturebackend.model.vo.space.analyze;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 空间用户上传行为分析响应
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SpaceUserAnalyzeResponse implements Serializable {
/**
* 时间区间
*/
private String period;
/**
* 上传数量
*/
private Long count;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,70 @@
package edu.whut.smilepicturebackend.service;
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> {
/**
* 获取空间使用情况分析
*
* @param spaceUsageAnalyzeRequest
* @param loginUser
* @return
*/
SpaceUsageAnalyzeResponse getSpaceUsageAnalyze(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest, User loginUser);
/**
* 获取空间图片分类分析
*
* @param spaceCategoryAnalyzeRequest
* @param loginUser
* @return
*/
List<SpaceCategoryAnalyzeResponse> getSpaceCategoryAnalyze(SpaceCategoryAnalyzeRequest spaceCategoryAnalyzeRequest, User loginUser);
/**
* 获取空间图片标签分析
*
* @param spaceTagAnalyzeRequest
* @param loginUser
* @return
*/
List<SpaceTagAnalyzeResponse> getSpaceTagAnalyze(SpaceTagAnalyzeRequest spaceTagAnalyzeRequest, User loginUser);
/**
* 获取空间图片大小分析
*
* @param spaceSizeAnalyzeRequest
* @param loginUser
* @return
*/
List<SpaceSizeAnalyzeResponse> getSpaceSizeAnalyze(SpaceSizeAnalyzeRequest spaceSizeAnalyzeRequest, User loginUser);
/**
* 获取空间用户上传行为分析
*
* @param spaceUserAnalyzeRequest
* @param loginUser
* @return
*/
List<SpaceUserAnalyzeResponse> getSpaceUserAnalyze(SpaceUserAnalyzeRequest spaceUserAnalyzeRequest, User loginUser);
/**
* 空间使用排行分析仅管理员
*
* @param spaceRankAnalyzeRequest
* @param loginUser
* @return
*/
List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeRequest spaceRankAnalyzeRequest, User loginUser);
}

View File

@ -0,0 +1,310 @@
package edu.whut.smilepicturebackend.service.impl;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.SpaceMapper;
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;
import edu.whut.smilepicturebackend.service.SpaceService;
import edu.whut.smilepicturebackend.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author 李鱼皮
* @createDate 2024-12-18 19:53:34
*/
@Service
@RequiredArgsConstructor
public class SpaceAnalyzeServiceImpl extends ServiceImpl<SpaceMapper, Space>
implements SpaceAnalyzeService {
private final UserService userService;
private final SpaceService spaceService;
private final PictureService pictureService;
@Override
public SpaceUsageAnalyzeResponse getSpaceUsageAnalyze(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest, User loginUser) {
// 校验参数
// 全空间或公共图库需要从 Picture 表查询
if (spaceUsageAnalyzeRequest.isQueryAll() || spaceUsageAnalyzeRequest.isQueryPublic()) {
// 权限校验仅管理员可以访问
checkSpaceAnalyzeAuth(spaceUsageAnalyzeRequest, loginUser);
// 统计图库的使用空间
QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
queryWrapper.select("pic_size");
// 补充查询范围
fillAnalyzeQueryWrapper(spaceUsageAnalyzeRequest, queryWrapper);
List<Object> pictureObjList = pictureService.getBaseMapper().selectObjs(queryWrapper); //不用pictureService.list()它会查完整的一条记录而我们仅需一列
long usedSize = 0L;
for (Object obj : pictureObjList) {
// 记得把 Object 强转成 Long再拆箱加到累加器里
usedSize += (Long) obj;
}
long usedCount = pictureObjList.size();
// 封装返回结果
SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
spaceUsageAnalyzeResponse.setUsedSize(usedSize);
spaceUsageAnalyzeResponse.setUsedCount(usedCount);
// 公共图库或者全部空间无数量和容量限制也没有比例
spaceUsageAnalyzeResponse.setMaxSize(null);
spaceUsageAnalyzeResponse.setSizeUsageRatio(null);
spaceUsageAnalyzeResponse.setMaxCount(null);
spaceUsageAnalyzeResponse.setCountUsageRatio(null);
return spaceUsageAnalyzeResponse;
} else {
// 特定空间可以直接从 Space 表查询!
Long spaceId = spaceUsageAnalyzeRequest.getSpaceId();
ThrowUtils.throwIf(spaceId == null || spaceId <= 0, ErrorCode.PARAMS_ERROR);
// 获取空间信息
Space space = spaceService.getById(spaceId);
ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
// 权限校验仅管理员可以访问
checkSpaceAnalyzeAuth(spaceUsageAnalyzeRequest, loginUser);
// 封装返回结果
SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
spaceUsageAnalyzeResponse.setUsedSize(space.getTotalSize());
spaceUsageAnalyzeResponse.setUsedCount(space.getTotalCount());
spaceUsageAnalyzeResponse.setMaxSize(space.getMaxSize());
spaceUsageAnalyzeResponse.setMaxCount(space.getMaxCount());
// 计算比例
double sizeUsageRatio = NumberUtil.round(space.getTotalSize() * 100.0 / space.getMaxSize(), 2).doubleValue();
double countUsageRatio = NumberUtil.round(space.getTotalCount() * 100.0 / space.getMaxCount(), 2).doubleValue();
spaceUsageAnalyzeResponse.setSizeUsageRatio(sizeUsageRatio);
spaceUsageAnalyzeResponse.setCountUsageRatio(countUsageRatio);
return spaceUsageAnalyzeResponse;
}
}
@Override
public List<SpaceCategoryAnalyzeResponse> getSpaceCategoryAnalyze(SpaceCategoryAnalyzeRequest spaceCategoryAnalyzeRequest, User loginUser) {
ThrowUtils.throwIf(spaceCategoryAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
// 检查权限
checkSpaceAnalyzeAuth(spaceCategoryAnalyzeRequest, loginUser);
// 构造查询条件
QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
fillAnalyzeQueryWrapper(spaceCategoryAnalyzeRequest, queryWrapper);
// 使用 MyBatis Plus 分组查询
queryWrapper.select("category", "count(*) as count", "sum(pic_size) as total_size")
.groupBy("category");
// 查询并转换结果
return pictureService.getBaseMapper().selectMaps(queryWrapper)
.stream()
.map(result -> {
String category = (String) result.get("category");
Long count = ((Number) result.get("count")).longValue();
Long totalSize = ((Number) result.get("total_size")).longValue();
return new SpaceCategoryAnalyzeResponse(category, count, totalSize);
})
.collect(Collectors.toList());
}
@Override
public List<SpaceTagAnalyzeResponse> getSpaceTagAnalyze(SpaceTagAnalyzeRequest spaceTagAnalyzeRequest, User loginUser) {
ThrowUtils.throwIf(spaceTagAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
// 检查权限
checkSpaceAnalyzeAuth(spaceTagAnalyzeRequest, loginUser);
// 构造查询条件
QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
fillAnalyzeQueryWrapper(spaceTagAnalyzeRequest, queryWrapper);
// 查询所有符合条件的标签
queryWrapper.select("tags");
List<String> tagsJsonList = pictureService.getBaseMapper().selectObjs(queryWrapper)
.stream()
.filter(ObjUtil::isNotNull)
.map(Object::toString)
.collect(Collectors.toList());
// 解析标签并统计
Map<String, Long> tagCountMap = tagsJsonList.stream()
// ["Java", "Python"], ["Java", "PHP"] => "Java", "Python", "Java", "PHP"
.flatMap(tagsJson -> JSONUtil.toList(tagsJson, String.class).stream())
.collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));
// 转换为响应对象按照使用次数进行排序
return tagCountMap.entrySet().stream()
.sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue())) // 降序排序
.map(entry -> new SpaceTagAnalyzeResponse(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
}
@Override
public List<SpaceSizeAnalyzeResponse> getSpaceSizeAnalyze(SpaceSizeAnalyzeRequest spaceSizeAnalyzeRequest, User loginUser) {
ThrowUtils.throwIf(spaceSizeAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
// 检查权限
checkSpaceAnalyzeAuth(spaceSizeAnalyzeRequest, loginUser);
// 构造查询条件
QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
fillAnalyzeQueryWrapper(spaceSizeAnalyzeRequest, queryWrapper);
// 查询所有符合条件的图片大小
queryWrapper.select("pic_size");
// 1001201000
List<Long> picSizeList = pictureService.getBaseMapper().selectObjs(queryWrapper)
.stream()
.filter(ObjUtil::isNotNull)
.map(size -> (Long) size)
.collect(Collectors.toList());
// 定义分段范围注意使用有序的 Map
Map<String, Long> sizeRanges = new LinkedHashMap<>();
sizeRanges.put("<100KB", picSizeList.stream().filter(size -> size < 100 * 1024).count());
sizeRanges.put("100KB-500KB", picSizeList.stream().filter(size -> size >= 100 * 1024 && size < 500 * 1024).count());
sizeRanges.put("500KB-1MB", picSizeList.stream().filter(size -> size >= 500 * 1024 && size < 1 * 1024 * 1024).count());
sizeRanges.put(">1MB", picSizeList.stream().filter(size -> size >= 1 * 1024 * 1024).count());
// 转换为响应对象
return sizeRanges.entrySet().stream()
.map(entry -> new SpaceSizeAnalyzeResponse(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
}
/**
* 根据前端传来的 时间维度按天 / / 来动态拼出不同的 SQL 聚合字段然后再按照这个时间段字段去分组和排序最终拿到每个周期period里上传的图片数量
* @param spaceUserAnalyzeRequest
* @param loginUser
* @return
*/
@Override
public List<SpaceUserAnalyzeResponse> getSpaceUserAnalyze(SpaceUserAnalyzeRequest spaceUserAnalyzeRequest, User loginUser) {
ThrowUtils.throwIf(spaceUserAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
// 检查权限
checkSpaceAnalyzeAuth(spaceUserAnalyzeRequest, loginUser);
// 构造查询条件
QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
fillAnalyzeQueryWrapper(spaceUserAnalyzeRequest, queryWrapper);
// 补充用户 id 查询
Long userId = spaceUserAnalyzeRequest.getUserId();
queryWrapper.eq(ObjUtil.isNotNull(userId), "user_id", userId);
// 补充分析维度每日每周每月
/**
* eg:
* SELECT
* DATE_FORMAT(create_time, '%Y-%m') AS period,
* COUNT(*) AS count
* FROM picture
* 其他 WHERE 条件
* GROUP BY period
* ORDER BY period ASC;
*/
String timeDimension = spaceUserAnalyzeRequest.getTimeDimension();
switch (timeDimension) {
case "day":
queryWrapper.select("DATE_FORMAT(create_time, '%Y-%m-%d') as period", "count(*) as count");
break;
case "week":
queryWrapper.select("YEARWEEK(create_time) as period", "count(*) as count");
break;
case "month":
queryWrapper.select("DATE_FORMAT(create_time, '%Y-%m') as period", "count(*) as count");
break;
default:
throw new BusinessException(ErrorCode.PARAMS_ERROR, "不支持的时间维度");
}
// 分组排序
queryWrapper.groupBy("period").orderByAsc("period");
// 查询并封装结果
List<Map<String, Object>> queryResult = pictureService.getBaseMapper().selectMaps(queryWrapper);
return queryResult
.stream()
.map(result -> {
String period = result.get("period").toString();
Long count = ((Number) result.get("count")).longValue();
return new SpaceUserAnalyzeResponse(period, count);
})
.collect(Collectors.toList());
}
@Override
public List<Space> getSpaceRankAnalyze(SpaceRankAnalyzeRequest spaceRankAnalyzeRequest, User loginUser) {
ThrowUtils.throwIf(spaceRankAnalyzeRequest == null, ErrorCode.PARAMS_ERROR);
// 检查权限仅管理员可以查看
ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR);
// 构造查询条件
QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
queryWrapper.select("id", "space_name", "user_id", "total_size")
.orderByDesc("total_size")
.last("limit " + spaceRankAnalyzeRequest.getTopN()); // 取前 N
// 查询并封装结果
return spaceService.list(queryWrapper);
}
/**
* 公共方法校验空间分析权限
*
* @param spaceAnalyzeRequest
* @param loginUser
*/
private void checkSpaceAnalyzeAuth(SpaceAnalyzeRequest spaceAnalyzeRequest, User loginUser) {
boolean queryPublic = spaceAnalyzeRequest.isQueryPublic();
boolean queryAll = spaceAnalyzeRequest.isQueryAll();
// 全空间分析或者公共图库权限校验仅管理员可访问
if (queryAll || queryPublic) {
ThrowUtils.throwIf(!userService.isAdmin(loginUser), ErrorCode.NO_AUTH_ERROR);
} else {
// 分析特定空间仅本人或管理员可以访问
Long spaceId = spaceAnalyzeRequest.getSpaceId();
ThrowUtils.throwIf(spaceId == null, ErrorCode.PARAMS_ERROR);
Space space = spaceService.getById(spaceId);
ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
spaceService.checkSpaceAuth(loginUser, space);
}
}
/**
* 公共方法根据请求对象封装查询条件
*
* @param spaceAnalyzeRequest
* @param queryWrapper
*/
private void fillAnalyzeQueryWrapper(SpaceAnalyzeRequest spaceAnalyzeRequest, QueryWrapper<Picture> queryWrapper) {
// 全空间分析
boolean queryAll = spaceAnalyzeRequest.isQueryAll();
if (queryAll) {
return;
}
// 公共图库
boolean queryPublic = spaceAnalyzeRequest.isQueryPublic();
if (queryPublic) {
queryWrapper.isNull("space_id");
return;
}
// 分析特定空间
Long spaceId = spaceAnalyzeRequest.getSpaceId();
if (spaceId != null) {
queryWrapper.eq("space_id", spaceId);
return;
}
throw new BusinessException(ErrorCode.PARAMS_ERROR, "未指定查询范围");
}
}