Browse Source

day08
feture 专辑详情

it_lv 3 weeks ago
parent
commit
47d40bab03
24 changed files with 484 additions and 22 deletions
  1. 5 0
      common/common-util/pom.xml
  2. 4 1
      common/common-util/src/main/java/com/atguigu/tingshu/common/util/AuthContextHolder.java
  3. 19 0
      model/src/main/java/com/atguigu/tingshu/vo/album/AlbumInfoDetailVo.java
  4. 9 0
      service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/AlbumFeignClient.java
  5. 7 0
      service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.java
  6. 20 0
      service-client/service-user-client/src/main/java/com/atguigu/tingshu/user/client/UserFeignClient.java
  7. 9 0
      service-client/service-user-client/src/main/java/com/atguigu/tingshu/user/client/impl/UserDegradeFeignClient.java
  8. 14 0
      service/service-album/src/main/java/com/atguigu/tingshu/album/api/AlbumInfoApiController.java
  9. 30 0
      service/service-album/src/main/java/com/atguigu/tingshu/album/api/TrackInfoApiController.java
  10. 3 1
      service/service-album/src/main/java/com/atguigu/tingshu/album/mapper/AlbumInfoMapper.java
  11. 10 0
      service/service-album/src/main/java/com/atguigu/tingshu/album/mapper/TrackInfoMapper.java
  12. 8 0
      service/service-album/src/main/java/com/atguigu/tingshu/album/service/AlbumInfoService.java
  13. 10 0
      service/service-album/src/main/java/com/atguigu/tingshu/album/service/TrackInfoService.java
  14. 11 0
      service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/AlbumInfoServiceImpl.java
  15. 87 0
      service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/TrackInfoServiceImpl.java
  16. 9 0
      service/service-album/src/main/resources/mapper/AlbumInfoMapper.xml
  17. 32 14
      service/service-album/src/main/resources/mapper/TrackInfoMapper.xml
  18. 18 0
      service/service-search/src/main/java/com/atguigu/tingshu/search/api/itemApiController.java
  19. 8 1
      service/service-search/src/main/java/com/atguigu/tingshu/search/service/ItemService.java
  20. 73 0
      service/service-search/src/main/java/com/atguigu/tingshu/search/service/impl/ItemServiceImpl.java
  21. 1 0
      service/service-search/src/test/java/com/atguigu/tingshu/ServiceSearchApplicationTest.java
  22. 22 4
      service/service-user/src/main/java/com/atguigu/tingshu/user/api/UserInfoApiController.java
  23. 10 0
      service/service-user/src/main/java/com/atguigu/tingshu/user/service/UserInfoService.java
  24. 65 1
      service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.java

+ 5 - 0
common/common-util/pom.xml

@@ -43,5 +43,10 @@
             <artifactId>hutool-all</artifactId>
             <version>5.7.22</version>
         </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>transmittable-thread-local</artifactId>
+            <version>2.12.4</version>
+        </dependency>
     </dependencies>
 </project>

+ 4 - 1
common/common-util/src/main/java/com/atguigu/tingshu/common/util/AuthContextHolder.java

@@ -1,11 +1,14 @@
 package com.atguigu.tingshu.common.util;
 
