master
flying_pig 2 years ago
parent 9cb0aafb34
commit bd84f2242c

@ -22,7 +22,7 @@
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="auth-service" options="-parameters" />
<module name="common" options="" />
<module name="common" options="-parameters" />
<module name="eureka-server" options="-parameters" />
<module name="feign-api" options="" />
<module name="gateway" options="" />

@ -11,7 +11,7 @@ UI:https://www.figma.com/file/Y4OJRtIMkpFlonuqF8EFpX/%E5%96%B5%E5%90%AC%EF%BC%88
## 技术栈
后端采用SpirngBoot+Spring Cloud Alibaba+redis+rabbitmq进行开发。采用docker进行部署。
后端采用SpirngBoot+Spring Cloud Alibaba+Redis+Rabbitmq+ElasticSearch进行开发。采用Docker进行部署。
微服务方面选取的具体组件如下:
@ -45,18 +45,18 @@ UI:https://www.figma.com/file/Y4OJRtIMkpFlonuqF8EFpX/%E5%96%B5%E5%90%AC%EF%BC%88
### 优化性能方面
1.排行榜功能使用Spring Task定时任务实现并且采用了redis进行优化。
![202401031857681](https://github.com/flying-pig-z/CloudMusic/assets/117554874/a217bd6b-0004-4d2f-94c4-4f52eb5931a1)
1.排行榜功能使用XXX-JOB定时任务实现并且采用了redis进行优化。
![image-20240509125127647](C:/Users/86138/AppData/Roaming/Typora/typora-user-images/image-20240509125127647.png)
2.业务逻辑严密,比如对上传文件的格式进行检查,避免重复的点赞和收藏。
3.redis优化用户信息查询
3.redis优化用户信息和音乐信息查询
![image](https://github.com/flying-pig-z/CloudMusic/assets/117554874/3ba2601e-b6ea-45b7-a473-467fc1e4b6ca)
4.redis优化点赞
![whiteboard_exported_image (2)](https://github.com/flying-pig-z/CloudMusic/assets/117554874/66a57721-56c0-45a7-910d-8163d2d63595)
> 设计思路:<br>
> 【1】最终一致性一般一致性采用的是Cache Aside Pattern先更新数据库再删除缓存但是的话获取某个音乐的点赞集合到redis中是个耗时的操作。在加上更新的频繁所以不能采用删除缓存。<br>
> 那要不就先更新数据库再更新缓存,要不就先更新缓存再更新数据库。<br>
@ -77,5 +77,5 @@ UI:https://www.figma.com/file/Y4OJRtIMkpFlonuqF8EFpX/%E5%96%B5%E5%90%AC%EF%BC%88
## 代办
xxx-job优化大文件上传
实现大文件分片上传

@ -34,6 +34,11 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
</dependencies>

@ -1,4 +1,4 @@
package com.flyingpig.cloudmusic.util;
package com.flyingpig.cloudmusic.constant;
public class RabbitMQConstants {
public static final String MUSIC_UPLOAD_EXCHANGE_NAME = "music_upload_exchange";

@ -28,5 +28,13 @@ public class RedisConstants {
public static final String DISLIKE_LOCK_KEY = "lock:dislike:";
public static final String MUSIC_INFO_KEY="music:like-num:";
public static final Long MUSIC_INFO_TTL=30L;
public static final Long CACHE_NULL_TTL=30L;
}

@ -3,6 +3,7 @@ package com.flyingpig.cloudmusic.exception;
import com.flyingpig.cloudmusic.constant.StatusCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ -43,6 +44,15 @@ public class GlobalExceptionHandler {
return Result.error(StatusCode.METHODERROR,"请求方法错误");
}
/**
* Redis--500
*/
@ExceptionHandler(RedisConnectionFailureException.class)
public Result edisConnectionFailureExceptionHandler(RedisConnectionFailureException e) {
log.error("redis连接错误啦啦啦啦啦啦");
return Result.error(StatusCode.SERVERERROR,"redis连接错误啦啦啦啦啦啦");
}
/**
* --500

@ -2,11 +2,18 @@ package com.flyingpig.cloudmusic.util;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.internal.Mimetypes;
import com.aliyun.oss.model.*;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
@Component
public class AliOSSUtils {
private String endpoint = "";
@ -36,4 +43,88 @@ public class AliOSSUtils {
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
/**
*
*/
public String initMultipartUpload(String uploadId, int partNumber, InputStream inputStream, String originalFilename) {
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
// 创建InitiateMultipartUploadRequest对象。
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, fileName);
// 初始化分片。
InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
// 关闭ossClient
ossClient.shutdown();
return upresult.getUploadId();
}
/**
*
*/
public PartETag uploadPart(String uploadId, int partNumber, String filename, MultipartFile multipartFile, long startPos, long curPartSize, int i, String originalFilename) throws IOException {
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 创建UploadPartRequest对象。
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setKey(filename);
uploadPartRequest.setUploadId(uploadId);
// 设置上传的分片流。
// 以本地文件为例说明如何创建FIleInputstream并通过InputStream.skip()方法跳过指定数据。
InputStream instream = multipartFile.getInputStream();
instream.skip(startPos);
uploadPartRequest.setInputStream(instream);
// 设置分片大小。除了最后一个分片没有大小限制其他的分片最小为100 KB。
uploadPartRequest.setPartSize(curPartSize);
// 设置分片号。每一个上传的分片都有一个分片号取值范围是1~10000如果超出此范围OSS将返回InvalidArgument错误码。
uploadPartRequest.setPartNumber( i + 1);
// 每个分片不需要按顺序上传甚至可以在不同客户端上传OSS会按照分片号排序组成完整的文件。
UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
// 关闭ossClient
ossClient.shutdown();
// 每次上传分片之后OSS的返回结果包含PartETag。PartETag将被保存在partETags中。
return uploadPartResult.getPartETag();
}
/**
*
*/
public String completeMultipartUpload(String originalFilename, String uploadId, List<PartETag> partETags) {
//上传文件到 OSS
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 创建CompleteMultipartUploadRequest对象。
// 在执行完成分片上传操作时需要提供所有有效的partETags。OSS收到提交的partETags后会逐一验证每个分片的有效性。当所有的数据分片验证通过后OSS将把这些分片组合成一个完整的文件。
String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
CompleteMultipartUploadRequest completeMultipartUploadRequest =
new CompleteMultipartUploadRequest(bucketName, fileName, uploadId, partETags);
// 完成分片上传。
CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
//文件访问路径
String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
// 关闭ossClient
ossClient.shutdown();
return url;// 把上传到oss的路径返回
}
}

@ -1,6 +1,8 @@
package com.flyingpig.cloudmusic.util;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.core.StringRedisTemplate;
@ -8,7 +10,9 @@ import org.springframework.stereotype.Component;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import static com.flyingpig.cloudmusic.constant.RedisConstants.CACHE_NULL_TTL;
@Slf4j
@ -22,31 +26,17 @@ public class MyStringRedisTemplate {
}
public Boolean delete(String key) {
try {
return stringRedisTemplate.delete(key);
} catch (RedisConnectionFailureException e) {
log.error("redis崩溃啦啦啦啦啦");
}
return false;
public void delete(String key) {
stringRedisTemplate.delete(key);
}
public void set(String key, String jsonStr, Long ttl, TimeUnit timeUnit) {
try {
stringRedisTemplate.opsForValue().set(key, jsonStr, ttl, timeUnit);
} catch (RedisConnectionFailureException e) {
log.error("redis崩溃啦啦啦啦啦");
}
public void set(String key, Object value, Long time, TimeUnit unit) {
stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value), time, unit);
}
public String get(String key) {
try {
return stringRedisTemplate.opsForValue().get(key);
} catch (RedisConnectionFailureException e) {
log.error("redis崩溃啦啦啦啦啦");
}
return null;
return stringRedisTemplate.opsForValue().get(key);
}
@ -55,31 +45,104 @@ public class MyStringRedisTemplate {
// 获取线程标示
String threadId = ID_PREFIX + Thread.currentThread().getId();
Boolean flag = true;
try {
// 获取锁
flag = stringRedisTemplate.opsForValue().setIfAbsent(key , threadId, 10, TimeUnit.SECONDS);
} catch (RedisConnectionFailureException e) {
log.error("redis崩溃啦啦啦啦啦");
}
// 获取锁
flag = stringRedisTemplate.opsForValue().setIfAbsent(key, threadId, 10, TimeUnit.SECONDS);
return BooleanUtil.isTrue(flag);
}
public void unlock(String key) {
// 获取线程标示
String threadId = ID_PREFIX + Thread.currentThread().getId();
// 获取锁中的标示
String id = stringRedisTemplate.opsForValue().get(key);
// 判断标示是否一致
if (threadId.equals(id)) {
// 释放锁
stringRedisTemplate.delete(key);
}
}
// 查询时候缓存空值防止缓存穿透
public <R,ID> R queryWithPassThrough(
String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit unit){
String key = keyPrefix + id;
// 1.从redis查询
String json = stringRedisTemplate.opsForValue().get(key);
// 2.判断是否存在
if (StrUtil.isNotBlank(json)) {
// 3.存在,直接返回
return JSONUtil.toBean(json, type);
}
// 判断命中的是否是空值
if (json != null) {
// 返回一个错误信息
return null;
}
// 4.不存在根据id查询数据库
R r = dbFallback.apply(id);
// 5.不存在,返回错误
if (r == null) {
// 将空值写入redis
stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);
// 返回错误信息
return null;
}
// 6.存在写入redis
this.set(key, r, time, unit);
return r;
}
// 互斥锁和缓存空值查询防止缓存穿透和缓存击穿
public <R, ID> R queryWithMutex(
String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit unit) {
String key = keyPrefix + id;
// 1.从redis查询商铺缓存
String shopJson = stringRedisTemplate.opsForValue().get(key);
// 2.判断是否存在
if (StrUtil.isNotBlank(shopJson)) {
// 3.存在,直接返回
return JSONUtil.toBean(shopJson, type);
}
// 判断命中的是否是空值
if (shopJson != null) {
// 返回一个错误信息
return null;
}
// 4.实现缓存重建
// 4.1.获取互斥锁
String lockKey = "lock:" + key;
R r = null;
try {
// 获取锁中的标示
String id = stringRedisTemplate.opsForValue().get(key);
// 判断标示是否一致
if(threadId.equals(id)) {
// 释放锁
stringRedisTemplate.delete(key);
boolean isLock = tryLock(lockKey);
// 4.2.判断是否获取成功
if (!isLock) {
// 4.3.获取锁失败,休眠并重试
Thread.sleep(50);
return queryWithMutex(keyPrefix, id, type, dbFallback, time, unit);
}
// 4.4.获取锁成功根据id查询数据库
r = dbFallback.apply(id);
// 5.不存在,返回错误
if (r == null) {
// 将空值写入redis
stringRedisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);
// 返回错误信息
return null;
}
} catch (RedisConnectionFailureException e) {
log.error("redis崩溃啦啦啦啦啦");
// 6.存在写入redis
this.set(key, r, time, unit);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
// 7.释放锁
unlock(lockKey);
}
// 8.返回
return r;
}
}

