feat(music): 添加音乐点赞功能及前端交互
- 后端新增点赞接口 /music/{id}/like,支持用户登录后点赞/取消点赞音乐,记录点赞数据到 user_like_music 表
- 后端修改 MusicController.getMusicById 接口,支持传入用户ID以判断当前音乐是否被该用户点赞
- 后端 MusicDTO 新增 isLiked 字段,用于前端展示点赞状态
- 数据库新增 user_like_music 表,记录用户与音乐的点赞关系,包含唯一约束防止重复点赞
- 前端 MusicDetail.vue 页面新增点赞按钮及状态展示,支持点击切换点赞状态并实时更新 UI 与点赞数
- 前端新增 toggleLikeMusic API 调用及相应交互逻辑,成功后展示操作提示信息
- 评论表 comment 新增 target_type 字段注释及状态字段注释,播放历史与各关联表新增索引优化与外键约束微调
This commit is contained in:
@@ -31,7 +31,12 @@ public class MusicController {
|
|||||||
*/
|
*/
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
public Result<MusicDTO> getMusicById(@PathVariable Long id) {
|
public Result<MusicDTO> getMusicById(@PathVariable Long id) {
|
||||||
MusicDTO musicDTO = musicService.getMusicById(id);
|
Long userId = null;
|
||||||
|
// 检查用户是否登录,但不强制要求登录
|
||||||
|
if (StpUtil.isLogin()) {
|
||||||
|
userId = StpUtil.getLoginIdAsLong();
|
||||||
|
}
|
||||||
|
MusicDTO musicDTO = musicService.getMusicById(id, userId);
|
||||||
if (musicDTO == null) {
|
if (musicDTO == null) {
|
||||||
// 如果音乐不存在,返回空数据而不是错误
|
// 如果音乐不存在,返回空数据而不是错误
|
||||||
return Result.success(null);
|
return Result.success(null);
|
||||||
@@ -213,4 +218,20 @@ public class MusicController {
|
|||||||
MusicDTO musicDTO = musicService.playMusic(id);
|
MusicDTO musicDTO = musicService.playMusic(id);
|
||||||
return Result.success(musicDTO);
|
return Result.success(musicDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点赞/取消点赞音乐
|
||||||
|
*
|
||||||
|
* @param id 音乐ID
|
||||||
|
* @return 响应结果
|
||||||
|
*/
|
||||||
|
@SaCheckLogin
|
||||||
|
@PostMapping("/{id}/like")
|
||||||
|
public Result<Boolean> toggleLikeMusic(@PathVariable Long id) {
|
||||||
|
// 获取当前登录用户ID
|
||||||
|
Long userId = StpUtil.getLoginIdAsLong();
|
||||||
|
boolean isLiked = musicService.toggleLikeMusic(id, userId);
|
||||||
|
String message = isLiked ? "点赞成功" : "取消点赞成功";
|
||||||
|
return Result.success(message, isLiked);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,11 @@ public class MusicDTO {
|
|||||||
*/
|
*/
|
||||||
private Boolean isCollected;
|
private Boolean isCollected;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否已点赞
|
||||||
|
*/
|
||||||
|
private Boolean isLiked;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建时间
|
* 创建时间
|
||||||
*/
|
*/
|
||||||
@@ -107,4 +112,11 @@ public class MusicDTO {
|
|||||||
public void setCollected(boolean collected) {
|
public void setCollected(boolean collected) {
|
||||||
this.isCollected = collected;
|
this.isCollected = collected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置是否已点赞
|
||||||
|
*/
|
||||||
|
public void setLiked(boolean liked) {
|
||||||
|
this.isLiked = liked;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.test.musichouduan.entity;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Entity
|
||||||
|
@Table(name = "user_like_music", uniqueConstraints = {
|
||||||
|
@UniqueConstraint(columnNames = {"userId", "musicId"})
|
||||||
|
})
|
||||||
|
public class UserLikeMusic {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private Long musicId;
|
||||||
|
|
||||||
|
@CreationTimestamp
|
||||||
|
@Column(nullable = false, updatable = false)
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
}
|
||||||
@@ -1,109 +1,109 @@
|
|||||||
package com.test.musichouduan.init;
|
//package com.test.musichouduan.init;
|
||||||
|
//
|
||||||
import cn.dev33.satoken.secure.BCrypt;
|
//import cn.dev33.satoken.secure.BCrypt;
|
||||||
import com.test.musichouduan.entity.*;
|
//import com.test.musichouduan.entity.*;
|
||||||
import com.test.musichouduan.repository.*;
|
//import com.test.musichouduan.repository.*;
|
||||||
|
//
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
//import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.CommandLineRunner;
|
//import org.springframework.boot.CommandLineRunner;
|
||||||
import org.springframework.stereotype.Component;
|
//import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
//import org.springframework.transaction.annotation.Transactional;
|
||||||
|
//
|
||||||
import java.util.Arrays;
|
//import java.util.Arrays;
|
||||||
import java.util.List;
|
//import java.util.List;
|
||||||
|
//
|
||||||
/**
|
///**
|
||||||
* 数据初始化器
|
// * 数据初始化器
|
||||||
*/
|
// */
|
||||||
@Component
|
//@Component
|
||||||
public class DataInitializer implements CommandLineRunner {
|
//public class DataInitializer implements CommandLineRunner {
|
||||||
|
//
|
||||||
@Autowired
|
// @Autowired
|
||||||
private UserRepository userRepository;
|
// private UserRepository userRepository;
|
||||||
|
//
|
||||||
@Autowired
|
// @Autowired
|
||||||
private MusicTypeRepository musicTypeRepository;
|
// private MusicTypeRepository musicTypeRepository;
|
||||||
|
//
|
||||||
@Autowired
|
// @Autowired
|
||||||
private SingerTypeRepository singerTypeRepository;
|
// private SingerTypeRepository singerTypeRepository;
|
||||||
|
//
|
||||||
@Autowired
|
// @Autowired
|
||||||
private PlaylistTypeRepository playlistTypeRepository;
|
// private PlaylistTypeRepository playlistTypeRepository;
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
@Transactional
|
// @Transactional
|
||||||
public void run(String... args) throws Exception {
|
// public void run(String... args) throws Exception {
|
||||||
// 初始化管理员用户
|
// // 初始化管理员用户
|
||||||
initAdminUser();
|
// initAdminUser();
|
||||||
|
//
|
||||||
// 初始化音乐类型
|
// // 初始化音乐类型
|
||||||
initMusicTypes();
|
// initMusicTypes();
|
||||||
|
//
|
||||||
// 初始化歌手类型
|
// // 初始化歌手类型
|
||||||
initSingerTypes();
|
// initSingerTypes();
|
||||||
|
//
|
||||||
// 初始化歌单类型
|
// // 初始化歌单类型
|
||||||
initPlaylistTypes();
|
// initPlaylistTypes();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 初始化管理员用户
|
// * 初始化管理员用户
|
||||||
*/
|
// */
|
||||||
private void initAdminUser() {
|
// private void initAdminUser() {
|
||||||
if (!userRepository.existsByUsername("admin")) {
|
// if (!userRepository.existsByUsername("admin")) {
|
||||||
User admin = new User();
|
// User admin = new User();
|
||||||
admin.setUsername("admin");
|
// admin.setUsername("admin");
|
||||||
admin.setPassword(BCrypt.hashpw("123456"));
|
// admin.setPassword(BCrypt.hashpw("123456"));
|
||||||
admin.setNickname("管理员");
|
// admin.setNickname("管理员");
|
||||||
admin.setGender(0);
|
// admin.setGender(0);
|
||||||
admin.setRole(1);
|
// admin.setRole(1);
|
||||||
admin.setStatus(1);
|
// admin.setStatus(1);
|
||||||
userRepository.save(admin);
|
// userRepository.save(admin);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 初始化音乐类型
|
// * 初始化音乐类型
|
||||||
*/
|
// */
|
||||||
private void initMusicTypes() {
|
// private void initMusicTypes() {
|
||||||
if (musicTypeRepository.count() == 0) {
|
// if (musicTypeRepository.count() == 0) {
|
||||||
List<String> typeNames = Arrays.asList("流行", "摇滚", "民谣", "电子", "古典", "嘻哈", "爵士", "乡村");
|
// List<String> typeNames = Arrays.asList("流行", "摇滚", "民谣", "电子", "古典", "嘻哈", "爵士", "乡村");
|
||||||
for (String name : typeNames) {
|
// for (String name : typeNames) {
|
||||||
MusicType type = new MusicType();
|
// MusicType type = new MusicType();
|
||||||
type.setName(name);
|
// type.setName(name);
|
||||||
type.setDescription(name + "音乐");
|
// type.setDescription(name + "音乐");
|
||||||
musicTypeRepository.save(type);
|
// musicTypeRepository.save(type);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 初始化歌手类型
|
// * 初始化歌手类型
|
||||||
*/
|
// */
|
||||||
private void initSingerTypes() {
|
// private void initSingerTypes() {
|
||||||
if (singerTypeRepository.count() == 0) {
|
// if (singerTypeRepository.count() == 0) {
|
||||||
List<String> typeNames = Arrays.asList("华语男歌手", "华语女歌手", "华语组合", "欧美男歌手", "欧美女歌手", "欧美组合", "日韩男歌手", "日韩女歌手", "日韩组合");
|
// List<String> typeNames = Arrays.asList("华语男歌手", "华语女歌手", "华语组合", "欧美男歌手", "欧美女歌手", "欧美组合", "日韩男歌手", "日韩女歌手", "日韩组合");
|
||||||
for (String name : typeNames) {
|
// for (String name : typeNames) {
|
||||||
SingerType type = new SingerType();
|
// SingerType type = new SingerType();
|
||||||
type.setName(name);
|
// type.setName(name);
|
||||||
type.setDescription(name);
|
// type.setDescription(name);
|
||||||
singerTypeRepository.save(type);
|
// singerTypeRepository.save(type);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
// /**
|
||||||
* 初始化歌单类型
|
// * 初始化歌单类型
|
||||||
*/
|
// */
|
||||||
private void initPlaylistTypes() {
|
// private void initPlaylistTypes() {
|
||||||
if (playlistTypeRepository.count() == 0) {
|
// if (playlistTypeRepository.count() == 0) {
|
||||||
List<String> typeNames = Arrays.asList("流行", "摇滚", "民谣", "电子", "古典", "嘻哈", "爵士", "乡村", "轻音乐", "ACG");
|
// List<String> typeNames = Arrays.asList("流行", "摇滚", "民谣", "电子", "古典", "嘻哈", "爵士", "乡村", "轻音乐", "ACG");
|
||||||
for (String name : typeNames) {
|
// for (String name : typeNames) {
|
||||||
PlaylistType type = new PlaylistType();
|
// PlaylistType type = new PlaylistType();
|
||||||
type.setName(name);
|
// type.setName(name);
|
||||||
type.setDescription(name + "歌单");
|
// type.setDescription(name + "歌单");
|
||||||
playlistTypeRepository.save(type);
|
// playlistTypeRepository.save(type);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|||||||
@@ -43,6 +43,15 @@ public interface UserCollectMusicRepository extends JpaRepository<UserCollectMus
|
|||||||
*/
|
*/
|
||||||
boolean existsByUserAndMusic(User user, Music music);
|
boolean existsByUserAndMusic(User user, Music music);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断用户是否收藏了音乐
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param musicId 音乐ID
|
||||||
|
* @return 是否收藏
|
||||||
|
*/
|
||||||
|
boolean existsByUserIdAndMusicId(Long userId, Long musicId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据用户统计收藏的音乐数量
|
* 根据用户统计收藏的音乐数量
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package com.test.musichouduan.repository;
|
||||||
|
|
||||||
|
import com.test.musichouduan.entity.UserLikeMusic;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface UserLikeMusicRepository extends JpaRepository<UserLikeMusic, Long> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户ID和音乐ID查找点赞记录
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param musicId 音乐ID
|
||||||
|
* @return 点赞记录
|
||||||
|
*/
|
||||||
|
Optional<UserLikeMusic> findByUserIdAndMusicId(Long userId, Long musicId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户是否点赞了某音乐
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @param musicId 音乐ID
|
||||||
|
* @return 是否存在
|
||||||
|
*/
|
||||||
|
boolean existsByUserIdAndMusicId(Long userId, Long musicId);
|
||||||
|
}
|
||||||
@@ -13,6 +13,15 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
*/
|
*/
|
||||||
public interface MusicService {
|
public interface MusicService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID获取音乐,并根据用户ID判断是否收藏和点赞
|
||||||
|
*
|
||||||
|
* @param id 音乐ID
|
||||||
|
* @param userId 用户ID (可以为null)
|
||||||
|
* @return 音乐DTO
|
||||||
|
*/
|
||||||
|
MusicDTO getMusicById(Long id, Long userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据ID获取音乐
|
* 根据ID获取音乐
|
||||||
*
|
*
|
||||||
@@ -133,4 +142,13 @@ public interface MusicService {
|
|||||||
* @return CompletableFuture 包装的音乐DTO列表
|
* @return CompletableFuture 包装的音乐DTO列表
|
||||||
*/
|
*/
|
||||||
CompletableFuture<List<MusicDTO>> updateHotMusicCache();
|
CompletableFuture<List<MusicDTO>> updateHotMusicCache();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换音乐点赞状态
|
||||||
|
*
|
||||||
|
* @param musicId 音乐ID
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 是否点赞成功 (true: 点赞, false: 取消点赞)
|
||||||
|
*/
|
||||||
|
boolean toggleLikeMusic(Long musicId, Long userId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import com.test.musichouduan.entity.Music;
|
|||||||
import com.test.musichouduan.entity.MusicType;
|
import com.test.musichouduan.entity.MusicType;
|
||||||
import com.test.musichouduan.entity.Singer;
|
import com.test.musichouduan.entity.Singer;
|
||||||
import com.test.musichouduan.entity.User;
|
import com.test.musichouduan.entity.User;
|
||||||
|
import com.test.musichouduan.entity.UserCollectMusic;
|
||||||
|
import com.test.musichouduan.entity.UserLikeMusic;
|
||||||
import com.test.musichouduan.entity.UserMusic;
|
import com.test.musichouduan.entity.UserMusic;
|
||||||
import com.test.musichouduan.exception.BusinessException;
|
import com.test.musichouduan.exception.BusinessException;
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
@@ -72,7 +74,10 @@ public class MusicServiceImpl implements MusicService {
|
|||||||
private UserRepository userRepository;
|
private UserRepository userRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserMusicRepository userMusicRepository;
|
private UserCollectMusicRepository userCollectMusicRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserLikeMusicRepository userLikeMusicRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PlayHistoryRepository playHistoryRepository;
|
private PlayHistoryRepository playHistoryRepository;
|
||||||
@@ -81,13 +86,19 @@ public class MusicServiceImpl implements MusicService {
|
|||||||
private FileService fileService;
|
private FileService fileService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MusicDTO getMusicById(Long id) {
|
public MusicDTO getMusicById(Long id, Long userId) {
|
||||||
// 查找音乐,如果不存在则返回null
|
// 查找音乐,如果不存在则返回null
|
||||||
return musicRepository.findById(id)
|
return musicRepository.findById(id)
|
||||||
.map(this::convertToDTO)
|
.map(music -> convertToDTO(music, userId))
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MusicDTO getMusicById(Long id) {
|
||||||
|
// 对于未登录用户或不需要用户状态的场景,直接调用新方法并传入null
|
||||||
|
return getMusicById(id, null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<MusicDTO> getMusicList(Integer page, Integer size, String keyword, Long typeId) {
|
public PageResult<MusicDTO> getMusicList(Integer page, Integer size, String keyword, Long typeId) {
|
||||||
// 构建查询条件
|
// 构建查询条件
|
||||||
@@ -463,35 +474,37 @@ public class MusicServiceImpl implements MusicService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public boolean toggleCollectMusic(Long id, Long userId) {
|
public boolean toggleCollectMusic(Long musicId, Long userId) {
|
||||||
// 获取用户
|
// 直接通过ID判断是否存在,避免查询完整实体
|
||||||
Optional<User> userOpt = userRepository.findById(userId);
|
boolean isCollected = userCollectMusicRepository.existsByUserIdAndMusicId(userId, musicId);
|
||||||
if (!userOpt.isPresent()) {
|
|
||||||
// 如果用户不存在,返回false
|
Music music = musicRepository.findById(musicId)
|
||||||
return false;
|
.orElseThrow(() -> new BusinessException("音乐不存在"));
|
||||||
}
|
|
||||||
User user = userOpt.get();
|
|
||||||
|
|
||||||
// 获取音乐
|
|
||||||
Optional<Music> musicOpt = musicRepository.findById(id);
|
|
||||||
if (!musicOpt.isPresent()) {
|
|
||||||
// 如果音乐不存在,返回false
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Music music = musicOpt.get();
|
|
||||||
|
|
||||||
// 检查是否已收藏
|
|
||||||
boolean isCollected = userMusicRepository.existsByUserAndMusic(user, music);
|
|
||||||
|
|
||||||
if (isCollected) {
|
if (isCollected) {
|
||||||
// 如果已收藏,则取消收藏
|
// 已收藏,取消收藏
|
||||||
userMusicRepository.uncollectMusic(user.getId(), music.getId());
|
User user = userRepository.findById(userId).orElseThrow(() -> new BusinessException("用户不存在"));
|
||||||
|
UserCollectMusic collect = userCollectMusicRepository.findByUserAndMusic(user, music)
|
||||||
|
.orElseThrow(() -> new BusinessException("收藏记录不存在"));
|
||||||
|
userCollectMusicRepository.delete(collect);
|
||||||
|
|
||||||
|
int currentCollectCount = music.getCollectCount() != null ? music.getCollectCount() : 0;
|
||||||
|
music.setCollectCount(Math.max(0, currentCollectCount - 1));
|
||||||
|
musicRepository.save(music);
|
||||||
|
return false; // 返回 "未收藏" 状态
|
||||||
} else {
|
} else {
|
||||||
// 如果未收藏,则收藏
|
// 未收藏,执行收藏
|
||||||
userMusicRepository.collectMusic(user.getId(), music.getId());
|
User user = userRepository.findById(userId).orElseThrow(() -> new BusinessException("用户不存在"));
|
||||||
}
|
UserCollectMusic newCollect = new UserCollectMusic();
|
||||||
|
newCollect.setUser(user);
|
||||||
|
newCollect.setMusic(music);
|
||||||
|
userCollectMusicRepository.save(newCollect);
|
||||||
|
|
||||||
return !isCollected; // 返回当前收藏状态,true表示已收藏,false表示未收藏
|
int currentCollectCount = music.getCollectCount() != null ? music.getCollectCount() : 0;
|
||||||
|
music.setCollectCount(currentCollectCount + 1);
|
||||||
|
musicRepository.save(music);
|
||||||
|
return true; // 返回 "已收藏" 状态
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -501,24 +514,24 @@ public class MusicServiceImpl implements MusicService {
|
|||||||
.orElseThrow(() -> new BusinessException("用户不存在"));
|
.orElseThrow(() -> new BusinessException("用户不存在"));
|
||||||
|
|
||||||
// 获取用户收藏的音乐
|
// 获取用户收藏的音乐
|
||||||
Page<UserMusic> userMusicPage = userMusicRepository.findCollectedMusic(
|
Page<UserCollectMusic> userCollectMusicPage = userCollectMusicRepository.findByUser(
|
||||||
user.getId(),
|
user,
|
||||||
PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "collectTime"))
|
PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createTime"))
|
||||||
);
|
);
|
||||||
|
|
||||||
// 转换为DTO
|
// 转换为DTO
|
||||||
List<MusicDTO> musicDTOs = userMusicPage.getContent().stream()
|
List<MusicDTO> musicDTOs = userCollectMusicPage.getContent().stream()
|
||||||
.map(userMusic -> {
|
.map(userCollectMusic -> {
|
||||||
MusicDTO musicDTO = convertToDTO(userMusic.getMusic());
|
MusicDTO musicDTO = convertToDTO(userCollectMusic.getMusic());
|
||||||
// 设置收藏时间
|
// 设置收藏时间
|
||||||
musicDTO.setCollectTime(userMusic.getCollectTime());
|
musicDTO.setCollectTime(userCollectMusic.getCreateTime());
|
||||||
return musicDTO;
|
return musicDTO;
|
||||||
})
|
})
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
return new PageResult<>(
|
return new PageResult<>(
|
||||||
musicDTOs,
|
musicDTOs,
|
||||||
userMusicPage.getTotalElements(),
|
userCollectMusicPage.getTotalElements(),
|
||||||
page,
|
page,
|
||||||
size
|
size
|
||||||
);
|
);
|
||||||
@@ -539,8 +552,6 @@ public class MusicServiceImpl implements MusicService {
|
|||||||
// 增加播放次数
|
// 增加播放次数
|
||||||
long currentPlayCount = music.getPlayCount() != null ? music.getPlayCount() : 0;
|
long currentPlayCount = music.getPlayCount() != null ? music.getPlayCount() : 0;
|
||||||
music.setPlayCount(currentPlayCount + 1);
|
music.setPlayCount(currentPlayCount + 1);
|
||||||
// 根据要求,将点赞数与播放次数同步
|
|
||||||
music.setLikeCount((int) (currentPlayCount + 1));
|
|
||||||
musicRepository.save(music);
|
musicRepository.save(music);
|
||||||
|
|
||||||
// 如果用户已登录,记录播放历史
|
// 如果用户已登录,记录播放历史
|
||||||
@@ -560,6 +571,34 @@ public class MusicServiceImpl implements MusicService {
|
|||||||
return musicRepository.findById(id).orElse(null);
|
return musicRepository.findById(id).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public boolean toggleLikeMusic(Long musicId, Long userId) {
|
||||||
|
Music music = musicRepository.findById(musicId)
|
||||||
|
.orElseThrow(() -> new BusinessException("音乐不存在"));
|
||||||
|
|
||||||
|
Optional<UserLikeMusic> likeOpt = userLikeMusicRepository.findByUserIdAndMusicId(userId, musicId);
|
||||||
|
|
||||||
|
if (likeOpt.isPresent()) {
|
||||||
|
// 已点赞,取消点赞
|
||||||
|
userLikeMusicRepository.delete(likeOpt.get());
|
||||||
|
int currentLikeCount = music.getLikeCount() != null ? music.getLikeCount() : 0;
|
||||||
|
music.setLikeCount(Math.max(0, currentLikeCount - 1));
|
||||||
|
musicRepository.save(music);
|
||||||
|
return false; // 返回 "未点赞" 状态
|
||||||
|
} else {
|
||||||
|
// 未点赞,执行点赞
|
||||||
|
UserLikeMusic newLike = new UserLikeMusic();
|
||||||
|
newLike.setUserId(userId);
|
||||||
|
newLike.setMusicId(musicId);
|
||||||
|
userLikeMusicRepository.save(newLike);
|
||||||
|
int currentLikeCount = music.getLikeCount() != null ? music.getLikeCount() : 0;
|
||||||
|
music.setLikeCount(currentLikeCount + 1);
|
||||||
|
musicRepository.save(music);
|
||||||
|
return true; // 返回 "已点赞" 状态
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将实体转换为DTO
|
* 将实体转换为DTO
|
||||||
*
|
*
|
||||||
@@ -567,52 +606,49 @@ public class MusicServiceImpl implements MusicService {
|
|||||||
* @return 音乐DTO
|
* @return 音乐DTO
|
||||||
*/
|
*/
|
||||||
private MusicDTO convertToDTO(Music music) {
|
private MusicDTO convertToDTO(Music music) {
|
||||||
|
// 保留此方法以兼容不需要用户状态的转换
|
||||||
|
return convertToDTO(music, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将实体转换为DTO,并根据用户ID判断是否收藏和点赞
|
||||||
|
*
|
||||||
|
* @param music 音乐实体
|
||||||
|
* @param userId 用户ID (可以为null)
|
||||||
|
* @return 音乐DTO
|
||||||
|
*/
|
||||||
|
private MusicDTO convertToDTO(Music music, Long userId) {
|
||||||
MusicDTO musicDTO = new MusicDTO();
|
MusicDTO musicDTO = new MusicDTO();
|
||||||
BeanUtils.copyProperties(music, musicDTO);
|
BeanUtils.copyProperties(music, musicDTO);
|
||||||
|
|
||||||
// 确保专辑字段正确复制
|
// 确保专辑字段正确复制
|
||||||
musicDTO.setAlbum(music.getAlbum());
|
musicDTO.setAlbum(music.getAlbum());
|
||||||
|
|
||||||
// 设置类型ID列表
|
// 设置类型ID和名称列表
|
||||||
if (music.getTypes() != null) {
|
if (!CollectionUtils.isEmpty(music.getTypes())) {
|
||||||
List<Long> typeIds = music.getTypes().stream()
|
musicDTO.setTypeIds(music.getTypes().stream().map(MusicType::getId).collect(Collectors.toList()));
|
||||||
.map(MusicType::getId)
|
musicDTO.setTypeNames(music.getTypes().stream().map(MusicType::getName).collect(Collectors.toList()));
|
||||||
.collect(Collectors.toList());
|
|
||||||
musicDTO.setTypeIds(typeIds);
|
|
||||||
|
|
||||||
// 设置类型名称列表
|
|
||||||
List<String> typeNames = music.getTypes().stream()
|
|
||||||
.map(MusicType::getName)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
musicDTO.setTypeNames(typeNames);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置歌手ID列表
|
// 设置歌手ID和名称列表
|
||||||
if (music.getSingers() != null) {
|
if (!CollectionUtils.isEmpty(music.getSingers())) {
|
||||||
List<Long> singerIds = music.getSingers().stream()
|
musicDTO.setSingerIds(music.getSingers().stream().map(Singer::getId).collect(Collectors.toList()));
|
||||||
.map(Singer::getId)
|
List<String> singerNames = music.getSingers().stream().map(Singer::getName).collect(Collectors.toList());
|
||||||
.collect(Collectors.toList());
|
|
||||||
musicDTO.setSingerIds(singerIds);
|
|
||||||
|
|
||||||
// 设置歌手名称列表
|
|
||||||
List<String> singerNames = music.getSingers().stream()
|
|
||||||
.map(Singer::getName)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
musicDTO.setSingerNames(singerNames);
|
musicDTO.setSingerNames(singerNames);
|
||||||
|
musicDTO.setSinger(String.join("、", singerNames));
|
||||||
// 设置歌手名称字符串(用于前端显示)
|
|
||||||
if (!singerNames.isEmpty()) {
|
|
||||||
musicDTO.setSinger(String.join(", ", singerNames));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查当前登录用户是否已收藏该音乐
|
// 如果传入了用户ID,则查询该用户的收藏和点赞状态
|
||||||
if (StpUtil.isLogin()) {
|
if (userId != null) {
|
||||||
Long userId = StpUtil.getLoginIdAsLong();
|
boolean isCollected = userCollectMusicRepository.existsByUserIdAndMusicId(userId, music.getId());
|
||||||
boolean isCollected = userMusicRepository.existsByUserIdAndMusicId(userId, music.getId());
|
|
||||||
musicDTO.setCollected(isCollected);
|
musicDTO.setCollected(isCollected);
|
||||||
|
|
||||||
|
boolean isLiked = userLikeMusicRepository.existsByUserIdAndMusicId(userId, music.getId());
|
||||||
|
musicDTO.setLiked(isLiked);
|
||||||
} else {
|
} else {
|
||||||
|
// 如果未传入用户ID,则默认为未收藏和未点赞
|
||||||
musicDTO.setCollected(false);
|
musicDTO.setCollected(false);
|
||||||
|
musicDTO.setLiked(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return musicDTO;
|
return musicDTO;
|
||||||
|
|||||||
@@ -116,6 +116,15 @@ export function toggleCollectMusic(id) {
|
|||||||
return api.post(`/music/${id}/collect`)
|
return api.post(`/music/${id}/collect`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点赞/取消点赞音乐
|
||||||
|
* @param {number} id 音乐ID
|
||||||
|
* @returns {Promise<any>}
|
||||||
|
*/
|
||||||
|
export function toggleLikeMusic(id) {
|
||||||
|
return api.post(`/music/${id}/like`)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取收藏的音乐列表
|
* 获取收藏的音乐列表
|
||||||
* @param {number} page 页码
|
* @param {number} page 页码
|
||||||
|
|||||||
@@ -73,6 +73,14 @@
|
|||||||
{{ music.collected ? '已收藏' : '收藏' }}
|
{{ music.collected ? '已收藏' : '收藏' }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
:type="music.liked ? 'success' : 'default'"
|
||||||
|
@click="toggleLike"
|
||||||
|
>
|
||||||
|
<el-icon><component :is="music.liked ? 'Check' : 'Pointer'" /></el-icon>
|
||||||
|
{{ music.liked ? '已点赞' : '点赞' }} ({{ music.likeCount || 0 }})
|
||||||
|
</el-button>
|
||||||
|
|
||||||
<el-button
|
<el-button
|
||||||
@click="addToPlaylist"
|
@click="addToPlaylist"
|
||||||
icon="Plus"
|
icon="Plus"
|
||||||
@@ -194,7 +202,7 @@ import { ref, computed, onMounted, watch, onUnmounted } from 'vue'
|
|||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { usePlayerStore } from '../stores/player'
|
import { usePlayerStore } from '../stores/player'
|
||||||
import { useUserStore } from '../stores/user'
|
import { useUserStore } from '../stores/user'
|
||||||
import { getMusicById, toggleCollectMusic, getHotMusic } from '../api/music'
|
import { getMusicById, toggleCollectMusic, getHotMusic, toggleLikeMusic } from '../api/music'
|
||||||
import { getCommentList, addComment, deleteComment as apiDeleteComment } from '../api/comment'
|
import { getCommentList, addComment, deleteComment as apiDeleteComment } from '../api/comment'
|
||||||
import { connect, subscribe, unsubscribe, disconnect } from '../utils/websocket'
|
import { connect, subscribe, unsubscribe, disconnect } from '../utils/websocket'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
@@ -399,8 +407,9 @@ const toggleCollect = async () => {
|
|||||||
try {
|
try {
|
||||||
const res = await toggleCollectMusic(music.value.id)
|
const res = await toggleCollectMusic(music.value.id)
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
music.value.collected = !music.value.collected
|
// 后端直接返回了最新的收藏状态 (true/false),直接赋值即可
|
||||||
ElMessage.success(music.value.collected ? '收藏成功' : '已取消收藏')
|
music.value.collected = res.data
|
||||||
|
ElMessage.success(res.message || (music.value.collected ? '收藏成功' : '已取消收藏'))
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(res.message || '操作失败')
|
ElMessage.error(res.message || '操作失败')
|
||||||
}
|
}
|
||||||
@@ -410,6 +419,29 @@ const toggleCollect = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 切换点赞状态
|
||||||
|
const toggleLike = async () => {
|
||||||
|
try {
|
||||||
|
const res = await toggleLikeMusic(music.value.id);
|
||||||
|
if (res.code === 200) {
|
||||||
|
// 后端直接返回了最新的点赞状态 (true/false),直接赋值
|
||||||
|
music.value.liked = res.data;
|
||||||
|
// 更新点赞数
|
||||||
|
if (music.value.liked) {
|
||||||
|
music.value.likeCount = (music.value.likeCount || 0) + 1;
|
||||||
|
} else {
|
||||||
|
music.value.likeCount = Math.max(0, (music.value.likeCount || 0) - 1);
|
||||||
|
}
|
||||||
|
ElMessage.success(res.message || (music.value.liked ? '点赞成功' : '已取消点赞'));
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.message || '操作失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('点赞操作失败:', error);
|
||||||
|
ElMessage.error('操作失败,请稍后重试');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 添加到播放列表
|
// 添加到播放列表
|
||||||
const addToPlaylist = () => {
|
const addToPlaylist = () => {
|
||||||
playerStore.addToPlaylist(music.value)
|
playerStore.addToPlaylist(music.value)
|
||||||
|
|||||||
118
sql/music_db.sql
118
sql/music_db.sql
@@ -11,7 +11,7 @@
|
|||||||
Target Server Version : 80041 (8.0.41)
|
Target Server Version : 80041 (8.0.41)
|
||||||
File Encoding : 65001
|
File Encoding : 65001
|
||||||
|
|
||||||
Date: 23/07/2025 22:59:43
|
Date: 25/07/2025 22:22:53
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SET NAMES utf8mb4;
|
SET NAMES utf8mb4;
|
||||||
@@ -44,42 +44,37 @@ CREATE TABLE `comment` (
|
|||||||
`content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '评论内容',
|
`content` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '评论内容',
|
||||||
`user_id` bigint NOT NULL COMMENT '评论用户ID',
|
`user_id` bigint NOT NULL COMMENT '评论用户ID',
|
||||||
`target_id` bigint NOT NULL COMMENT '评论目标ID',
|
`target_id` bigint NOT NULL COMMENT '评论目标ID',
|
||||||
`target_type` int NOT NULL,
|
`target_type` int NOT NULL COMMENT '评论目标类型:1-音乐,2-歌单,3-歌手',
|
||||||
`parent_id` bigint NULL DEFAULT NULL COMMENT '父评论ID',
|
`parent_id` bigint NULL DEFAULT NULL COMMENT '父评论ID',
|
||||||
`status` int NULL DEFAULT NULL,
|
`status` int NULL DEFAULT NULL COMMENT '状态:0-禁用,1-正常',
|
||||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
INDEX `idx_user_id`(`user_id` ASC) USING BTREE,
|
INDEX `idx_user_id`(`user_id` ASC) USING BTREE,
|
||||||
INDEX `idx_target`(`target_id` ASC, `target_type` ASC) USING BTREE,
|
INDEX `idx_target`(`target_id` ASC, `target_type` ASC) USING BTREE,
|
||||||
INDEX `idx_parent_id`(`parent_id` ASC) USING BTREE,
|
INDEX `idx_parent_id`(`parent_id` ASC) USING BTREE
|
||||||
CONSTRAINT `FK8kcum44fvpupyw6f5baccx25c` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
) ENGINE = InnoDB AUTO_INCREMENT = 56 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '评论表' ROW_FORMAT = Dynamic;
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 28 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '评论表' ROW_FORMAT = Dynamic;
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for music
|
-- Table structure for music
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
DROP TABLE IF EXISTS `music`;
|
DROP TABLE IF EXISTS `music`;
|
||||||
CREATE TABLE `music` (
|
CREATE TABLE `music` (
|
||||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '音乐ID',
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '音乐ID',
|
||||||
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '音乐名称',
|
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '音乐名称',
|
||||||
`cover` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '封面URL',
|
`cover` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '封面URL',
|
||||||
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '音乐文件URL',
|
`url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '音乐文件URL',
|
||||||
`lyric` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '歌词',
|
`lyric` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '歌词',
|
||||||
`duration` int NULL DEFAULT 0 COMMENT '时长(秒)',
|
`duration` int NULL DEFAULT 0 COMMENT '时长(秒)',
|
||||||
`album` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
|
`play_count` bigint NULL DEFAULT 0 COMMENT '播放次数',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
-- Interaction and Hot Score Fields
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
`play_count` bigint NULL DEFAULT 0 COMMENT '播放次数',
|
`album` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
|
||||||
`like_count` int NULL DEFAULT 0 COMMENT '点赞数',
|
`like_count` int NULL DEFAULT NULL COMMENT '点赞数',
|
||||||
`collect_count` int NULL DEFAULT 0 COMMENT '收藏数',
|
`collect_count` int NULL DEFAULT NULL COMMENT '收藏数',
|
||||||
`comment_count` int NULL DEFAULT 0 COMMENT '评论数',
|
`comment_count` int NULL DEFAULT NULL COMMENT '评论数',
|
||||||
`hot_score` double NULL DEFAULT 0.0 COMMENT '热度分数',
|
`hot_score` double NULL DEFAULT NULL COMMENT '热度分数',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE
|
||||||
-- Timestamps
|
|
||||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
|
||||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
|
||||||
PRIMARY KEY (`id`) USING BTREE
|
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '音乐表' ROW_FORMAT = Dynamic;
|
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '音乐表' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
@@ -121,9 +116,7 @@ CREATE TABLE `music_type_relation` (
|
|||||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
UNIQUE INDEX `uk_music_type`(`music_id` ASC, `type_id` ASC) USING BTREE,
|
UNIQUE INDEX `uk_music_type`(`music_id` ASC, `type_id` ASC) USING BTREE,
|
||||||
INDEX `idx_type_id`(`type_id` ASC) USING BTREE,
|
INDEX `idx_type_id`(`type_id` ASC) USING BTREE
|
||||||
CONSTRAINT `FK2i7xdrmrh0l6thp9u2r16fdcm` FOREIGN KEY (`music_id`) REFERENCES `music` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
|
||||||
CONSTRAINT `FKjtxip1yvwn66p4cbpycekychq` FOREIGN KEY (`type_id`) REFERENCES `music_type` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '音乐-类型关联表' ROW_FORMAT = Dynamic;
|
) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '音乐-类型关联表' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
@@ -137,10 +130,8 @@ CREATE TABLE `play_history` (
|
|||||||
`play_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '播放时间',
|
`play_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '播放时间',
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
INDEX `idx_user_id`(`user_id` ASC) USING BTREE,
|
INDEX `idx_user_id`(`user_id` ASC) USING BTREE,
|
||||||
INDEX `idx_music_id`(`music_id` ASC) USING BTREE,
|
INDEX `idx_music_id`(`music_id` ASC) USING BTREE
|
||||||
CONSTRAINT `FKm05jb66wc5epn38vuwm55o933` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
) ENGINE = InnoDB AUTO_INCREMENT = 51 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '播放历史表' ROW_FORMAT = Dynamic;
|
||||||
CONSTRAINT `FKt6cp1qv95qi4abyn69soyvibk` FOREIGN KEY (`music_id`) REFERENCES `music` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 43 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '播放历史表' ROW_FORMAT = Dynamic;
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for playlist
|
-- Table structure for playlist
|
||||||
@@ -159,10 +150,8 @@ CREATE TABLE `playlist` (
|
|||||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
INDEX `idx_creator_id`(`creator_id` ASC) USING BTREE,
|
INDEX `idx_creator_id`(`creator_id` ASC) USING BTREE,
|
||||||
INDEX `idx_type_id`(`type_id` ASC) USING BTREE,
|
INDEX `idx_type_id`(`type_id` ASC) USING BTREE
|
||||||
CONSTRAINT `FKi45kpenvb301c9yb1labp8b4j` FOREIGN KEY (`creator_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '歌单表' ROW_FORMAT = Dynamic;
|
||||||
CONSTRAINT `FKttnmgs0esm9njqa0g52mbp48` FOREIGN KEY (`type_id`) REFERENCES `playlist_type` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '歌单表' ROW_FORMAT = Dynamic;
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for playlist_music
|
-- Table structure for playlist_music
|
||||||
@@ -176,9 +165,7 @@ CREATE TABLE `playlist_music` (
|
|||||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
UNIQUE INDEX `uk_playlist_music`(`playlist_id` ASC, `music_id` ASC) USING BTREE,
|
UNIQUE INDEX `uk_playlist_music`(`playlist_id` ASC, `music_id` ASC) USING BTREE,
|
||||||
INDEX `idx_music_id`(`music_id` ASC) USING BTREE,
|
INDEX `idx_music_id`(`music_id` ASC) USING BTREE
|
||||||
CONSTRAINT `FK5g0xtl5e89uycye0jo1ll65sq` FOREIGN KEY (`music_id`) REFERENCES `music` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
|
||||||
CONSTRAINT `FKq9o07ljjk03aeeqt0q9lwhndk` FOREIGN KEY (`playlist_id`) REFERENCES `playlist` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '歌单-音乐关联表' ROW_FORMAT = Dynamic;
|
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '歌单-音乐关联表' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
@@ -208,8 +195,7 @@ CREATE TABLE `singer` (
|
|||||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
INDEX `idx_type_id`(`type_id` ASC) USING BTREE,
|
INDEX `idx_type_id`(`type_id` ASC) USING BTREE
|
||||||
CONSTRAINT `FKdwhlvo45iuspxcjg0gax5exwm` FOREIGN KEY (`type_id`) REFERENCES `singer_type` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '歌手表' ROW_FORMAT = Dynamic;
|
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '歌手表' ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
@@ -220,9 +206,7 @@ CREATE TABLE `singer_music` (
|
|||||||
`singer_id` bigint NOT NULL,
|
`singer_id` bigint NOT NULL,
|
||||||
`music_id` bigint NOT NULL,
|
`music_id` bigint NOT NULL,
|
||||||
PRIMARY KEY (`singer_id`, `music_id`) USING BTREE,
|
PRIMARY KEY (`singer_id`, `music_id`) USING BTREE,
|
||||||
INDEX `FKk0fdv208e2ulhcxd9gge63h6j`(`music_id` ASC) USING BTREE,
|
INDEX `FKk0fdv208e2ulhcxd9gge63h6j`(`music_id` ASC) USING BTREE
|
||||||
CONSTRAINT `FKf33uki3h3ftg9ne16xr4n1srp` FOREIGN KEY (`singer_id`) REFERENCES `singer` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
|
||||||
CONSTRAINT `FKk0fdv208e2ulhcxd9gge63h6j` FOREIGN KEY (`music_id`) REFERENCES `music` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
|
||||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
@@ -289,10 +273,8 @@ CREATE TABLE `user_collect_music` (
|
|||||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
UNIQUE INDEX `uk_user_music`(`user_id` ASC, `music_id` ASC) USING BTREE,
|
UNIQUE INDEX `uk_user_music`(`user_id` ASC, `music_id` ASC) USING BTREE,
|
||||||
INDEX `idx_music_id`(`music_id` ASC) USING BTREE,
|
INDEX `idx_music_id`(`music_id` ASC) USING BTREE
|
||||||
CONSTRAINT `FK1bm2wy4dgmhdfvp6k9fhqpf73` FOREIGN KEY (`music_id`) REFERENCES `music` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户收藏音乐表' ROW_FORMAT = Dynamic;
|
||||||
CONSTRAINT `FKt8w479d40yle3jxmqiovm6quo` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
|
||||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户收藏音乐表' ROW_FORMAT = Dynamic;
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for user_collect_playlist
|
-- Table structure for user_collect_playlist
|
||||||
@@ -305,10 +287,8 @@ CREATE TABLE `user_collect_playlist` (
|
|||||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
UNIQUE INDEX `uk_user_playlist`(`user_id` ASC, `playlist_id` ASC) USING BTREE,
|
UNIQUE INDEX `uk_user_playlist`(`user_id` ASC, `playlist_id` ASC) USING BTREE,
|
||||||
INDEX `idx_playlist_id`(`playlist_id` ASC) USING BTREE,
|
INDEX `idx_playlist_id`(`playlist_id` ASC) USING BTREE
|
||||||
CONSTRAINT `FKe4f1odrrb8yq287v9gwsbq5px` FOREIGN KEY (`playlist_id`) REFERENCES `playlist` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户收藏歌单表' ROW_FORMAT = Dynamic;
|
||||||
CONSTRAINT `FKqxg6amofxpxuxf6uwjebb5jak` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
|
||||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户收藏歌单表' ROW_FORMAT = Dynamic;
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for user_collect_singer
|
-- Table structure for user_collect_singer
|
||||||
@@ -321,10 +301,22 @@ CREATE TABLE `user_collect_singer` (
|
|||||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
UNIQUE INDEX `uk_user_singer`(`user_id` ASC, `singer_id` ASC) USING BTREE,
|
UNIQUE INDEX `uk_user_singer`(`user_id` ASC, `singer_id` ASC) USING BTREE,
|
||||||
INDEX `idx_singer_id`(`singer_id` ASC) USING BTREE,
|
INDEX `idx_singer_id`(`singer_id` ASC) USING BTREE
|
||||||
CONSTRAINT `FKlvx6pnysffce263knm6iivjjj` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户收藏歌手表' ROW_FORMAT = Dynamic;
|
||||||
CONSTRAINT `FKn8hu81ynti2nku5p7nsh6mk1k` FOREIGN KEY (`singer_id`) REFERENCES `singer` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
|
||||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户收藏歌手表' ROW_FORMAT = Dynamic;
|
-- ----------------------------
|
||||||
|
-- Table structure for user_like_music
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `user_like_music`;
|
||||||
|
CREATE TABLE `user_like_music` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||||
|
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||||
|
`music_id` bigint NOT NULL COMMENT '音乐ID',
|
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '点赞时间',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
UNIQUE INDEX `uk_user_music`(`user_id` ASC, `music_id` ASC) USING BTREE,
|
||||||
|
INDEX `idx_music_id`(`music_id` ASC) USING BTREE
|
||||||
|
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户点赞音乐表' ROW_FORMAT = DYNAMIC;
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for user_music
|
-- Table structure for user_music
|
||||||
@@ -337,10 +329,8 @@ CREATE TABLE `user_music` (
|
|||||||
`user_id` bigint NULL DEFAULT NULL,
|
`user_id` bigint NULL DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
INDEX `FKb53nc2rlyaotl1socy90u0v8`(`music_id` ASC) USING BTREE,
|
INDEX `FKb53nc2rlyaotl1socy90u0v8`(`music_id` ASC) USING BTREE,
|
||||||
INDEX `FKq3jkqxxm4lxvoaauy93dq1hjl`(`user_id` ASC) USING BTREE,
|
INDEX `FKq3jkqxxm4lxvoaauy93dq1hjl`(`user_id` ASC) USING BTREE
|
||||||
CONSTRAINT `FKb53nc2rlyaotl1socy90u0v8` FOREIGN KEY (`music_id`) REFERENCES `music` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
CONSTRAINT `FKq3jkqxxm4lxvoaauy93dq1hjl` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for user_playlist
|
-- Table structure for user_playlist
|
||||||
@@ -353,8 +343,7 @@ CREATE TABLE `user_playlist` (
|
|||||||
`user_id` bigint NULL DEFAULT NULL,
|
`user_id` bigint NULL DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
INDEX `FK7k6xercebs1wg014xb49hw3h0`(`playlist_id` ASC) USING BTREE,
|
INDEX `FK7k6xercebs1wg014xb49hw3h0`(`playlist_id` ASC) USING BTREE,
|
||||||
INDEX `FKmofufj03yw1wqauec6vrdnfw1`(`user_id` ASC) USING BTREE,
|
INDEX `FKmofufj03yw1wqauec6vrdnfw1`(`user_id` ASC) USING BTREE
|
||||||
CONSTRAINT `FKmofufj03yw1wqauec6vrdnfw1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
@@ -368,8 +357,7 @@ CREATE TABLE `user_singer` (
|
|||||||
`user_id` bigint NULL DEFAULT NULL,
|
`user_id` bigint NULL DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`) USING BTREE,
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
INDEX `FKacl5uu14x3io8qygn0cp27nvb`(`singer_id` ASC) USING BTREE,
|
INDEX `FKacl5uu14x3io8qygn0cp27nvb`(`singer_id` ASC) USING BTREE,
|
||||||
INDEX `FKnogaivkt6y4jy5vbt85tu8qj0`(`user_id` ASC) USING BTREE,
|
INDEX `FKnogaivkt6y4jy5vbt85tu8qj0`(`user_id` ASC) USING BTREE
|
||||||
CONSTRAINT `FKnogaivkt6y4jy5vbt85tu8qj0` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
|
|
||||||
|
|
||||||
SET FOREIGN_KEY_CHECKS = 1;
|
SET FOREIGN_KEY_CHECKS = 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user