+import com.alibaba.ttl.TransmittableThreadLocal;
+
 /**
  * 获取当前用户信息帮助类
  */
 public class AuthContextHolder {
 
-    private static ThreadLocal<Long> userId = new ThreadLocal<Long>();
+    //private static ThreadLocal<Long> userId = new ThreadLocal<Long>();
+    private static ThreadLocal<Long> userId = new TransmittableThreadLocal<Long>();
 
     public static void setUserId(Long _userId) {
         userId.set(_userId);

+ 19 - 0
model/src/main/java/com/atguigu/tingshu/vo/album/AlbumInfoDetailVo.java

@@ -0,0 +1,19 @@
+package com.atguigu.tingshu.vo.album;
+
+import com.atguigu.tingshu.model.album.AlbumInfo;
+import com.atguigu.tingshu.model.album.BaseCategoryView;
+import com.atguigu.tingshu.vo.user.UserInfoVo;
+import lombok.Data;
+
+/**
+ * @author: atguigu
+ * @create: 2025-03-17 13:51
+ */
+@Data
+public class AlbumInfoDetailVo {
+
+    private AlbumInfo albumInfo;
+    private AlbumStatVo albumStatVo;
+    private BaseCategoryView baseCategoryView;
+    private UserInfoVo announcer;
+}

+ 9 - 0
service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/AlbumFeignClient.java

@@ -5,6 +5,7 @@ import com.atguigu.tingshu.common.result.Result;
 import com.atguigu.tingshu.model.album.AlbumInfo;
 import com.atguigu.tingshu.model.album.BaseCategory3;
 import com.atguigu.tingshu.model.album.BaseCategoryView;
+import com.atguigu.tingshu.vo.album.AlbumStatVo;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -37,4 +38,12 @@ public interface AlbumFeignClient {
     @GetMapping("/category/findTopBaseCategory3/{category1Id}")
     public Result<List<BaseCategory3>> findTopBaseCategory3(@PathVariable("category1Id") Long category1Id);
 
+    /**
+     * 根据专辑ID查询专辑统计信息
+     * @param albumId
+     * @return
+     */
+    @GetMapping("/albumInfo/getAlbumStatVo/{albumId}")
+    public Result<AlbumStatVo> getAlbumStatVo(@PathVariable("albumId") Long albumId);
+
 }

+ 7 - 0
service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.java

@@ -6,6 +6,7 @@ import com.atguigu.tingshu.common.result.Result;
 import com.atguigu.tingshu.model.album.AlbumInfo;
 import com.atguigu.tingshu.model.album.BaseCategory3;
 import com.atguigu.tingshu.model.album.BaseCategoryView;
+import com.atguigu.tingshu.vo.album.AlbumStatVo;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 
@@ -34,5 +35,11 @@ public class AlbumDegradeFeignClient implements AlbumFeignClient {
         return null;
     }
 
+    @Override
+    public Result<AlbumStatVo> getAlbumStatVo(Long albumId) {
+        log.error("[专辑服务]提供远程{}调用执行服务降级", "getAlbumStatVo");
+        return null;
+    }
+
 
 }

+ 20 - 0
service-client/service-user-client/src/main/java/com/atguigu/tingshu/user/client/UserFeignClient.java

@@ -6,6 +6,11 @@ import com.atguigu.tingshu.vo.user.UserInfoVo;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.util.List;
+import java.util.Map;
 
 /**
  * <p>
@@ -19,4 +24,19 @@ public interface UserFeignClient {
 
     @GetMapping("/userInfo/getUserInfoVo/{userId}")
     public Result<UserInfoVo> getUserInfoVo(@PathVariable("userId") Long userId);
+
+    /**
+     * 根据用户ID+专辑ID+声音ID列表查询得到声音购买情况
+     *
+     * @param userId
+     * @param albumId
+     * @param needCheckBuyStateTrackIds
+     * @return
+     */
+    @PostMapping("/userInfo/userIsPaidTrack/{userId}/{albumId}")
+    public Result<Map<Long, Integer>> userIsPaidTrack(
+            @PathVariable("userId") Long userId,
+            @PathVariable("albumId") Long albumId,
+            @RequestBody List<Long> needCheckBuyStateTrackIds
+    );
 }

+ 9 - 0
service-client/service-user-client/src/main/java/com/atguigu/tingshu/user/client/impl/UserDegradeFeignClient.java

@@ -7,6 +7,9 @@ import com.atguigu.tingshu.vo.user.UserInfoVo;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 
+import java.util.List;
+import java.util.Map;
+
 @Slf4j
 @Component
 public class UserDegradeFeignClient implements UserFeignClient {
@@ -16,4 +19,10 @@ public class UserDegradeFeignClient implements UserFeignClient {
         log.error("[用户服务]提供远程{}调用执行服务降级", "getUserInfoVo");
         return null;
     }
+
+    @Override
+    public Result<Map<Long, Integer>> userIsPaidTrack(Long userId, Long albumId, List<Long> needCheckBuyStateTrackIds) {
+        log.error("[用户服务]提供远程{}调用执行服务降级", "userIsPaidTrack");
+        return null;
+    }
 }

+ 14 - 0
service/service-album/src/main/java/com/atguigu/tingshu/album/api/AlbumInfoApiController.java

@@ -8,6 +8,7 @@ import com.atguigu.tingshu.model.album.AlbumInfo;
 import com.atguigu.tingshu.query.album.AlbumInfoQuery;
 import com.atguigu.tingshu.vo.album.AlbumInfoVo;
 import com.atguigu.tingshu.vo.album.AlbumListVo;
+import com.atguigu.tingshu.vo.album.AlbumStatVo;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -129,5 +130,18 @@ public class AlbumInfoApiController {
         List<AlbumInfo> list = albumInfoService.findUserAllAlbumList(userId);
         return Result.ok(list);
     }
+
+
+    /**
+     * 根据专辑ID查询专辑统计信息
+     * @param albumId
+     * @return
+     */
+    @Operation(summary = "根据专辑ID查询专辑统计信息")
+    @GetMapping("/albumInfo/getAlbumStatVo/{albumId}")
+    public Result<AlbumStatVo> getAlbumStatVo(@PathVariable("albumId") Long albumId) {
+        AlbumStatVo albumStatVo = albumInfoService.getAlbumStatVo(albumId);
+        return Result.ok(albumStatVo);
+    }
 }
 

