From da407669c82c56860656817762552df5100bc1a6 Mon Sep 17 00:00:00 2001 From: abu <3109389044@qq.com> Date: Wed, 14 May 2025 04:20:56 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BE=E6=8A=A5=E6=8B=89=E9=BB=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/imooc/controller/FansController.java | 183 +++++++++++++++++- .../com/imooc/controller/VlogController.java | 6 + .../src/main/resources/application-dev.yml | 22 +-- .../grace/result/ResponseStatusEnum.java | 2 +- .../java/com/imooc/utils/RedisOperator.java | 24 ++- .../src/main/resources/mapper/VlogMapper.xml | 6 + .../resources/mapper/VlogMapperCustom.xml | 25 ++- .../com/imooc/base/BaseInfoProperties.java | 5 + .../java/com/imooc/service/VlogService.java | 2 + .../imooc/service/impl/VlogServiceImpl.java | 123 ++++++++++++ 10 files changed, 383 insertions(+), 15 deletions(-) diff --git a/book-api/src/main/java/com/imooc/controller/FansController.java b/book-api/src/main/java/com/imooc/controller/FansController.java index 4ab50a6..1745d77 100644 --- a/book-api/src/main/java/com/imooc/controller/FansController.java +++ b/book-api/src/main/java/com/imooc/controller/FansController.java @@ -1,5 +1,8 @@ package com.imooc.controller; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.imooc.base.BaseInfoProperties; import com.imooc.grace.result.GraceJSONResult; import com.imooc.grace.result.ResponseStatusEnum; @@ -12,6 +15,13 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + @Slf4j @Api(tags = "FansController 粉丝相关业务功能的接口") @RequestMapping("fans") @@ -26,6 +36,30 @@ public class FansController extends BaseInfoProperties { @PostMapping("follow") public GraceJSONResult follow(@RequestParam String myId, @RequestParam String vlogerId) { + // 从redis中获取拉黑信息 + String redisKey = REDIS_USER_BLOCK + ":" + myId; + Boolean hasKey = redis.keyIsExist(redisKey); + if(hasKey){ + List blockUserList = new ArrayList<>(); + ObjectMapper objectMapper = new ObjectMapper(); + List reports = redis.lrange(redisKey, 0, -1); // 查询用户的所有举报记录 + + for (String report : reports) { + try { + Map reportMap = objectMapper.readValue(report, new TypeReference>() {}); + // 处理拉黑信息 + String queryvlogerId = (String) reportMap.get("vlogerId"); + blockUserList.add(queryvlogerId); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + System.out.println(blockUserList); + Boolean isBlock = blockUserList.contains(vlogerId); + if(isBlock){ + return GraceJSONResult.errorCustom(ResponseStatusEnum.ON_BLOCK); + } + } // 判断两个id不能为空 if (StringUtils.isBlank(myId) || StringUtils.isBlank(vlogerId)) { @@ -68,7 +102,10 @@ public class FansController extends BaseInfoProperties { @PostMapping("cancel") public GraceJSONResult cancel(@RequestParam String myId, @RequestParam String vlogerId) { - + // 判断两个id不能为空 + if (StringUtils.isBlank(myId) || StringUtils.isBlank(vlogerId)) { + return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_ERROR); + } // 是否已经存在关系 Boolean flow = fansService.queryDoIFollowVloger(myId,vlogerId); if(!flow){ @@ -87,6 +124,150 @@ public class FansController extends BaseInfoProperties { return GraceJSONResult.ok(); } + @GetMapping("queryBlockVloger") + public GraceJSONResult queryBlockVloger(@RequestParam String myId, + @RequestParam String vlogerId) { + // 从redis中获取拉黑信息 + String redisKey = REDIS_USER_BLOCK + ":" + myId; + Boolean hasKey = redis.keyIsExist(redisKey); + if(hasKey){ + List blockUserList = new ArrayList<>(); + ObjectMapper objectMapper = new ObjectMapper(); + List reports = redis.lrange(redisKey, 0, -1); // 查询用户的所有举报记录 + + for (String report : reports) { + try { + Map reportMap = objectMapper.readValue(report, new TypeReference>() {}); + // 处理拉黑信息 + String queryvlogerId = (String) reportMap.get("vlogerId"); + blockUserList.add(queryvlogerId); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + System.out.println(blockUserList); + return GraceJSONResult.ok(blockUserList.contains(vlogerId)); + }else{ + return GraceJSONResult.ok(false); + } + } + + @PostMapping("block") + public GraceJSONResult block(@RequestParam String myId, + @RequestParam String vlogerId) { + // 先执行cancel + // 判断两个id不能为空 + if (StringUtils.isBlank(myId) || StringUtils.isBlank(vlogerId)) { + return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_ERROR); + } + // 是否已经存在关系 + Boolean flow = fansService.queryDoIFollowVloger(myId,vlogerId); + if(flow){ + // 删除业务的执行 + fansService.doCancel(myId, vlogerId); + + // 博主的粉丝-1,我的关注-1 + redis.decrement(REDIS_MY_FOLLOWS_COUNTS + ":" + myId, 1); + redis.decrement(REDIS_MY_FANS_COUNTS + ":" + vlogerId, 1); + + // 我和博主的关联关系,依赖redis,不要存储数据库,避免db的性能瓶颈 + redis.del(REDIS_FANS_AND_VLOGGER_RELATIONSHIP + ":" + myId + ":" + vlogerId); + } + // 拉黑 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + String blockTime = LocalDateTime.now().format(formatter); + try{ + Map blockInfo = new HashMap<>(); + blockInfo.put("vlogerId", vlogerId); + blockInfo.put("myId", myId); + blockInfo.put("time", blockTime); + // 转成 JSON 字符串 + ObjectMapper objectMapper = new ObjectMapper(); + String blockJson = objectMapper.writeValueAsString(blockInfo); + String redisKey = REDIS_USER_BLOCK + ":" + myId ; + log.info("写入Redis => key: {}, value: {}", redisKey, blockJson); + redis.rpush(redisKey , blockJson); + + return GraceJSONResult.ok(); + }catch (JsonProcessingException e){ + // 打日志,或者抛出业务异常 + e.printStackTrace(); + throw new RuntimeException("JSON序列化失败: " + e.getMessage()); + } + } + + @PostMapping("cancelBlock") + public GraceJSONResult cancelBlock(@RequestParam String myId, + @RequestParam String vlogerId) { + // 判断两个id不能为空 + if (StringUtils.isBlank(myId) || StringUtils.isBlank(vlogerId)) { + return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_ERROR); + } + // 解除拉黑 + String redisKey = REDIS_USER_BLOCK + ":" + myId; + Boolean hasKey = redis.keyIsExist(redisKey); + if(hasKey){ + List blockList = redis.lrange(redisKey, 0, -1); + ObjectMapper objectMapper = new ObjectMapper(); + if (blockList != null && !blockList.isEmpty()) { + for (String item : blockList) { + try { + Map itemMap = objectMapper.readValue(item, new TypeReference>() {}); + String storedVlogerId = itemMap.get("vlogerId"); + + if (storedVlogerId != null && storedVlogerId.equals(vlogerId)) { + redis.lrem(redisKey, 1, item); // 删除找到的 JSON 字符串 + break; + } + }catch (JsonProcessingException e){ + e.printStackTrace(); + } + } + } + return GraceJSONResult.ok(); + }else{ + return GraceJSONResult.error(); + } + } + + @PostMapping("blockVideo") + public GraceJSONResult blockVideo(@RequestParam String myId, + @RequestParam String vlogId, + @RequestParam String reason, + @RequestParam(defaultValue = "") String description) { + // 判断两个id不能为空 + if (StringUtils.isBlank(myId) || StringUtils.isBlank(vlogId)) { + return GraceJSONResult.errorCustom(ResponseStatusEnum.SYSTEM_ERROR); + } + // 拉黑 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + String blockTime = LocalDateTime.now().format(formatter); + // + try{ + Map blockInfo = new HashMap<>(); + blockInfo.put("vlogId", vlogId); + blockInfo.put("reporter", myId); + blockInfo.put("time", blockTime); + blockInfo.put("reason", reason); + blockInfo.put("description", description); + // 转成 JSON 字符串 + ObjectMapper objectMapper = new ObjectMapper(); + String blockJson = objectMapper.writeValueAsString(blockInfo); + + String redisKey = REDIS_VIDEO_BLOCK + ":" + myId ; + log.info("写入Redis => key: {}, value: {}", redisKey, blockJson); + redis.rpush(redisKey , blockJson); + + return GraceJSONResult.ok(); + }catch (JsonProcessingException e){ + // 打日志,或者抛出业务异常 + e.printStackTrace(); + throw new RuntimeException("JSON序列化失败: " + e.getMessage()); + } + } + + + @GetMapping("queryDoIFollowVloger") public GraceJSONResult queryDoIFollowVloger(@RequestParam String myId, @RequestParam String vlogerId) { diff --git a/book-api/src/main/java/com/imooc/controller/VlogController.java b/book-api/src/main/java/com/imooc/controller/VlogController.java index 09256da..0d7d768 100644 --- a/book-api/src/main/java/com/imooc/controller/VlogController.java +++ b/book-api/src/main/java/com/imooc/controller/VlogController.java @@ -220,6 +220,7 @@ public class VlogController extends BaseInfoProperties { @GetMapping("myPublicList") public GraceJSONResult myPublicList(@RequestParam String userId, + @RequestParam(defaultValue = "") String myId, @RequestParam Integer page, @RequestParam Integer pageSize) { @@ -231,6 +232,7 @@ public class VlogController extends BaseInfoProperties { } PagedGridResult gridResult = vlogService.queryMyVlogList(userId, + myId, page, pageSize, YesOrNo.NO.type); @@ -239,6 +241,7 @@ public class VlogController extends BaseInfoProperties { @GetMapping("myPrivateList") public GraceJSONResult myPrivateList(@RequestParam String userId, + @RequestParam(defaultValue = "") String myId, @RequestParam Integer page, @RequestParam Integer pageSize) { @@ -250,6 +253,7 @@ public class VlogController extends BaseInfoProperties { } PagedGridResult gridResult = vlogService.queryMyVlogList(userId, + myId, page, pageSize, YesOrNo.YES.type); @@ -258,6 +262,7 @@ public class VlogController extends BaseInfoProperties { @GetMapping("myLikedList") public GraceJSONResult myLikedList(@RequestParam String userId, + @RequestParam(defaultValue = "") String myId, @RequestParam Integer page, @RequestParam Integer pageSize) { @@ -269,6 +274,7 @@ public class VlogController extends BaseInfoProperties { } PagedGridResult gridResult = vlogService.getMyLikedVlogList(userId, + myId, page, pageSize); return GraceJSONResult.ok(gridResult); diff --git a/book-api/src/main/resources/application-dev.yml b/book-api/src/main/resources/application-dev.yml index b77881c..d012133 100644 --- a/book-api/src/main/resources/application-dev.yml +++ b/book-api/src/main/resources/application-dev.yml @@ -19,17 +19,17 @@ spring: max-lifetime: 540000 # 连接池的最大生命时长(毫秒),超时则会被释放(retired) connection-test-query: SELECT 1 redis: -# host: 82.156.121.2 -# port: 26379 -# password: e4ea0caebfd2 -# database: 1 # 使用的数据库编号 -# jedis: -# pool: -# max-idle: 50 # 最大空闲连接 -# max-active: 200 # 连接池最大连接数 -# max-wait: 5000 # 连接池最大阻塞等待时间, -1表示没有限制 -# min-idle: 4 # 最小空闲连接 -# timeout: 50000 + host: 82.156.121.2 + port: 26379 + password: e4ea0caebfd2 + database: 1 # 使用的数据库编号 + jedis: + pool: + max-idle: 200 # 最大空闲连接 + max-active: 200 # 连接池最大连接数 + max-wait: 100 # 连接池最大阻塞等待时间, -1表示没有限制 + min-idle: 4 # 最小空闲连接 + timeout: 50000 redisson: file: classpath:redisson.yml data: diff --git a/book-common/src/main/java/com/imooc/grace/result/ResponseStatusEnum.java b/book-common/src/main/java/com/imooc/grace/result/ResponseStatusEnum.java index 26832b1..34afda8 100644 --- a/book-common/src/main/java/com/imooc/grace/result/ResponseStatusEnum.java +++ b/book-common/src/main/java/com/imooc/grace/result/ResponseStatusEnum.java @@ -9,7 +9,7 @@ public enum ResponseStatusEnum { SUCCESS(200, true, "操作成功!"), FAILED(500, false, "操作失败!"), - + ON_BLOCK(201,false,"用户已被拉黑"), // 50x UN_LOGIN(501,false,"请登录后再继续操作!"), TICKET_INVALID(502,false,"会话失效,请重新登录!"), diff --git a/book-common/src/main/java/com/imooc/utils/RedisOperator.java b/book-common/src/main/java/com/imooc/utils/RedisOperator.java index 8c9ab01..75ac3dd 100644 --- a/book-common/src/main/java/com/imooc/utils/RedisOperator.java +++ b/book-common/src/main/java/com/imooc/utils/RedisOperator.java @@ -283,5 +283,27 @@ public class RedisOperator { public long rpush(String key, String value) { return redisTemplate.opsForList().rightPush(key, value); } - + // List(列表) + /** + * 实现命令:LRANGE key start stop,返回列表key中指定区间内的元素 + * + * @param key Redis key + * @param start 开始索引 + * @param stop 结束索引 + * @return 返回指定区间的元素 + */ + public List lrange(String key, long start, long stop) { + return redisTemplate.opsForList().range(key, start, stop); + } + /** + * 实现命令:LREM key count value,移除列表中与 value 相等的元素 + * + * @param key Redis key + * @param count 删除的数量(正数表示从头部开始删除,负数从尾部,0表示删除全部匹配项) + * @param value 要删除的元素值 + * @return 被删除的元素个数 + */ + public Long lrem(String key, long count, Object value) { + return redisTemplate.opsForList().remove(key, count, value); + } } \ No newline at end of file diff --git a/book-mapper/src/main/resources/mapper/VlogMapper.xml b/book-mapper/src/main/resources/mapper/VlogMapper.xml index 56495cc..ecdc68b 100644 --- a/book-mapper/src/main/resources/mapper/VlogMapper.xml +++ b/book-mapper/src/main/resources/mapper/VlogMapper.xml @@ -112,6 +112,12 @@ AND v.title like '%${paramMap.search}%' + + AND v.id NOT IN + + #{vlogId} + + ORDER BY v.created_time DESC diff --git a/book-mapper/src/main/resources/mapper/VlogMapperCustom.xml b/book-mapper/src/main/resources/mapper/VlogMapperCustom.xml index 6afafc4..3749350 100644 --- a/book-mapper/src/main/resources/mapper/VlogMapperCustom.xml +++ b/book-mapper/src/main/resources/mapper/VlogMapperCustom.xml @@ -44,6 +44,18 @@ AND v.title like '%${paramMap.search}%' + + AND v.id NOT IN + + #{vlogId} + + + + AND v.vloger_id NOT IN + + #{vlogerId} + + ORDER BY v.created_time DESC @@ -115,7 +127,18 @@ AND v.status = 1 AND v.first_frame_img IS NOT NULL AND v.is_private = 0 - + + AND v.id NOT IN + + #{vlogId} + + + + AND v.vloger_id NOT IN + + #{vlogerId} + + ORDER BY v.created_time DESC diff --git a/book-service/src/main/java/com/imooc/base/BaseInfoProperties.java b/book-service/src/main/java/com/imooc/base/BaseInfoProperties.java index 34decce..b62c726 100644 --- a/book-service/src/main/java/com/imooc/base/BaseInfoProperties.java +++ b/book-service/src/main/java/com/imooc/base/BaseInfoProperties.java @@ -40,6 +40,11 @@ public class BaseInfoProperties { // 博主和粉丝的关联关系,用于判断他们是否互粉 public static final String REDIS_FANS_AND_VLOGGER_RELATIONSHIP = "redis_fans_and_vlogger_relationship"; + // 拉黑 + public static final String REDIS_USER_BLOCK = "redis_user_block"; + // 举报视频 + public static final String REDIS_VIDEO_BLOCK = "redis_video_block"; + // 用户是否喜欢/点赞视频,取代数据库的关联关系,1:喜欢,0:不喜欢(默认) redis_user_like_vlog:{userId}:{vlogId} public static final String REDIS_USER_LIKE_VLOG = "redis_user_like_vlog"; diff --git a/book-service/src/main/java/com/imooc/service/VlogService.java b/book-service/src/main/java/com/imooc/service/VlogService.java index d488191..3a1220f 100644 --- a/book-service/src/main/java/com/imooc/service/VlogService.java +++ b/book-service/src/main/java/com/imooc/service/VlogService.java @@ -49,6 +49,7 @@ public interface VlogService { * 查询用的公开/私密的视频列表 */ public PagedGridResult queryMyVlogList(String userId, + String myId, Integer page, Integer pageSize, Integer yesOrNo); @@ -72,6 +73,7 @@ public interface VlogService { * 查询用户点赞过的短视频 */ public PagedGridResult getMyLikedVlogList(String userId, + String myId, Integer page, Integer pageSize); diff --git a/book-service/src/main/java/com/imooc/service/impl/VlogServiceImpl.java b/book-service/src/main/java/com/imooc/service/impl/VlogServiceImpl.java index 71da027..fb1c775 100644 --- a/book-service/src/main/java/com/imooc/service/impl/VlogServiceImpl.java +++ b/book-service/src/main/java/com/imooc/service/impl/VlogServiceImpl.java @@ -1,5 +1,8 @@ package com.imooc.service.impl; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.github.pagehelper.PageHelper; import com.imooc.base.BaseInfoProperties; import com.imooc.bo.VlogBO; @@ -168,6 +171,51 @@ public class VlogServiceImpl extends BaseInfoProperties implements VlogService { if (StringUtils.isNotBlank(status)) { map.put("status", status); } + if(StringUtils.isNotBlank(userId)){ + // 从redis中获取举报信息 + String redisKey = REDIS_VIDEO_BLOCK + ":" + userId; + Boolean hasKey = redis.keyIsExist(redisKey); + if(hasKey){ + List blockVdList = new ArrayList<>(); + ObjectMapper objectMapper = new ObjectMapper(); + List reports = redis.lrange(redisKey, 0, -1); // 查询用户的所有举报记录 + + for (String report : reports) { + try { + Map reportMap = objectMapper.readValue(report, new TypeReference>() {}); + // 处理举报信息 + String vlogId = (String) reportMap.get("vlogId"); + blockVdList.add(vlogId); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + map.put("blockVd",blockVdList); + } + } + if(StringUtils.isNotBlank(userId)){ + // 从redis中获取拉黑信息 + String redisKey = REDIS_USER_BLOCK + ":" + userId; + Boolean hasKey = redis.keyIsExist(redisKey); + if(hasKey){ + List blockUserList = new ArrayList<>(); + ObjectMapper objectMapper = new ObjectMapper(); + List reports = redis.lrange(redisKey, 0, -1); // 查询用户的所有举报记录 + + for (String report : reports) { + try { + Map reportMap = objectMapper.readValue(report, new TypeReference>() {}); + // 处理拉黑信息 + String vlogerId = (String) reportMap.get("vlogerId"); + blockUserList.add(vlogerId); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + map.put("blockUser",blockUserList); + } + } + List list = vlogMapperCustom.getIndexVlogList(map); for (IndexVlogVO v : list) { @@ -302,6 +350,7 @@ public class VlogServiceImpl extends BaseInfoProperties implements VlogService { @Override public PagedGridResult queryMyVlogList(String userId, + String myId, Integer page, Integer pageSize, Integer yesOrNo) { @@ -320,6 +369,29 @@ public class VlogServiceImpl extends BaseInfoProperties implements VlogService { // } map.put("vlogerId", userId); + if (StringUtils.isNotBlank(myId)) { + // 从redis中获取举报信息 + String redisKeyRp = REDIS_VIDEO_BLOCK + ":" + myId; + Boolean hasKeyRp = redis.keyIsExist(redisKeyRp); + if(hasKeyRp){ + List blockVdList = new ArrayList<>(); + ObjectMapper objectMapper = new ObjectMapper(); + List reports = redis.lrange(redisKeyRp, 0, -1); // 查询用户的所有举报记录 + + for (String report : reports) { + try { + Map reportMap = objectMapper.readValue(report, new TypeReference>() {}); + // 处理举报信息 + String vlogId = (String) reportMap.get("vlogId"); + blockVdList.add(vlogId); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + map.put("blockVd",blockVdList); + } + } + List list = vlogMapper.selectMyPublic(map); @@ -426,11 +498,62 @@ public class VlogServiceImpl extends BaseInfoProperties implements VlogService { @Override public PagedGridResult getMyLikedVlogList(String userId, + String myId, Integer page, Integer pageSize) { PageHelper.startPage(page, pageSize); Map map = new HashMap<>(); map.put("userId", userId); + String useWho; + if (StringUtils.isNotBlank(myId)) { + useWho = myId; + }else{ + useWho = userId; + } + // 从redis中获取拉黑信息 + String redisKey = REDIS_USER_BLOCK + ":" + useWho; + Boolean hasKey = redis.keyIsExist(redisKey); + if(hasKey){ + List blockUserList = new ArrayList<>(); + ObjectMapper objectMapper = new ObjectMapper(); + List reports = redis.lrange(redisKey, 0, -1); // 查询用户的所有举报记录 + + for (String report : reports) { + try { + Map reportMap = objectMapper.readValue(report, new TypeReference>() {}); + // 处理拉黑信息 + String vlogerId = (String) reportMap.get("vlogerId"); + blockUserList.add(vlogerId); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + map.put("blockUser",blockUserList); + System.out.println(blockUserList); + } + + // 从redis中获取举报信息 + String redisKeyRp = REDIS_VIDEO_BLOCK + ":" + useWho; + Boolean hasKeyRp = redis.keyIsExist(redisKeyRp); + if(hasKeyRp){ + List blockVdList = new ArrayList<>(); + ObjectMapper objectMapper = new ObjectMapper(); + List reports = redis.lrange(redisKeyRp, 0, -1); // 查询用户的所有举报记录 + + for (String report : reports) { + try { + Map reportMap = objectMapper.readValue(report, new TypeReference>() {}); + // 处理举报信息 + String vlogId = (String) reportMap.get("vlogId"); + blockVdList.add(vlogId); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + map.put("blockVd",blockVdList); + } + + List list = vlogMapperCustom.getMyLikedVlogList(map); return setterPagedGrid(list, page);