it_lv 3 semanas atrás
pai
commit
c2fde51ed6
1 arquivos alterados com 214 adições e 192 exclusões
  1. 214 192
      第5章 详情介绍.md

+ 214 - 192
第5章 详情介绍.md

@@ -175,29 +175,40 @@ public class itemApiController {
 	@Autowired
 	private ItemService itemService;
 
-	/**
-	 * 专辑详情页面渲染所需要数据
-	 * @param albumId
-	 * @return
-	 */
-	@Operation(summary = "专辑详情页面渲染所需要数据")
-	@GetMapping("/albumInfo/{albumId}")
-	public Result<Map<String, Object>> getItemData(@PathVariable Long albumId){
-		Map<String, Object> map = itemService.getItemData(albumId);
-		return Result.ok(map);
-	}
+    /**
+     * 根据专辑ID汇总详情页所需参数
+     *
+     * @param albumId
+     * @return
+     */
+    @Operation(summary = "根据专辑ID汇总详情页所需参数")
+    @GetMapping("/albumInfo/{albumId}")
+    public Result<Map<String, Object>> getItem(@PathVariable Long albumId) {
+        Map<String, Object> map = itemService.getItem(albumId);
+        return Result.ok(map);
+    }
 }
 ```
 
 接口与实现
 
 ```java