+ 30 - 0
service/service-album/src/main/java/com/atguigu/tingshu/album/api/TrackInfoApiController.java

@@ -7,6 +7,7 @@ import com.atguigu.tingshu.common.result.Result;
 import com.atguigu.tingshu.common.util.AuthContextHolder;
 import com.atguigu.tingshu.model.album.TrackInfo;
 import com.atguigu.tingshu.query.album.TrackInfoQuery;
+import com.atguigu.tingshu.vo.album.AlbumTrackListVo;
 import com.atguigu.tingshu.vo.album.TrackInfoVo;
 import com.atguigu.tingshu.vo.album.TrackListVo;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -117,5 +118,34 @@ public class TrackInfoApiController {
         trackInfoService.removeTrackInfo(id);
         return Result.ok();
     }
+
+
+    /**
+     * 分页下专辑声音列表(动态设置付费标识)
+     *
+     * @param albumId
+     * @param page
+     * @param limit
+     * @return
+     */
+    @GuiGuLogin(required = false)
+    @Operation(summary = "分页下专辑声音列表(动态设置付费标识)")
+    @GetMapping("/trackInfo/findAlbumTrackPage/{albumId}/{page}/{limit}")
+    public Result<Page<AlbumTrackListVo>> findAlbumTrackPage(
+            @PathVariable("albumId") Long albumId,
+            @PathVariable("page") Long page,
+            @PathVariable("limit") Long limit
+    ) {
+        //1.获取当前登录用户ID
+        Long userId = AuthContextHolder.getUserId();
+        //2.创建MP分页需要分页对象Page,在控制层封装当前页,页大小
+        Page<AlbumTrackListVo> pageInfo = new Page<>(page, limit);
+
+        //3.调用业务层分页方法 封装分页对象中:总记录数、当前页数据、总页数等
+        pageInfo = trackInfoService.findAlbumTrackPage(pageInfo, albumId, userId);
+
+        //4.返回结果
+        return Result.ok(pageInfo);
+    }
 }
 

+ 3 - 1
service/service-album/src/main/java/com/atguigu/tingshu/album/mapper/AlbumInfoMapper.java

@@ -3,9 +3,9 @@ package com.atguigu.tingshu.album.mapper;
 import com.atguigu.tingshu.model.album.AlbumInfo;
 import com.atguigu.tingshu.query.album.AlbumInfoQuery;
 import com.atguigu.tingshu.vo.album.AlbumListVo;
+import com.atguigu.tingshu.vo.album.AlbumStatVo;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
 //@Mapper
@@ -18,4 +18,6 @@ public interface AlbumInfoMapper extends BaseMapper<AlbumInfo> {
      * @return
      */
     Page<AlbumListVo> findUserAlbumPage(Page<AlbumListVo> pageInfo,@Param("vo") AlbumInfoQuery albumInfoQuery);
+
+    AlbumStatVo getAlbumStatVo(@Param("albumId") Long albumId);
 }

+ 10 - 0
service/service-album/src/main/java/com/atguigu/tingshu/album/mapper/TrackInfoMapper.java

@@ -2,6 +2,7 @@ package com.atguigu.tingshu.album.mapper;
 
 import com.atguigu.tingshu.model.album.TrackInfo;
 import com.atguigu.tingshu.query.album.TrackInfoQuery;
+import com.atguigu.tingshu.vo.album.AlbumTrackListVo;
 import com.atguigu.tingshu.vo.album.TrackListVo;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -19,4 +20,13 @@ public interface TrackInfoMapper extends BaseMapper<TrackInfo> {
      * @return
      */
     Page<TrackListVo> findUserTrackPage(Page<TrackListVo> pageInfo, @Param("vo") TrackInfoQuery trackInfoQuery);
+
+    /**
+     * 分页获取专辑下声音列表
+     *
+     * @param pageInfo 分页对象
+     * @param albumId
+     * @return
+     */
+    Page<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> pageInfo,@Param("albumId") Long albumId);
 }

+ 8 - 0
service/service-album/src/main/java/com/atguigu/tingshu/album/service/AlbumInfoService.java

@@ -4,6 +4,7 @@ import com.atguigu.tingshu.model.album.AlbumInfo;
 import com.atguigu.tingshu.query.album.AlbumInfoQuery;
 import com.atguigu.tingshu.vo.album.AlbumInfoVo;
 import com.atguigu.tingshu.vo.album.AlbumListVo;
+import com.atguigu.tingshu.vo.album.AlbumStatVo;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
 
@@ -64,4 +65,11 @@ public interface AlbumInfoService extends IService<AlbumInfo> {
      * @return
      */
     List<AlbumInfo> findUserAllAlbumList(Long userId);
+
+    /**
+     * 根据专辑ID查询专辑统计信息
+     * @param albumId
+     * @return
+     */
+    AlbumStatVo getAlbumStatVo(Long albumId);
 }