@ -10,5 +10,5 @@ import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient(value = "music-service",fallbackFactory = MusicClientFallbackFactory.class)
public interface MusicClients {
@GetMapping("/musics/{musicId}/detail")
MusicDetail selectMusicDetailById(@PathVariable Long musicId);
MusicDetail selectMusicDetailById(@PathVariable("musicId") Long musicId);
}

@ -130,6 +130,13 @@
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
<build>

@ -0,0 +1,51 @@
package com.flyingpig.cloudmusic.config;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* xxl-job config
*
* @author xuxueli 2017-04-28
*/
@Configuration
public class XxlJobConfig {
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.executor.appname}")
private String appname;
@Value("${xxl.job.executor.port}")
private int port;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setPort(port);
return xxlJobSpringExecutor;
}
}

@ -1,6 +1,7 @@
package com.flyingpig.cloudmusic.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.flyingpig.cloudmusic.constant.StatusCode;
import com.flyingpig.cloudmusic.dataobject.entity.Like;
import com.flyingpig.cloudmusic.result.Result;
import com.flyingpig.cloudmusic.service.LikeService;
@ -30,7 +31,7 @@ public class LikeController {
like.setUserId(UserContext.getUser().getUserId());
boolean judge = likeService.likeMusic(like);
if (!judge) {
return Result.error(500, "音乐不存在");
return Result.error(StatusCode.SERVERERROR, "音乐不存在");
}
return Result.success();
}

