Commit eb2d3c39e21ed1f607ef4afe76de2df43a1baf55
1 parent
b5f5c408
♻️ refactor(im):用户申请列表,增加流式查询,避免一次性加载过多,或者历史无法被加载到。
Showing
4 changed files
with
47 additions
and
12 deletions
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/friend/ImFriendRequestController.java
| 1 | package cn.iocoder.yudao.module.im.controller.admin.friend; | 1 | package cn.iocoder.yudao.module.im.controller.admin.friend; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.util.ObjUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | 6 | import cn.iocoder.yudao.framework.common.util.collection.MapUtils; |
| 6 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 7 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| @@ -15,6 +16,7 @@ import io.swagger.v3.oas.annotations.Parameter; | @@ -15,6 +16,7 @@ import io.swagger.v3.oas.annotations.Parameter; | ||
| 15 | import io.swagger.v3.oas.annotations.tags.Tag; | 16 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 16 | import jakarta.annotation.Resource; | 17 | import jakarta.annotation.Resource; |
| 17 | import jakarta.validation.Valid; | 18 | import jakarta.validation.Valid; |
| 19 | +import jakarta.validation.constraints.Min; | ||
| 18 | import jakarta.validation.constraints.NotNull; | 20 | import jakarta.validation.constraints.NotNull; |
| 19 | import jakarta.validation.constraints.Size; | 21 | import jakarta.validation.constraints.Size; |
| 20 | import org.springframework.validation.annotation.Validated; | 22 | import org.springframework.validation.annotation.Validated; |
| @@ -75,12 +77,29 @@ public class ImFriendRequestController { | @@ -75,12 +77,29 @@ public class ImFriendRequestController { | ||
| 75 | } | 77 | } |
| 76 | 78 | ||
| 77 | @GetMapping("/list") | 79 | @GetMapping("/list") |
| 78 | - @Operation(summary = "查询「我相关」的好友申请列表(含我发起的、别人加我的)") | ||
| 79 | - public CommonResult<List<ImFriendRequestRespVO>> getMyFriendRequestList() { | ||
| 80 | - List<ImFriendRequestDO> list = friendRequestService.getMyFriendRequestList(getLoginUserId()); | 80 | + @Operation(summary = "查询「我相关」的好友申请列表(游标分页:传 lastRequestId 加载更多)") |
| 81 | + public CommonResult<List<ImFriendRequestRespVO>> getMyFriendRequestList( | ||
| 82 | + @Parameter(description = "当前列表最旧记录的 id;首页不传") | ||
| 83 | + @RequestParam(value = "lastRequestId", required = false) Long lastRequestId, | ||
| 84 | + @Parameter(description = "单次拉取条数", required = true) @RequestParam("limit") @Min(1) Integer limit) { | ||
| 85 | + List<ImFriendRequestDO> list = friendRequestService.getMyFriendRequestList(getLoginUserId(), lastRequestId, limit); | ||
| 81 | return success(buildList(list)); | 86 | return success(buildList(list)); |
| 82 | } | 87 | } |
| 83 | 88 | ||
| 89 | + @GetMapping("/get") | ||
| 90 | + @Operation(summary = "按 id 单查「我相关」的申请记录(带越权过滤;WebSocket 通知到达后用)") | ||
| 91 | + @Parameter(name = "id", description = "申请记录编号", required = true) | ||
| 92 | + public CommonResult<ImFriendRequestRespVO> getMyFriendRequest(@RequestParam("id") Long id) { | ||
| 93 | + ImFriendRequestDO request = friendRequestService.getFriendRequest(id); | ||
| 94 | + // 越权过滤:fromUser / toUser 必有一方是当前用户,否则当不存在返回 null | ||
| 95 | + Long currentUserId = getLoginUserId(); | ||
| 96 | + if (request == null || (ObjUtil.notEqual(request.getFromUserId(), currentUserId) | ||
| 97 | + && ObjUtil.notEqual(request.getToUserId(), currentUserId))) { | ||
| 98 | + return success(null); | ||
| 99 | + } | ||
| 100 | + return success(CollUtil.getFirst(buildList(Collections.singletonList(request)))); | ||
| 101 | + } | ||
| 102 | + | ||
| 84 | // ========== 私有方法:VO 组装 ========== | 103 | // ========== 私有方法:VO 组装 ========== |
| 85 | 104 | ||
| 86 | private List<ImFriendRequestRespVO> buildList(List<ImFriendRequestDO> list) { | 105 | private List<ImFriendRequestRespVO> buildList(List<ImFriendRequestDO> list) { |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/friend/ImFriendRequestMapper.java
| @@ -24,10 +24,14 @@ public interface ImFriendRequestMapper extends BaseMapperX<ImFriendRequestDO> { | @@ -24,10 +24,14 @@ public interface ImFriendRequestMapper extends BaseMapperX<ImFriendRequestDO> { | ||
| 24 | .last("LIMIT 1")); | 24 | .last("LIMIT 1")); |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | - default List<ImFriendRequestDO> selectMyList(Long userId, int limit) { | ||
| 28 | - // 先放扩展过滤再放双向 OR;否则 .and() 返回 LambdaQueryWrapper 基类,丢失 eqIfPresent 等扩展方法 | 27 | + /** |
| 28 | + * 拉取「我相关」的好友申请列表;游标分页:lastRequestId 为 null 拉首页,非 null 拉 id 严格小于它的下一页 | ||
| 29 | + */ | ||
| 30 | + default List<ImFriendRequestDO> selectMyList(Long userId, Long lastRequestId, int limit) { | ||
| 31 | + // 先放扩展过滤再放双向 OR;否则 .and() 返回 LambdaQueryWrapper 基类,丢失 ltIfPresent 等扩展方法 | ||
| 29 | LambdaQueryWrapperX<ImFriendRequestDO> wrapper = new LambdaQueryWrapperX<>(); | 32 | LambdaQueryWrapperX<ImFriendRequestDO> wrapper = new LambdaQueryWrapperX<>(); |
| 30 | - wrapper.and(w -> w.eq(ImFriendRequestDO::getFromUserId, userId) | 33 | + wrapper.ltIfPresent(ImFriendRequestDO::getId, lastRequestId) |
| 34 | + .and(w -> w.eq(ImFriendRequestDO::getFromUserId, userId) | ||
| 31 | .or().eq(ImFriendRequestDO::getToUserId, userId)) | 35 | .or().eq(ImFriendRequestDO::getToUserId, userId)) |
| 32 | .orderByDesc(ImFriendRequestDO::getId) | 36 | .orderByDesc(ImFriendRequestDO::getId) |
| 33 | .last("LIMIT " + limit); | 37 | .last("LIMIT " + limit); |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestService.java
| @@ -39,11 +39,18 @@ public interface ImFriendRequestService { | @@ -39,11 +39,18 @@ public interface ImFriendRequestService { | ||
| 39 | void refuseFriendRequest(Long userId, Long requestId, String handleContent); | 39 | void refuseFriendRequest(Long userId, Long requestId, String handleContent); |
| 40 | 40 | ||
| 41 | /** | 41 | /** |
| 42 | - * 查询「我相关」的申请列表(含我发起的、别人加我的) | 42 | + * 查询「我相关」的申请列表(含我发起的、别人加我的);游标分页:传 lastRequestId 拉它之前的下一页 |
| 43 | * | 43 | * |
| 44 | - * @param userId 用户编号 | ||
| 45 | - * @return 申请记录列表 | 44 | + * @param userId 用户编号 |
| 45 | + * @param lastRequestId 当前列表最旧记录的 id;首页传 null | ||
| 46 | + * @param limit 单次拉取条数(page size,由前端常量控制) | ||
| 47 | + * @return 申请记录列表,按 id 倒序 | ||
| 46 | */ | 48 | */ |
| 47 | - List<ImFriendRequestDO> getMyFriendRequestList(Long userId); | 49 | + List<ImFriendRequestDO> getMyFriendRequestList(Long userId, Long lastRequestId, Integer limit); |
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * 按 id 单查申请记录;通用读接口,调用方自行做越权过滤 | ||
| 53 | + */ | ||
| 54 | + ImFriendRequestDO getFriendRequest(Long id); | ||
| 48 | 55 | ||
| 49 | } | 56 | } |
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/friend/ImFriendRequestServiceImpl.java
| @@ -183,8 +183,13 @@ public class ImFriendRequestServiceImpl implements ImFriendRequestService { | @@ -183,8 +183,13 @@ public class ImFriendRequestServiceImpl implements ImFriendRequestService { | ||
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | @Override | 185 | @Override |
| 186 | - public List<ImFriendRequestDO> getMyFriendRequestList(Long userId) { | ||
| 187 | - return friendRequestMapper.selectMyList(userId, imProperties.getFriend().getRequestListMaxSize()); | 186 | + public List<ImFriendRequestDO> getMyFriendRequestList(Long userId, Long lastRequestId, Integer limit) { |
| 187 | + return friendRequestMapper.selectMyList(userId, lastRequestId, limit); | ||
| 188 | + } | ||
| 189 | + | ||
| 190 | + @Override | ||
| 191 | + public ImFriendRequestDO getFriendRequest(Long id) { | ||
| 192 | + return friendRequestMapper.selectById(id); | ||
| 188 | } | 193 | } |
| 189 | 194 | ||
| 190 | /** | 195 | /** |