+ 10 - 0
service/service-album/src/main/java/com/atguigu/tingshu/album/service/TrackInfoService.java

@@ -2,6 +2,7 @@ package com.atguigu.tingshu.album.service;
 
 import com.atguigu.tingshu.model.album.TrackInfo;
 import com.atguigu.tingshu.query.album.TrackInfoQuery;
+import com.atguigu.tingshu.vo.album.AlbumTrackListVo;
 import com.atguigu.tingshu.vo.album.TrackInfoVo;
 import com.atguigu.tingshu.vo.album.TrackListVo;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -41,4 +42,13 @@ public interface TrackInfoService extends IService<TrackInfo> {
      * @return
      */
     void removeTrackInfo(Long id);
+
+    /**
+     * 分页查询指定专辑下声音列表,综合根据登录状态、用户身份、购买情况显示付费标识
+     * @param pageInfo 分页对象
+     * @param albumId 专辑ID
+     * @param userId 用户ID
+     * @return
+     */
+    Page<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> pageInfo, Long albumId, Long userId);
 }

+ 11 - 0
service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/AlbumInfoServiceImpl.java

@@ -21,6 +21,7 @@ import com.atguigu.tingshu.query.album.AlbumInfoQuery;
 import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
 import com.atguigu.tingshu.vo.album.AlbumInfoVo;
 import com.atguigu.tingshu.vo.album.AlbumListVo;
+import com.atguigu.tingshu.vo.album.AlbumStatVo;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -254,6 +255,16 @@ public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo
         return baseMapper.selectList(queryWrapper);
     }
 
+    /**
+     * 根据专辑ID查询专辑统计信息
+     * @param albumId
+     * @return
+     */
+    @Override
+    public AlbumStatVo getAlbumStatVo(Long albumId) {
+        return baseMapper.getAlbumStatVo(albumId);
+    }
+
 
     /**
      * a方法有事务,B方法没有事务,默认传播特性:Required B会自动加入到A事务中

+ 87 - 0
service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/TrackInfoServiceImpl.java

@@ -1,6 +1,7 @@
 package com.atguigu.tingshu.album.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
 import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
 import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
 import com.atguigu.tingshu.album.mapper.TrackStatMapper;
@@ -11,9 +12,12 @@ import com.atguigu.tingshu.model.album.AlbumInfo;
 import com.atguigu.tingshu.model.album.TrackInfo;
 import com.atguigu.tingshu.model.album.TrackStat;
 import com.atguigu.tingshu.query.album.TrackInfoQuery;
+import com.atguigu.tingshu.user.client.UserFeignClient;
+import com.atguigu.tingshu.vo.album.AlbumTrackListVo;
 import com.atguigu.tingshu.vo.album.TrackInfoVo;
 import com.atguigu.tingshu.vo.album.TrackListVo;
 import com.atguigu.tingshu.vo.album.TrackMediaInfoVo;
+import com.atguigu.tingshu.vo.user.UserInfoVo;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -25,6 +29,13 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static com.atguigu.tingshu.common.constant.SystemConstant.ALBUM_PAY_TYPE_REQUIRE;
+import static com.atguigu.tingshu.common.constant.SystemConstant.ALBUM_PAY_TYPE_VIPFREE;
 
 @Slf4j
 @Service
@@ -43,6 +54,9 @@ public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo
     @Autowired
     private TrackStatMapper trackStatMapper;
 
+    @Autowired
+    private UserFeignClient userFeignClient;
+
     /**
      * 保存声音,发起内容审核任务
      *
@@ -193,4 +207,77 @@ public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo
         //6.删除点播平台音频文件
         vodService.deleteMedia(trackInfo.getMediaFileId());
     }
+
+    /**
+     * 分页查询指定专辑下声音列表,综合根据登录状态、用户身份、购买情况显示付费标识
+     *
+     * @param pageInfo 分页对象
+     * @param albumId  专辑ID
+     * @param userId   用户ID
+     * @return
+     */
+    @Override
+    public Page<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> pageInfo, Long albumId, Long userId) {
+        //1.根据专辑ID分页查询声音列表 TODO 暂不考虑处理付费标识 isShowPaidMark默认:false
+        pageInfo = baseMapper.findAlbumTrackPage(pageInfo, albumId);
+        //2.根据专辑ID查询专辑信息 得到付费类型以及面试试听集数
+        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
+        //付费类型: 0101-免费、0102-vip免费、0103-付费
+        String payType = albumInfo.getPayType();
+        Integer tracksForFree = albumInfo.getTracksForFree();
+        //3.处理未登录情况
+        if (userId == null) {
+            //3.1 付费类型为VIP免费/付费。过滤出当前页中声音所有声音序号大于免费试听将付费标识改为true
+            if (ALBUM_PAY_TYPE_VIPFREE.equals(payType) || ALBUM_PAY_TYPE_REQUIRE.equals(payType)) {
+                pageInfo.getRecords()
+                        .stream()
+                        //获取当前页声音序号大于免费试听的
+                        .filter(track -> track.getOrderNum() > tracksForFree)
+                        //付费标识改为true
+                        .forEach(track -> track.setIsShowPaidMark(true));
+            }
+        } else {
+            //3. 处理已登录情况
+            //3.1 远程调用用户服务获取用户身份 判断是否为VIP
+            Boolean isVIP = false;
+            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
+            if (userInfoVo.getIsVip().intValue() == 1 && userInfoVo.getVipExpireTime().after(new Date())) {
+                //VIP用户要求:VIP标识等于1且会员在有效期内
+                isVIP = true;
+            }
+            //3.2 是否需要进一步判断声音购买情况变量:false
+            Boolean needCheckBuyState = false;
+
+            //3.2.1 如果是普通用户查看付费类型为“VIP免费”专辑,进一步查询当前页面中声音购买情况
+            if (!isVIP && ALBUM_PAY_TYPE_VIPFREE.equals(payType)) {
+                needCheckBuyState = true;
+            }
+            //3.2.2 所有用户查看付费类型为“付费”专辑,进一步查询当前页面中声音购买情况
+            if(ALBUM_PAY_TYPE_REQUIRE.equals(payType)){
+                needCheckBuyState = true;
+            }
+
+            //3.3 如果需要进一步判断声音购买情况,远程调用用户服务获取每个声音购买情况(去除试听声音ID)
+            if (needCheckBuyState) {
+                //3.3.1 去除掉本页中试听声音ID得到待检查购买情况声音ID列表
+                List<Long> needCheckBuyStateTrackIds = pageInfo.getRecords()
+                        .stream()
+                        .filter(track -> track.getOrderNum() > tracksForFree)
+                        .map(AlbumTrackListVo::getTrackId)
+                        .collect(Collectors.toList());
+                //3.3.2 远程调用用户服务获取每个声音购买情况
+                Map<Long, Integer> trackBuyStateMap = userFeignClient.userIsPaidTrack(userId, albumId, needCheckBuyStateTrackIds).getData();
+                //3.4 根据购买情况设置付费标识(去除试听声音ID),未购买声音将标识设置为:true
+                if(CollUtil.isNotEmpty(trackBuyStateMap)){
+                    pageInfo.getRecords()
+                            .stream()
+                            .filter(track -> track.getOrderNum() > tracksForFree)
+                            .forEach(albumTrackVo-> albumTrackVo.setIsShowPaidMark(trackBuyStateMap.get(albumTrackVo.getTrackId())==0));
+                }
+            }
+        }
+        return pageInfo;
+    }
+
+
 }