-/**
- * 专辑详情页面渲染所需要数据
- * @param albumId
- * @return
- */
-Map<String, Object> getItemData(Long albumId);
+package com.atguigu.tingshu.search.service;
+
+import java.util.Map;
+
+public interface ItemService {
+    /**
+     * 根据专辑ID汇总详情页所需参数
+     *
+     * @param albumId
+     * @return
+     */
+    //ItemVo getItem(Long albumId);
+
+    Map<String, Object> getItem(Long albumId);
+}
+
 ```
 
 
@@ -236,56 +247,65 @@ public class ItemServiceImpl implements ItemService {
     private UserFeignClient userFeignClient;
 
     @Autowired
-    private Executor threadPoolTaskExecutor;
+    @Qualifier("threadPoolTaskExecutor")
+    private Executor executor;
 
     /**
-     * 专辑详情页面渲染所需要数据
+     * 根据专辑ID汇总详情页所需参数
      *
      * @param albumId
-     * @return {albumInfo:{},baseCategoryView:{},announcer:{},albumStatVo:{}}
+     * @return
      */
     @Override
-    public Map<String, Object> getItemData(Long albumId) {
-        //1.TODO 根据专辑ID查询布隆过滤器判断专辑是否存在-解决缓存传统问题
-        //注意:引入多线程异步任务优化后,存在多线程并发写hashmap(线程不安全)改为线程安全:ConcurrentHashMap
+    public Map<String, Object> getItem(Long albumId) {
+        //0.TODO 采用布隆过滤器解决缓存穿透问题
+
+        //1.创建Map对象用于封装详情页数据
         Map<String, Object> map = new ConcurrentHashMap<>();
-        //2.远程调用专辑服务获取专辑信息
+
+        //2.远程调用专辑服务:根据专辑ID查询专辑信息
         CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
+            log.info("获取专辑信息异步任务:{}", albumId);
             AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(albumId).getData();
-            Assert.notNull(albumInfo, "专辑:{}不存在", albumId);
+            Assert.notNull(albumInfo, "专辑{}不存在", albumId);
             map.put("albumInfo", albumInfo);
             return albumInfo;
-        }, threadPoolTaskExecutor);
+        }, executor);
+
+        //3.远程调用专辑服务:根据专辑所属分类ID查询分类信息
+        CompletableFuture<Void> baseCategoryCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
+            BaseCategoryView categoryView = albumFeignClient.getCategoryView(albumInfo.getCategory3Id()).getData();
+            Assert.notNull(categoryView, "分类{}不存在", albumInfo.getCategory3Id());
+            map.put("baseCategoryView", categoryView);
+        }, executor);
 
-        //3.远程调用专辑服务获取分类信息
-        CompletableFuture<Void> baseCategoryViewCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
-            BaseCategoryView baseCategoryView = albumFeignClient.getCategoryView(albumInfo.getCategory3Id()).getData();
-            Assert.notNull(baseCategoryView, "分类:{}不存在!", albumInfo.getCategory3Id());
-            map.put("baseCategoryView", baseCategoryView);
-        }, threadPoolTaskExecutor);
 
-        //4.远程调用用户服务获取主播信息
+        //4.远程调用用户服务:根据专辑所属主播ID查询主播信息
         CompletableFuture<Void> announcerCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
             UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(albumInfo.getUserId()).getData();
-            Assert.notNull(userInfoVo, "主播:{}不存在!", albumInfo.getUserId());
+            Assert.notNull(userInfoVo, "用户{}不存在", albumInfo.getUserId());
             map.put("announcer", userInfoVo);
-        }, threadPoolTaskExecutor);
+        }, executor);
 
-        //4.远程调用专辑服务获取统计信息
+        //5.远程调用专辑服务:根据专辑ID查询专辑统计信息
         CompletableFuture<Void> albumStatVoCompletableFuture = CompletableFuture.runAsync(() -> {
+            log.info("获取专辑统计异步任务:{}", albumId);
             AlbumStatVo albumStatVo = albumFeignClient.getAlbumStatVo(albumId).getData();
-            Assert.notNull(albumStatVo, "专辑统计:{}不存在", albumId);
+            Assert.notNull(albumStatVo, "专辑统计{}不存在", albumId);
             map.put("albumStatVo", albumStatVo);
-        }, threadPoolTaskExecutor);
+        }, executor);
 
-        //5.汇总异步任务
-        CompletableFuture.allOf(
-                albumInfoCompletableFuture,
-                albumStatVoCompletableFuture,
-                baseCategoryViewCompletableFuture,
-                announcerCompletableFuture
-        ).join();
 
+        //6.组合异步任务
+        CompletableFuture.allOf(
+                        albumInfoCompletableFuture,
+                        baseCategoryCompletableFuture,
+                        announcerCompletableFuture,
+                        albumStatVoCompletableFuture
+                ).orTimeout(1, TimeUnit.SECONDS)
+                .join();
+
+        //7.响应Map对象
         return map;
     }
 }
@@ -330,22 +350,21 @@ public class ItemServiceImpl implements ItemService {
 
 ```java
 /**
- * 检查提交声音ID列表购买情况
- *
- * @param userId                    用户ID
- * @param albumId                   专辑ID
- * @param needCheckBuyStateTrackIds 待检查购买情况声音ID列表
- * @return 提交待检查购买声音ID购买结果 {38679:1,38678:0}
+ * 提交需要检查购买状态声音ID列表,响应每个声音购买状态
+ * @param userId
+ * @param albumId
+ * @param needCheckPayStatusTrackIdList 待检查购买状态声音ID列表
+ * @return
  */
-@Operation(summary = "检查提交声音ID列表购买情况")
+@Operation(summary = "提交需要检查购买状态声音ID列表,响应每个声音购买状态")
 @PostMapping("/userInfo/userIsPaidTrack/{userId}/{albumId}")
 public Result<Map<Long, Integer>> userIsPaidTrack(
-        @PathVariable Long userId,
-        @PathVariable Long albumId,
-        @RequestBody List<Long> needCheckBuyStateTrackIds
-) {
-    Map<Long, Integer> map = userInfoService.userIsPaidTrack(userId, albumId, needCheckBuyStateTrackIds);
-    return Result.ok(map);
+		@PathVariable Long userId,
+		@PathVariable Long albumId,
+		@RequestBody List<Long> needCheckPayStatusTrackIdList
+		) {
+	Map<Long, Integer> map = userInfoService.userIsPaidTrack(userId, albumId, needCheckPayStatusTrackIdList);
+	return Result.ok(map);
 }
 ```
 
@@ -353,71 +372,69 @@ public Result<Map<Long, Integer>> userIsPaidTrack(
 
 ```java
 /**
- * 检查提交声音ID列表购买情况
+ * 提交需要检查购买状态声音ID列表,响应每个声音购买状态
  *
- * @param userId                    用户ID
- * @param albumId                   专辑ID
- * @param needCheckBuyStateTrackIds 待检查购买情况声音ID列表
- * @return 提交待检查购买声音ID购买结果 {38679:1,38678:0}
+ * @param userId
+ * @param albumId
+ * @param needCheckPayStatusTrackIdList
+ * @return
  */
-Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> needCheckBuyStateTrackIds);
+Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> needCheckPayStatusTrackIdList);
 ```
 
 **UserInfoServiceImpl实现类**:
 
 ```java
-@Autowired
-private UserPaidAlbumMapper userPaidAlbumMapper;
-
-@Autowired
-private UserPaidTrackMapper userPaidTrackMapper;
-
 /**
- * 检查提交声音ID列表购买情况
+ * 提交需要检查购买状态声音ID列表,响应每个声音购买状态
  *
- * @param userId                    用户ID
- * @param albumId                   专辑ID
- * @param needCheckBuyStateTrackIds 待检查购买情况声音ID列表
- * @return 提交待检查购买情况,声音ID购买结果 {38679:1,38678:0}
+ * @param userId                        用户ID
+ * @param albumId                       专辑ID
+ * @param needCheckPayStatusTrackIdList 待检查购买状态声音ID列表
+ * @return
  */
 @Override
-public Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> needCheckBuyStateTrackIds) {
+public Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> needCheckPayStatusTrackIdList) {
     Map<Long, Integer> map = new HashMap<>();
     //1.根据用户ID+专辑ID查询专辑购买记录
-    LambdaQueryWrapper<UserPaidAlbum> userPaidAlbumLambdaQueryWrapper = new LambdaQueryWrapper<>();
-    userPaidAlbumLambdaQueryWrapper.eq(UserPaidAlbum::getAlbumId, albumId);
-    userPaidAlbumLambdaQueryWrapper.eq(UserPaidAlbum::getUserId, userId);
-    Long count = userPaidAlbumMapper.selectCount(userPaidAlbumLambdaQueryWrapper);
-    //1.1 存在购买记录
+    Long count = userPaidAlbumMapper.selectCount(
+            new LambdaQueryWrapper<UserPaidAlbum>()
+                    .eq(UserPaidAlbum::getUserId, userId)
+                    .eq(UserPaidAlbum::getAlbumId, albumId)
+    );
+
+    //2. 如果已购买专辑,将所有待检查购买状态声音 购买状态设置为 1 响应
     if (count > 0) {
-        for (Long needCheckBuyStateTrackId : needCheckBuyStateTrackIds) {
-            //1.1 将所有提交待检查声音ID购买情况设置1
-            map.put(needCheckBuyStateTrackId, 1);
+        for (Long trackId : needCheckPayStatusTrackIdList) {
+            map.put(trackId, 1);
         }
         return map;
     }
 
-    //2.根据用户ID+专辑ID查询已购声音表
-    LambdaQueryWrapper<UserPaidTrack> userPaidTrackLambdaQueryWrapper = new LambdaQueryWrapper<>();
-    userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getUserId, userId);
-    userPaidTrackLambdaQueryWrapper.eq(UserPaidTrack::getAlbumId, albumId);
-    userPaidTrackLambdaQueryWrapper.select(UserPaidTrack::getTrackId);
-    List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(userPaidTrackLambdaQueryWrapper);
-    if (CollectionUtil.isEmpty(userPaidTrackList)) {
-        //2.1 如果不存在已购声音 将所有提交待检查声音ID购买情况设置0返回
-        for (Long needCheckBuyStateTrackId : needCheckBuyStateTrackIds) {
-            map.put(needCheckBuyStateTrackId, 0);
+    //3. 根据用户ID+专辑ID查询已购声音记录
+    List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper.selectList(
+            new LambdaQueryWrapper<UserPaidTrack>()
+                    .eq(UserPaidTrack::getUserId, userId)
+                    .eq(UserPaidTrack::getAlbumId, albumId)
+                    .select(UserPaidTrack::getTrackId)
+    );
+
+    //4. 如果不存再已购声音,将所有待检查购买状态声音 购买状态设置为 0 响应
+    if (CollUtil.isEmpty(userPaidTrackList)) {
+        for (Long trackId : needCheckPayStatusTrackIdList) {
+            map.put(trackId, 0);
         }
         return map;
     }
-    //2.2 存在已购声音,遍历待检查声音ID列表判断找出已购声音购买情况设置1,未购买声音购买情况设置为0
+
+
+    //5.如果存在已购声音,将提交检查声音ID列表中,已购声购买状态设置为:1。未购买设置为0
     List<Long> userPaidTrackIdList = userPaidTrackList.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
-    for (Long needCheckBuyStateTrackId : needCheckBuyStateTrackIds) {
-        //判断已购声音ID列表中是否存在待检查声音ID
-        if(userPaidTrackIdList.contains(needCheckBuyStateTrackId)){
-            map.put(needCheckBuyStateTrackId, 1);
-        }else{
-            map.put(needCheckBuyStateTrackId, 0);
+    for (Long trackId : needCheckPayStatusTrackIdList) {
+        if (userPaidTrackIdList.contains(trackId)) {
+            map.put(trackId, 1);
+        } else {
+            map.put(trackId, 0);
         }
     }
     return map;
@@ -428,18 +445,17 @@ public Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long>
 
 ```java
 /**
- * 检查提交声音ID列表购买情况
- *
- * @param userId                    用户ID
- * @param albumId                   专辑ID
- * @param needCheckBuyStateTrackIds 待检查购买情况声音ID列表
- * @return 提交待检查购买声音ID购买结果 {38679:1,38678:0}
+ * 提交需要检查购买状态声音ID列表,响应每个声音购买状态
+ * @param userId
+ * @param albumId
+ * @param needCheckPayStatusTrackIdList 待检查购买状态声音ID列表
+ * @return
  */
 @PostMapping("/userInfo/userIsPaidTrack/{userId}/{albumId}")
 public Result<Map<Long, Integer>> userIsPaidTrack(
         @PathVariable Long userId,
         @PathVariable Long albumId,
-        @RequestBody List<Long> needCheckBuyStateTrackIds
+        @RequestBody List<Long> needCheckPayStatusTrackIdList
 );
 ```
 
@@ -447,8 +463,8 @@ public Result<Map<Long, Integer>> userIsPaidTrack(
 
 ```java
 @Override
-public Result<Map<Long, Integer>> userIsPaidTrack(Long userId, Long albumId, List<Long> needCheckBuyStateTrackIds) {
-    log.error("[用户服务]远程调用userIsPaidTrack执行服务降级");
+public Result<Map<Long, Integer>> userIsPaidTrack(Long userId, Long albumId, List<Long> needCheckPayStatusTrackIdList) {
+    log.error("【用户服务】提供userIsPaidTrack远程调用失败");
     return null;
 }
 ```
@@ -463,27 +479,30 @@ public Result<Map<Long, Integer>> userIsPaidTrack(Long userId, Long albumId, Lis
 
 ```java
 /**
- * TODO 该方法不登录可以访问,但用户登录状态就可以从ThreadLocal获取用户ID
- * 分页查询当前用户可见声音列表-动态判断声音付费标识
- * @param albumId 专辑ID
- * @param page 页码
- * @param limit 页大小
+ * 需求:用户未登录,可以给用户展示声音列表;用户已登录,可以给用户展示声音列表,并动态渲染付费标识
+ * 分页查询专辑下声音列表(动态渲染付费标识)
+ *
+ * @param albumId
+ * @param page
+ * @param limit
  * @return
  */
 @GuiGuLogin(required = false)
-@Operation(summary = "分页查询当前用户可见声音列表-动态判断声音付费标识")
+@Operation(summary = "分页查询专辑下声音列表(动态渲染付费标识)")
 @GetMapping("/trackInfo/findAlbumTrackPage/{albumId}/{page}/{limit}")
-public Result<Page<AlbumTrackListVo>> getAlbumTrackPage(
+public Result<IPage<AlbumTrackListVo>> findAlbumTrackPage(
         @PathVariable Long albumId,
-        @PathVariable int page,
-        @PathVariable int limit
-){
-    //1.获取当前登录用户信息
+        @PathVariable Long page,
+        @PathVariable Long limit) {
+    //1.尝试获取用户ID
     Long userId = AuthContextHolder.getUserId();
-    //2.构建分页所需Page对象
-    Page<AlbumTrackListVo> pageInfo = new Page<>(page, limit);
-    //3.调用业务层获取业务数据
-    pageInfo = trackInfoService.getAlbumTrackPage(pageInfo, albumId, userId);
+    //2.构建分页对象:封装当前页码、每页记录数
+    IPage<AlbumTrackListVo> pageInfo = new Page<>(page, limit);
+
+    //3.调用业务逻辑层->持久层:封装:总记录数,总页数,当前页数据
+    pageInfo = trackInfoService.findAlbumTrackPage(pageInfo, albumId, userId);
+
+    //4.响应分页对象
     return Result.ok(pageInfo);
 }
 ```
@@ -492,13 +511,15 @@ public Result<Page<AlbumTrackListVo>> getAlbumTrackPage(
 
 ```java
 /**
- * 分页查询当前用户可见声音列表-动态判断声音付费标识
- * @param pageInfo 分页对象
- * @param albumId 专辑ID
- * @param userId 用户ID
- * @return
- */
-Page<AlbumTrackListVo> getAlbumTrackPage(Page<AlbumTrackListVo> pageInfo, Long albumId, Long userId);
+* 需求:用户未登录,可以给用户展示声音列表;用户已登录,可以给用户展示声音列表,并动态渲染付费标识
+* 分页查询专辑下声音列表(动态渲染付费标识)
+*
+* @param pageInfo MP分页对象
+* @param albumId 专辑ID
+* @param userId 用户ID
+* @return
+*/
+IPage<AlbumTrackListVo> findAlbumTrackPage(IPage<AlbumTrackListVo> pageInfo, Long albumId, Long userId);
 ```
 
 **TrackInfoServiceImpl实现类:**
@@ -524,77 +545,77 @@ Page<AlbumTrackListVo> getAlbumTrackPage(Page<AlbumTrackListVo> pageInfo, Long a
 @Autowired
 private UserFeignClient userFeignClient;
 
+
 /**
- * 分页查询当前用户可见声音列表-动态判断声音付费标识
+ * 需求:用户未登录,可以给用户展示声音列表;用户已登录,可以给用户展示声音列表,并动态渲染付费标识
+ * 分页查询专辑下声音列表(动态渲染付费标识)
  *
- * @param pageInfo 分页对象
+ * @param pageInfo MP分页对象
  * @param albumId  专辑ID
  * @param userId   用户ID
  * @return
  */
 @Override
-public Page<AlbumTrackListVo> getAlbumTrackPage(Page<AlbumTrackListVo> pageInfo, Long albumId, Long userId) {
-    //1.分页查询专辑下声音列表 TODO 暂不考虑声音付费标识 默认Vo对象AlbumTrackListVo付费标识:false
-    pageInfo = trackInfoMapper.getAlbumTrackPage(pageInfo, albumId);
+public IPage<AlbumTrackListVo> findAlbumTrackPage(IPage<AlbumTrackListVo> pageInfo, Long albumId, Long userId) {
+    //1.分页获取声音列表(包含统计数值) isShowPaidMark默认为false
+    pageInfo = trackInfoMapper.findAlbumTrackPage(pageInfo, albumId);
 
-    //2.根据专辑ID查询专辑信息.得到付费类型,试听集数
+    //动态渲染付费标识
+    //2.根据专辑ID查询专辑信息,得到专辑付费类型以及免费试听的集数
     AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
-    //2.1 付费类型: 0101-免费、0102-vip免费、0103-付费
+    Assert.notNull(albumInfo, "专辑{}不存在", albumId);
+    //2.1 付费类型:0101-免费、0102-vip免费、0103-付费
     String payType = albumInfo.getPayType();
-    //2.2 获取当前专辑免费试听集数
+    //2.2 免费实体集数
     Integer tracksForFree = albumInfo.getTracksForFree();
-
-    //3.判断用户未登录情况
+    //3.如果用户未登录 情况一:且专辑付费类型是:VIP免费或付费,将除试听以外其他声音付费标识设置true
     if (userId == null) {
-        //3.1 专辑付费类型:VIP免费或付费
-        if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType) || SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
-            //3.2 除去试听其他声音将付费标识全部设置true
+        if (ALBUM_PAY_TYPE_VIPFREE.equals(payType) || ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
             pageInfo.getRecords()
                     .stream()
-                    .filter(vo -> vo.getOrderNum() > tracksForFree)
-                    .forEach(vo -> vo.setIsShowPaidMark(true));
+                    .filter(t -> t.getOrderNum() > tracksForFree)
+                    .forEach(t -> t.setIsShowPaidMark(true));
         }
     } else {
-        //4.判断用户已登录情况
-        //4.1 远程调用用户服务获取用户信息:是否VIP用户
+        //4. 如果用户已登录 满足以下两种情况需要进一步获取当前页声音购买状态
+        //4.1 远程调用用户服务获取用户身份,判断是否为会员(有效期内会员)
         UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
-        Assert.notNull(userInfoVo, "用户{}不存在", userId);
+        Assert.notNull(userInfoVo, "用户{}不存在", userId);
         Boolean isVIP = false;
-        if (1 == userInfoVo.getIsVip().intValue() && userInfoVo.getVipExpireTime().after(new Date())) {
-            //会员标识必须是1,且会员过期时间大于当前系统时间
+        if (userInfoVo.getIsVip().intValue() == 1 && userInfoVo.getVipExpireTime().after(new Date())) {
             isVIP = true;
         }
-        Boolean isNeedCheck = false;
-        //4.2 判断专辑付费类型=VIP免费 当前用户是普通用户,都需要进一步判断声音购买情况
-        if (SystemConstant.ALBUM_PAY_TYPE_VIPFREE.equals(payType) && !isVIP) {
-            isNeedCheck = true;
+
+        //4.2 情况二:如果专辑 付费类型:VIP免费 且 当前用户是普通用户,满足进一步查询当前页声音购买状态
+        Boolean isNeedCheckPayStatus = false;
+        if (!isVIP && ALBUM_PAY_TYPE_VIPFREE.equals(payType)) {
+            isNeedCheckPayStatus = true;
         }
-        //4.3 判断专辑付费类型=付费 所有用户都需要进一步判断声音购买情况
-        if (SystemConstant.ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
-            isNeedCheck = true;
+        //4.3 情况三:如果专辑 付费类型:付费,无论什么用户,满足进一步查询当前页声音购买状态
+        if (ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
+            isNeedCheckPayStatus = true;
         }
-        //4.4 远程调用用户服务获取本页中所有声音购买情况
-        if (isNeedCheck) {
-            //4.4.1 获取本页中需要检查购买情况声音(去掉免费试听)
-            List<Long> needCheckBuyStateTrackIds =
-                    pageInfo.getRecords()
-                            .stream()
-                            .filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree)
-                            .map(AlbumTrackListVo::getTrackId)
-                            .collect(Collectors.toList());
-            //4.4.1 根据用户ID+专辑ID+本页中声音ID列表,远程调用用户服务检查声音购买情况
-            Map<Long, Integer> buyStateMap = userFeignClient.userIsPaidTrack(userId, albumId, needCheckBuyStateTrackIds).getData();
-
-            //4.5 根据本页中购买情况:如果声音购买状态为未购买(0)将付费标识改为:true
-            pageInfo.getRecords()
+
+        //4.4 如果满足情况二或情况三,远程调用用户服务,得到当前页除试听部分每个声音购买状态
+        if (isNeedCheckPayStatus) {
+            //4.4.1 获取当前页中除试听以外其他声音ID列表
+            List<Long> needCheckPayStatusTrackIdList = pageInfo
+                    .getRecords()
+                    .stream()
+                    .filter(t -> t.getOrderNum() > tracksForFree)
+                    .map(AlbumTrackListVo::getTrackId)
+                    .collect(Collectors.toList());
+
+            //4.4.2 远程调用用户服务,获取当前页中声音购买状态Map<Long-专辑ID,Integer-购买状态>
+            Map<Long, Integer> payStatusMap =
+                    userFeignClient.userIsPaidTrack(userId, albumId, needCheckPayStatusTrackIdList).getData();
+
+            //4.5 根据响应声音购买状态,动态修改付费标识。购买状态为0的声音付费标识isShowPaidMark全部设置:true
+            pageInfo
+                    .getRecords()
                     .stream()
-                    .filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > tracksForFree)
-                    .forEach(albumTrackListVo -> {
-                        //如果声音ID未购买,将付费标识设置true
-                        if (buyStateMap.get(albumTrackListVo.getTrackId()).intValue() == 0) {
-                            albumTrackListVo.setIsShowPaidMark(true);
-                        }
-                    });
+                    .filter(t -> t.getOrderNum() > tracksForFree)
+                    .forEach(t -> t.setIsShowPaidMark(payStatusMap.get(t.getTrackId()) == 0));
         }
     }
     return pageInfo;
@@ -605,12 +626,12 @@ public Page<AlbumTrackListVo> getAlbumTrackPage(Page<AlbumTrackListVo> pageInfo,
 
 ```java
 /**
- * 分页展示专辑下声音列表
- * @param pageInfo 分页对象 MP会自动进行分页
- * @param albumId 专辑ID
+ * 分页获取声音列表(包含统计数值)
+ * @param pageInfo 分页对象,框架自动SQL后面拼接limit部分
+ * @param albumId
  * @return
  */
-Page<AlbumTrackListVo> getAlbumTrackPage(Page<AlbumTrackListVo> pageInfo, @Param("albumId") Long albumId);
+IPage<AlbumTrackListVo> findAlbumTrackPage(IPage<AlbumTrackListVo> pageInfo, @Param("albumId") Long albumId);
 ```
 
 **TrackInfoMapper.xml** 映射文件
@@ -636,19 +657,20 @@ limit 0,10;
 ```
 
 ```sql
-<!--分页查询当前专辑下包含声音列表-->
-<select id="getAlbumTrackPage" resultType="com.atguigu.tingshu.vo.album.AlbumTrackListVo">
+<!--分页获取声音列表(包含统计数值)-->
+<select id="findAlbumTrackPage" resultType="com.atguigu.tingshu.vo.album.AlbumTrackListVo">
     select
-        ti.id trackId,
+        ti.id as track_id,
         ti.track_title,
         ti.media_duration,
         ti.order_num,
         ti.create_time,
-        max(if(stat_type='0701', stat_num, 0)) playStatNum,
-        max(if(stat_type='0704', stat_num, 0)) commentStatNum
-    from track_info ti inner join  track_stat stat
-                                   on stat.track_id = ti.id
-    where ti.album_id = #{albumId} and ti.status = '0501' and  ti.is_deleted = 0
+        max(if(stat.stat_type='0701', stat.stat_num, 0)) playStatNum,
+        max(if(stat.stat_type='0702', stat.stat_num, 0)) collectStatNum,
+        max(if(stat.stat_type='0703', stat.stat_num, 0)) praiseStatNum,
+        max(if(stat.stat_type='0704', stat.stat_num, 0)) commentStatNum
+    from track_info ti inner join  track_stat stat on stat.track_id = ti.id and stat.is_deleted = 0
+    where album_id = #{albumId} and ti.status = '0501' and ti.is_deleted = 0
     group by ti.id
     order by ti.order_num asc
 </select>