@ -5,7 +5,6 @@ import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.flyingpig.cloudmusic.aop.BeforeAuthorize;
import com.flyingpig.cloudmusic.dataobject.dto.*;
import com.flyingpig.cloudmusic.dataobject.entity.Music;
import com.flyingpig.cloudmusic.dataobject.es.MusicDoc;
import com.flyingpig.cloudmusic.dataobject.message.MusicUploadMessage;
import com.flyingpig.cloudmusic.result.Result;
import com.flyingpig.cloudmusic.service.MusicService;
@ -23,7 +22,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import static com.flyingpig.cloudmusic.util.RabbitMQConstants.MUSIC_UPLOAD_EXCHANGE_NAME;
import static com.flyingpig.cloudmusic.constant.RabbitMQConstants.MUSIC_UPLOAD_EXCHANGE_NAME;
@Slf4j

@ -14,7 +14,7 @@ import org.springframework.stereotype.Component;
import java.io.IOException;
import static com.flyingpig.cloudmusic.util.RabbitMQConstants.*;
import static com.flyingpig.cloudmusic.constant.RabbitMQConstants.*;
@Component
@Slf4j

@ -6,7 +6,6 @@ import com.flyingpig.cloudmusic.dataobject.message.LikeMessage;
import com.flyingpig.cloudmusic.mapper.LikeMapper;
import com.flyingpig.cloudmusic.mapper.MusicMapper;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.amqp.AmqpRejectAndDontRequeueException;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
@ -14,7 +13,7 @@ import org.springframework.stereotype.Component;
import java.io.IOException;
import static com.flyingpig.cloudmusic.util.RabbitMQConstants.*;
import static com.flyingpig.cloudmusic.constant.RabbitMQConstants.*;
@Component
@Slf4j