+ 9 - 0
service/service-album/src/main/resources/mapper/AlbumInfoMapper.xml

@@ -34,5 +34,14 @@
         group by ai.id
         order by ai.id desc
     </select>
+    <select id="getAlbumStatVo" resultType="com.atguigu.tingshu.vo.album.AlbumStatVo">
+        select
+            album_id,
+            max(if(stat_type='0401', stat_num, 0)) playStatNum,
+            max(if(stat_type='0402', stat_num, 0)) subscribeStatNum,
+            sum(if(stat_type='0403', stat_num, 0)) buyStatNum,
+            max(if(stat_type='0404', stat_num, 0)) commentStatNum
+        from album_stat where album_id = #{albumId} and is_deleted = 0
+    </select>
 </mapper>
 

+ 32 - 14
service/service-album/src/main/resources/mapper/TrackInfoMapper.xml

@@ -7,30 +7,48 @@
 
     <select id="findUserTrackPage" resultType="com.atguigu.tingshu.vo.album.TrackListVo">
         select
-            ti.id track_id,
-            ti.track_title,
-            ti.cover_url,
-            ti.media_duration,
-            ti.status,
-            max(if(stat_type='0701', stat_num, 0)) playStatNum,
-            max(if(stat_type='0702', stat_num, 0)) collectStatNum,
-            max(if(stat_type='0703', stat_num, 0)) praiseStatNum,
-            max(if(stat_type='0704', stat_num, 0)) commentStatNum
+        ti.id track_id,
+        ti.track_title,
+        ti.cover_url,
+        ti.media_duration,
+        ti.status,
+        max(if(stat_type='0701', stat_num, 0)) playStatNum,
+        max(if(stat_type='0702', stat_num, 0)) collectStatNum,
+        max(if(stat_type='0703', stat_num, 0)) praiseStatNum,
+        max(if(stat_type='0704', 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>
             <if test="vo.userId != null">
-                and  ti.user_id = #{vo.userId}
+                and ti.user_id = #{vo.userId}
             </if>
-            <if test="vo.status != null and vo.status != ''" >
-                and  ti.status = #{vo.status}
+            <if test="vo.status != null and vo.status != ''">
+                and ti.status = #{vo.status}
             </if>
-            <if test="vo.trackTitle != null and vo.trackTitle != ''" >
-                and  ti.track_title like concat('%',#{vo.trackTitle},'%')
+            <if test="vo.trackTitle != null and vo.trackTitle != ''">
+                and ti.track_title like concat('%',#{vo.trackTitle},'%')
             </if>
             and ti.is_deleted = 0
         </where>
         group by ti.id
         order by ti.id desc
     </select>
+
+    <!--分页获取专辑下声音列表-->
+    <select id="findAlbumTrackPage" resultType="com.atguigu.tingshu.vo.album.AlbumTrackListVo">
+        select
+            ti.id 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='0702', stat_num, 0)) collectStatNum,
+            max(if(stat_type='0703', stat_num, 0)) praiseStatNum,
+            max(if(stat_type='0704', stat_num, 0)) commentStatNum
+        from track_info ti inner join track_stat ts on ts.track_id = ti.id and ts.is_deleted = 0
+        where ti.album_id = #{albumId} and ti.status = '0501' and ti.is_deleted = 0
+        group by ti.id
+        order by ti.id asc
+    </select>
 </mapper>
 

+ 18 - 0
service/service-search/src/main/java/com/atguigu/tingshu/search/api/itemApiController.java

@@ -1,11 +1,17 @@
 package com.atguigu.tingshu.search.api;
 
+import com.atguigu.tingshu.common.result.Result;
 import com.atguigu.tingshu.search.service.ItemService;
+import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.Map;
+
 @Tag(name = "专辑详情管理")
 @RestController
 @RequestMapping("api/search")
@@ -15,5 +21,17 @@ public class itemApiController {
 	@Autowired
 	private ItemService itemService;
 
+
+	/**
+	 * 根据专辑ID查询专辑详情
+	 * @param albumId
+	 * @return {"albumInfo":{专辑信息},"albumStatVo":{统计信息},"baseCategoryView":{分类对象},"announcer":{}}
+	 */
+	@Operation(summary = "根据专辑ID查询专辑详情")
+	@GetMapping("/albumInfo/{albumId}")
+	public Result<Map<String, Object>> getItemData(@PathVariable("albumId") Long albumId){
+		Map<String, Object> map = itemService.getItemData(albumId);
+		return Result.ok(map);
+	}
 }
 

+ 8 - 1
service/service-search/src/main/java/com/atguigu/tingshu/search/service/ItemService.java

@@ -1,7 +1,14 @@
 package com.atguigu.tingshu.search.service;
 
-public interface ItemService {
+import java.util.Map;
 
+public interface ItemService {
 
 
+    /**
+     * 根据专辑ID查询专辑详情
+     * @param albumId
+     * @return
+     */
+    Map<String, Object> getItemData(Long albumId);
 }

+ 73 - 0
service/service-search/src/main/java/com/atguigu/tingshu/search/service/impl/ItemServiceImpl.java

@@ -1,13 +1,86 @@
 package com.atguigu.tingshu.search.service.impl;
 
+import cn.hutool.core.lang.Assert;
+import com.atguigu.tingshu.album.AlbumFeignClient;
+import com.atguigu.tingshu.model.album.AlbumInfo;
+import com.atguigu.tingshu.model.album.BaseCategoryView;
 import com.atguigu.tingshu.search.service.ItemService;
+import com.atguigu.tingshu.user.client.UserFeignClient;
+import com.atguigu.tingshu.vo.album.AlbumStatVo;
+import com.atguigu.tingshu.vo.user.UserInfoVo;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
 @Slf4j
 @Service
 @SuppressWarnings({"all"})
 public class ItemServiceImpl implements ItemService {
 
+    @Autowired
+    private AlbumFeignClient albumFeignClient;
+
+    @Autowired
+    private UserFeignClient userFeignClient;
+
+
+    @Autowired
+    private Executor threadPoolTaskExecutor;
+
+    /**
+     * 根据专辑ID查询专辑详情
+     * @param albumId
+     * @return
+     */
+    @Override
+    public Map<String, Object> getItemData(Long albumId) {
+        //1.创建封装专辑详情相关数据Map 存在多线程并发写,选择线程安全集合类HashTable,ConcurrentHashMap
+        Map<String, Object> map = new ConcurrentHashMap<>();
+        //2.远程调用专辑服务获取专辑信息-封装专辑信息
+        CompletableFuture<AlbumInfo> albumInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
+            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(albumId).getData();
+            Assert.notNull(albumInfo, "专辑:{}不存在", albumId);
+            map.put("albumInfo", albumInfo);
+            return albumInfo;
+        }, threadPoolTaskExecutor).exceptionally(e->{
+            log.error("查询专辑详情失败:{}", e.getMessage());
+            return null;
+        }).orTimeout(1, TimeUnit.SECONDS);
+
+        //3.远程调用专辑服务获取分类信息-封装分类信息
+        CompletableFuture<Void> categorViewCompletableFuture = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
+            BaseCategoryView categoryView = albumFeignClient.getCategoryView(albumInfo.getCategory3Id()).getData();
+            Assert.notNull(categoryView, "专辑分类:{}不存在", albumInfo.getCategory3Id());
+            map.put("baseCategoryView", categoryView);
+        }, threadPoolTaskExecutor);
+
+        //4.远程调用专辑服务获取统计信息-封统计信息
+        CompletableFuture<Void> albumStatCompletableFuture = CompletableFuture.runAsync(() -> {
+            AlbumStatVo albumStatVo = albumFeignClient.getAlbumStatVo(albumId).getData();
+            Assert.notNull(albumStatVo, "专辑统计:{}不存在", albumId);
+            map.put("albumStatVo", albumStatVo);
+        }, threadPoolTaskExecutor);
+
+        //5.远程调用用户服务获取主播信息-封主播信息
+        CompletableFuture<Void> announcerCompletableFuture  = albumInfoCompletableFuture.thenAcceptAsync(albumInfo -> {
+            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(albumInfo.getUserId()).getData();
+            Assert.notNull(userInfoVo, "主播:{}不存在", albumInfo.getUserId());
+            map.put("announcer", userInfoVo);
+        }, threadPoolTaskExecutor);
 
+        //6.通过异步任务对象组合任务  所有异步任务都必须执行完成
+        CompletableFuture.allOf(
+                albumInfoCompletableFuture,
+                albumStatCompletableFuture,
+                categorViewCompletableFuture,
+                announcerCompletableFuture
+        ).join();
+        return map;
+    }
 }

