UserMomentsServiceImpl.java 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. package com.zhentao.moment.service.impl;
  2. import com.aliyun.oss.OSSClient;
  3. import com.aliyun.oss.model.ObjectMetadata;
  4. import com.aliyun.oss.model.PutObjectRequest;
  5. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  6. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  7. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  8. import com.zhentao.moment.domain.MomentComments;
  9. import com.zhentao.moment.domain.MomentLikes;
  10. import com.zhentao.moment.domain.UserMoments;
  11. import com.zhentao.moment.dto.CommentsDto;
  12. import com.zhentao.moment.dto.MonmentDto;
  13. import com.zhentao.moment.enums.ContentTypeEnum;
  14. import com.zhentao.moment.mapper.MomentCommentsMapper;
  15. import com.zhentao.moment.mapper.MomentLikesMapper;
  16. import com.zhentao.moment.service.UserMomentsService;
  17. import com.zhentao.moment.mapper.UserMomentsMapper;
  18. import com.zhentao.osspicture.OssConfig;
  19. import com.zhentao.osspicture.OssUtil;
  20. import com.zhentao.tool.TokenUtils;
  21. import com.zhentao.user.domain.UserLogin;
  22. import com.zhentao.user.mapper.UserLoginMapper;
  23. import com.zhentao.userRelationships.domain.UserRelationships;
  24. import com.zhentao.userRelationships.mapper.UserRelationshipsMapper;
  25. import com.zhentao.utils.SensitiveWordFilter;
  26. import com.zhentao.utils.SnowflakeUtil;
  27. import com.zhentao.vo.Result;
  28. import io.jsonwebtoken.Claims;
  29. import lombok.extern.slf4j.Slf4j;
  30. import org.springframework.beans.BeanUtils;
  31. import org.springframework.beans.factory.annotation.Autowired;
  32. import org.springframework.stereotype.Service;
  33. import org.springframework.util.CollectionUtils;
  34. import org.springframework.web.bind.annotation.RequestMapping;
  35. import org.springframework.web.multipart.MultipartFile;
  36. import java.io.IOException;
  37. import java.text.SimpleDateFormat;
  38. import java.util.*;
  39. import java.util.concurrent.CompletableFuture;
  40. import java.util.stream.Collectors;
  41. import java.util.stream.Stream;
  42. /**
  43. * @author 86159
  44. * @description 针对表【user_moments(朋友圈动态表)】的数据库操作Service实现
  45. * @createDate 2025-06-04 11:56:59
  46. */
  47. @Service
  48. @Slf4j
  49. public class UserMomentsServiceImpl extends ServiceImpl<UserMomentsMapper, UserMoments>
  50. implements UserMomentsService{
  51. @Autowired
  52. private UserMomentsMapper userMomentsMapper;
  53. @Autowired
  54. private UserLoginMapper userLoginMapper;
  55. @Autowired
  56. private MomentLikesMapper momentLikesMapper;
  57. @Autowired
  58. private OssUtil ossUtil;
  59. @Autowired
  60. private OssConfig ossConfig;
  61. @Autowired
  62. private UserRelationshipsMapper userRelationshipsMapper;
  63. @Autowired
  64. private MomentCommentsMapper momentCommentsMapper;
  65. // 发送朋友圈
  66. @Override
  67. public Result sendMonment(String token,MonmentDto monmentDto) {
  68. if (monmentDto.getContent()==null){
  69. return Result.error(400,"请输入内容");
  70. }
  71. if (monmentDto.getContentType()==null){
  72. return Result.error(400,"内容类型不能为空");
  73. }
  74. try {
  75. UserMoments userMoments=new UserMoments();
  76. userMoments.setMomentId(SnowflakeUtil.nextId());
  77. String userId = TokenUtils.getUserIdFromToken(token);
  78. userMoments.setUserId(Long.valueOf(userId));
  79. String filter = SensitiveWordFilter.filter(monmentDto.getContent());
  80. userMoments.setContent(filter);
  81. Integer typeCode = monmentDto.getContentType();
  82. System.err.println(typeCode);
  83. ContentTypeEnum type = ContentTypeEnum.getByCodeOrThrow(typeCode);
  84. userMoments.setContentType(typeCode);
  85. if (monmentDto.getFiles()!=null && !monmentDto.getFiles().isEmpty()){
  86. // if (type!=ContentTypeEnum.IMAGE){
  87. // return Result.error(400,"只有图片类型支持上传多张");
  88. // }
  89. switch (type){
  90. case IMAGE:
  91. for (MultipartFile file : monmentDto.getFiles()){
  92. if (file.isEmpty()){
  93. return Result.error(400,"图片不能为空");
  94. }
  95. validateImageContent(file);
  96. }
  97. List<String> imageUrls = new ArrayList<>();
  98. List<String> imageNames = new ArrayList<>();
  99. Long totalSize = 0L;
  100. String imageDir = ossConfig.getUpload().getImage().getDir();
  101. for (MultipartFile file : monmentDto.getFiles()){
  102. String imageFileName = userId + "/" + System.currentTimeMillis() +
  103. getFileExtension(file.getOriginalFilename());
  104. String ossFilePath = imageDir + imageFileName;
  105. // 上传OSS
  106. String url = uploadToOss(file, ossFilePath);
  107. imageUrls.add(url);
  108. imageNames.add(file.getOriginalFilename());
  109. totalSize+=file.getSize();
  110. }
  111. String urlJson = "[" + imageUrls.stream()
  112. .map(url -> "\"" + url.replace("\"", "\\\"") + "\"") // 确保URL中的双引号被转义
  113. .collect(Collectors.joining(",")) + "]";
  114. userMoments.setUrl(urlJson);
  115. String nameJson = "[" + imageNames.stream()
  116. .map(name -> "\"" + name.replace("\"", "\\\"") + "\"")
  117. .collect(Collectors.joining(",")) + "]";
  118. userMoments.setFilename(nameJson);
  119. userMoments.setFilesize(totalSize);
  120. break;
  121. case VIDEO:
  122. MultipartFile videoFile = monmentDto.getFiles().get(0);
  123. if (videoFile.isEmpty()){
  124. return Result.error(400,"视频不能为空");
  125. }
  126. validateVideoContent(videoFile);
  127. String videoDir = ossConfig.getUpload().getVideo().getDir();
  128. String videoFileName = userId + "/" + System.currentTimeMillis() +
  129. getFileExtension(videoFile.getOriginalFilename());
  130. String ossFilePath = videoDir + videoFileName;
  131. String url = uploadToOss(videoFile, ossFilePath);
  132. userMoments.setUrl(url);
  133. userMoments.setFilename(videoFile.getOriginalFilename());
  134. userMoments.setFilesize(videoFile.getSize());
  135. break;
  136. default:
  137. return Result.error(400,"内容类型错误");
  138. }
  139. }
  140. else if (type!=ContentTypeEnum.TEXT){
  141. return Result.ERR(null,"类型上传不正确");
  142. }
  143. //// userMoments.setContentType();
  144. // userMoments.setContent(monmentDto.getContent());
  145. userMoments.setVisibility(monmentDto.getVisible());
  146. userMoments.setLocation(monmentDto.getLocation());
  147. userMoments.setMomentId(SnowflakeUtil.nextId());
  148. userMomentsMapper.insert(userMoments);
  149. Map<String,Object> map=new HashMap<>();
  150. map.put("monmentId",userMoments.getMomentId());
  151. map.put("ossFilePath",userMoments.getUrl());
  152. return Result.OK(map,"发送成功");
  153. }catch (Exception e){
  154. e.printStackTrace();
  155. return Result.error(500,"发送失败");
  156. }
  157. }
  158. // 删除朋友圈
  159. @Override
  160. public Result deleteMonment(String token,MonmentDto monmentDto) {
  161. if (monmentDto.getMomentId()==null){
  162. return Result.error(400,"朋友圈id不能为空");
  163. }
  164. Long userId = Long.valueOf(TokenUtils.getUserIdFromToken(token));
  165. UserMoments userMoments = userMomentsMapper.selectById(monmentDto.getMomentId());
  166. if (userMoments.getMomentId()==null){
  167. return Result.error(400,"没有此朋友圈");
  168. }else{
  169. if (!userId.equals(userMoments.getUserId())){
  170. return Result.error(400,"没有权限");
  171. }
  172. userMomentsMapper.deleteById(monmentDto.getMomentId());
  173. return Result.ERR(200,"删除成功");
  174. }
  175. }
  176. // 查询个人信息
  177. @Override
  178. public Result userinfo(String token) {
  179. String userId = TokenUtils.getUserIdFromToken(token);
  180. if (userId==null){
  181. return Result.error(400,"没有userid");
  182. }
  183. UserLogin userLogin = userLoginMapper.selectById(userId);
  184. return Result.OK(userLogin,"查询成功");
  185. }
  186. // 查询我的朋友圈
  187. @Override
  188. public Result getMyMonment(Long userId) {
  189. QueryWrapper<UserMoments> queryWrapper=new QueryWrapper<>();
  190. queryWrapper.eq("user_id",userId);
  191. queryWrapper.orderByDesc("created_at");
  192. UserLogin userLogin = userLoginMapper.selectById(userId);
  193. List<UserMoments> userMoments = userMomentsMapper.selectList(queryWrapper);
  194. Map<String,Object> map=new HashMap<>();
  195. map.put("userMoments",userMoments);
  196. map.put("userLogin",userLogin);
  197. return Result.OK(map,"查询成功");
  198. }
  199. // 查询好友的朋友圈
  200. @Override
  201. public Result getFriendMonment(Long userId) {
  202. log.info("查询好友朋友圈,用户ID: {}", userId);
  203. // 构建查询条件,只查询user_id=userId的好友关系
  204. QueryWrapper<UserRelationships> queryWrapper = new QueryWrapper<>();
  205. queryWrapper.eq("user_id", userId)
  206. .eq("status", 1)
  207. .eq("is_blacklist", 0)
  208. .eq("is_del", 0)
  209. .eq("is_moments", 0)
  210. .orderByDesc("created_at");
  211. // 查询好友关系
  212. List<UserRelationships> userRelationships = userRelationshipsMapper.selectList(queryWrapper);
  213. log.info("查询到的好友关系数量: {}", userRelationships.size());
  214. // 调试:打印查询到的每条好友关系
  215. for (UserRelationships rel : userRelationships) {
  216. log.info("好友关系: user_id={}, friend_id={}, status={}, is_blacklist={}, is_del={}, is_moments={}",
  217. rel.getUserId(), rel.getFriendId(), rel.getStatus(),
  218. rel.getIsBlacklist(), rel.getIsDel(), rel.getIsMoments());
  219. }
  220. // 提取好友ID(单向查询:直接从friend_id获取)
  221. List<Long> friendIds = userRelationships.stream()
  222. .map(UserRelationships::getFriendId)
  223. .collect(Collectors.toList());
  224. // 处理无好友情况
  225. if (friendIds.isEmpty()) {
  226. log.warn("没有找到好友,返回空结果");
  227. return Result.OK(new ArrayList<>(), "没有好友的朋友圈");
  228. }
  229. // 查询好友的朋友圈
  230. QueryWrapper<UserMoments> momentQuery = new QueryWrapper<>();
  231. momentQuery.in("user_id", friendIds)
  232. .ne("visibility",2)
  233. .orderByDesc("created_at");
  234. List<UserMoments> userMoments = userMomentsMapper.selectList(momentQuery);
  235. // 关联用户信息
  236. // 1. 提取朋友圈中所有不同的userId
  237. Set<Long> userIdsInMoments = userMoments.stream()
  238. .map(UserMoments::getUserId)
  239. .collect(Collectors.toSet());
  240. // 2. 根据userId列表查询用户信息
  241. if (userIdsInMoments.isEmpty()) {
  242. log.warn("好友没有发布任何朋友圈");
  243. Map<String, Object> map = new HashMap<>();
  244. map.put("userMoments", Collections.emptyList());
  245. map.put("userList", Collections.emptyList());
  246. return Result.OK(map, "查询成功");
  247. }
  248. QueryWrapper<UserLogin> userQuery = new QueryWrapper<>();
  249. userQuery.in("id", userIdsInMoments);
  250. List<UserLogin> users = userLoginMapper.selectList(userQuery);
  251. // 3. 将用户信息转换为Map,根据userId查找
  252. Map<Long, UserLogin> userMap = users.stream()
  253. .collect(Collectors.toMap(UserLogin::getId, user -> user));
  254. // 4. 包含用户信息的列表
  255. List<Map<String, Object>> userList = userMoments.stream()
  256. .map(moment -> {
  257. Map<String, Object> momentMap = new HashMap<>();
  258. BeanUtils.copyProperties(moment, momentMap);
  259. UserLogin user = userMap.get(moment.getUserId());
  260. if (user != null) {
  261. momentMap.put("nickName", user.getNickName());
  262. momentMap.put("avatar", user.getAvatar());
  263. }
  264. return momentMap;
  265. })
  266. .collect(Collectors.toList());
  267. log.info("查询到的朋友圈数量: {}", userMoments.size());
  268. Map<String, Object> map = new HashMap<>();
  269. map.put("userMoments", userMoments);
  270. map.put("userList", userList);
  271. return Result.OK(map, "查询成功");
  272. }
  273. // 点赞朋友圈
  274. @Override
  275. public Result likeMonment(Long uid, MonmentDto monmentDto) {
  276. System.err.println("赞"+monmentDto.getMomentId());
  277. if (monmentDto.getMomentId()==null){
  278. return Result.error(400,"请选择要点赞的朋友圈");
  279. }
  280. QueryWrapper<MomentLikes> queryWrapper=new QueryWrapper<>();
  281. queryWrapper.eq("moment_id",monmentDto.getMomentId());
  282. queryWrapper.eq("user_id",uid);
  283. // 查询是否已点赞
  284. MomentLikes momentLikes = momentLikesMapper.selectOne(queryWrapper);
  285. if (momentLikes==null){
  286. // 没有点赞
  287. MomentLikes momentLikes1=new MomentLikes();
  288. momentLikes1.setLikeId(SnowflakeUtil.nextId());
  289. momentLikes1.setMomentId(Long.valueOf(monmentDto.getMomentId()));
  290. momentLikes1.setUserId(uid);
  291. momentLikesMapper.insert(momentLikes1);
  292. return Result.OK(200,"点赞成功");
  293. }else{
  294. // 已点赞
  295. momentLikesMapper.delete(queryWrapper);
  296. return Result.error(400,"取消点赞");
  297. }
  298. }
  299. // 评论朋友圈
  300. @Override
  301. public Result commentsMonment(Long userId, CommentsDto commentsDto) {
  302. System.err.println("轮"+commentsDto.getMomentId());
  303. MomentComments momentComments = new MomentComments();
  304. momentComments.setUserId(userId);
  305. momentComments.setCommentId(SnowflakeUtil.nextId());
  306. UserMoments userMoments = userMomentsMapper.selectById(commentsDto.getMomentId());
  307. System.err.println(userMoments);
  308. if (userMoments==null){
  309. return Result.error(400,"朋友圈不存在");
  310. }
  311. if (commentsDto.getContent()==null){
  312. return Result.error(400,"评论不能为空");
  313. }
  314. commentsDto.setReplyTo(Long.valueOf(commentsDto.getMomentId()));
  315. commentsDto.setReplyToUser(userMoments.getUserId());
  316. momentComments.setMomentId(Long.valueOf(commentsDto.getMomentId()));
  317. momentComments.setContent(commentsDto.getContent());
  318. momentComments.setReplyToUser(commentsDto.getReplyToUser());
  319. momentComments.setReplyTo(commentsDto.getReplyTo());
  320. momentCommentsMapper.insert(momentComments);
  321. return Result.OK(200,"评论成功");
  322. }
  323. // 查询点赞列表
  324. @Override
  325. public Result likeList(Long uid, MonmentDto monmentDto) {
  326. if (monmentDto.getMomentId()==null){
  327. return Result.error(400,"朋友圈id不能为空");
  328. }
  329. QueryWrapper<MomentLikes> queryWrapper=new QueryWrapper<>();
  330. queryWrapper.eq("moment_id",monmentDto.getMomentId());
  331. List<MomentLikes> momentLikes = momentLikesMapper.selectList(queryWrapper);
  332. // 如果没有点赞
  333. if (CollectionUtils.isEmpty(momentLikes)){
  334. Map<String,Object> map = new HashMap<>();
  335. map.put("likeList", Collections.emptyList());
  336. map.put("userList", Collections.emptyList());
  337. map.put("total", 0);
  338. return Result.OK(map, "查询成功,暂无点赞数据");
  339. }
  340. // 提取去重后的用户ID列表
  341. List<Long> userIds = momentLikes.stream()
  342. .map(MomentLikes::getUserId)
  343. .distinct()
  344. .collect(Collectors.toList());
  345. List<Long> userLikes=new ArrayList<>();
  346. for (MomentLikes like:momentLikes){
  347. userLikes.add(like.getUserId());
  348. }
  349. // 查询用户信息(需恢复此功能)
  350. List<UserLogin> userLogins = userLoginMapper.selectBatchIds(userIds);
  351. Map<Long, UserLogin> userMap = userLogins.stream()
  352. .collect(Collectors.toMap(UserLogin::getId, user -> user));
  353. Map<String, Object> map = new HashMap<>();
  354. map.put("likeList",momentLikes);
  355. map.put("userList",userLogins);
  356. return Result.OK(map,"查询成功");
  357. }
  358. // 查询评论列表
  359. @Override
  360. public Result commentList(Long valueOf, CommentsDto commentsDto) {
  361. QueryWrapper<MomentComments> queryWrapper=new QueryWrapper<>();
  362. queryWrapper.eq("moment_id",commentsDto.getMomentId());
  363. queryWrapper.orderByDesc("created_at");
  364. List<MomentComments> momentComments = momentCommentsMapper.selectList(queryWrapper);
  365. // 查询朋友圈发布者信息
  366. UserMoments userMoments = userMomentsMapper.selectById(commentsDto.getMomentId());
  367. Long publisherId = null;
  368. if (userMoments!=null){
  369. publisherId = userMoments.getUserId();
  370. }
  371. List<Long> replyToUserIds=new ArrayList<>(); //存储每条评论的replyToUser
  372. List<Long> replyToMomentIds=new ArrayList<>(); //存储每条评论的朋友圈id
  373. List<String> userUsernames=new ArrayList<>();
  374. for (MomentComments comment:momentComments){
  375. UserLogin user = userLoginMapper.selectById(comment.getUserId());
  376. if (user!=null){
  377. userUsernames.add(user.getUserUsername());
  378. }
  379. // 设置replyTo和replyToUser
  380. if (comment.getReplyTo() == null) {
  381. // 如果当前评论没有回复目标(直接评论朋友圈)
  382. replyToMomentIds.add(comment.getMomentId()); // replyTo设为当前朋友圈ID
  383. replyToUserIds.add(publisherId); // replyToUser设为朋友圈发布者ID
  384. } else {
  385. // 如果当前评论是回复其他评论
  386. replyToMomentIds.add(comment.getReplyTo()); // replyTo设为被回复的评论ID
  387. replyToUserIds.add(comment.getReplyToUser()); // replyToUser设为被回复的用户ID
  388. }
  389. }
  390. commentsDto.setUserUsernames(userUsernames);
  391. Map<String, Object> map = new HashMap<>();
  392. map.put("commentList",momentComments);
  393. map.put("usernames",userUsernames);
  394. map.put("replyToUserIds", replyToUserIds); // 添加replyToUser
  395. map.put("replyToMomentIds", replyToMomentIds); // 添加replyTo
  396. return Result.OK(map,"查询成功");
  397. }
  398. // 更改朋友圈背景图
  399. @Override
  400. public Result updateBackground(Long userId, MultipartFile file) throws IOException {
  401. String ossUrl = ossUtil.uploadFile(file);
  402. UserLogin userLogin=new UserLogin();
  403. userLogin.setId(userId);
  404. userLogin.setLabelList(ossUrl);
  405. userLoginMapper.updateById(userLogin);
  406. return Result.OK(ossUrl,"修改成功");
  407. }
  408. @Override
  409. public Result allListPage(Long userId, MonmentDto monmentDto) {
  410. try {
  411. // 1. 校验用户ID
  412. if (userId == null) {
  413. return Result.error(400, "用户ID不能为空");
  414. }
  415. // 2. 查询个人信息
  416. UserLogin userLogin = userLoginMapper.selectById(userId);
  417. if (userLogin == null) {
  418. return Result.error(404, "用户信息不存在");
  419. }
  420. // 3. 查询好友关系
  421. QueryWrapper<UserRelationships> friendRelQuery = new QueryWrapper<>();
  422. friendRelQuery.eq("user_id", userId)
  423. .eq("status", 1)
  424. .eq("is_blacklist", 0)
  425. .eq("is_del", 0)
  426. .eq("is_moments", 0)
  427. .orderByDesc("created_at");
  428. List<UserRelationships> friendRelationships = userRelationshipsMapper.selectList(friendRelQuery);
  429. List<Long> friendIds = friendRelationships.stream()
  430. .map(UserRelationships::getFriendId)
  431. .collect(Collectors.toList());
  432. // 4. 合并查询当前用户和好友的动态(真正的分页实现)
  433. Page<UserMoments> allMomentsPage = new Page<>(monmentDto.getCurrentPage(), monmentDto.getPageSize());
  434. QueryWrapper<UserMoments> allMomentQuery = new QueryWrapper<>();
  435. // 如果有好友,查询自己和好友的动态;否则只查询自己的
  436. if (!friendIds.isEmpty()) {
  437. allMomentQuery.in("user_id", Stream.concat(
  438. Stream.of(userId),
  439. friendIds.stream()
  440. ).collect(Collectors.toList()));
  441. } else {
  442. allMomentQuery.eq("user_id", userId);
  443. }
  444. // 排除仅自己可见的动态(除了自己发布的)
  445. allMomentQuery.and(wrapper ->
  446. wrapper.eq("user_id", userId)
  447. .or()
  448. .ne("visibility", 2)
  449. );
  450. // 按创建时间降序排列
  451. allMomentQuery.orderByDesc("created_at");
  452. // 执行分页查询
  453. userMomentsMapper.selectPage(allMomentsPage, allMomentQuery);
  454. List<UserMoments> allUserMoments = allMomentsPage.getRecords();
  455. // 5. 提取所有动态相关用户ID
  456. Set<Long> allUserIds = allUserMoments.stream()
  457. .map(UserMoments::getUserId)
  458. .collect(Collectors.toSet());
  459. // 6. 批量查询所有动态相关用户信息
  460. QueryWrapper<UserLogin> userQuery = new QueryWrapper<>();
  461. userQuery.in("id", allUserIds);
  462. List<UserLogin> users = userLoginMapper.selectList(userQuery);
  463. Map<Long, UserLogin> userMap = users.stream()
  464. .collect(Collectors.toMap(UserLogin::getId, user -> user));
  465. // 7. 处理动态数据,添加用户信息
  466. List<Map<String, Object>> momentList = allUserMoments.stream()
  467. .map(moment -> wrapMomentWithUser(moment, userMap))
  468. .collect(Collectors.toList());
  469. // 8. 提取所有动态ID,用于查询点赞和评论
  470. List<Long> allMomentIds = allUserMoments.stream()
  471. .map(UserMoments::getMomentId)
  472. .collect(Collectors.toList());
  473. if (allMomentIds.isEmpty()) {
  474. // 没有动态时直接返回
  475. Map<String, Object> resultMap = new HashMap<>();
  476. resultMap.put("userInfo", userLogin);
  477. resultMap.put("moments", momentList);
  478. resultMap.put("allLikesAndComments", new HashMap<>());
  479. resultMap.put("total", allMomentsPage.getTotal());
  480. resultMap.put("currentPage", allMomentsPage.getCurrent());
  481. resultMap.put("pageSize", allMomentsPage.getSize());
  482. resultMap.put("totalPages", allMomentsPage.getPages());
  483. return Result.OK(resultMap, "查询成功");
  484. }
  485. // 9. 批量查询所有动态的点赞和评论
  486. Map<Long, Object> allLikesAndComments = new HashMap<>();
  487. for (Long momentId : allMomentIds) {
  488. Map<String, Object> momentInfo = new HashMap<>();
  489. // 查询点赞
  490. QueryWrapper<MomentLikes> likeQuery = new QueryWrapper<>();
  491. likeQuery.eq("moment_id", momentId);
  492. List<MomentLikes> likes = momentLikesMapper.selectList(likeQuery);
  493. // 查询评论
  494. QueryWrapper<MomentComments> commentQuery = new QueryWrapper<>();
  495. commentQuery.eq("moment_id", momentId)
  496. .orderByDesc("created_at");
  497. List<MomentComments> comments = momentCommentsMapper.selectList(commentQuery);
  498. // 提取点赞和评论涉及的用户ID
  499. Set<Long> likeCommentUserIds = new HashSet<>();
  500. likes.forEach(like -> likeCommentUserIds.add(like.getUserId()));
  501. comments.forEach(comment -> {
  502. likeCommentUserIds.add(comment.getUserId());
  503. if (comment.getReplyToUser() != null) {
  504. likeCommentUserIds.add(comment.getReplyToUser());
  505. }
  506. });
  507. // 批量查询用户信息
  508. List<UserLogin> likeCommentUsers = new ArrayList<>();
  509. if (!likeCommentUserIds.isEmpty()) {
  510. likeCommentUsers = userLoginMapper.selectBatchIds(likeCommentUserIds);
  511. }
  512. Map<Long, UserLogin> likeCommentUserMap = likeCommentUsers.stream()
  513. .collect(Collectors.toMap(UserLogin::getId, user -> user));
  514. // 处理点赞数据,统一使用字符串格式的时间
  515. List<Map<String, Object>> likeList = likes.stream()
  516. .map(like -> {
  517. Map<String, Object> likeInfo = new HashMap<>();
  518. likeInfo.put("id", like.getLikeId());
  519. likeInfo.put("userId", like.getUserId());
  520. if (like.getCreatedAt() != null) {
  521. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  522. likeInfo.put("createTime", sdf.format(like.getCreatedAt()));
  523. }
  524. // 手动构建用户信息,只包含必要字段
  525. UserLogin user = likeCommentUserMap.get(like.getUserId());
  526. if (user != null) {
  527. Map<String, Object> userInfo = new HashMap<>();
  528. userInfo.put("id", user.getId());
  529. userInfo.put("nickName", user.getNickName());
  530. userInfo.put("avatar", user.getAvatar());
  531. userInfo.put("username", user.getUserUsername());
  532. likeInfo.put("userInfo", userInfo);
  533. }
  534. return likeInfo;
  535. })
  536. .collect(Collectors.toList());
  537. // 处理评论数据,统一使用字符串格式的时间
  538. List<Map<String, Object>> commentList = comments.stream()
  539. .map(comment -> {
  540. Map<String, Object> commentInfo = new HashMap<>();
  541. commentInfo.put("id", comment.getCommentId());
  542. commentInfo.put("userId", comment.getUserId());
  543. commentInfo.put("content", comment.getContent());
  544. // 统一转换为字符串格式
  545. if (comment.getCreatedAt() != null) {
  546. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  547. commentInfo.put("createdAt", sdf.format(comment.getCreatedAt()));
  548. }
  549. commentInfo.put("replyTo", comment.getReplyTo());
  550. commentInfo.put("replyToUser", comment.getReplyToUser());
  551. UserLogin user = likeCommentUserMap.get(comment.getUserId());
  552. if (user != null) {
  553. Map<String, Object> userInfo = new HashMap<>();
  554. userInfo.put("id", user.getId());
  555. userInfo.put("username", user.getUserUsername());
  556. userInfo.put("avatar", user.getAvatar());
  557. commentInfo.put("userInfo", userInfo);
  558. }
  559. return commentInfo;
  560. })
  561. .collect(Collectors.toList());
  562. // 封装点赞评论信息
  563. momentInfo.put("likeList", likeList);
  564. momentInfo.put("commentList", commentList);
  565. momentInfo.put("likeCount", likeList.size());
  566. momentInfo.put("commentCount", commentList.size());
  567. allLikesAndComments.put(momentId, momentInfo);
  568. }
  569. // 10. 封装最终结果
  570. Map<String, Object> resultMap = new HashMap<>();
  571. resultMap.put("userInfo", userLogin);
  572. resultMap.put("moments", momentList);
  573. resultMap.put("allLikesAndComments", allLikesAndComments);
  574. resultMap.put("total", allMomentsPage.getTotal());
  575. resultMap.put("currentPage", allMomentsPage.getCurrent());
  576. resultMap.put("pageSize", allMomentsPage.getSize());
  577. resultMap.put("totalPages", allMomentsPage.getPages());
  578. return Result.OK(resultMap, "查询成功");
  579. } catch (Exception e) {
  580. log.error("综合朋友圈查询异常: {}", e.getMessage(), e);
  581. return Result.error(500, "查询失败");
  582. }
  583. }
  584. /**
  585. * 封装动态数据并关联用户信息,确保包含momentId
  586. */
  587. private Map<String, Object> wrapMomentWithUser(UserMoments moment, Map<Long, UserLogin> userMap) {
  588. Map<String, Object> momentMap = new HashMap<>();
  589. // 手动添加所有需要的字段,确保momentId存在
  590. momentMap.put("momentId", moment.getMomentId().toString());
  591. momentMap.put("contentType", moment.getContentType());
  592. momentMap.put("url", moment.getUrl());
  593. momentMap.put("content", moment.getContent());
  594. momentMap.put("location", moment.getLocation());
  595. momentMap.put("visibility", moment.getVisibility());
  596. // 转换日期为字符串格式
  597. if (moment.getCreatedAt() != null) {
  598. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  599. momentMap.put("createdAt", sdf.format(moment.getCreatedAt()));
  600. }
  601. // 手动添加用户信息,只包含必要字段
  602. UserLogin user = userMap.get(moment.getUserId());
  603. if (user != null) {
  604. Map<String, Object> userInfo = new HashMap<>();
  605. userInfo.put("id", user.getId());
  606. userInfo.put("nickName", user.getNickName());
  607. userInfo.put("avatar", user.getAvatar());
  608. userInfo.put("username", user.getUserUsername());
  609. momentMap.put("userInfo", userInfo);
  610. }
  611. momentMap.put("isSelf", user != null && user.getId().equals(moment.getUserId()));
  612. return momentMap;
  613. }
  614. /**
  615. * 上传到oss
  616. * */
  617. private String uploadToOss(MultipartFile file, String ossFilePath) throws IOException {
  618. OSSClient ossClient = new OSSClient(ossConfig.getEndpoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());
  619. String bucketName = ossConfig.getBucketName();
  620. // 创建PutObject请求
  621. PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, ossFilePath,
  622. file.getInputStream(), null);
  623. // 设置对象元信息
  624. ObjectMetadata metadata = new ObjectMetadata();
  625. metadata.setContentType(file.getContentType());
  626. metadata.setContentLength(file.getSize());
  627. putObjectRequest.setMetadata(metadata);
  628. // 上传文件
  629. ossClient.putObject(putObjectRequest);
  630. // 构建访问URL
  631. String endpoint = ossConfig.getEndpoint();
  632. String cleanEndpoint = endpoint.replaceAll("^https://", "");
  633. String domain = "https://" + bucketName + "." + cleanEndpoint;
  634. return domain + "/" + ossFilePath;
  635. }
  636. /**
  637. * 获取文件扩展名
  638. */
  639. private String getFileExtension(String fileName) {
  640. if (fileName == null || !fileName.contains(".")) {
  641. return "";
  642. }
  643. return fileName.substring(fileName.lastIndexOf("."));
  644. }
  645. /**
  646. * 验证图片内容
  647. */
  648. private void validateImageContent(MultipartFile file) throws Exception {
  649. if (file == null || file.isEmpty()) {
  650. throw new Exception("图片不能为空");
  651. }
  652. String contentType = file.getContentType();
  653. if (!contentType.startsWith("image/")) {
  654. throw new Exception("请上传图片格式文件");
  655. }
  656. // 验证图片大小(例如限制为10MB)
  657. if (file.getSize() > ossConfig.getUpload().getImage().getMaxSize()) {
  658. throw new Exception("图片大小不能超过" +
  659. (ossConfig.getUpload().getImage().getMaxSize() / (1024 * 1024)) + "MB");
  660. }
  661. }
  662. /**
  663. * 验证视频内容
  664. */
  665. private void validateVideoContent(MultipartFile file) throws Exception {
  666. if (file == null || file.isEmpty()) {
  667. throw new Exception("视频不能为空");
  668. }
  669. String contentType = file.getContentType();
  670. if (!contentType.startsWith("video/")) {
  671. throw new Exception("请上传视频格式文件");
  672. }
  673. // 验证视频大小(例如限制为50MB)
  674. if (file.getSize() > ossConfig.getUpload().getVideo().getMaxSize()) {
  675. throw new Exception("视频大小不能超过" +
  676. (ossConfig.getUpload().getVideo().getMaxSize() / (1024 * 1024)) + "MB");
  677. }
  678. }
  679. }