From 4bd206c1a12dfebef2b19631ab11974e481510b7 Mon Sep 17 00:00:00 2001 From: Y1NanPing <735289578@qq.com> Date: Wed, 30 Jul 2025 08:40:00 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC10=E5=A4=A9=20redis?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/service-util/pom.xml | 36 +++- .../tingshu/common/cache/GuiGuCache.java | 30 +++ .../common/cache/GuiGuCacheAspect.java | 81 +++++++ .../common/config/pool/ThreadPoolConfig.java | 7 + .../common/constant/RedisConstant.java | 3 + .../tingshu/common/zipkin/ZipkinHelper.java | 147 +++++++++++++ .../common/zipkin/ZipkinTaskDecorator.java | 36 ++++ .../common/config/pool/ThreadPoolConfig.class | Bin 2528 -> 2926 bytes .../common/constant/RedisConstant.class | Bin 1683 -> 1750 bytes .../tingshu/vo/album/TrackStatMqVo.java | 6 +- .../tingshu/vo/search/SearchStatMqVo.java | 27 +++ .../tingshu/vo/album/TrackStatMqVo.class | Bin 3985 -> 4077 bytes .../tingshu/album/AlbumFeignClient.java | 4 + .../album/impl/AlbumDegradeFeignClient.java | 7 + .../tingshu/album/AlbumFeignClient.class | Bin 1577 -> 1822 bytes .../album/impl/AlbumDegradeFeignClient.class | Bin 2151 -> 2489 bytes .../album/api/AlbumInfoApiController.java | 3 +- .../album/api/BaseCategoryApiController.java | 12 ++ .../album/api/TrackInfoApiController.java | 20 ++ .../tingshu/album/mapper/TrackInfoMapper.java | 3 + .../tingshu/album/receiver/AlbumReceiver.java | 68 ++++++ .../album/service/AlbumInfoService.java | 2 +- .../album/service/TrackInfoService.java | 7 +- .../service/impl/AlbumInfoServiceImpl.java | 13 +- .../service/impl/BaseCategoryServiceImpl.java | 7 + .../service/impl/TrackInfoServiceImpl.java | 53 ++++- .../main/resources/mapper/TrackInfoMapper.xml | 10 + .../album/api/AlbumInfoApiController.class | Bin 5717 -> 5738 bytes .../album/api/BaseCategoryApiController.class | Bin 3953 -> 6540 bytes .../album/api/TrackInfoApiController.class | Bin 6744 -> 7317 bytes .../album/mapper/TrackInfoMapper.class | Bin 1499 -> 1626 bytes .../album/service/AlbumInfoService.class | Bin 1601 -> 1607 bytes .../album/service/TrackInfoService.class | Bin 1765 -> 1953 bytes .../service/impl/AlbumInfoServiceImpl.class | Bin 13563 -> 13856 bytes .../impl/BaseCategoryServiceImpl.class | Bin 11009 -> 11350 bytes .../service/impl/TrackInfoServiceImpl.class | Bin 15666 -> 17554 bytes .../target/classes/mapper/TrackInfoMapper.xml | 10 + service/service-search/pom.xml | 15 ++ .../search/api/SearchApiController.java | 29 +++ .../search/receiver/SearchReciever.java | 43 +++- .../repository/AlbumInfoIndexRepository.java | 2 +- .../repository/SuggestIndexRepository.java | 7 + .../tingshu/search/service/SearchService.java | 18 ++ .../service/impl/SearchServiceImpl.java | 202 ++++++++++++++++-- .../search/api/SearchApiController.class | Bin 3262 -> 4917 bytes .../search/receiver/SearchReciever.class | Bin 2615 -> 2705 bytes .../search/service/SearchService.class | Bin 603 -> 1513 bytes .../service/impl/SearchServiceImpl.class | Bin 35889 -> 48945 bytes .../api/UserListenProcessApiController.java | 56 ++++- .../service/UserListenProcessService.java | 11 + .../service/impl/UserInfoServiceImpl.java | 4 +- .../impl/UserListenProcessServiceImpl.java | 146 +++++++++++++ .../api/UserListenProcessApiController.class | Bin 828 -> 3164 bytes .../service/UserListenProcessService.class | Bin 162 -> 606 bytes .../service/impl/UserInfoServiceImpl.class | Bin 11784 -> 11871 bytes .../impl/UserListenProcessServiceImpl.class | Bin 684 -> 7273 bytes 56 files changed, 1091 insertions(+), 34 deletions(-) create mode 100644 common/service-util/src/main/java/com/atguigu/tingshu/common/cache/GuiGuCache.java create mode 100644 common/service-util/src/main/java/com/atguigu/tingshu/common/cache/GuiGuCacheAspect.java create mode 100644 common/service-util/src/main/java/com/atguigu/tingshu/common/zipkin/ZipkinHelper.java create mode 100644 common/service-util/src/main/java/com/atguigu/tingshu/common/zipkin/ZipkinTaskDecorator.java create mode 100644 model/src/main/java/com/atguigu/tingshu/vo/search/SearchStatMqVo.java create mode 100644 service/service-album/src/main/java/com/atguigu/tingshu/album/receiver/AlbumReceiver.java create mode 100644 service/service-search/src/main/java/com/atguigu/tingshu/search/repository/SuggestIndexRepository.java 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 d74c9d5019684a376a082181594e73c715945c9f..6f36dc4b5f74cfdf50da3c2eea5b9dbddc616956 100644 GIT binary patch delta 816 zcmZutT~8BH5Iwha*=^Y-VpB~(RN@DvT31D^S{p+`3{gTTBG~%XZCRuiw`IE(!H?=c zFxfvMse#5O`~cs4^3`A9yD!FbThh?P-P}8KXU?2CGrz*Wj|IQ~{k9Jvg-<)dhF?s2 z`~Kmv?P8@=w2f@rESlBQv{fiOrdxIbNMk|8109Qa=(YT}!UB2+K4Yy{EJxt-tmHV; z!_mnlgP6mz4h4?{CZcUz;(xgDr64XLtK%`A2pp+eZjT7|hOx4`- zX3?=$k^-7zZPcXS$3?-bDSt$q)zLbMA$g>#4M+E)>xbK;Z delta 483 zcmZ9ISxN&z6h%+BNq5po#DN4&6j8*WA{bE-2SlPE`H1rrr#R2k3bF%#dLv3eL?H`s z6)r&h6aU29iHKNGRd2ZOy;Jobd#!g~zMe|J7&rG$(dU}}p@_pA^EL}%7Flu|t=T}9 zl`yNUxi?m``(b^$w^mc}%}yDKET*ar;$B*oPqrURXU?4q#**ubc^=fTp)*{z{cN%& z&tRLpI^^8j;8elW#-)Y^Y#IrXpoKPi=%9~exxPyip#P`dR&Iw~^$F3*o-9)lTV405 z;y_Ao_MvWrqsk=NCFQ&>nMdpgBBKfau`fUN?9MwQg*(MfJd!@KLa(}|h{%g-YMen4 z4T)!%Zbp?ES7buJmu8yDKZKcI!ZgQa!iZEA!YBiraQcrhz!}zzKyw<~s@q$^y6hvf hMV9a77-g=?Z&s`NTrrc2-*;ZhztVQ3Y^RoMg5ShIJRtx8 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 4fe44a991c91e57e68df16a899af90c61d0d4cca..ca48547bbd45f2bab136e5eacf4de514010be13f 100644 GIT binary patch delta 192 zcmbQtdySXt)W2Q(7#J9A86r1wl`tE~g$BC@#Rt1O2044g2e}5gI)=mthX9FyAXhif z2o45UMh2eJ;?yFm;?%^VQk!?N zOk|9ZWbkL;Vqj$82HL~K5CCK`GO#kR0m&esh(4Ilz`&}toq=&9SV=ID1W7Y6Ff)Vz WNggnpl_8WN49H_-2nUi(3=sfRTO_{# delta 127 zcmcb{JDHd3)W2Q(7#J9A8NxPll`v1<$SlF=I{6f{9;3(PpUm2f-jh{XG#ULS`?Jht zl-&H5Wg?>oBLgD?D+3#l^apCx2hxl{npJB%1LH;@gNY#kNP?sp7?>FXfg}$^0YeZ& OFp$T{5CSBb7(xMeAQhSb 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 385437d821889585af37e37d2535f3447d6b715f..c3b79c3cdd5607c8d823b7ebf11e3c9a6c8b6b36 100644 GIT binary patch delta 1508 zcma)6OHUJF6g}Ux)2Rc6qEMiO5_}}4HNj}2k${hYAjSFssZxAUv}mEW+7?uNRE;r4 zH&{dx7J6jsnFP&*Nyj<+Q;i`v@YzB2G0+Hq zVKr8mM+nGdCD70F+qep@a_~LGyg~3VpL!T@Bf_Unl^bvbN4W~7Z0Gae+vH<7PAPPS+PO+xUBS>>C}sKe*n)ro@LT;+(qJZo2k=nSr4^-@FpL-h>hJ|4Y;Oshv4GQj=RgpzafX%?y?BbV zv}Atl$2dpJg%l<+N=rc&3B+l+G0PDiqqPptIP2#TYk-P(XvGD-tiVS!achk8G_GYU zd&Vu+!({D5v&ow5_K=U>GIHoM+^=Yq4ppg;e;%*rak)$P&_&rPz)PYU(CuuqP7mKiNU58=pz-3x4QJ=&RP#sTw@!89ic#Fv^8a8KIR@OMljl8yTl7>~w^1Oe#y?FJp56ce delta 1450 zcma)6TWb?R6#jOT-A%JeYA|L^B`wt!N+KuERo`BQP^dxY zm}C4+oE6Sm<~@`J0u}o>3bPn{ISQ#l_I@1Ttk7jM$DCaWB`ejlrtjHStQTkLR}J(A z(Rpro1I2uuJA9qv9_NZ9E$-{RRm!Xho$z=&&Iw=VEH?V+wrZWzmaq3g^fA4hJ>Ot? zDkQ6!q(xL#R#PC^42QU@DO`vK=*M9}z^zWsjzcE<7E%8Ts;87~Bq%H7l&d5DobmtV zlpW~Gl#2nGXRXYHhf?0qN~z1{bvctx>PKD=2&l(Owz$`njd&UQ2lPJ6)o zQFk8?5vBg6fA_J3JO=5r247HM$E#?=B93z}fDB$^h$zU@&v1fBV^N>rB$19WlyHj3 zz&MH+CJJGW{c)P80ngEcGZB~vb?XqoV_d*R zp4RXPmxxpfe}Ky*4PXOCafK*|ZsuPk(wO-cj1cLVgoUd_29uhJ{WM11|HW8icBnS0 l{I@i@QG>YVBzL{`*H~h4L4gWx@SDICS7D+%xQA(^{s0b2ihck9 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 5022b354ebee43a5bac3de4566d9c26307d727f0..b4bb2b8ddf3ff35ac5650ba42aecbfecd91a538f 100644 GIT binary patch delta 189 zcmZ3T7V_;<90b<^02F79r1)#VhSXK!vD+-iRW?*LEEoM+*P)%k~V^A+<&;S5Y C8>IOlDAGP%dUr0RS^744(i1 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 173bdc23290b8052f280f7eaa13e17bd24d9a25a..fb595b320f00a45937b09671bf4d1398c0909c96 100644 GIT binary patch delta 701 zcmZ{i%P#{_6vn?h?R2UpQS}U3s`aWe>aF!=(WQldK;jXJkcf?yjSXQTvmvq2Rkt1s zt%a?`|KYW^CcZnZx)Bz0&$)Nb`F&sRxi9{FmGANM?jFDdX0Lp@=JBFQAboPtZmq6w zF3)Ui%q{J#tZi-YCY}$nubHFg^W&$(%-h-V%U#xo5Sk6NmO0KU$1HpaJDD>BnHM!^5?WJBv{;>akmh zD<&G+xys)_03BS-LIFC_#T|X18!oijr=DP1*8123)G^jO^|j94EY{2ZIC|LE%PO5l z87zJp`goWq!ah8~y&qVRu+TrSeihbVf(;NhSb*_to_OiXyoM2|%cDYrxO7B+L?RT4 zDk8nA5tc-XM&%@ujPlYQ%Z-0qwkXo) wh!lph_^nd7&~bSA+`dN}c5pyhz?(zx28JB3P{vzH#YvuNn8GxpY@7kU02u{N4gdfE delta 533 zcmZ{hOH#r>6h&`$2pwZvB33~a5*6YHq5>MlFEa-Y9k>cN;m`$S<|;%6iUSzy3fzIa zP;ZA+=!vOH-ly(6_od!=^}FPM{=82B3@{k_u3Yj_N1(8-v4PFxUfvd(0#VX%YNIb1 zJIS>8c-MeH4U5p6D>8S}Z^)|4N-(<7E5wkA#8xH(R}UpK z@0xhCm41OLSI1bE5YMUU+@wj9&@$=RE627=oVy&;ZdAq3pe3Z3JbmA*^eZ_($jLNnGHPk%uhc3ityZ04PKN 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 49be6a018d0f5b8e0b5728ec882c0dcab8978572..a282306821df4856a2460cb9bdaf38d163ad9b38 100644 GIT binary patch delta 483 zcmZ8dNlSuJ6g}UUAL5j$pEfQM8Ym=?uvUgeMY>QIO=trJr9^6^rj2H0vz6Wd5rms) z(K^~j+jedG5z#G0ti|J=_wKppocrEvpEmW&*W(iaC+J>nRalInrNrRsVlv{6F2_dK zW0Bz@0Zxi(Iw@LfDW(-grA}MTDRyb?lF&p!gGbc{1=^uU2i+MS40cH9g$53^pby>X zr4$ zvB_X22qBIw%yCmG@I#b=02j8&EB8n~mi1Fs9?|V!w?f~eSJ|(c<*4%n*Z zfpjAlHmvMzt;NRPLVQ%DEbcwuJ;U#ub6lc467 zw?cO|u4au{zqL+NJQ8sPOqEbk1v{$c-f`n-fQCj`(2P>Fpa!jyE`HWJU`D4bI0uwA zd2rTi0cP~dyVKhf!y*hAVna*vn*z_S5qQP{w(@fRe=KDMF=89`=wGCB*{Y3F7`30*?75|MFB*YLKv7|sk%@VLNFf~qCDj+dtiHKN&s8feFbR-S(;L(hj#g3Dv zI7#C`0>RyqQqly{Qqs^6Xj5a%lI}~||DYe^g?!4loYRxjp58Yzl15@=vz$|(BfmRu z?z`{z?*8WE{|;RTupa*mp#qfwRPm_BBo4I)#4b@#L^Un!OdODsCWlGuWK}jdaHyMo2-!9A!6pq9rpggHEPM^Xq>S~9(uW3oXC z2-i2nY_(XXtO#r_62c733}6^?v)&Tt-s`T{0}i6n5JKhYGEe!-jfCphwS< z2H&Im39(N*hsRvp$6@MzSxvQ=rY|mBX%bulo+)b{k1wN+Lk*ocXQ4J( z>gKS?M}Xh)GFnPfTw8l}#-!K?7w}lf5YAu-_h?x!Q!~Tx0FT93!lBMb>l=G=sG6cF z4$b92DRM$gh{Ar+Fb^1{?QQX$I~>Q21kk{tg+WhYk{&`m3y@{5vzM1;YMRn1n}T6wvzl%S@hz5` zWU|8)X)AaL_zH(=lBx7?h>%Z>53Q`YNEjSeFj&nz9>hZwp@yW`p?au(?;T5>2+u93 z$~OCI9&50cLzQ9&54qF$=k&;RHGZ?lh7iHJ0M_%^fQLEEFC-~h?b13Wf%1SXD)KW@ z$}u2^Y2;MVOjg-0nH^echnS(*n2`%)JMQ8XGZY>nv|wWZtvohib5R0x7&rtwM5CjX z+}%!r(IB>R2#|Otl&y~P*oMc*4AMbMR16L?z2542W5bg{Y$y9OSSfa%oji824U2(3 zMzO-)?&c9^N1aRjIX@DWsA@|3elaPvDxzTov5aN!DC2*E$JZG@izOfaf);`h82?@# z-(dU?jK?3B)2e7%x)j7y92WbX>gGJgq<@Qt$fWb^v}6PqZj!_D+esx&OqRrBKa(}f zmE|181MT4;WDX7G1+z+HSB=f8DVse(PzKKDblVl|JQ+ZS(r3Z7qEx8TqSB(Lt&F6a zo1acfSr*PgXdLE6)h=?lRGnfcjJlLW<;iwIN-&xlf`Wsrq*A3T@&?!G8rnF_-fa<{ zjMOF@azc?>R8=$W#pFS2Vw#>7j4boe{W|$sx2AUr2}z_xMfNwTo(f`qfzV=^TDPoA zsR+fL zeSRhVn#YFD<|dDDc+l4$x}}7WpoHPsP1q`#+o{H|%tqOUeAFV--!CNHE=-^(@)lyJ z!&&DIZMSLgi>ERsosyGo*J{_mg}|aJ?6299zOl5U$aggnrsY~E@OOzU94HNv*B-hH z*kz1;8;}^Nw$W3UM~|H!9_-EAE1J6T+NF`>uRGQox%k#-@7duiXGV^{;?N_#SIN$! zr(Pa=|N2P(vCpm^b!j$Fj_}5f)9+GVE?BIn!4sbK==wRzSH(#rubrZ7vg($-XP0Pp z z@ZfvHg9Wwa9CTShQGWe>L0gm)NLwM+o#$?p^CwK>9QNJ4lT1)1Ry)UR%6r7{;Hx7? zUmEE@=j7z!p`-N530NRrc~FQPk@*UV*_`P_ZLdt0V%+v&VGEOd&C z{kEJ0x+lj?G1*C_(QSM}am~_`(iWMuM)SNSvFJm^3f2$O1%HAPZ;EL{*dwxP%cc~m#ZxuaxDvuuTnj+vu^pYY_=rQR za|bPLP|H<~CO?O(q)U7?`v=qH`51 zB!G{}`Nn4@Pj|G3`Sk6rf&kD*B=+@(=1(SM7c1R6OStCwB^caew+ zbkTqI8uZPooBlHa#DJ&KLnB>8@eC^M#qIROHmX_rAp(~%l|!s?5YsQvRHZG3T{}S^ zkV2@lMa^>9T~Q$tx(3gZkZ%(g+s2uBj;Qa@Oa%_v$nPbpm*$=~@B&^W;=6mn8F-1P zx#%My>>w#(Vrs8tSQ;;5b_KRC^8vG%RIa~CT|?m3mH{`uE?+OeE$H%%Qn)|%z&%k4cX1wW zsV*0J;Cgl0N^mz#2=^yA=?Cu3QgA=@fP1SH+}rsWIYhCns%Y^x@|+kJ&{&Th_6eLwTJAb;{Y{bN%$y>hb0X<< zDg1Xl@PAet!q0Jrm?@IDH53;tl0IKLfUm|X);A8|k#qFCl71CmyzmLj2D7XGHFp|~ zOB%yl2Jq+!Os`yj7WXuUWA;;Z)%yF`5}caoNlYz$$_8a7dT7r-=$v|lm3H60km*a zLvy}B^xue*seVasD)64I?71Z89G&=A2Hv+7@c}(Jsp|q*s+~uyzb4CF#t^RKclf>g U^auCpFT@j~HGjq5@ej=YAN?lc5)0yweO+WxmYj1>&OQEoeJ^|7;_B1a!y|wZ9A2x>vT+goREkcH_0yZPlJ{am z4!vqfpae2|B>tA7jIo)kV#XE`6?3H-FX5`Dl&Aqwv@$RB0}9&E&L|;-4g{bXu}Ix{ zp;t9$*D%J-{wi}_A^KJB>_iv$b&FY6rH7SXR%G;Z~?l;0B)0C`XkFjqGTw$`}WabFd<@5dt>h zhh;smNldXZD4{~aG&2dc7Sq^@COoE2KC|l=(~M)9#hfdcaRl>z!GcGyXbWsWy>m{+ zM>Os+q-n_fV)*-9mRyy4E;+v{?@=w=s&kvw=&;s&pD!sR*LsKW6<=6}dzU8Y&Hn3M t!Rk-CHKEHp_i5e3+pu|-PR6GB>@9OsjJIZ+UvfvsF825bub{Yx2j5JAOSS+2 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 07e189013f42e9bcc195c6d56c27371cb05ebb35..4fa11a42dd69bd52bf6e597e9e88014b69e713f8 100644 GIT binary patch delta 1707 zcmZuxTTfG27+t%iCA82M3q_*|Bx967wZ!-$D#rL=cp!0vK~P7nPy{c4v?yNd{W8ud zGe=asQN|hX*I?o;(RY7=KfvpYKf$=Zy-yDZ8x&#pLeChAeyRubTc!W!-#1X0Yh+g8MPpY~{@M}lvPyRYUM z)Ds=j&Q%fsl~~JF63_wbu%5d@DSqdh1b4E4mwTkD zvx2ZWlSwk%Z5V?t7`rr#pkmN&dJOSVEVGAwsy3@Bwp^o#@fB$1+QNogF^i1W5Q{M0 zK>mR`2TdLJ5`#>k4*N73Iqk;*g7BeMBP?KsG8{yfmOPQha)=fovc$_YV1i%4*gT_$ zf7Z?sS35^_J5ev|A7fO0HEkWo31)AzHdGjH&CpW_aZ=KW8M>R-le&`-qfX)UB(EnO zK!0dJ5@>UK27j{ZUum4hIUdZchc&7~5wAhj=*QoB%-<@iT>9HdatB;c!Valn7%1R~ zW!Oe-MIM?#gBi0+Y5%}-s-M@@OFedV_n@1|h*#v6n_lU{v7i6L0gWTZN+3bzcaoFA zVQXEgi@;o!M{vQZeDTM=SK*ROfDt#T8qrPsIcC%syuyNZt6@g9#xRY{fc*H_LkuIB zgNrVq#T_hhjM_qrYsm@HxR#s=!GSmrL`9?E42mq+mha8cZ+||21+Wq2kJ0hS%&$nc zN;G@rWaG?a&9v>US@O4O7ym~fu$#Mu7^-8;w|ruI;#eyZ{+C&`rH7UREnz`N z;1E9xhZV#$PemKZ6JK`%lCwk5q<0gEdj8)$1m z0<8wPQ~)l8BF->2M31vLHw&f63X-J;Ch6nu!#HoixS(Lf1cOTSxX4dnGcK`Dk@tS4 zw<;74ufPtjZEUz5%Q%QEIux2sq#eiwXmaQ$21$1g0}72iUB(rH2%||M3^7A3uHqUk z6(Y6eIxPjpF0z>hOwbO-Rv5i8UpqIAb_P{DDVz0&7*$zyTeonV+4J7-rJ7qk^d7`n zQHn$l-Q;yxbrNUP9o(JebvOWYZ|;ci;{mJc5kFL57Ki}GHawEUWwckWTW$!im#h{I z42giv1T+S4wsOi^W>pr=ph3^qkk|-DgZg8te$w*mn-ktnDr}{*`V|I_em;Z&g~MSb zkQx18QY%o<;QpuR34w(`A$5Q)HC7(+enMSq=nK|&c|YpcDGZBA z4lqK;F*wY&mO*kZT48R0#l?iLFjr|!B6XG4q{1@3!W`!KUt!wf(Wk%&Dr|zARvERg x-|VDnODds{-Ar}kS>@F{HzxaHewht1pM{rdeHBRcH50ul;Vs_r$NPYz>3_$1m}39{ 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 6b2c1bc5974ac48b89fa6117dbf415a3dcb9bfb1..9a508d5ac896946070067eeb4e5348245f7f1726 100644 GIT binary patch delta 166 zcmcc3eTzrn)W2Q(7#J9A8RXa*m>3xhCMPn9Y*dM7QQ=EZEeR<~OwJB2Nh}G=XJoL^ z@X1OnOVrOv%uCnz$#5{})j12rhEKm#-V`kt1iZL-rGDv}GX$Bb}%?6Z~WncgR`Z6E# delta 70 zcmcb`bDLY>)W2Q(7#J9A8Kl`6m>3xhCMPn9Y*dM7nS7V!IV02LqpU%449pBXKqX8J VVhrM7T7p3mNV738GDtBn004N)46XnG 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 52c8b3762dc3e0a80ad79652e06deb32d23eb766..f72b6a724c8ea3dd2ae9dea6cb9435be364af4d9 100644 GIT binary patch delta 43 zcmX@ebDU>`53`t1dTNPdPEu*EXI@&qTTyJo-dTPn!70j}em#~OU)?*dhJfC?569AL+33mVh 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 ab27e2101ab982cf486c451b05a96cfe0fc219da..560fe4d35f0d03bd885cf3cd3ccceadcd7363e5f 100644 GIT binary patch delta 193 zcmaFLyO5vj)W2Q(7#J9A88kL>HM6SnrKgsJ6eT8S2bUz4gyl0b*l74-*&ArCV$IOcW5AoX^TBhosP&k%6nUASJOR6{L}oL0D)9L_! C4=il} delta 48 zcmZ3;|CE>O)W2Q(7#J9A8I(72HM34uW?Rn4Hu*H$JRt@q22r2{6N3VSBA8YJ0AgAS Ai~s-t 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 8d5b3c7ae3f94a493b2eb35ec2c5b6d4f64d056b..8b349ab6dd6db0186c8cbbe63a9b7306cbbe03d7 100644 GIT binary patch delta 2398 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 + + + 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 9831179854737d357f7a8d71f4a73ba3300e1979..5b99a41dd271c003e60c956db61506c454cbc734 100644 GIT binary patch literal 4917 zcmcIo{dW}A8Gi33ux45LvLI@!XsJygI0TR?iP1m>(=HGanpVM&+1;DXklmSeK9c6- z^c>IW0Yd?y+JIU-HHyg5f}w{4A)x);zaujnfAT-@_}rPv?%mCf8f$;pxpVK_``+h$ z-jDm<{qmccFNo+VauO7yhB!4QX$dW5wDPDrtSWg`&nXAeM|s9(w6sIhHM^5hLvu@i z6Wv8kaY`g<86_EQ%@_qmwR4V^a}-t$^rap4+_7$>q2O*W4fr=(9~YAW-?HtQOIlq|NjgqjgR(tJ*w;Uw+hQ zsaMs9u#C}KSys1h^Bgzf2EqnglGH|987xetF{K(89k9Q%$#Bsg)Rf8THqswIi#eys$0r{nz0R78T5qU`<+6Xn}<}0XS6zHWYm1WYHFe%4mR3@8ur^>*P8-oiwa@v)v-YH z`aV|I8{h+~2)ynr5{|@}&me~OaeL6n_NYRAo0~w{lG5O;BP#4}D#P0pL$xFpEad=V z*=G>Y;+9h=sOBi6&EAQV?%yuEQ^&niue(>@ot=Jb?u)VvRM0J5|G>R7 z;m*7zxTwed2u~|%P0vajDto!TPc0UOzcE@etmYli{E!l8r4JZNCA%nNp{{>{!&e)= ztYMW0?D)YbdQ^LG-m1W{Ayjw#{jc7+SfkwR^cC;i>)zyt)i5i$Muz#)PnKdL%)cTe zYCb_lodMsO)EKSt#nk34MvvF^>F-N-jGFqioUYoA31d$DUpeUbQ3yL>bEHH&Jog#R%!;u#IK!GP0upwJd{#nnP-86CvH0 z_mg87*_A|$99x};MvL>wXm3r@?vVNjw6N=!C1F~X(nfe3b+!wBj{OgbN#0c?c)7nA z6avRK?_VFyefB|HY35^h{CMfw?b+#*rO&T^HF;xOd8qW)EAGstLkD_x1kuW9eZ?9| zcuXo|61m7BRVQ)zj6t9+sKX+HFFwRaaj3vht0fXcNys7+^%4m(_d>s{%=4mQ$jnA= zBDUGDr$MlH@`O8n zes1#e*LTLf3$Gza+P2J2fAaO66VOYhwz`l|#zIO!@6)ngil0loGe| zVi?`;{qwqaZmO4OHOrkkdWJ$tGgmqFKi zEM2gP7d91qFd*kpYwdQt?+EmdaR}J{Tv_XE7FT!1X9FpmS{aC07*z% z8_W(RVI8$o2P8g)Z%Y_DgKyv_;QQ7hZN9CT7uY`Yk5J1>R@z!f-*00&-tn zAe#WB^+y8PBLUf43*ol#e<>W~iW~UEjeK5bw$x7;` z-$A)$kobE_L0-sCH^lD4FGl-oSvo*HWtI+B!1ZD_!!2)T2rgR#?w1m{2H)&~!JftD zdm_N~`34i<4$&VVuOE8|2MI?0Sb^JDhWn>lxX(*mzEFW17`25CN5K7c1l)tzyf*^w z5qhxC+m4bmw zKn8pu_|HcK10uwt44O8|h2$AF<4Oc#8ng+ z8$xIhJjO6HFndGU?7@hJ%>?YG7?uzw&wJ|8S`~&Q74p6c$QkqTEF2(41^=o0D<6Ph T1K*1ly-FrNSVC7n8`$3hVEML! delta 670 zcmbVJ$xgyh6g{uCkN_5piN;`njRUO%&Nu)LAkG7#E==5-xMgeNNAv^y27<)sf)DT; z{1)SReU&y%+_>nw@7|t!&$;JyCwpVD&+m^OfD&%ou@|lLq*o%H`$1har&x_ZV4Bfj zG~6uDY@V5rRqG9+&5H($rvwATuz4mF05h0nCNP9K3?T1x&FrJZ#@GX78FMav#LZ0) z511q=uy27VLoflPo>9UUSzc;k87sW3-a)jmh9ZAPrK)va1kxT|IhlR-=`7OO|D@Xp z&~1k4GT5R$(wYVZ>WnGt6;b;gIaDs!ju5o&BmRsJGE@?yhp-Hl^voC8sx9xI&XZuKVlU`~ViGHhcg8 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 0f1cedbe691ef066875a6ecbfc9eec532d62f841..25754f4e6226b12c3a4cdd4de758085cc30f625a 100644 GIT binary patch delta 597 zcmchU%SyvQ7==$RHMLk&u!~f>a3zSCYQ=?E4cOY$YpwNKtENrVf}%9tiVxsQ@+8GY z!G#atWB3BTfQTm(!7g+wL&862&VOdUneNDABKG?E`~o10W+yhM4#!)r)ATCt_3f42 zb|qx|Avuw9?6z%)6{B&}a*cAY=_#u&DU#yfX{m^e6%_mjO<%MaYCz%uA`@Lm9TqZ* z{PziQ6sxQULIc*Y&Y6T1HlV=r-?ZZW9+fB*y`*7U6`e`;0#i^KJ%}`P%wU|uKt`m^ zB7#ZwZ(@rc&=KYaRSDZ-uQbZo;Yk9mf?c|EtmnCQ!0)gM$;1)WYTm>#eKij!IQ4Lb znh84;>Y>n}*+U)s42Ub-0n7$d1Cs1F$$Ru~l4YJUN0K~A3glQIiS@4}PA`e`8%Y$d bcrnZW=ueLQyr0giI47x$3vq+Nt6l+x9d?7W@>JQ=tiHC-fvWv^mz6u#cj6Lqs7XC7 zIh?7^^*HCk;}X~5sw>pH!nKM$>Kw^n*w6{c8@c) xPtxp9()dl%_>08iru%-PnhtIdqNCOe#SW2nfco>O3Ej`Fv@mzyzrnqlz5wm@J?Q`d 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 d3d5a684360e876618bf196847452215131878c0..1285a22e9a4855ffb27911df5bfe6c5a52bd1cff 100644 GIT binary patch literal 1513 zcmbVM+iuf95S>kFLQ+UW3Z>kk6lh*BNIW2=AR#2ANGX?Es>B;xd+WH}?3%r#2beT37N=a z_w$-|m`C`;NsWx%o1w3ZL=)!j53ZyEORZO8=Vg>ED zl5><=ECuFm=V1ycHecuEzejBm`2K$kwkoAFmLcPXdR&(?yrLe%3BKR(R>J5(H^k_fDp=RFW8TBfoMT`)4i zP!TikZYq_G(us9GyKE=0W*Co|&^Ryx`{k6`i*SC3>S>%<DrMNSgZL OEXW4leS}sG9{&N0lfN4P delta 49 zcmaFKeVaw#)W2Q(7#J9A8AR9_m>3xhCTLMh`ut?ctQb)r!)IHA|XS&#YZmH?wwW z{Im#JWE7ykJezFl3P{W20DQ~9*+GC@5Q%uhn(C@}Y4z&*n$ijlw!&$eiI(!&X+&q& z)h;g&1l0yk<%1juO^wwxrOTRXs~W58YD+7c>g#K&;|=9qD4(Jhb+@U23I&brG@^of zHLhrg$Cl2otE*WMORSoDTD+>Mv93YTfj$hX>T0W+8XDrYjisp@$|Ka1dRerOP5V-j zp#GX-jj!+S$#vjHyfL<6|ct#|9Fo^IEd#R9?{8lwTY(H7*Xctfi@jPeFfz=u87x8 z)JV3;CGX+A$0bSo6_7#wY&w+sVcP)id>&rrKH-08QgSn+8#_pfDi2 z#GUAhK<3SRiza4liA_Ujs30>|Q!{Uwpo)RV2ZPTRoSY@hgaYCJ%q}#7Mp`t=ro(8o zp#1~q#e(Y9@rBS^f~<8>>uUWo!KR5cNzlHr3~hQ$yuL0`4GpqR(1bv>=W5Uf z@5UDTI1QmZkEYO6i>BE$on{CcA2jE32M3xGu{BUZ{rwW>7?PC2^-~#vmYrqOQ8XKt zho7uyTE0A^W@t(cFx&tg0)G*TfQy)m5cc zu$Z-tiPX6(E>(36ao27i69=$FBZRt&mRc0IX&Hf5pRZA|F3}iY4RsiAfMM+E%(m*f z()r*@Be)Qctu7B!wV;7J*FU)P!8>-|dG3dsHvs*T9d})^qLpWTv52}pNsXTB%X=EqpWzlN1 zsfpI0f0tPfb0%w!2^!r#8>c!<_CE)CI*ry@bh=Gv(3zMf?cx>y1XkLCDd=n#fYj*a zKAO%T>FGQfNG3Wg6p4D+W;R;+bhb_B(7AA3>SGOw_%ZQBQw{X)Z5>6-g%~(n+m+{R zmv&8EhWuA(ClttOyesRnyF7us|YT?~<~se`N+%&u!#UYe*` zHfm+*>^dm92FUZJg7(>Y*~VRWT<*y8j=LV+wfSxc?-^%B=sfz7O+RLR5rMZnC!R>e zmdEqx3cAvwt8BWOeu5d)5-2P%W)M4<1N_>~6=>gxrF1eJ`fCOCPHQCi5{cnPbU5}4nqam$Rs zyeD!nGVOC4{oX^{Y-*fEOv~;^%v@SPA$o$ZKWEePEw7K{>y~rG^*zr$nz z`V$*54VE-D#%EVE3q1lf54jBlzf6Cy=oOn@rPl-b6Dwd4LEr8g)*6BJOGKISq0hoBLuP$g4Uq!9}q=1*+;7k!GZwIe0y zNYJ|n$^oPHIelT#mo|Mx|Cft0ZC&&+4ktI(X`KT=ox)2$44iJDuWkBqDXppJ@qcXkFMSUqfr&65=5Q`NyPhdQ)8jX@7PDJN`}fdpTM*x! z=iXgWeR@11q%bU@Y+;I!pzdkI=RV0oT-#U~t7$?Q1NocDPlRpJMMNN(Yq*^Q++G7` z`lGgVw>Jpe7F|U*D7j?~b#Q5q@#~P(eS6A^8${F=-E}VsP*p%(L?Pr^^gxiC;)kAi zLBe~3=w*w2#J=F;it6PnYVZ$p=LG+(&wgxAF}_Fiw#9yI>%th0c?~f7VX;332=iDR zXp4h*IKr6uD<&h67#0U(jt}Q+{cLfl=ns7ggA`-CmEo$V{FvjyVj!Lv5f(^&h>>AY z!qDm(D_Ek!0;!3-`kL6fipE&u+@{rGF$_Ad3SmWKoMZT~7=gi#C91lJQQ|O5jJCz$ zVhpTYt~0u#uEC)RU?wJzbsL$pGVmTP=g!M)QO-T9De**A0Y$_(9#$j^Qnu2sr8?0^ zd-m%FF~JrSSvFJxG!;;uD1;giQ*1GnTSJMuriQ9GH%*5I6v!DIo{NUbp4jDl$OQ$7LNwXaPURSOJ^G;y6njZ;KPei3l;<6=BU7 z7aI=@P|>%dvyxH#DsrwC*Yx+K!Nw^yKUtK{3OY_XJY&vS3r%9kp|GFGJshzbYJ z@+(m7T=8?&wpc0PkcRP`#)fb81ul*krn^{ei(0<5YwA`u2?-vJdPoKR4&I7ruth>Z zyM+=uiNKDoe+oFQ>=$!}p@3{rm?zeX(=4&h7N?6d5TK92|x=o8$FRx7{I7*-1cz4*gNx9_<0hFy2u8xiZp&n$7PEp8LHBMxujt7~OHF@dEph_F>#2isKx?QoQz zDtE|yQv}kCTw=N3?@gIW-(7A~0oLOR3#c2^JOuJCTih+~(RyeOOZTyU$;oyK9B{2T z8UgbxEp(Q+7ZW!v^XRPrq6AE$;sG{!52m9ppS-o%A<|;vVdTUFV&LFauW6}Z)W?TC z%U!_=J!*@`#N&eO*z)BK@#QfNtuSS~XUtU4$AOtZ1pKN zFboeqX3DR{)0TL~7QYeCVmYf_o0A({$o!I~s#S3|(Gxn0?j#2SaC~08V2KxP@mr3i zkxB0aOI=`?AhCvq*t!DhE`G<-`g=h`vqsc6!r44xPv%SUtu4M2|6yC(w8XKsJqFH91(<2|7Z!+S_uH|(dDp`a?|S5lU606+n9cpRVQn4xn9(o|x8Esj%0PAGoET;|eE%Em>sC-kke0 zA!9R_@&kQrxj!#inQ*+EmIG~h5VvTbm_^W%2#?3>(7 zKE1<9XF!qiON~QB_LZnYFy*0~&G0)5saXrrd{qvxR_e_7()oJgFVtB|o%Ye^X}>!o9@hSZzs2v{x@0j? z!)-Z&iHfF)a{6JUM%nT(#)y-})2bU1jkDv8u$lba;kF#Z&lRMfOXbOVjdm(LSXpk% zBjh;1W{(v5E9H$27gVAJKieP1e#9{3S6pUjf<)qk#(s}G{&%ui}eG)=J02|{hWp4 zFK5_trbH0mwIRN=I2ynob z)HT&EWxF@89%Rh%li@kQxxk&2hQsM>_UFpO@)(wvrX`6ga+V3aF>V(*I*}v7iNhoHT2FDmhz8r_+ULPdVF_D4<>lTjdGzL`$Az%ai3P zP}-fO6DF;mOI|WE>DeJhik+2VxkS(*J8#*%^QW8ifbQ6I)y^A|JFmQkS2eHSwDXFG zUDE{omfA8dm%*|l%?Di)+>3w8^4eKERtw=+A*(I9(w3`u)xejvb??xFukY2FTQEa3 z7tlVU(2~%bLopy(^@=SPcfDf8%DRX=RW?{MVarC@B&bhXGig=21Q?Z0!XHN|VYKVl z&2OlyN03$>huqEbk8w8ZoOmNh-}*$seXIbLe^?>9L7s*zyx6yZis;b->dj%&ehAp) zS@LX4o`VG^d9I*|9Wq-LI**50zpQ$BD#tEpnv1*kIkF`!FbS;hbr5z}b1_-4FuqSL zwN$0YMA!7Na}$;qLS@8iYcb2J;tg|Qx+3yod5I-2wdG~0m-g4i-DpT>f*n63O^3OxI$pCh zBCnCxTJkyud3`P^Mi=BXewg8=0nQ8HM&P(+RIHS?1`u=e8hL{)Z=qWP&@%12s7qJZ|tM3L*|&n$VXEpKDKAKC73y5RK6mR_sZ>r`o0DGrsx@(yG% zVI@Z5j=0cVNIv6BEi$BBR6}0#vO!0H_c}u=v%NONuI~u^aQBb@gEvgZ>zc^=$PYoc` zF)kg^>zVW4ACG1A553oqNB&SI>}B}}OTJ>uSLJKD%nm7i3tN84YPS6Zf~&1E(zRY*)k!kK6GzWs ziDHnhOZ=-E$PLS{+0Fl^MHHOvYq~9duDeaZSUeh*$T_LTy86+`5Xa-|gM2tMkux+EOfg+6}9U9c2c6dpwbQ$WIohK^h&E<*#E=F}2#>?E7OBD|NO)c!#JmLk8@-HuEMs5W zC^CBIqDF#7A~mK6iqqD|WJd`CbGl1a=V{2X%WTD2Ktq_q{fz@G1LY)-83(~y1V}`t zRqJebf-e6b3}9!m!SD`shW8N6VWW4%IMnEG83T|FH&7KbuTyMjF^4n8JGHu|6GG`E z#a`|QWR)^mhZ=)XlVX(UxT38@NDg)(h{df_3Jiuh7?fgBz$hu8;q2RvVBIs)7Zspb zGh!TOjJ6D92(LEAAoQGB{opAa0!{x0O!HnFQ1ybvMdelpF2o2)EW@0gV(7 z!1p)CLnX;`BgO<{qGe2C7EbPf70rx(68|HgpTnI@*pQAS;kQa-;CL?(z%LS5K!%xrWN^EKLMPq369FOes}Df=ja)8Wszmf>tJ4bWW+ey zIL0z6Y-5435Y@Q35~C53`r1(i!1QQp=zRO0& z%QBD_J~Tj5v*$$tjiHZO#hqpw>o~m;s)b(`hq*YzIMXuDvW>Hib2{J^r|0lo4X1^& zQ}wY%4A=1iY|GtRwAlxg-dIos^v_4O!?>W`Qk%WkZ<)i%i*4f)=A>GJ)qw&kr;iKh z2>vsUJ`Nj~qXN2>#PiTKT)hobE$=k0{D*OqakFLIVjJs?p9wmk#o~dMkYi%COY2rIbk;N*^a)HXQeV92 zKNG9M#%;E7J6BJ3gOZt_u3P3y8*JlFzEp@y6)l#d`1;+paSvZ-{WQs2nBpt<+Qxl+ zr8}-5E8ttAvWy2%LZ@9TWZzblPO4r$C0K{>)%p~F zFzhrVMQRx@*v5+nGI3n5I>W6SZ&7RR-mQxsjo;bE?~Rv{t7$@Yp0A1#OP7HahJ2g5 zx3Y9$<|8oZuNbdd#%s3mI+p?r3RVBMsU2S%F!OGbQ!Qf^t%`^UJ{K+!@Y#VQK z^(59ULtra$BV?7%rg6a7M^d!d8;2d3!UzGj8ng+IOa?Az)(4GBU0x&kiXaCX1Ke)`EzWlvf@ zS#Bx2mC<&qTOj-TH8D=!qry2uUdP?XT3MZ_hLT_r!`2U8$w$&Gusng6brVPdX;e#j zdD3~HbRss-t*wT)gRp3S4A81r18Qu1H=tlnFQ($UV)@2Ys#rLE`qYXAC(oQaW$Ll0 z7x9g&y8wxsQY9Cz28-yMPo6t*&Qt*6T`&;-*+>p!!^)C)!vfxG%b@D2Vl|bqhH5@{ z8&%_qY7iFu5}X!{YUO=8SgFBVW8w{3g5m#YO~YFxqdweq#R4XYa}jz%3r}k*FH>wX z-eCb&_4a_k7PWkZjVl}4T2`fBjgxgJ;Ph=d)w6DbG_b;Ag&A%Fjozks?RoG^pxn1U2s*6&#YG(zq(H&{MBu4)u>&WyTPKIt zC1e0{o&zL-iIaY*gm0rhuI0OOn0mJbV$i^W(_V4L`vA1?YX=-)syj%egIilN;?7%7 zNOX64u)CtNsA?4!A6$tn3@{RK4LsKsvY;2{b(jT;QJEG)1cya;x1|g3_0oItF!Pr< zTk^3hs)HoyaZAOlU`Zdm3X6rQTgE!Noo30+6PU)*vt`c6QS#AMG1BPaNyJ#SzPZ3`G0O8!eU@wa`q@ z0-b?Pzyxp}(D{GYQ5~-#P0WH6#B0A1^qcRI8peDd4DiC=yXJM^@U;zcnh#{hc&9a_ z9tDkCl@Cx0++5WF?An=cL2D4HWwp5OC8NwCP`+HIq~yiVqZA%#FCk-u@-ZOn>!jYb z)uP_leL6s%jTQWg1vZZD(3hFwV@qz~QAddR-447hB~#+jfV<)y2HhEbA!vDy{iOVn zoK3Y`3XwL{hxnugGzN?kE6&swQh#}MOa8a=sM*Nd0bt;q{R=4I%#k)%-B0$m1Gu<5 zn-_pos-Os_8})`AgX+SeGx}#w z&)pxAw=BJN1M3$}_1GB`pN)TbF)D|m$ic4CZ`{Mn_v+_5ve;!Q-UU&c&?2uDmEK1% zHZWbFH`*X6P@O=g4X@P++B1Nl1KC~fW=aaM-W&#>)$b8tXGmLw>iDG8ZzhLhL^FJf z;ST-=NWmIRfT*>@#DExMLuaWD7};#0*b6AKSnrv)FY^=QP-l!T&NqSU$&K&!IWPgAR?K(b>oYG z?Iax-$Q+VCZS<1^eTR(|w8pP$J4&C9%=~*>IzSy~%Cja~AQ!WH$%QslfTe07eY!o@ zKGXTGqxo&SUP`S4a(XHo$35*Y7fKJ;?~hGOsiP@7-gEYDk`7RdaI!Pm#Oyw?RNxva z*hGJn-0!f_ot=(a)$OUiZxtBHdHmp@fzyh4nDMn;i*OuF9I-n-`_44hg$+o*{ow!j@|L5*8agKK0 z0}69c8-5B~>8}kkVF^&g)*&`#j0&gLlwf8!1gG88s)7o6D^+-&%6sN+$J^R!1FmWV=0Qas!FlmeM>Ig2Jz$Xu!TD$>COj;& zyS5`{FL@il5opRRE*)3;eFysvAQE#vi*U^KtTxPX%-LL-v1cJm zR_9P6OLOl$+tbgT=UH7tS9Rb`$r-9cZ!}1)2X#*R=jF`t+^hs;5m2r=8Q5ChTIX6ba^fR{U8B}xdS^`+O1uhlwPX4Bk(_^T;hl_t+ShN)>nO?{ zxgQG(ZnwVgr1TpBWt@wi^E*Hxxi=PT`ew<2z0+&)u{K&F(HpmZ0pgS-V{iCUbJR zZ`IG#bGf?{as_(rU})-5li6tyNw6hn1-mJz-Raac-00)trcju*Bvr;N8rnr&Zn;<&ayaGaZ$t8%UR5E_ZsonsE4vo z%kmoZ)=g~pZHU+LXW{TUOubnN5*3A(ZiMd~t9LeTB=SS%u!uR_9ATLwZF7_fZE$dU zRjs;qP2H+^>1~?3BCSCTssx0|3}K3G76Afi(!XSHE?#U8iv`xl`zUKKFjKZFW<);;e$t7TBh(&+r-3 zd~=a)M)cWYK0D4<|55+NohR_wiMIMueHB$-q2Uy6h}r5>^;uNCh6a3HFyD;Z>JxQ! zR9%gR72Hs5t6l1&sQL)Jsfn1Y@$Lr`e$$}V*~+R|N9KD)zKH>ewN?M^VG#jKg%c^?=UJkA(ww$**=ew-!wY>TZnYW%UiIp1uy)x8?| zU+~!zwt7H47&U(>s4jPbOegXJR=9JGZGqme7=>TkYLj|2YChBPEP-3`+lfU{bp9-N z{+z9Tp*Ba&7jhdbe`xRINIJdX3=DqD7`$YwX0;h-zvr`;ZS}Z5dxg(lwN+AWiK;EQ z{02At(N^2_*`N9BOdza7Nv(*{|{uEVzLc>Sg@Ug9at1thP&pxr$@6_+3>i4+(88>`xt5>xR_>#}Qveh57ME#r3 zzP8mXTB5$?v+r#6x}FRF<+JZ?^_Kc;)WpjKJ0)LQ({(N&%nyYGPzXs|y`%mX4Pi@r zV`oG>jY4KRC3iUwg%}UZR{vr)g}U%r#8#iHFK}k_Syx+qt-gt>Z_p6shVHidUi}aa z6?W(i%ISF-l!52~!aW&>UbZRNGYIX=XGOLtO(PoGFSnVJrPVs0ivR}uGX@9PW?18M z5TEt6O;ev8!e{+#Gh|x0vp=5=u+1*|Y!IIn+h(5HfNLduHpDi&>a$Wl8)lpN`fLQB z!QJkz9>kr8@!4qG9AFNNns{%XJrleA8uY6P_*JCVBxhr+6@nK!wp}ys*Bbt!S}QcJ zbB`nVXpA>lp(Ato8ofIbzO1wrg5#U>2Q3{vhh4!|2(Mym{}V7-Bd@2g6`ITYZ>njwnFof0`E{~lUr{8V);4-l@lF;;_-`p^_Fh{wn7W=YJ<+h!$!dt?-aH| zi*ljUmB(L>Cj`d?H>(CRA4( zhw$4?xABM3oVGmt=Hp*9fv?R;{(Pr4lnrKanw%)3{DnMHycOaia#}%}o z#XXY064autx9X98j&7!Tgx8;GRC@waDbDa|Xflhpka(0qt6umEg+yzOKy-a=jG6b~+G25+c%Gj-caJ?0K6#(8h&JV^(XDcx{z zy1~TtLsIt-C<|FnP|wB2kc!2sNL4IG4ya;rs3=sil?L~q(#L3ck`7N&`69qSvSb@g z##^R~OOiB`5jQmALn#l(N8_vW75JjdG8#m+R0eL&q)VupE~gs0g6ipNI)kpEbLo0b z;0%Wdmq3uC_EUX8bePtu{nY{B^uAQB4paw`0eHu%zBp2VI$a%%BNMR4s6%iRQvJ|( zF|IlHAL`xT-@CuRcYlA}KLGc`3EU4qLJdsu6~ij=Kcan^&cWMgj%1D=Jvd1Vx6$#E z(&N+(T@c+0p5I3M(CwO>Ue2=~Ir}=~WOPPns6oyk(jNgr0m!6cz&~luW3;4TMUqzH z7o4rf5xP#46j(`GJGXcU?m24{Zn~i05?sD)8(nVDcDiP9$rifqms(H;fdl7}(xY)O zcu4dB#OWdGMh}B8n=ssu;f}{?Fm1;B4S%jt9;GF+pDI>^f&3wOi&lvm0=x#(K5D2c z)dWrQ2%4mZso`K4bDM?Jxqk#CU?f@~x+^V=q08H0Xp(da#T;_cY*2Tw`-kmx17!B5 zIVA-*8&A;sB;C4bJ8eMIU2{R?-DQx#t#toQls}|MH3M%-(&k0Dvb79i`7Ae^&GZXy z{v|j6x(tG0oXcpd0p4+|ZpH2I+>7IXc=is)3c_S^kgb0JH}_>VauhCZ(Q*is2eam&e4&jTCxJj4g|n6y+C1o5c}K+mVYvn=Yll(MI|^1m#^w#e0DCA)tJWJO72NpVIsE8GS*Y3qfCt zF8IV$A^jkVXt(GK{aY-A7%e2eM{kHt!W2IjA$*}WES|szyq^+z_|$7R@q&nock#{5 zPeo7ht>~kt%~Qa56DHM%Y82GoM(V2$gQ|~+a@wp$;|Nbte|0#H^2NKcw7DhP!yGmr{x_`jwT%=9yG4U zQHZL=^~OjXS#+*ATa8oW!OOQrUv;FKKwap4v7efVqX>N=Y|&Ls!gubAXotKJ@N91i zJ5Nrgu%5yfP~i`Bm_;{Ow85hF|D|3QRr>#a&n<6Q^w#L_Nd7?6Eg|uLv76>ocZ>2Z zy2pDMPp1C=hI<=8T51aarS&j#(P-EGEbCiRx`*|XEHUaE%Fomv=U|KtZS(E}7i>t( z`t4%o;w|E+xln`Ol_~uFq0Gbtnw=EKB*n3ZhkAvIOw7BBPVI8t&6J-yTfLFGdB>61 z;bCZ(q&Nx6Bq^2*=@r^4;z_Y$NUyLysBr++u^Q0YVn9)3n>bZavuGmPCe}#WD$d*{ z&X-UYZBwd0jbDbDRH;V~c%9dg5uA`7)Vr1F4u20Dfj#y2zr?6g2kHpAdr>3fDkeP0D zrIr9iJ?K&`0VW+pXNpQS9WpbW7OELI3S$lp74rc(qGf?itkc&_x33a40zEi)&B9%* zUtm~w!~R-4)M5^gwwURREezQ#^*t?65Dz_qU8I60Qm_JwHI!7dVL0Zfxz1?H{^+j@ z+FvT(EPgb2o48U!MO+77&M7GrH^DB*t>TtNB`(kJATWLdf#-KRJQo}1rmo!=Fdm9c zC#;8nR)YZ*53%V;icM@Pwu;R+K|vw|wPl;whVc{Ilj4b__*GIo$2LQEIiy*<6aW{t zW0TNUxKO+tV1^|q+5{7O9z2D|^si%%XTb#}F$14co=N+Qqv!xJ8{cx6Lu18!DicRj zrC2~K#4@}sbUCdR)pQj+k~_rN^sqRG9u?=&1%=4*FvwaO0Ta)USG$0eT{&=a{5{fr;8j41qsZ#Jb) zU4i>AB>o4#)5p^G8f@Hou#SJ#zmBw362}PFK-zAkA^{gb+>95t-$K*Gt#q`wjh2YJ zs7BmPjp81<7F@qw+)MX~`ygTW(-!d{rrIX@4Puhl#pAFio9P|#bNW~$wd9=ucHd6> z$VXvC!gMY5QzxpEAQwyMSh%)BFdQ{BSDg%bGa-#HX?c_QrsFf}6cvMnyhA-bdHd3n zw=cDobL5R(QU~r55AFyL?ko>(6(rAryA;B}vNe*--E@{KTkBatiFdS`VuM9A_8XE# zyMeVMVCypk>>r+h#YylN!yN$=4d?}N6(TK+%@!%(qDqN@V8sE&uYFZGlT}5^kp&2c zD+}}ah-E>Vtag&pO3FOvCe|{J$2pLX^i5HAOp~(UDTuEuEbB4^zNqX4f!VnG^^Ln9 z^qH1oMo2sj)A9^H|M?qyi|$z(FP@_+@jTVT@mMEbgu4GNog;pyhwK=TTu)upG7MQ4 zxKO>+a7Pmh;pqJi(@Aoi;%R0-cqrhE<6+89Y!9wACK8 zS{GW0s=`cmo}7$fcb=@nlRQxSllp-MYDa>H=6mXANfQU((onb+e)F-)8(5pC}SXCyJugG_hU`Lb$~^i2_k1k7(I>Ki zKEsFEKbKMZ9v@T>$wEE0SHk^z13v5;%#wTrDS7g0j9HZKrX%&d>PnB`D;jK~yCD~{ zK&{198#D1i*SVigcgio(7DC8#qdHBkgPgCSMs+&EhA8Wjs&kll46vqUY&b zyXhpdwciKz$+Omy6SRN7-jXMvWE$L6s9R8QbCi-DhZind0c)Il{rl{jt+)4)e_Xt_1&7~ z>HrCHTsQRL*vJtaOUQls>-5xJ?uUBc5 z)}-QV%;<06=zI&!`yCxB{sV{SYuzbl1OZqN2M%bEo^OooAU!|Wff}T)M9>Y7i)&$A zlty95_^t>LIfD^7Gu@|7(2D=~h>ED6sA~|-M!0^)g|GmaF@$39_Ph-B31!LZ6N(e+ z6G{~7^MZ<`yr``niq-Y%r@9AJ@3=i22^<;!yum>7$Bg9VEkS&%k#w?>d754q<_|8Ew^ImiZx1n= zYn$c6_!X0*5uLBgPxsObN{z(r5VbpC@R6ep;lMCn!&Hd-aRd zBivV(NNordDU>w15JtPx)rLrI;^~@{kEQW*#L^FgN5&BvluWrWGKA*mj7G90h&wVy zhLcbHUwULvRpkOp3k?uT%54~#C)T3d#O8 zBl&bou-EvI?CF8+>G2(PS1#CPF4+Eq5d{JsCy3>_R`Z(PWyIdr$ zrC#DX#M#$Ftz7Htv%lA8f6S)GG$|-=a{HX*&ZcfWn||LcUuW2Fq+vT_<3c&2cHZgNxw!{o2YOP@QQ6OgiF$ls8Rbv5|ecUEy4$PLAp_K9lLoX&o#WRU zMu1mhmJ}M=z2WCecsQNaw9z_AjJQhFQCCrqL~sMFS^{xJBR(kDgpaVTL42_mpFTN_ zW{5Lrp*WLb;w(LI?C$|xo&LcAj-FD#f&hi-cyT(CJ`%7ikvN`?sj(2r>0iT@F}0`2 z!sy)fG>)8W=a2~zLIIx3*m15f7HV^Egpx+Mz}jkbL87CjG@h=}aX4G(S$o$)R^1mrly2H-VbzFQQ5Om?ys%J2iwlhrNn=#h(qk~TCC~kG5CzZwtg%5!std<& zVhvsbGsd+9QR$P^JWo>7CKiRIF0iRUik+YCgEdk|LK3Dh$f<3C?Cyc=4*cHM#sr0; zJ~|m>2*$~n(H5ML2PdTduHMyfu;0LibC}DoJb;-4pKPl!za_AveFC4SK2SR}tFVW` z1yKTqGs|Uh%O~gfo|N8`*p1;n`2=P#yY}PVm}54OsGL)xQ~L)%HE(isFg|v<%{Z2$ z#PxFr4@nxw!?$P=={V7#6G$M$7Erw6a7_0x_@wn%Diuy81_u(wP?8_R9fBH1;*7JN zhkWVmn4>*?%!ojp zIk5&xZe0j_K1cmMq~|EM$GAPr0?|yiT~a)_**H0HmUh=za`1}#^wK8|aKuZWJjgaM zzlkJhM|rRdcLrpL?~jzgQThqyZdTCYhZ^yqMm(qyJ(C$KcK5hY4+l){u`4^u&BiG_ zVPY*LjGO?(u}xjo|EYg#*+i|f3xrqF7)T$egXP*CHL9O7Ru&p{&dI4y8I5hh?4!O_ z-)WfGgyh1^Pz@a58f#mEcu#ZD4cYW!F>rwQeZ6wxBGgX1z~-b?gFG*3oDS7+E`vNT z4brJmc^{Ja0Y&M3AL#BL=JPGuqe)`qCPqZ)gJ+9R;WokT0!+8 zhoxLz?E;&GF=te}LEHYALrn!ka77wPhjc%@ZXR;oQjsQ?at9%IRUmSHO8tCHA%|-3 z0OYP_b<{>A%kF&^aKLgSGw#-mB&aX#teHEwYllg2h~-`{KB zp3&Y@c^97WE|i(YC>$_;xz%_&X*{1^_bEfx9IH=QiCarO=rlTj)}e6ebQEHpfxPOO zC`~k_rN;g0N`9o4H`=)e>%)dY!7pt9rR`HXZ8V> zJ*bblzj*-ir;>LbyBJ;VVl;-AqR{UL+l(D9M!OiJk3Eb&@G$yk()ffi`z&dEp2ke4 z-Do-bSpm$df!Ru|f~@jkH^#$mjECJA54(QmL1tf#9rjkcLYNQiIG{htDLpa1a#4GQ zQTy6KZLr2`NC_MJt;V;&>%ZPw?*Odz>QW%o!eo~MnI#YyMZWb~r!sZ{68HwzHV{^vUqw*xTMwZ*08rkkNN7HKn z>QJ*Eo^aM@d3tLY=AnS0ubHTa)hj#N9X-J^Ucp)p3@Ww*xkKk$6i|ky9*Y9XXlVpb z(pWm~Q@(n^M4U=tvlx7J))x9|=Lt&?1^HW*`8Zv`Ln?d~&SOZKgV83?#$x?)1AWfF@~lvq z{=GPKg#NuEG+zH+6PloZ*M}zQ-#bH7^lx)$n*Mz*G(-Qs9Gbv RoHIfz^!dtAO{kWN{vU)W8`A&) literal 35889 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 S|2}T~Nniia_^a`ED*u0U#}G*X 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 74d4107548fbb019b127ba20daae680d97793aa6..1d292a0c64bf24109d2415f27f4e49d0020db1d9 100644 GIT binary patch literal 3164 zcmbtWO>-1Q7=C+qlTE@BVgeXM`4*Fq&>$e-hG0GHvV3}G6Lyn961_}+%=_{5^L}*y{`bB6 zM0A2KG*N`2af&6Vj_Mh;ToN;a7lfVXXD2VotY%c-YuT3WV-)S^%rsF0HO8qaLF*{N z=wMbAxzKsf%6nW}cHW)xIQELl=AO0+yx-GPgUZ(O1AST*a?)Ycn3wvTE1ferMy(y4 zsmC5u%FZVnshKv!sU<wS?Rj{CCj*TRH0yewHwJA zfwXjHtgM9L)Dta3$H=U-UQtf2qm8sFPMZ_-EVVN_{+}%|Y6BY+j>t|AI8scfWmehX z;saKGNM@~~C?uQcIocYh=M(e-ZDZ6Ch75ZqK8|#~g68A?z$l`o z8TD2B4H6*P8A?=`5ucYG3ED}!a4@fw6I#}g&uFM4)Y^>VeoR-yGoz9#PM$IJ?@7>$ zw3ksc_)Ec0Va{if(a!24_!(89%Fo9UQA#q}GVa;hD$0!IT9XCYZ`(=>Z7JIY^(p1# zxm$9O%@-X}l(Wj2=95y`F25+US~+uEEGd`-SF@HQb1)klR5@hUhLmN?QLi{Doe2T+ zNb{7+ib6&>mRVOeV|vPhzZ0Q^_-s5q!{M|yU2-p*;r-O#Ba&z2QFlfW9Y`yh?5sRNk`ruxAZ> zDKmw9XUbCCofY{!8pzBcu7q0^OqZW6NykqF!;I?{i^7>h7kPB~&cc;z3pZ~4`R%Xe zuYM|Dz5nRJ^@V#sFghHXEwgfxPg-`a$~GUC8p&5eR>5}Nj3{`Z<$#~|H8sLR8Up{Y z5~YtAy|?xXT0;e!x<$-u5M>k^eJIiYRQRj2tkTs3DmRB5=*Hc*hC+=NMalFQpTVkLwz;;q%#{}V%b{A)N)`E6ds>_B zwxY9|iV|x;RWZ2;W>p@Hk8MFc1wk%<^YNnxUj|hb1Q|U%BtXmid{bI^PF9|>OoQFM z;^L@z2<$hc;Wm6q^=pxL`Ghb98ne;H811Pf;)=?Dc=Nl5Uwl%&{Qbg}8&A43!ny!% zTmATf0!QK3O}MI`J&&76gSj6}wc^5U#xu^;PsF^MFusIUJ;n}3`{t=FN~1k@ zY0EAA2#hsDjPL@9(Kc$K?Y_~jK(S&JCV=DsjK_fZAZ8Ir*3rv!2)c)%UB@6mbi_CM zihrQ3_;nQPV^BNp(yNrjr1t_b7cW_44fVmAfmwo}LC|hscK=4r2I{`cN-eWqXj?;M-8JBhX($+fFCxHTZ~uq5y3_q#B6*MQw2!SVVjhn}&L$eiY(E z=jruDxTk0sI|1C&bOus!6Nxu4VR*~D2^E9A045CfjliDranIB42#s{t;0_q>2cALN zKtolSH&!smz^6fqo&jD{Gy=P$uxo-F?3~3;K<`)>y>C^~I}Xt_lp{2;Bzg{pGA_MM N@8HL~SOiBq{|}kpyy^e| delta 196 zcmca3v4@T8)W2Q(7#J9A8Kft2>9esja4<4hPyWCvGI4*y5y=qVo1WinqNV3YkmPsk>Zb`Q#@vnLC2l%6mvkM8z zns{hBA1`m__4V`X{R04Qp<L;98oL3#YtRo;#hXeCD~&(Q-N~Es?)a5b4}uHnv7$ zp2zD(2zv}VbFmUU5t-souXB`+L06%Bwn8oj7R4e)X|gGUt6sE)MkZ7J-TY!*NQIm6 zfmTD5Iu%KuW{l9y%ycZQNYSCq88nIwABi?}#iSzY`sGwO{Iw~AVK4ei;L5BuR`UmY5hhm3x>Cw>%}sA4<$3Zoe}0|O%iD^QM!feio@FA1Cg 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 cfa39b82e7105a3ca06b1a2929627813ddb2ce8f..61b0d710f2cab6dd14dd9071492d58f69133933e 100644 GIT binary patch delta 985 zcmY*WX-Je&6g@|09Q*v5ra~f9!^za9BqAtskao4jqJ%NbCJ6 ziYVHw%$CU(+ihR8-S%wLHZ$9I>CR|Ue7yJWz2}^J&->our1B)~Vr|he0MV@7qpc5M zr0V1w7(QYAgh|OAV>2DGnZ4bio$yIZPoC(QNobiF$>~uJ=fu<~S6+Z_FrU_VhG$JY zr}I27sN&!=%`R)`!V;ZB5p3ZVB056a`m4Ey=IUhY5c3UP3*QJO&id9}s1)R#JE+k)LU=y>;I{u!=O=zvheOJZUx^-n?KV+U z12t7*wep9mvDys3h+x&z8l>!PiW%;zZIj6HQLw-ce?%h;-O)kLF6b$h-smG=fAqyj z#9%C9Fu>FVIA$*z<$`sf!M?);x$d&Cc?~oZi2}oax-^I=qrNu z%vag%f|3g)_X0SWySN+PXv7%qVGa!F%s}oH)F|V((j};m3>(aS5}CMG+S`Oxrz~tx z?w48}|3Cx3P&Ky2`4d!GG4J^qMKJ$N1a m`G469zWxWRs>>qkh1K=odw9#3YJTB28LY{e@BGQ%X!!@Dq-ql}7-?@YhbQ#NYYe zUo%>dYdpb|W}eb{nrD=y{pnWcHAL`&&VdN9@e&aes=_UPYL?MgnL7kpuWG!;>t^22 z5yzV1c2rqQrsjQV8{_XfFv8&&U+etuc7U;>&WTXx7nJLDo1d8#BN)@u_tI~zi> zSuh1Ym&BJ2M#~Lg^spOln1Ql3{Diop` zMX13t)L}WEU4+gS)By0I;H2y2qHHnBojZ?PnCryw&|OCyJ< zTs_LUtI6qvuhC=J-DKFMMmhTVm5I1qo)WPdxW}e(FZVf*JBkb~gWcEAT{{^jaz78K zkzK-Asg`ze6a>TMu^i+fxAidR%ISJ5@^|p4;5=wNCc3jc$BVqoDqa!xmOI{Y$9o?B s0c+fRqq_FL>`sy)yE|cbHk97A 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 Ai2wiq delta 171 zcmaE9v4)lF)W2Q(7#J9A8N?@Y>9esja4<4BO?KoKnS5SQkC~l;Yw~*myU7cf+$L)a zUY)Ec8db`m$iU9P#K6eF3B*hc+zdQGnipsU8<6G$(u_dJ3g+