+ 1 - 0
service/service-search/src/test/java/com/atguigu/tingshu/ServiceSearchApplicationTest.java

@@ -36,6 +36,7 @@ class ServiceSearchApplicationTest {
             try {
                 searchService.upperAlbum(i);
             } catch (Exception e) {
+                e.printStackTrace();
                 continue;
             }
         }

+ 22 - 4
service/service-user/src/main/java/com/atguigu/tingshu/user/api/UserInfoApiController.java

@@ -6,10 +6,10 @@ import com.atguigu.tingshu.vo.user.UserInfoVo;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Map;
 
 @Tag(name = "用户管理接口")
 @RestController
@@ -27,5 +27,23 @@ public class UserInfoApiController {
 		return Result.ok(userInfoVo);
 	}
 
+
+	/**
+	 * 根据用户ID+专辑ID+声音ID列表查询得到声音购买情况
+	 * @param userId
+	 * @param albumId
+	 * @param needCheckBuyStateTrackIds
+	 * @return
+	 */
+	@Operation(summary = "根据专辑ID+声音ID列表查询得到声音购买情况")
+	@PostMapping("/userInfo/userIsPaidTrack/{userId}/{albumId}")
+	public Result<Map<Long, Integer>> userIsPaidTrack(
+			@PathVariable("userId") Long userId,
+			@PathVariable("albumId") Long albumId,
+			@RequestBody List<Long> needCheckBuyStateTrackIds
+			){
+		Map<Long, Integer> map = userInfoService.userIsPaidTrack(userId, albumId, needCheckBuyStateTrackIds);
+		return Result.ok(map);
+	}
 }
 