@ -11,8 +11,8 @@ import org.springframework.stereotype.Component;
import java.io.IOException;
import static com.flyingpig.cloudmusic.util.RabbitMQConstants.MUSIC_UPLOAD_QUEUE_NAME1;
import static com.flyingpig.cloudmusic.util.RabbitMQConstants.MUSIC_UPLOAD_QUEUE_NAME2;
import static com.flyingpig.cloudmusic.constant.RabbitMQConstants.MUSIC_UPLOAD_QUEUE_NAME1;
import static com.flyingpig.cloudmusic.constant.RabbitMQConstants.MUSIC_UPLOAD_QUEUE_NAME2;
@Component
@Slf4j

@ -4,7 +4,7 @@ import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static com.flyingpig.cloudmusic.util.RabbitMQConstants.*;
import static com.flyingpig.cloudmusic.constant.RabbitMQConstants.*;
@Configuration
public class DislikeMQConfig {

@ -4,7 +4,7 @@ import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static com.flyingpig.cloudmusic.util.RabbitMQConstants.*;
import static com.flyingpig.cloudmusic.constant.RabbitMQConstants.*;
@Configuration
public class LikeMQConfig {

@ -6,7 +6,7 @@ import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static com.flyingpig.cloudmusic.util.RabbitMQConstants.*;
import static com.flyingpig.cloudmusic.constant.RabbitMQConstants.*;
@Configuration

@ -1,5 +1,6 @@
package com.flyingpig.cloudmusic.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.flyingpig.cloudmusic.dataobject.dto.*;
import com.flyingpig.cloudmusic.dataobject.entity.Music;
import com.flyingpig.cloudmusic.dataobject.es.MusicDoc;
@ -12,7 +13,7 @@ import java.util.List;
* @author flyingpig
*/
@Service
public interface MusicService {
public interface MusicService extends IService<Music> {
MusicInfo selectMusicInfoByUserIdAndMusicId(Long userId, Long musicId);

@ -19,7 +19,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.TimeUnit;
import static com.flyingpig.cloudmusic.util.RabbitMQConstants.*;
import static com.flyingpig.cloudmusic.constant.RabbitMQConstants.*;
import static com.flyingpig.cloudmusic.constant.RedisConstants.*;
@Slf4j

@ -1,15 +1,16 @@
package com.flyingpig.cloudmusic.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.flyingpig.cloudmusic.dataobject.dto.*;
import com.flyingpig.cloudmusic.dataobject.entity.Collection;
import com.flyingpig.cloudmusic.dataobject.entity.Music;
import com.flyingpig.cloudmusic.dataobject.es.MusicDoc;
import com.flyingpig.cloudmusic.mapper.CollectionMapper;
import com.flyingpig.cloudmusic.mapper.MusicMapper;
import com.flyingpig.cloudmusic.service.MusicService;
import com.flyingpig.cloudmusic.cache.LikeCache;
import com.flyingpig.cloudmusic.util.ElasticSearchUtil;
import com.flyingpig.cloudmusic.util.MyStringRedisTemplate;
import com.flyingpig.cloudmusic.util.UserContext;
import com.flyingpig.feign.clients.UserClients;
import com.flyingpig.feign.dataobject.dto.UserInfo;
@ -24,8 +25,9 @@ import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static com.flyingpig.cloudmusic.constant.RedisConstants.MUSIC_RANKLIST_KEY;
import static com.flyingpig.cloudmusic.constant.RedisConstants.*;
/**
* @author flyingpig
@ -33,15 +35,18 @@ import static com.flyingpig.cloudmusic.constant.RedisConstants.MUSIC_RANKLIST_KE
@Slf4j
@Service
@Transactional(rollbackFor = {Exception.class})
public class MusicServiceImpl implements MusicService {
public class MusicServiceImpl extends ServiceImpl<MusicMapper, Music> implements MusicService {
@Autowired
private MusicMapper musicMapper;
MusicMapper musicMapper;
@Autowired
private CollectionMapper collectionMapper;
CollectionMapper collectionMapper;
@Autowired
private UserClients userClients;
UserClients userClients;
@Autowired
private RedisTemplate redisTemplate;
RedisTemplate redisTemplate;
@Autowired
MyStringRedisTemplate myStringRedisTemplate;
@Autowired
LikeCache likeCache;
@ -52,7 +57,7 @@ public class MusicServiceImpl implements MusicService {
@Override
public MusicInfo selectMusicInfoByUserIdAndMusicId(Long userId, Long musicId) {
Music music = musicMapper.selectById(musicId);
Music music = myStringRedisTemplate.queryWithPassThrough(MUSIC_INFO_KEY, musicId, Music.class, this::getById, MUSIC_INFO_TTL, TimeUnit.DAYS);
MusicInfo result = new MusicInfo();
BeanUtils.copyProperties(music, result); // 将 music 对象属性值复制到 result 对象上
result.setLikeOrNot(likeCache.judgeLikeOrNotByMusicIdAndUserId(musicId, userId));
@ -74,7 +79,7 @@ public class MusicServiceImpl implements MusicService {
@Override
public MusicDetail selectMusicDetailByMusicId(Long musicId) {
Music music = musicMapper.selectById(musicId);
Music music = myStringRedisTemplate.queryWithPassThrough(MUSIC_INFO_KEY, musicId, Music.class, this::getById, MUSIC_INFO_TTL, TimeUnit.DAYS);
MusicDetail result = new MusicDetail();
BeanUtils.copyProperties(music, result); // 将 music 对象属性值复制到 result 对象上
UserInfo uploadUser = userClients.selectUserInfoByUserId(music.getUploadUser());
@ -89,8 +94,10 @@ public class MusicServiceImpl implements MusicService {
@Override
public void deleteMusicByIdAndUserId(Long musicId, Long userId) {
if (musicMapper.selectById(musicId).getUploadUser().equals(userId)) {
if (myStringRedisTemplate.queryWithPassThrough(MUSIC_INFO_KEY, musicId, Music.class, this::getById, MUSIC_INFO_TTL, TimeUnit.DAYS)
.getUploadUser().equals(userId)) {
musicMapper.deleteById(musicId);
myStringRedisTemplate.delete(MUSIC_INFO_KEY+musicId);
}
}
@ -111,6 +118,7 @@ public class MusicServiceImpl implements MusicService {
@Override
public void deleteMusicById(Long musicId) {
musicMapper.deleteById(musicId);
myStringRedisTemplate.delete(MUSIC_INFO_KEY+musicId);
}

@ -0,0 +1,24 @@
package com.flyingpig.cloudmusic.task;
import com.flyingpig.cloudmusic.mapper.MusicMapper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import static com.flyingpig.cloudmusic.constant.RedisConstants.MUSIC_RANKLIST_KEY;
@Component
@Slf4j
public class RankingListDistributedTask {
@Autowired
MusicMapper musicMapper;
@Autowired
RedisTemplate redisTemplate;
//每天0点和12点进行排行榜的更新
@XxlJob("rankingListJob")
public void rankingListTask(){
redisTemplate.opsForValue().set(MUSIC_RANKLIST_KEY, musicMapper.selectRankList());
}
}

@ -1,24 +1,24 @@
package com.flyingpig.cloudmusic.task;
import com.flyingpig.cloudmusic.mapper.MusicMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import static com.flyingpig.cloudmusic.constant.RedisConstants.MUSIC_RANKLIST_KEY;
@Component
@Slf4j
public class RankingListTask {
@Autowired
MusicMapper musicMapper;
@Autowired
RedisTemplate redisTemplate;
//每天0点和12点进行排行榜的更新
@Scheduled(cron = "0 */5 * * * *")
public void rankingListTask(){
redisTemplate.opsForValue().set(MUSIC_RANKLIST_KEY, musicMapper.selectRankList());
}
}
//package com.flyingpig.cloudmusic.task;
//
//import com.flyingpig.cloudmusic.mapper.MusicMapper;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.data.redis.core.RedisTemplate;
//import org.springframework.scheduling.annotation.Scheduled;
//import org.springframework.stereotype.Component;
//
//import static com.flyingpig.cloudmusic.constant.RedisConstants.MUSIC_RANKLIST_KEY;
//
//@Component
//@Slf4j
//public class RankingListTask {
// @Autowired
// MusicMapper musicMapper;
// @Autowired
// RedisTemplate redisTemplate;
// //每天0点和12点进行排行榜的更新
// @Scheduled(cron = "0 */5 * * * *")
// public void rankingListTask(){
// redisTemplate.opsForValue().set(MUSIC_RANKLIST_KEY, musicMapper.selectRankList());
// }
//}

@ -14,7 +14,7 @@ spring:
name: music-service
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://111.229.173.12:3306/cloudmusic
url: jdbc:mysql://localhost:3306/cloudmusic
username: root
password: "@Aa123456"
redis:
@ -56,17 +56,12 @@ feign:
max-connections-per-route: 50 # 每个路径的最大连接数
sentinel:
enabled: true
seata:
registry: # TC服务注册中心的配置微服务根据这些信息去注册中心获取tc服务地址
# 参考tc服务自己的registry.conf中的配置
type: nacos
nacos: # tc
server-addr: localhost:8848
namespace: ""
group: DEFAULT_GROUP
application: seata-tc-server # tc服务在nacos中的服务名称
cluster: SH
tx-service-group: seata-demo # 事务组根据这个获取tc服务的cluster名称
service:
vgroup-mapping: # 事务组与TC服务cluster的映射关系
seata-demo: SH
#xxl-job
xxl:
job:
admin:
addresses: http://localhost:8888/xxl-job-admin
executor:
appname: music-job-executor
port: 9999

@ -1,6 +1,6 @@
#端口配置
server:
port: 8081
port: 8082
servlet:
encoding:
charset: UTF-8
@ -15,11 +15,11 @@ spring:
password: "@Aa123456"
cloud:
nacos:
server-addr: http://47.122.56.65:8848
server-addr: http://localhost:8848
discovery:
cluster-name: FJ # 集群名称
ip: 124.71.110.199 # 注册到nacos的ip与端口
port: 8081
ip: localhost # 注册到nacos的ip与端口
port: 8082
#ribbon配置
songlistservice:
ribbon:

Loading…
Cancel
Save