diff --git a/common/service-util/pom.xml b/common/service-util/pom.xml index cf9e591..3a67934 100644 --- a/common/service-util/pom.xml +++ b/common/service-util/pom.xml @@ -51,11 +51,11 @@ spring-boot-starter-data-redis - - - - - + + + org.redisson + redisson-spring-boot-starter + org.springframework.boot @@ -87,6 +87,32 @@ com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config + + io.micrometer + micrometer-tracing-bridge-brave + + + io.zipkin.reporter2 + zipkin-reporter-brave + + + io.micrometer + micrometer-observation + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.cloud + spring-cloud-starter-zipkin + 2.2.8.RELEASE + + + io.github.openfeign + feign-micrometer + 12.5 + diff --git a/common/service-util/src/main/java/com/atguigu/tingshu/common/cache/GuiGuCache.java b/common/service-util/src/main/java/com/atguigu/tingshu/common/cache/GuiGuCache.java new file mode 100644 index 0000000..ae5bfce --- /dev/null +++ b/common/service-util/src/main/java/com/atguigu/tingshu/common/cache/GuiGuCache.java @@ -0,0 +1,30 @@ +package com.atguigu.tingshu.common.cache; + +import com.atguigu.tingshu.common.constant.RedisConstant; + +import java.lang.annotation.*; +import java.util.concurrent.TimeUnit; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface GuiGuCache { + /** + * 缓存(业务数据或锁)前缀 + * @return + */ + String prefix() default ""; + + /** + * 缓存时间 + * @return + */ + long ttl() default RedisConstant.ALBUM_TIMEOUT; + + /** + * 时间单位 + * @return + */ + TimeUnit timeUnit() default TimeUnit.SECONDS; +} diff --git a/common/service-util/src/main/java/com/atguigu/tingshu/common/cache/GuiGuCacheAspect.java b/common/service-util/src/main/java/com/atguigu/tingshu/common/cache/GuiGuCacheAspect.java new file mode 100644 index 0000000..c0c3a96 --- /dev/null +++ b/common/service-util/src/main/java/com/atguigu/tingshu/common/cache/GuiGuCacheAspect.java @@ -0,0 +1,81 @@ +package com.atguigu.tingshu.common.cache; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.RandomUtil; +import com.atguigu.tingshu.common.constant.RedisConstant; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static com.atguigu.tingshu.common.constant.RedisConstant.ALBUM_LOCK_EXPIRE_PX2; +import static com.atguigu.tingshu.common.constant.RedisConstant.ALBUM_LOCK_WAIT_PX1; + +@Aspect +@Slf4j +@Component +public class GuiGuCacheAspect { + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private RedissonClient redissonClient; + + @Around("@annotation(guiGuCache)") + public Object doBasicProfiling(ProceedingJoinPoint pjp, GuiGuCache guiGuCache) throws Throwable { + try { + //1.优先从Redis缓存中获取业务数据,命中缓存响应即可 + //1.1 构建缓存业务数据Key 形式=前缀+目标方法参数(采用_拼接) + List argsList = Arrays.asList(pjp.getArgs()); + String args = "none"; + if (CollUtil.isNotEmpty(argsList)) { + //将argsList转换成字符串,用_拼接 + args = argsList.stream() + .map(Object::toString) + .collect(Collectors.joining("_")); + } + //用写这个注解的prefix属性拼接上参数args,得到缓存数据Key + String dataKey = guiGuCache.prefix() + args; + Object result = redisTemplate.opsForValue().get(dataKey); + if (result != null) { + return result; + } + //2.尝试获取分布式锁 + //2.1 构建锁Key + String lockKey = dataKey + RedisConstant.CACHE_LOCK_SUFFIX; + RLock lock = redissonClient.getLock(lockKey); + boolean flag= lock.tryLock(ALBUM_LOCK_WAIT_PX1, ALBUM_LOCK_EXPIRE_PX2, TimeUnit.SECONDS); + //3.获取锁成功,执行目标方法,将结果缓存到Redis中,业务执行结束,释放锁 + if(flag){ + try { + //3.1 执行查询数据库方法 + result = pjp.proceed(); + //设置超时时间,防止缓存雪崩 + long ttl = RedisConstant.ALBUM_TIMEOUT + RandomUtil.randomInt(600); + return result; + } finally { + //3.3 释放锁 + lock.unlock(); + + } + }else{ + //4.获取锁失败,自旋 + TimeUnit.MILLISECONDS.sleep(30); + return this.doBasicProfiling(pjp, guiGuCache); + } + } catch (Throwable e) { + log.error("Redis服务不可用,请检查Redis服务是否正常!"); + return pjp.proceed(); + } + + } +} diff --git a/common/service-util/src/main/java/com/atguigu/tingshu/common/config/pool/ThreadPoolConfig.java b/common/service-util/src/main/java/com/atguigu/tingshu/common/config/pool/ThreadPoolConfig.java index 2405bac..ee4d346 100644 --- a/common/service-util/src/main/java/com/atguigu/tingshu/common/config/pool/ThreadPoolConfig.java +++ b/common/service-util/src/main/java/com/atguigu/tingshu/common/config/pool/ThreadPoolConfig.java @@ -1,6 +1,9 @@ package com.atguigu.tingshu.common.config.pool; +import com.atguigu.tingshu.common.zipkin.ZipkinHelper; +import com.atguigu.tingshu.common.zipkin.ZipkinTaskDecorator; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @@ -15,6 +18,8 @@ import java.util.concurrent.*; @Configuration public class ThreadPoolConfig { + @Autowired(required = false) + ZipkinHelper zipkinHelper; /** * 基于JDK(JUC)提供线程池Class */ @@ -65,6 +70,8 @@ public class ThreadPoolConfig { taskExecutor.setAwaitTerminationSeconds(300); // 线程不够用时由调用的线程处理该任务 taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + //设置解决zipkin链路追踪不完整装饰器对象 + taskExecutor.setTaskDecorator(new ZipkinTaskDecorator(zipkinHelper)); return taskExecutor; } } diff --git a/common/service-util/src/main/java/com/atguigu/tingshu/common/constant/RedisConstant.java b/common/service-util/src/main/java/com/atguigu/tingshu/common/constant/RedisConstant.java index 7dfec26..e0c9711 100644 --- a/common/service-util/src/main/java/com/atguigu/tingshu/common/constant/RedisConstant.java +++ b/common/service-util/src/main/java/com/atguigu/tingshu/common/constant/RedisConstant.java @@ -52,6 +52,9 @@ public class RedisConstant { //更新声音统计前缀 public static final String USER_TRACK_REPEAT_STAT_PREFIX = "user:track:"; + public static final String USER_SEARCH_REPEAT_STAT_PREFIX = "user:search:"; + + //重复锁定账户 diff --git a/common/service-util/src/main/java/com/atguigu/tingshu/common/zipkin/ZipkinHelper.java b/common/service-util/src/main/java/com/atguigu/tingshu/common/zipkin/ZipkinHelper.java new file mode 100644 index 0000000..3c71bdc --- /dev/null +++ b/common/service-util/src/main/java/com/atguigu/tingshu/common/zipkin/ZipkinHelper.java @@ -0,0 +1,147 @@ +package com.atguigu.tingshu.common.zipkin; + +import brave.Span; +import brave.Tracer; +import org.slf4j.MDC; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.concurrent.Callable; + +@Component +public class ZipkinHelper { + @Autowired(required = false) + private Tracer tracer; + + public ZipkinHelper() { + } + + public Runnable wrap(Runnable runnable) { + Span currentSpan = this.tracer.currentSpan(); + return () -> { + Tracer.SpanInScope scope = this.tracer.withSpanInScope(currentSpan); + Throwable var4 = null; + + try { + Span span = this.tracer.nextSpan(); + MDC.put("X-B3-TraceId", span.context().traceIdString()); + MDC.put("X-B3-SpanId", span.context().spanIdString()); + MDC.put("X-B3-ParentSpanId", span.context().parentIdString()); + span.name("new_thread_started").kind(Span.Kind.SERVER).tag("thread_id", Thread.currentThread().getId() + "").tag("thread_name", Thread.currentThread().getName() + ""); + span.start(); + + try { + Tracer.SpanInScope ws = this.tracer.withSpanInScope(span); + Throwable var7 = null; + + try { + runnable.run(); + } catch (Throwable var44) { + var7 = var44; + throw var44; + } finally { + if (ws != null) { + if (var7 != null) { + try { + ws.close(); + } catch (Throwable var43) { + var7.addSuppressed(var43); + } + } else { + ws.close(); + } + } + + } + } catch (Error | RuntimeException var46) { + span.error(var46); + throw var46; + } finally { + span.finish(); + } + } catch (Throwable var48) { + var4 = var48; + throw var48; + } finally { + if (scope != null) { + if (var4 != null) { + try { + scope.close(); + } catch (Throwable var42) { + var4.addSuppressed(var42); + } + } else { + scope.close(); + } + } + + } + + }; + } + + public Callable wrap(Callable callable) { + Span currentSpan = this.tracer.currentSpan(); + return () -> { + Tracer.SpanInScope scope = this.tracer.withSpanInScope(currentSpan); + Throwable var4 = null; + + T var8; + try { + Span span = this.tracer.nextSpan(); + MDC.put("X-B3-TraceId", span.context().traceIdString()); + MDC.put("X-B3-SpanId", span.context().spanIdString()); + MDC.put("X-B3-ParentSpanId", span.context().parentIdString()); + span.name("new_thread_started").kind(Span.Kind.SERVER).tag("thread_id", Thread.currentThread().getId() + "").tag("thread_name", Thread.currentThread().getName() + ""); + span.start(); + + try { + Tracer.SpanInScope ws = this.tracer.withSpanInScope(span); + Throwable var7 = null; + + try { + var8 = callable.call(); + } catch (Throwable var45) { + var8 = (T) var45; + var7 = var45; + throw var45; + } finally { + if (ws != null) { + if (var7 != null) { + try { + ws.close(); + } catch (Throwable var44) { + var7.addSuppressed(var44); + } + } else { + ws.close(); + } + } + + } + } catch (Error | RuntimeException var47) { + span.error(var47); + throw var47; + } finally { + span.finish(); + } + } catch (Throwable var49) { + var4 = var49; + throw var49; + } finally { + if (scope != null) { + if (var4 != null) { + try { + scope.close(); + } catch (Throwable var43) { + var4.addSuppressed(var43); + } + } else { + scope.close(); + } + } + } + return var8; + }; + } +} diff --git a/common/service-util/src/main/java/com/atguigu/tingshu/common/zipkin/ZipkinTaskDecorator.java b/common/service-util/src/main/java/com/atguigu/tingshu/common/zipkin/ZipkinTaskDecorator.java new file mode 100644 index 0000000..bf2be67 --- /dev/null +++ b/common/service-util/src/main/java/com/atguigu/tingshu/common/zipkin/ZipkinTaskDecorator.java @@ -0,0 +1,36 @@ +package com.atguigu.tingshu.common.zipkin; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.task.TaskDecorator; + +/** + + * @Author: chenyangu + + * @Date: 2021/8/16 17:05 + + * @Description: zipkin装饰器 + + */ + +@Slf4j + +public class ZipkinTaskDecorator implements TaskDecorator { + + private ZipkinHelper zipkinHelper; + + public ZipkinTaskDecorator(ZipkinHelper zipkinHelper) { + + this.zipkinHelper = zipkinHelper; + + } + + @Override + + public Runnable decorate(Runnable runnable) { + + return zipkinHelper.wrap(runnable); + + } + +} diff --git a/common/service-util/target/classes/com/atguigu/tingshu/common/config/pool/ThreadPoolConfig.class b/common/service-util/target/classes/com/atguigu/tingshu/common/config/pool/ThreadPoolConfig.class index d74c9d5..6f36dc4 100644 Binary files a/common/service-util/target/classes/com/atguigu/tingshu/common/config/pool/ThreadPoolConfig.class and b/common/service-util/target/classes/com/atguigu/tingshu/common/config/pool/ThreadPoolConfig.class differ diff --git a/common/service-util/target/classes/com/atguigu/tingshu/common/constant/RedisConstant.class b/common/service-util/target/classes/com/atguigu/tingshu/common/constant/RedisConstant.class index 4fe44a9..ca48547 100644 Binary files a/common/service-util/target/classes/com/atguigu/tingshu/common/constant/RedisConstant.class and b/common/service-util/target/classes/com/atguigu/tingshu/common/constant/RedisConstant.class differ diff --git a/model/src/main/java/com/atguigu/tingshu/vo/album/TrackStatMqVo.java b/model/src/main/java/com/atguigu/tingshu/vo/album/TrackStatMqVo.java index ce07e98..27ace13 100644 --- a/model/src/main/java/com/atguigu/tingshu/vo/album/TrackStatMqVo.java +++ b/model/src/main/java/com/atguigu/tingshu/vo/album/TrackStatMqVo.java @@ -3,9 +3,13 @@ package com.atguigu.tingshu.vo.album; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import java.io.Serializable; + @Data @Schema(description = "TrackStatMqVo") -public class TrackStatMqVo { +public class TrackStatMqVo implements Serializable { + //防止 生产消息 消费消息使用对象不是同一个 + private static final long serialVersionUID = 1L; @Schema(description = "业务编号:去重使用") private String businessNo; diff --git a/model/src/main/java/com/atguigu/tingshu/vo/search/SearchStatMqVo.java b/model/src/main/java/com/atguigu/tingshu/vo/search/SearchStatMqVo.java new file mode 100644 index 0000000..aa2ea61 --- /dev/null +++ b/model/src/main/java/com/atguigu/tingshu/vo/search/SearchStatMqVo.java @@ -0,0 +1,27 @@ +package com.atguigu.tingshu.vo.search; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +@Data +@Schema(description = "SearchStatMqVo") +public class SearchStatMqVo implements Serializable { + //防止 生产消息 消费消息使用对象不是同一个 + private static final long serialVersionUID = 1L; + @Schema(description = "业务编号:去重使用") + private String businessNo; + + @Schema(description = "专辑id") + private Long albumId; + + @Schema(description = "声音id") + private Long trackId; + + @Schema(description = "统计类型") + private String statType; + + @Schema(description = "更新数目") + private Integer count; +} diff --git a/model/target/classes/com/atguigu/tingshu/vo/album/TrackStatMqVo.class b/model/target/classes/com/atguigu/tingshu/vo/album/TrackStatMqVo.class index 385437d..c3b79c3 100644 Binary files a/model/target/classes/com/atguigu/tingshu/vo/album/TrackStatMqVo.class and b/model/target/classes/com/atguigu/tingshu/vo/album/TrackStatMqVo.class differ diff --git a/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/AlbumFeignClient.java b/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/AlbumFeignClient.java index 9586c27..fd50ec3 100644 --- a/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/AlbumFeignClient.java +++ b/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/AlbumFeignClient.java @@ -3,6 +3,7 @@ package com.atguigu.tingshu.album; import com.atguigu.tingshu.album.impl.AlbumDegradeFeignClient; import com.atguigu.tingshu.common.result.Result; import com.atguigu.tingshu.model.album.AlbumInfo; +import com.atguigu.tingshu.model.album.BaseCategory1; import com.atguigu.tingshu.model.album.BaseCategory3; import com.atguigu.tingshu.model.album.BaseCategoryView; import com.atguigu.tingshu.vo.album.AlbumStatVo; @@ -45,6 +46,9 @@ public interface AlbumFeignClient { @GetMapping("/albumInfo/getAlbumStatVo/{albumId}") public ResultgetAlbumStatVo(@PathVariable Long albumId); + @GetMapping("/category/findAllCategory1") + Result> findAllCategory1(); + } diff --git a/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.java b/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.java index d8a1ebe..a4dec8c 100644 --- a/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.java +++ b/service-client/service-album-client/src/main/java/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.java @@ -4,6 +4,7 @@ package com.atguigu.tingshu.album.impl; import com.atguigu.tingshu.album.AlbumFeignClient; import com.atguigu.tingshu.common.result.Result; import com.atguigu.tingshu.model.album.AlbumInfo; +import com.atguigu.tingshu.model.album.BaseCategory1; import com.atguigu.tingshu.model.album.BaseCategory3; import com.atguigu.tingshu.model.album.BaseCategoryView; import com.atguigu.tingshu.vo.album.AlbumStatVo; @@ -40,4 +41,10 @@ public class AlbumDegradeFeignClient implements AlbumFeignClient { log.error("[专辑服务]提供远程调用方法getAlbumStatVo执行服务降级"); return null; } + + @Override + public Result> findAllCategory1() { + log.error("[专辑服务]提供远程调用方法findAllCategory1执行服务降级"); + return null; + } } diff --git a/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/AlbumFeignClient.class b/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/AlbumFeignClient.class index 5022b35..b4bb2b8 100644 Binary files a/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/AlbumFeignClient.class and b/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/AlbumFeignClient.class differ diff --git a/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.class b/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.class index 173bdc2..fb595b3 100644 Binary files a/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.class and b/service-client/service-album-client/target/classes/com/atguigu/tingshu/album/impl/AlbumDegradeFeignClient.class differ diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/api/AlbumInfoApiController.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/api/AlbumInfoApiController.java index e915f84..3092efc 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/api/AlbumInfoApiController.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/api/AlbumInfoApiController.java @@ -18,7 +18,6 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import java.util.List; -import java.util.Map; @Tag(name = "专辑管理") @RestController @@ -71,7 +70,7 @@ public class AlbumInfoApiController { @Operation(summary = "查询专辑信息,包含专辑标签列表") @GetMapping("/albumInfo/getAlbumInfo/{id}") public Result getAlbumInfo(@PathVariable Long id) { - AlbumInfo albumInfo = albumInfoService.getAlbumInfo(id); + AlbumInfo albumInfo = albumInfoService.getAlbumInfoFromDB(id); return Result.ok(albumInfo); } @Operation(summary = "更新专辑信息") diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/api/BaseCategoryApiController.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/api/BaseCategoryApiController.java index 6d8211e..40ab7b8 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/api/BaseCategoryApiController.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/api/BaseCategoryApiController.java @@ -4,8 +4,10 @@ import com.alibaba.fastjson.JSONObject; import com.atguigu.tingshu.album.service.BaseCategoryService; import com.atguigu.tingshu.common.result.Result; import com.atguigu.tingshu.model.album.BaseAttribute; +import com.atguigu.tingshu.model.album.BaseCategory1; import com.atguigu.tingshu.model.album.BaseCategory3; import com.atguigu.tingshu.model.album.BaseCategoryView; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; @@ -66,6 +68,16 @@ public class BaseCategoryApiController { return Result.ok(jsonObject); } + @Operation(summary = "查询所有一级分类集合") + @GetMapping("/category/findAllCategory1") + public Result> findAllCategory1(){ + List list=baseCategoryService.list( + new LambdaQueryWrapper() + .select(BaseCategory1::getId,BaseCategory1::getName) + ); + return Result.ok(list); + } + diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/api/TrackInfoApiController.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/api/TrackInfoApiController.java index e765ff1..2c9ce8c 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/api/TrackInfoApiController.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/api/TrackInfoApiController.java @@ -2,6 +2,7 @@ package com.atguigu.tingshu.album.api; import com.atguigu.tingshu.album.service.TrackInfoService; import com.atguigu.tingshu.album.service.VodService; +import com.atguigu.tingshu.common.cache.GuiGuCache; import com.atguigu.tingshu.common.login.GuiGuLogin; import com.atguigu.tingshu.common.result.Result; import com.atguigu.tingshu.common.util.AuthContextHolder; @@ -10,6 +11,8 @@ 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.atguigu.tingshu.vo.album.TrackStatVo; +import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -18,6 +21,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import java.util.List; import java.util.Map; @Tag(name = "声音管理") @@ -34,6 +38,7 @@ public class TrackInfoApiController { @Autowired private VodService vodService; + //用MultipartFile来接收文件 @Operation(summary = "将音频文件上传到腾讯云点播平台") @PostMapping("/trackInfo/uploadTrack") @@ -90,6 +95,7 @@ public class TrackInfoApiController { * @return */ @Operation(summary = "查询声音信息") + @GuiGuCache(prefix = "album:trackInfo:") @GetMapping("/trackInfo/getTrackInfo/{id}") public Result getTrackInfo(@PathVariable Long id){ TrackInfo trackInfo = trackInfoService.getById(id); @@ -144,6 +150,20 @@ public class TrackInfoApiController { //4.响应结果 return Result.ok(pageInfo); } + /** + * 获取声音统计信息 + * @param trackId + * @return + */ + @Operation(summary = "获取声音统计信息") + @GetMapping("/trackInfo/getTrackStatVo/{trackId}") + public Result getTrackStatVo(@PathVariable Long trackId) { + TrackStatVo trackStatVo = trackInfoService.getTrackStatVo(trackId); + return Result.ok(trackStatVo); + } + + + } diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/mapper/TrackInfoMapper.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/mapper/TrackInfoMapper.java index 3c869a2..c05411d 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/mapper/TrackInfoMapper.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/mapper/TrackInfoMapper.java @@ -4,6 +4,7 @@ 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.atguigu.tingshu.vo.album.TrackStatVo; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.ibatis.annotations.Mapper; @@ -16,4 +17,6 @@ public interface TrackInfoMapper extends BaseMapper { Page findUserTrackPage(Page pageInfo,@Param("vo")TrackInfoQuery trackInfoQuery); Page findAlbumTrackPage(Page pageInfo, Long albumId); + + TrackStatVo getTrackStatVo(@Param("trackId")Long trackId); } diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/receiver/AlbumReceiver.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/receiver/AlbumReceiver.java new file mode 100644 index 0000000..f4ac1f5 --- /dev/null +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/receiver/AlbumReceiver.java @@ -0,0 +1,68 @@ +package com.atguigu.tingshu.album.receiver; + +import com.atguigu.tingshu.album.service.TrackInfoService; +import com.atguigu.tingshu.common.constant.RedisConstant; +import com.atguigu.tingshu.common.rabbit.constant.MqConst; +import com.atguigu.tingshu.vo.album.TrackStatMqVo; +import com.rabbitmq.client.Channel; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.annotation.Exchange; +import org.springframework.amqp.rabbit.annotation.Queue; +import org.springframework.amqp.rabbit.annotation.QueueBinding; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +/** + * @author: atguigu + * @create: 2025-07-28 14:14 + */ +@Slf4j +@Component +public class AlbumReceiver { + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private TrackInfoService trackInfoService; + + /** + * 监听更新声音/专辑统计信息 + * + * @param mqVo + * @param message + * @param channel + */ + @SneakyThrows + @RabbitListener(bindings = @QueueBinding( + exchange = @Exchange(value = MqConst.EXCHANGE_TRACK, durable = "true"), + value = @Queue(value = MqConst.QUEUE_TRACK_STAT_UPDATE, durable = "true"), + key = MqConst.ROUTING_TRACK_STAT_UPDATE + )) + public void updateStat(TrackStatMqVo mqVo, Message message, Channel channel) { + if (mqVo != null) { + log.info("更新声音/专辑统计信息:{}", mqVo); + //1.幂等性处理 + //1.1 从MQ消息对象中获取消息唯一标识 + String key = RedisConstant.BUSINESS_PREFIX + "db:" + mqVo.getBusinessNo(); + //1.2 尝试采用set nx写入Redis + Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, "1", 5, TimeUnit.MINUTES); + + //1.3 写入成功消息才进行业务处理,写入失败(消息重复被MQ服务器投递)忽略消息 + if (flag) { + //2.业务处理 + trackInfoService.updateStat(mqVo); + + } + } + channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); + } + + +} diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/AlbumInfoService.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/AlbumInfoService.java index 2e9d904..2cb5807 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/AlbumInfoService.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/AlbumInfoService.java @@ -23,7 +23,7 @@ public interface AlbumInfoService extends IService { void removeAlbumInfo(Long id); - AlbumInfo getAlbumInfo(Long id); + AlbumInfo getAlbumInfoFromDB(Long id); void updateAlbumInfo(Long id, AlbumInfoVo albumInfoVo); diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/TrackInfoService.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/TrackInfoService.java index b9872db..98b6f11 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/TrackInfoService.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/TrackInfoService.java @@ -2,9 +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.atguigu.tingshu.vo.album.*; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; @@ -36,4 +34,7 @@ public interface TrackInfoService extends IService { Page findAlbumTrackPage(Page pageInfo, Long userId, Long albumId); + TrackStatVo getTrackStatVo(Long trackId); + + void updateStat(TrackStatMqVo mqVo); } diff --git a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/AlbumInfoServiceImpl.java b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/AlbumInfoServiceImpl.java index 2de8053..d330573 100644 --- a/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/AlbumInfoServiceImpl.java +++ b/service/service-album/src/main/java/com/atguigu/tingshu/album/service/impl/AlbumInfoServiceImpl.java @@ -8,6 +8,8 @@ import com.atguigu.tingshu.album.mapper.TrackInfoMapper; import com.atguigu.tingshu.album.service.AlbumAttributeValueService; import com.atguigu.tingshu.album.service.AlbumInfoService; import com.atguigu.tingshu.album.service.AuditService; +import com.atguigu.tingshu.common.cache.GuiGuCache; +import com.atguigu.tingshu.common.constant.RedisConstant; import com.atguigu.tingshu.common.constant.SystemConstant; import com.atguigu.tingshu.common.execption.GuiguException; import com.atguigu.tingshu.common.rabbit.constant.MqConst; @@ -26,7 +28,9 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -51,6 +55,11 @@ public class AlbumInfoServiceImpl extends ServiceImpl getBaseCategoryList() { //1.创建响应结果集合对象-用于封装所有一级分类对象 //创建一个新的List对象 @@ -99,6 +102,7 @@ public class BaseCategoryServiceImpl extends ServiceImpl findAttribute(Long category1Id) { List list=baseAttributeMapper.findAttribute(category1Id); return list; @@ -110,11 +114,13 @@ public class BaseCategoryServiceImpl extends ServiceImpl findTopBaseCategory3(Long category1Id) { List baseCategory2List = baseCategory2Mapper.selectList( new LambdaQueryWrapper() .eq(BaseCategory2::getCategory1Id, category1Id) @@ -134,6 +140,7 @@ public class BaseCategoryServiceImpl extends ServiceImpl() + .eq(TrackStat::getTrackId, mqVo.getTrackId()) + .eq(TrackStat::getStatType, mqVo.getStatType()) + .setSql("stat_num = stat_num +" + mqVo.getCount()) + ); + + //2.如果是声音播放、评论。还需要更新声音所属专辑统计数值 + if(SystemConstant.TRACK_STAT_PLAY.equals(mqVo.getStatType())){ + albumStatMapper.update( + null, + new LambdaUpdateWrapper() + .eq(AlbumStat::getAlbumId, mqVo.getAlbumId()) + .eq(AlbumStat::getStatType, SystemConstant.ALBUM_STAT_PLAY) + .setSql("stat_num = stat_num +" + mqVo.getCount()) + ); + } + + if(SystemConstant.TRACK_STAT_COMMENT.equals(mqVo.getStatType())){ + albumStatMapper.update( + null, + new LambdaUpdateWrapper() + .eq(AlbumStat::getAlbumId, mqVo.getAlbumId()) + .eq(AlbumStat::getStatType, SystemConstant.ALBUM_STAT_COMMENT) + .setSql("stat_num = stat_num +" + mqVo.getCount()) + ); + } + } +} + + diff --git a/service/service-album/src/main/resources/mapper/TrackInfoMapper.xml b/service/service-album/src/main/resources/mapper/TrackInfoMapper.xml index e026e08..005d3ed 100644 --- a/service/service-album/src/main/resources/mapper/TrackInfoMapper.xml +++ b/service/service-album/src/main/resources/mapper/TrackInfoMapper.xml @@ -50,5 +50,15 @@ order by ti.order_num + + + diff --git a/service/service-album/target/classes/com/atguigu/tingshu/album/api/AlbumInfoApiController.class b/service/service-album/target/classes/com/atguigu/tingshu/album/api/AlbumInfoApiController.class index 49be6a0..a282306 100644 Binary files a/service/service-album/target/classes/com/atguigu/tingshu/album/api/AlbumInfoApiController.class and b/service/service-album/target/classes/com/atguigu/tingshu/album/api/AlbumInfoApiController.class differ diff --git a/service/service-album/target/classes/com/atguigu/tingshu/album/api/BaseCategoryApiController.class b/service/service-album/target/classes/com/atguigu/tingshu/album/api/BaseCategoryApiController.class index 22d597f..932caa0 100644 Binary files a/service/service-album/target/classes/com/atguigu/tingshu/album/api/BaseCategoryApiController.class and b/service/service-album/target/classes/com/atguigu/tingshu/album/api/BaseCategoryApiController.class differ diff --git a/service/service-album/target/classes/com/atguigu/tingshu/album/api/TrackInfoApiController.class b/service/service-album/target/classes/com/atguigu/tingshu/album/api/TrackInfoApiController.class index 07e1890..4fa11a4 100644 Binary files a/service/service-album/target/classes/com/atguigu/tingshu/album/api/TrackInfoApiController.class and b/service/service-album/target/classes/com/atguigu/tingshu/album/api/TrackInfoApiController.class differ diff --git a/service/service-album/target/classes/com/atguigu/tingshu/album/mapper/TrackInfoMapper.class b/service/service-album/target/classes/com/atguigu/tingshu/album/mapper/TrackInfoMapper.class index 6b2c1bc..9a508d5 100644 Binary files a/service/service-album/target/classes/com/atguigu/tingshu/album/mapper/TrackInfoMapper.class and b/service/service-album/target/classes/com/atguigu/tingshu/album/mapper/TrackInfoMapper.class differ diff --git a/service/service-album/target/classes/com/atguigu/tingshu/album/service/AlbumInfoService.class b/service/service-album/target/classes/com/atguigu/tingshu/album/service/AlbumInfoService.class index 52c8b37..f72b6a7 100644 Binary files a/service/service-album/target/classes/com/atguigu/tingshu/album/service/AlbumInfoService.class and b/service/service-album/target/classes/com/atguigu/tingshu/album/service/AlbumInfoService.class differ diff --git a/service/service-album/target/classes/com/atguigu/tingshu/album/service/TrackInfoService.class b/service/service-album/target/classes/com/atguigu/tingshu/album/service/TrackInfoService.class index ab27e21..560fe4d 100644 Binary files a/service/service-album/target/classes/com/atguigu/tingshu/album/service/TrackInfoService.class and b/service/service-album/target/classes/com/atguigu/tingshu/album/service/TrackInfoService.class differ diff --git a/service/service-album/target/classes/com/atguigu/tingshu/album/service/impl/AlbumInfoServiceImpl.class b/service/service-album/target/classes/com/atguigu/tingshu/album/service/impl/AlbumInfoServiceImpl.class index 8d5b3c7..8b349ab 100644 Binary files a/service/service-album/target/classes/com/atguigu/tingshu/album/service/impl/AlbumInfoServiceImpl.class and b/service/service-album/target/classes/com/atguigu/tingshu/album/service/impl/AlbumInfoServiceImpl.class differ diff --git a/service/service-album/target/classes/com/atguigu/tingshu/album/service/impl/BaseCategoryServiceImpl.class b/service/service-album/target/classes/com/atguigu/tingshu/album/service/impl/BaseCategoryServiceImpl.class index f7d87d5..482c1a1 100644 Binary files a/service/service-album/target/classes/com/atguigu/tingshu/album/service/impl/BaseCategoryServiceImpl.class and b/service/service-album/target/classes/com/atguigu/tingshu/album/service/impl/BaseCategoryServiceImpl.class differ diff --git a/service/service-album/target/classes/com/atguigu/tingshu/album/service/impl/TrackInfoServiceImpl.class b/service/service-album/target/classes/com/atguigu/tingshu/album/service/impl/TrackInfoServiceImpl.class index 4b6e5c8..7c48afa 100644 Binary files a/service/service-album/target/classes/com/atguigu/tingshu/album/service/impl/TrackInfoServiceImpl.class and b/service/service-album/target/classes/com/atguigu/tingshu/album/service/impl/TrackInfoServiceImpl.class differ diff --git a/service/service-album/target/classes/mapper/TrackInfoMapper.xml b/service/service-album/target/classes/mapper/TrackInfoMapper.xml index e026e08..005d3ed 100644 --- a/service/service-album/target/classes/mapper/TrackInfoMapper.xml +++ b/service/service-album/target/classes/mapper/TrackInfoMapper.xml @@ -50,5 +50,15 @@ order by ti.order_num + + + diff --git a/service/service-search/pom.xml b/service/service-search/pom.xml index ba14291..6e59f97 100644 --- a/service/service-search/pom.xml +++ b/service/service-search/pom.xml @@ -36,6 +36,21 @@ org.apache.kafka kafka-streams + + io.github.biezhi + TinyPinyin + 2.0.3.RELEASE + + + com.belerweb + pinyin4j + 2.5.1 + + + com.github.stuxuhai + jpinyin + 1.1.8 + diff --git a/service/service-search/src/main/java/com/atguigu/tingshu/search/api/SearchApiController.java b/service/service-search/src/main/java/com/atguigu/tingshu/search/api/SearchApiController.java index 3b67ae2..4c728c9 100644 --- a/service/service-search/src/main/java/com/atguigu/tingshu/search/api/SearchApiController.java +++ b/service/service-search/src/main/java/com/atguigu/tingshu/search/api/SearchApiController.java @@ -3,6 +3,7 @@ package com.atguigu.tingshu.search.api; import com.atguigu.tingshu.common.result.Result; import com.atguigu.tingshu.query.search.AlbumIndexQuery; import com.atguigu.tingshu.search.service.SearchService; +import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo; import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -69,6 +70,34 @@ public class SearchApiController { return Result.ok(list); } + /** + * 根据用户已录入字符展示提示词下拉列表(最多10个) + * @param keyword + * @return + */ + @Operation(summary = "根据用户已录入字符展示提示词下拉列表(最多10个)") + @GetMapping("/albumInfo/completeSuggest/{keyword}") + public Result> completeSuggest(@PathVariable String keyword) { + List list = searchService.completeSuggest(keyword); + return Result.ok(list); + } + /** + * 更新Redis小时榜数据 + * @return + */ + @Operation(summary = "更新Redis小时榜数据") + @GetMapping("/albumInfo/updateLatelyAlbumRanking/{top}") + public Result updateLatelyAlbumRanking(@PathVariable("top") Integer top){ + searchService.updateLatelyAlbumRanking(top); + return Result.ok(); + } + @Operation(summary = "获取不同分类下不同排行维度TOP20") + @GetMapping("/albumInfo/findRankingList/{category1Id}/{dimension}") + public Result> getRankingList(@PathVariable Long category1Id, @PathVariable String dimension){ + List list = searchService.getRankingList(category1Id, dimension); + return Result.ok(list); + } + } diff --git a/service/service-search/src/main/java/com/atguigu/tingshu/search/receiver/SearchReciever.java b/service/service-search/src/main/java/com/atguigu/tingshu/search/receiver/SearchReciever.java index 439dc83..2928f2d 100644 --- a/service/service-search/src/main/java/com/atguigu/tingshu/search/receiver/SearchReciever.java +++ b/service/service-search/src/main/java/com/atguigu/tingshu/search/receiver/SearchReciever.java @@ -1,7 +1,9 @@ package com.atguigu.tingshu.search.receiver; +import com.atguigu.tingshu.common.constant.RedisConstant; import com.atguigu.tingshu.common.rabbit.constant.MqConst; import com.atguigu.tingshu.search.service.SearchService; +import com.atguigu.tingshu.vo.album.TrackStatMqVo; import com.rabbitmq.client.Channel; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -11,8 +13,11 @@ import org.springframework.amqp.rabbit.annotation.Queue; import org.springframework.amqp.rabbit.annotation.QueueBinding; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; +import java.util.concurrent.TimeUnit; + /** * @author: atguigu * @create: 2025-07-22 15:22 @@ -23,6 +28,8 @@ public class SearchReciever { @Autowired private SearchService searchService; + @Autowired + private RedisTemplate redisTemplate; /** * 监听专辑上架消息 @@ -63,4 +70,38 @@ public class SearchReciever { } channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); } -} + +// /** +// * 监听更新声音/搜索统计信息 +// * +// * @param mqVo +// * @param message +// * @param channel +// */ +// +// @RabbitListener(bindings = @QueueBinding( +// exchange = @Exchange(value = MqConst.EXCHANGE_TRACK, durable = "true"), +// value = @Queue(value = MqConst.QUEUE_ALBUM_ES_STAT_UPDATE, durable = "true"), +// key = MqConst.ROUTING_TRACK_STAT_UPDATE) +// ) +// @SneakyThrows +// public void updateStat(TrackStatMqVo mqVo, Message message, Channel channel){ +// if (mqVo != null)log.info("更新声音/专辑统计信息:{}", mqVo); +// //1.幂等性处理 +// //1.1 从MQ消息对象中获取消息唯一标识 +// String key = RedisConstant.BUSINESS_PREFIX + "db:" + mqVo.getBusinessNo(); +// //1.2 尝试采用set nx写入Redis +// Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, "1", 5, TimeUnit.MINUTES); +// +// //1.3 写入成功消息才进行业务处理,写入失败(消息重复被MQ服务器投递)忽略消息 +// if (flag) { +// //2.业务处理 +// searchService.upperAlbum(mqVo.getAlbumId()); +// +// } +// channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); +// } + + + } + diff --git a/service/service-search/src/main/java/com/atguigu/tingshu/search/repository/AlbumInfoIndexRepository.java b/service/service-search/src/main/java/com/atguigu/tingshu/search/repository/AlbumInfoIndexRepository.java index d5a69e5..a8b269b 100644 --- a/service/service-search/src/main/java/com/atguigu/tingshu/search/repository/AlbumInfoIndexRepository.java +++ b/service/service-search/src/main/java/com/atguigu/tingshu/search/repository/AlbumInfoIndexRepository.java @@ -2,6 +2,6 @@ package com.atguigu.tingshu.search.repository; import com.atguigu.tingshu.model.search.AlbumInfoIndex; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; - +//当启动这个服务的启动类的时候 当检测到有这个接口,可以自动创建索引库 public interface AlbumInfoIndexRepository extends ElasticsearchRepository { } diff --git a/service/service-search/src/main/java/com/atguigu/tingshu/search/repository/SuggestIndexRepository.java b/service/service-search/src/main/java/com/atguigu/tingshu/search/repository/SuggestIndexRepository.java new file mode 100644 index 0000000..366e9bc --- /dev/null +++ b/service/service-search/src/main/java/com/atguigu/tingshu/search/repository/SuggestIndexRepository.java @@ -0,0 +1,7 @@ +package com.atguigu.tingshu.search.repository; + +import com.atguigu.tingshu.model.search.SuggestIndex; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; + +public interface SuggestIndexRepository extends ElasticsearchRepository { +} diff --git a/service/service-search/src/main/java/com/atguigu/tingshu/search/service/SearchService.java b/service/service-search/src/main/java/com/atguigu/tingshu/search/service/SearchService.java index 25ee879..bc9e9fa 100644 --- a/service/service-search/src/main/java/com/atguigu/tingshu/search/service/SearchService.java +++ b/service/service-search/src/main/java/com/atguigu/tingshu/search/service/SearchService.java @@ -1,8 +1,13 @@ package com.atguigu.tingshu.search.service; +import co.elastic.clients.elasticsearch.core.SearchResponse; +import com.atguigu.tingshu.model.search.AlbumInfoIndex; +import com.atguigu.tingshu.model.search.SuggestIndex; import com.atguigu.tingshu.query.search.AlbumIndexQuery; +import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo; import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -18,5 +23,18 @@ public interface SearchService { List> channel(Long category1Id); + List completeSuggest(String keyword); + /** + * 解析自动补全建议结果 + * @param searchResponse 检索响应结果对象 + * @param suggestName 建议器名称 + * @return + */ + Collection parseSuggestResult(SearchResponse searchResponse, String suggestName); + void saveSuggestIndex(AlbumInfoIndex albumInfoIndex); + + void updateLatelyAlbumRanking(Integer top); + + List getRankingList(Long category1Id, String dimension); } diff --git a/service/service-search/src/main/java/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.java b/service/service-search/src/main/java/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.java index 960f129..622a6d1 100644 --- a/service/service-search/src/main/java/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.java +++ b/service/service-search/src/main/java/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.java @@ -2,9 +2,10 @@ package com.atguigu.tingshu.search.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.CollectionUtil; + import cn.hutool.core.lang.Assert; import cn.hutool.core.util.RandomUtil; +import cn.hutool.extra.pinyin.PinyinUtil; import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.elasticsearch._types.FieldValue; import co.elastic.clients.elasticsearch._types.SortOrder; @@ -13,18 +14,20 @@ import co.elastic.clients.elasticsearch._types.aggregations.LongTermsBucket; import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery; import co.elastic.clients.elasticsearch.core.SearchRequest; import co.elastic.clients.elasticsearch.core.SearchResponse; +import co.elastic.clients.elasticsearch.core.search.CompletionSuggestOption; import co.elastic.clients.elasticsearch.core.search.Hit; +import co.elastic.clients.elasticsearch.core.search.Suggestion; import com.alibaba.fastjson.JSON; import com.atguigu.tingshu.album.AlbumFeignClient; -import com.atguigu.tingshu.common.result.Result; -import com.atguigu.tingshu.model.album.AlbumAttributeValue; -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.common.constant.RedisConstant; + +import com.atguigu.tingshu.model.album.*; import com.atguigu.tingshu.model.search.AlbumInfoIndex; import com.atguigu.tingshu.model.search.AttributeValueIndex; +import com.atguigu.tingshu.model.search.SuggestIndex; import com.atguigu.tingshu.query.search.AlbumIndexQuery; import com.atguigu.tingshu.search.repository.AlbumInfoIndexRepository; +import com.atguigu.tingshu.search.repository.SuggestIndexRepository; import com.atguigu.tingshu.search.service.SearchService; import com.atguigu.tingshu.user.client.UserFeignClient; import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo; @@ -34,14 +37,16 @@ import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.elasticsearch.core.suggest.Completion; + +import org.springframework.data.redis.core.BoundHashOperations; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; + import java.io.IOException; import java.math.BigDecimal; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -63,6 +68,11 @@ public class SearchServiceImpl implements SearchService { private UserFeignClient userFeignClient; @Autowired private ElasticsearchClient elasticsearchClient; + private static final String SUGGEST_INDEX = "suggestinfo"; + @Autowired + private SuggestIndexRepository suggestIndexRepository; + @Autowired + private RedisTemplate redisTemplate; @Override @@ -132,6 +142,8 @@ public class SearchServiceImpl implements SearchService { //7.保存专辑到索引库 albumInfoIndexRepository.save(albumInfoIndex); + //8.将专辑标题作为提示词文档存入提示词索引库 + this.saveSuggestIndex(albumInfoIndex); } @@ -144,10 +156,11 @@ public class SearchServiceImpl implements SearchService { @Override public void lowerAlbum(Long albumId) { albumInfoIndexRepository.deleteById(albumId); + suggestIndexRepository.deleteById(albumId.toString()); } - /*可以将这个想成kibana中开发工具哪个 buildDsl可以想象成左侧我们写的数据 我们在写 + /*可以将这个想成kibana中开发工具那个 buildDsl可以想象成左侧我们写的数据 我们在写 buildDSL这个方法的时候就是在拼接这个dsl语句 第二步执行检索的时候就是在执行那个播放键 第三步就是在看右边的数据 我们要对这个数据进行分析*/ @@ -374,4 +387,169 @@ public class SearchServiceImpl implements SearchService { log.error("ES检索异常:{}", e.getMessage()); throw new RuntimeException(e); } -}} + } + + /** + * 根据用户已录入字符展示提示词下拉列表(最多10个) + * + * @param keyword + * @return + */ + @Override + public List completeSuggest(String keyword) { + try { + //1.优先进行检索提示词索引库 + SearchResponse searchResponse = elasticsearchClient.search(s -> s.index(SUGGEST_INDEX).suggest( + s1 -> s1.suggesters("keywordSuggest", suggest -> suggest.prefix(keyword).completion(c -> c.field("keyword").skipDuplicates(true))) + .suggesters("pinyinSuggest", suggest -> suggest.prefix(keyword).completion(c -> c.field("keywordPinyin").skipDuplicates(true))) + .suggesters("sequenceSuggest", suggest -> suggest.prefix(keyword).completion(c -> c.field("keywordSequence").skipDuplicates(true))) + ), SuggestIndex.class); + //2.解析自动补全结果,将提示词列表放入hashset集合中(去重) + Set hashSet = new HashSet<>(); + hashSet.addAll(this.parseSuggestResult(searchResponse, "keywordSuggest")); + hashSet.addAll(this.parseSuggestResult(searchResponse, "pinyinSuggest")); + hashSet.addAll(this.parseSuggestResult(searchResponse, "sequenceSuggest")); + + //3.如果上面结果数量小于10个,尝试采用全文检索补齐到10个 + if (hashSet.size() < 10) { + SearchResponse search = elasticsearchClient.search( + s -> s.index(INDEX_NAME) + .query(q -> q.match(m -> m.field("albumTitle").query(keyword))) + .source(s1 -> s1.filter(f -> f.includes("albumTitle"))) + .size(10), AlbumInfoIndex.class); + List> hitList = search.hits().hits(); + if (CollUtil.isNotEmpty(hitList)) { + for (Hit hit : hitList) { + String albumTitle = hit.source().getAlbumTitle(); + hashSet.add(albumTitle); + if (hashSet.size() >= 10) { + break; + } + } + } + } + //4.将所有提示词列表返回 + if (hashSet.size() >= 10) { + return new ArrayList<>(hashSet).subList(0, 10); + } + return new ArrayList<>(hashSet); + } catch (IOException e) { + log.error("建议词自动补全异常", e); + throw new RuntimeException(e); + } + } + + /** + * 解析自动补全建议结果 + * + * @param searchResponse 检索响应结果对象 + * @param suggestName 建议器名称 + * @return + */ + @Override + public Collection parseSuggestResult(SearchResponse searchResponse, String suggestName) { + List list = new ArrayList<>(); + List> suggestionList = searchResponse.suggest().get(suggestName); + if (CollUtil.isNotEmpty(suggestionList)) { + for (Suggestion suggestion : suggestionList) { + for (CompletionSuggestOption option : suggestion.completion().options()) { + String title = option.source().getTitle(); + list.add(title); + } + } + } + return list; + } + + @Override + public void saveSuggestIndex(AlbumInfoIndex albumInfoIndex) { + SuggestIndex suggestIndex = new SuggestIndex(); + suggestIndex.setId(albumInfoIndex.getId().toString()); + //原始内容 + String albumTitle = albumInfoIndex.getAlbumTitle(); + suggestIndex.setTitle(albumTitle); + //用于汉字自动补全字段 + suggestIndex.setKeyword(new Completion(new String[]{albumTitle})); + //用于汉语拼音自动补全字段 + String pinyin = PinyinUtil.getPinyin(albumTitle, ""); + suggestIndex.setKeywordPinyin(new Completion(new String[]{pinyin})); + //用于汉语拼音首字母自动补全字段 + String firstLetter = PinyinUtil.getFirstLetter(albumTitle, ""); + suggestIndex.setKeywordSequence(new Completion(new String[]{firstLetter})); + suggestIndexRepository.save(suggestIndex); + + } + + @Override + public void updateLatelyAlbumRanking(Integer top) { + try { + //1.从Redis检索获取分类下五种排序维度专辑TOPN(n=top)记录 + //1.1 远程调用专辑服务获取所有1级分类列表 + List baseCategory1List = albumFeignClient.findAllCategory1().getData(); + Assert.notNull(baseCategory1List, "1级分类列表为空"); + //1.2 遍历1级分类 + for (BaseCategory1 baseCategory1 : baseCategory1List) { + //从内容中找出id 设定一个key + Long category1Id = baseCategory1.getId(); + String key = RedisConstant.RANKING_KEY_PREFIX + category1Id; + //绑定大key + BoundHashOperations> hashOps = redisTemplate.boundHashOps(key); + //1.3 遍历5种排序维度 + String[] rankingDimensionArray + = new String[]{"hotScore", "playStatNum", "subscribeStatNum", "buyStatNum", "commentStatNum"}; + for (String dimension : rankingDimensionArray) { + //1.4 根据1级分类ID+排序字段检索ES + SearchResponse searchResponse = elasticsearchClient.search(s -> + s.index(INDEX_NAME) + .query(q -> q.term(t -> t.field("category1Id").value(category1Id))) + .sort(s1 -> s1.field(f -> f.field(dimension).order(SortOrder.Desc))) + .size(top) + .source(s1 -> s1.filter(f -> f.excludes("attributeValueIndexList", + "hotScore", + "commentStatNum", + "buyStatNum", + "subscribeStatNum", + "announcerName"))), AlbumInfoIndex.class); + //2.解析ES检索结果 获取专辑TOPN记录 + List> hits = searchResponse.hits().hits(); + if (CollUtil.isNotEmpty(hits)) { + List topNList + = hits.stream().map(hit -> hit.source()) + .collect(Collectors.toList()); + //3.将TOPN记录存入Redis中hash小时排行中 + //3.1 构建Hash排行榜中field 当前排序方式 + String field = dimension; + //redisTemplate.opsForHash().put(key, field, topNList); + hashOps.put(field, topNList); + } + } + } + } catch (IOException e) { + log.error("更新Redis小时排行数据异常", e); + throw new RuntimeException(e); + } + } + + @Override + public List getRankingList(Long category1Id, String dimension) { + //基于1级分类ID构建Redis中hash结构的Key + String key =RedisConstant.RANKING_KEY_PREFIX+category1Id; + BoundHashOperations> hashOps = redisTemplate.boundHashOps(key); + //构建Hash排行榜中field 当前排序方式 + String field = dimension; + Boolean flag = hashOps.hasKey(field); + if(flag){ + //List list = (List) redisTemplate.opsForHash().get(key, field); + List list = hashOps.get(field); + if (CollUtil.isNotEmpty(list)) { + List albumInfoIndexVoList = list.stream() + .map(albumInfoIndex -> BeanUtil.copyProperties(albumInfoIndex, AlbumInfoIndexVo.class)) + .collect(Collectors.toList()); + return albumInfoIndexVoList; + } + } + return null; + + + } +} diff --git a/service/service-search/target/classes/com/atguigu/tingshu/search/api/SearchApiController.class b/service/service-search/target/classes/com/atguigu/tingshu/search/api/SearchApiController.class index 9831179..5b99a41 100644 Binary files a/service/service-search/target/classes/com/atguigu/tingshu/search/api/SearchApiController.class and b/service/service-search/target/classes/com/atguigu/tingshu/search/api/SearchApiController.class differ diff --git a/service/service-search/target/classes/com/atguigu/tingshu/search/receiver/SearchReciever.class b/service/service-search/target/classes/com/atguigu/tingshu/search/receiver/SearchReciever.class index 0f1cedb..25754f4 100644 Binary files a/service/service-search/target/classes/com/atguigu/tingshu/search/receiver/SearchReciever.class and b/service/service-search/target/classes/com/atguigu/tingshu/search/receiver/SearchReciever.class differ diff --git a/service/service-search/target/classes/com/atguigu/tingshu/search/service/SearchService.class b/service/service-search/target/classes/com/atguigu/tingshu/search/service/SearchService.class index d3d5a68..1285a22 100644 Binary files a/service/service-search/target/classes/com/atguigu/tingshu/search/service/SearchService.class and b/service/service-search/target/classes/com/atguigu/tingshu/search/service/SearchService.class differ diff --git a/service/service-search/target/classes/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.class b/service/service-search/target/classes/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.class index 8c02d8b..5b2302a 100644 Binary files a/service/service-search/target/classes/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.class and b/service/service-search/target/classes/com/atguigu/tingshu/search/service/impl/SearchServiceImpl.class differ diff --git a/service/service-user/src/main/java/com/atguigu/tingshu/user/api/UserListenProcessApiController.java b/service/service-user/src/main/java/com/atguigu/tingshu/user/api/UserListenProcessApiController.java index 090660a..2be5141 100644 --- a/service/service-user/src/main/java/com/atguigu/tingshu/user/api/UserListenProcessApiController.java +++ b/service/service-user/src/main/java/com/atguigu/tingshu/user/api/UserListenProcessApiController.java @@ -1,10 +1,17 @@ package com.atguigu.tingshu.user.api; +import com.atguigu.tingshu.common.login.GuiGuLogin; +import com.atguigu.tingshu.common.result.Result; +import com.atguigu.tingshu.common.util.AuthContextHolder; import com.atguigu.tingshu.user.service.UserListenProcessService; +import com.atguigu.tingshu.vo.user.UserListenProcessVo; +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.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.math.BigDecimal; +import java.util.Map; @Tag(name = "用户声音播放进度管理接口") @RestController @@ -15,5 +22,50 @@ public class UserListenProcessApiController { @Autowired private UserListenProcessService userListenProcessService; + @GuiGuLogin + @Operation(summary = "获取声音播放进度") + @GetMapping("/userListenProcess/getTrackBreakSecond/{trackId}") + public Result getTrackBreakSecond (Long trackId){ + Long userId = AuthContextHolder.getUserId(); + BigDecimal second =userListenProcessService.getTrackBreakSecond(userId, trackId); + return Result.ok(second); + + } + /** + * 更新用户对于指定声音播放进度 + * + * @param userListenProcessVo + * @return + */ + @GuiGuLogin(required = false) + @Operation(summary = "更新用户对于指定声音播放进度") + @PostMapping("/userListenProcess/updateListenProcess") + public Result updateListenProcess(@RequestBody UserListenProcessVo userListenProcessVo) { + //1.尝试获取用户ID + Long userId = AuthContextHolder.getUserId(); + //2.更新用户对于指定声音播放进度 + if (userId != null) { + //3.返回 + userListenProcessService.updateListenProcess(userListenProcessVo, userId); + } + //3.返回 + return Result.ok(null); + +} + /** + * 获取用户最近播放声音 + * + * @return + */ + @GuiGuLogin + @Operation(summary = "获取用户最近播放声音") + @GetMapping("/userListenProcess/getLatelyTrack") + public Result> getLatelyTrack() { + //1.尝试获取用户ID + Long userId = AuthContextHolder.getUserId(); + //2.查询用户对于指定声音播放进度 + Map map = userListenProcessService.getLatelyTrack(userId); + return Result.ok(map); + } } diff --git a/service/service-user/src/main/java/com/atguigu/tingshu/user/service/UserListenProcessService.java b/service/service-user/src/main/java/com/atguigu/tingshu/user/service/UserListenProcessService.java index 723d5ec..41c409f 100644 --- a/service/service-user/src/main/java/com/atguigu/tingshu/user/service/UserListenProcessService.java +++ b/service/service-user/src/main/java/com/atguigu/tingshu/user/service/UserListenProcessService.java @@ -1,5 +1,16 @@ package com.atguigu.tingshu.user.service; +import com.atguigu.tingshu.vo.user.UserListenProcessVo; + +import java.math.BigDecimal; +import java.util.Map; + public interface UserListenProcessService { + BigDecimal getTrackBreakSecond(Long userId, Long trackId); + + void updateListenProcess(UserListenProcessVo userListenProcessVo, Long userId); + + Map getLatelyTrack(Long userId); + } diff --git a/service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.java b/service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.java index 203c074..1584a1c 100644 --- a/service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.java +++ b/service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.java @@ -6,6 +6,7 @@ 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.cache.GuiGuCache; import com.atguigu.tingshu.common.constant.RedisConstant; import com.atguigu.tingshu.common.rabbit.constant.MqConst; import com.atguigu.tingshu.common.rabbit.service.RabbitService; @@ -97,7 +98,8 @@ public class UserInfoServiceImpl extends ServiceImpl i } @Override - public UserInfoVo getUserInfo(Long userId) { + @GuiGuCache(prefix = "user:info:") + public UserInfoVo getUserInfo(Long userId) { UserInfo userInfo = userInfoMapper.selectById(userId); return BeanUtil.copyProperties(userInfo, UserInfoVo.class); diff --git a/service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserListenProcessServiceImpl.java b/service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserListenProcessServiceImpl.java index e0c32e6..a3b584e 100644 --- a/service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserListenProcessServiceImpl.java +++ b/service/service-user/src/main/java/com/atguigu/tingshu/user/service/impl/UserListenProcessServiceImpl.java @@ -1,15 +1,161 @@ package com.atguigu.tingshu.user.service.impl; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.IdUtil; +import com.atguigu.tingshu.common.constant.RedisConstant; +import com.atguigu.tingshu.common.constant.SystemConstant; +import com.atguigu.tingshu.common.rabbit.constant.MqConst; +import com.atguigu.tingshu.common.rabbit.service.RabbitService; +import com.atguigu.tingshu.common.util.MongoUtil; +import com.atguigu.tingshu.model.user.UserListenProcess; import com.atguigu.tingshu.user.service.UserListenProcessService; +import com.atguigu.tingshu.vo.album.TrackStatMqVo; +import com.atguigu.tingshu.vo.search.SearchStatMqVo; +import com.atguigu.tingshu.vo.user.UserListenProcessVo; +import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.TimeUnit; + @Service @SuppressWarnings({"all"}) public class UserListenProcessServiceImpl implements UserListenProcessService { @Autowired private MongoTemplate mongoTemplate; + @Autowired + private RedisTemplate redisTemplate; + @Autowired + private RabbitService rabbitService; + + @Override + public BigDecimal getTrackBreakSecond(Long userId, Long trackId) { + //确定一下集合名称 + String collectionName = this.getCollectionName(userId); + //构建查询条件 + Query query =new Query(); + query.addCriteria(Criteria.where("trackId").is(trackId)); + //执行mongodb + UserListenProcess userListenProcess = mongoTemplate.findOne(query, UserListenProcess.class, collectionName); + //如果有值 则从当前值去返回 + if (userListenProcess != null) { + return userListenProcess.getBreakSecond(); + } + //如果没有值 则从第0秒开始 + return BigDecimal.valueOf(0); + + } + + @Override + public void updateListenProcess(UserListenProcessVo userListenProcessVo, Long userId) { + //1.确定用户播放进度集合名称 + String collectionName = this.getCollectionName(userId); + //2.构建查询条件:声音ID。 + Query query = new Query(Criteria.where("trackId").is(userListenProcessVo.getTrackId())); + UserListenProcess userListenProcess = mongoTemplate.findOne(query, UserListenProcess.class, collectionName); + //3.如果vo中有断的时间,将其拿出来 + //从vo视图中拿出来的时间进行删除小数点. + BigDecimal breakSeconds = userListenProcessVo.getBreakSecond().setScale(0, RoundingMode.DOWN); + //如果userListenProcess有值 我们就将其进行修改 + if(userListenProcess!=null){ + userListenProcess.setBreakSecond(breakSeconds); + userListenProcess.setUpdateTime(new Date()); + + }else{ + //如果里面没有值 说明没有断的时间 所以我们进行新建 + userListenProcess = new UserListenProcess(); + userListenProcess.setAlbumId(userListenProcessVo.getAlbumId()); + userListenProcess.setTrackId(userListenProcessVo.getTrackId()); + userListenProcess.setBreakSecond(breakSeconds); + userListenProcess.setCreateTime(new Date()); + userListenProcess.setUpdateTime(new Date()); + + } + mongoTemplate.save(userListenProcess, collectionName); + + //TODO 设置rabbitmq发送消息去更新声音的统计情况 分别要给专辑服务和搜索服务发 + //要保证幂等性情况,我们要单独在专辑服务和搜索服务中设置一个特殊的业务逻辑 + //这是为了给专辑服务去发送一个更新声音的统计信息 + //定义一个key为user:track:userid_albumid_trackid + String userKey = + RedisConstant.USER_TRACK_REPEAT_STAT_PREFIX + userId + "_" + userListenProcessVo.getAlbumId() + "_" + userListenProcessVo.getTrackId(); + + //设置一个超时时间,方法是每一天的23:59:59去减修改的时间 这样可以做到一天只更新一次 + long time = DateUtil.endOfDay(new Date()).getTime() - System.currentTimeMillis(); + //将其存到redis中 作为一个锁 + Boolean flag = redisTemplate.opsForValue().setIfAbsent(userKey, 1, time, TimeUnit.MILLISECONDS); + //如果存进去了 我们就在rabbitmq中发送数据 + if(flag){ + //5.2 创建更新统计数值MQ消息对象 注意:MQ消息如果是对象,必须实现序列化接口,生成序列化ID + TrackStatMqVo mqVo = new TrackStatMqVo(); + //业务消息不足以为消费者提供幂等处理,固设置消息唯一标识用于消费者幂等性处理 + mqVo.setBusinessNo(IdUtil.randomUUID()); + mqVo.setAlbumId(userListenProcessVo.getAlbumId()); + mqVo.setTrackId(userListenProcessVo.getTrackId()); + mqVo.setStatType(SystemConstant.TRACK_STAT_PLAY); + mqVo.setCount(1); + //5.3 发送MQ消息到RabbitMQ + rabbitService.sendMessage(MqConst.EXCHANGE_TRACK, MqConst.ROUTING_TRACK_STAT_UPDATE,mqVo); + } + //反之不处理即可 + + +// //这是为了给搜索服务去更新声音的统计信息 +// String searchKey = +// RedisConstant.USER_SEARCH_REPEAT_STAT_PREFIX+userId+"_"+ userListenProcessVo.getAlbumId() + "_" + userListenProcessVo.getTrackId(); +// Boolean searchFlag = redisTemplate.opsForValue().setIfAbsent(userKey, 1, time, TimeUnit.MILLISECONDS); +// if(searchFlag){ +// TrackStatMqVo mqVo = new TrackStatMqVo(); +// //业务消息不足以为消费者提供幂等处理,固设置消息唯一标识用于消费者幂等性处理 +// mqVo.setBusinessNo(IdUtil.randomUUID()); +// mqVo.setAlbumId(userListenProcessVo.getAlbumId()); +// mqVo.setTrackId(userListenProcessVo.getTrackId()); +// mqVo.setStatType(SystemConstant.TRACK_STAT_PLAY); +// mqVo.setCount(1); +// //发送MQ消息到RabbitMQ +// rabbitService.sendMessage(MqConst.EXCHANGE_TRACK,MqConst.ROUTING_TRACK_STAT_UPDATE,mqVo); +// } +// //反之不处理即可 + + + + + + } + + @Override + public Map getLatelyTrack(Long userId) { + //1.确定用户播放进度集合名称 + String collectionName = this.getCollectionName(userId); + //2.构建查询条件-按照更新时间排序 + Query query = new Query(); + query.with(Sort.by(Sort.Direction.DESC, "updateTime")); + query.limit(1); + //3.查询MongoDB获取一条记录 + UserListenProcess listenProcess = mongoTemplate.findOne(query, UserListenProcess.class, collectionName); + if (listenProcess != null) { + return Map.of("trackId", listenProcess.getTrackId(), "albumId", listenProcess.getAlbumId()); + } + return null; + + + + + } + + private String getCollectionName(Long userId) { + String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId); + return collectionName; + } } diff --git a/service/service-user/target/classes/com/atguigu/tingshu/user/api/UserListenProcessApiController.class b/service/service-user/target/classes/com/atguigu/tingshu/user/api/UserListenProcessApiController.class index 74d4107..1d292a0 100644 Binary files a/service/service-user/target/classes/com/atguigu/tingshu/user/api/UserListenProcessApiController.class and b/service/service-user/target/classes/com/atguigu/tingshu/user/api/UserListenProcessApiController.class differ diff --git a/service/service-user/target/classes/com/atguigu/tingshu/user/service/UserListenProcessService.class b/service/service-user/target/classes/com/atguigu/tingshu/user/service/UserListenProcessService.class index a03898a..197fb17 100644 Binary files a/service/service-user/target/classes/com/atguigu/tingshu/user/service/UserListenProcessService.class and b/service/service-user/target/classes/com/atguigu/tingshu/user/service/UserListenProcessService.class differ diff --git a/service/service-user/target/classes/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.class b/service/service-user/target/classes/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.class index cfa39b8..61b0d71 100644 Binary files a/service/service-user/target/classes/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.class and b/service/service-user/target/classes/com/atguigu/tingshu/user/service/impl/UserInfoServiceImpl.class differ diff --git a/service/service-user/target/classes/com/atguigu/tingshu/user/service/impl/UserListenProcessServiceImpl.class b/service/service-user/target/classes/com/atguigu/tingshu/user/service/impl/UserListenProcessServiceImpl.class index 5b12d39..61be379 100644 Binary files a/service/service-user/target/classes/com/atguigu/tingshu/user/service/impl/UserListenProcessServiceImpl.class and b/service/service-user/target/classes/com/atguigu/tingshu/user/service/impl/UserListenProcessServiceImpl.class differ