+ 10 - 0
service/service-user/src/main/java/com/atguigu/tingshu/user/service/UserInfoService.java

@@ -4,6 +4,7 @@ import com.atguigu.tingshu.model.user.UserInfo;
 import com.atguigu.tingshu.vo.user.UserInfoVo;
 import com.baomidou.mybatisplus.extension.service.IService;
 
+import java.util.List;
 import java.util.Map;
 
 public interface UserInfoService extends IService<UserInfo> {
@@ -27,4 +28,13 @@ public interface UserInfoService extends IService<UserInfo> {
      * @param userInfoVo
      */
     void updateUser(UserInfoVo userInfoVo);
+
+    /**
+     * 根据用户ID + 专辑ID + 音轨ID列表查询用户购买情况
+     * @param userId
+     * @param albumId
+     * @param needCheckBuyStateTrackIds
+     * @return
+     */
+    Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> needCheckBuyStateTrackIds);
 }

+ 65 - 1
service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.java

@@ -4,6 +4,7 @@ import cn.binarywang.wx.miniapp.api.WxMaService;
 import cn.binarywang.wx.miniapp.api.WxMaUserService;
 import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.IdUtil;
 import com.atguigu.tingshu.common.constant.RedisConstant;
@@ -11,7 +12,11 @@ import com.atguigu.tingshu.common.rabbit.constant.MqConst;
 import com.atguigu.tingshu.common.rabbit.service.RabbitService;
 import com.atguigu.tingshu.common.util.AuthContextHolder;
 import com.atguigu.tingshu.model.user.UserInfo;
+import com.atguigu.tingshu.model.user.UserPaidAlbum;
+import com.atguigu.tingshu.model.user.UserPaidTrack;
 import com.atguigu.tingshu.user.mapper.UserInfoMapper;
+import com.atguigu.tingshu.user.mapper.UserPaidAlbumMapper;
+import com.atguigu.tingshu.user.mapper.UserPaidTrackMapper;
 import com.atguigu.tingshu.user.service.UserInfoService;
 import com.atguigu.tingshu.vo.user.UserInfoVo;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -24,8 +29,10 @@ import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 @Slf4j
 @Service
@@ -44,6 +51,12 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
     @Autowired
     private RabbitService rabbitService;
 
+    @Autowired
+    private UserPaidAlbumMapper userPaidAlbumMapper;
+
+    @Autowired
+    private UserPaidTrackMapper userPaidTrackMapper;
+
     /**
      * 微信登录
      *
@@ -77,7 +90,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
                 Map<String, Object> map = new HashMap<>();
                 map.put("userId", userInfo.getId());
                 map.put("amount", new BigDecimal("100"));
-                String orderNo = "ZS"+ DateUtil.today().replaceAll("-", "")+IdUtil.getSnowflakeNextId();
+                String orderNo = "ZS" + DateUtil.today().replaceAll("-", "") + IdUtil.getSnowflakeNextId();
                 map.put("orderNo", orderNo);
                 map.put("title", "首次注册赠送");
                 //3.3.2 发送消息
@@ -104,6 +117,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
 
     /**
      * 查询指定用户基本信息
+     *
      * @param userId
      * @return
      */
@@ -115,6 +129,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
 
     /**
      * 更新用户信息
+     *
      * @param userInfoVo
      */
     @Override
@@ -127,4 +142,53 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
         baseMapper.updateById(userInfo);
     }
 
+    /**
+     * 根据用户ID + 专辑ID + 音轨ID列表查询用户购买情况
+     *
+     * @param userId
+     * @param albumId
+     * @param needCheckBuyStateTrackIds
+     * @return
+     */
+    @Override
+    public Map<Long, Integer> userIsPaidTrack(Long userId, Long albumId, List<Long> needCheckBuyStateTrackIds) {
+        Map<Long, Integer> map = new HashMap<>();
+        //1.尝试根据用户ID+专辑ID查询已购专辑 如果存在专辑购买记录,则将提交声音购买情况设置为1,返回即可
+        Long count = userPaidAlbumMapper.selectCount(
+                new LambdaQueryWrapper<UserPaidAlbum>().eq(UserPaidAlbum::getUserId, userId)
+                        .eq(UserPaidAlbum::getAlbumId, albumId)
+        );
+        if (count > 0) {
+            for (Long needCheckBuyStateTrackId : needCheckBuyStateTrackIds) {
+                map.put(needCheckBuyStateTrackId, 1);
+            }
+            return map;
+        }
+        //2.如果用户没有购买专辑,则尝试根据用户ID+专辑ID,查询已购声音列表
+        List<UserPaidTrack> userPaidTrackList = userPaidTrackMapper
+                .selectList(
+                        new LambdaQueryWrapper<UserPaidTrack>().eq(UserPaidTrack::getUserId, userId)
+                                .eq(UserPaidTrack::getAlbumId, albumId)
+                );
+        //2.1 如果已购声音列表不存在,则将提交声音购买情况设置为0,返回即可
+        if(CollUtil.isEmpty(userPaidTrackList)){
+            for (Long needCheckBuyStateTrackId : needCheckBuyStateTrackIds) {
+                map.put(needCheckBuyStateTrackId, 0);
+            }
+            return map;
+        }
+        //2.2 如果存在已购声音列表,将已购声音ID设置为1,未购买声音ID设置为0
+        List<Long> userPaidTrackIdList = userPaidTrackList.stream().map(UserPaidTrack::getTrackId).collect(Collectors.toList());
+        for (Long needCheckBuyStateTrackId : needCheckBuyStateTrackIds) {
+            //2.2.1 已购声音ID集合中包含待检查声音ID,说明该声音已购买 将购买声音ID设置为1
+            //2.2.2 反之 将声音ID购买情况设置为0
+            if(userPaidTrackIdList.contains(needCheckBuyStateTrackId)){
+                map.put(needCheckBuyStateTrackId, 1);
+            }else{
+                map.put(needCheckBuyStateTrackId, 0);
+            }
+        }
+        return map;
+    }
+
 }