基于SpringBoot+Vue的民谣网站实现方案
一、技术选型
模块 | 技术栈 |
---|---|
前端框架 | Vue3 + TypeScript + Pinia (状态管理) + Vite (构建工具) |
UI组件库 | Element Plus / Ant Design Vue |
前端播放器 | vue-aplayer (支持歌词滚动) |
后端框架 | SpringBoot 3.x + JDK17 |
安全框架 | Spring Security + JWT |
ORM框架 | MyBatis-Plus |
数据库 | MySQL 8.0 + Redis 7.0 (缓存) |
文件存储 | 阿里云OSS/MinIO (音频文件存储) |
搜索引擎 | Elasticsearch 8.x (歌曲搜索) |
部署 | Docker + Nginx |
二、核心功能模块
graph TD
A[用户系统] --> B[登录注册]
A --> C[个人收藏]
A --> D[评论互动]
E[音乐系统] --> F[音频播放]
E --> G[歌词同步]
E --> H[歌单管理]
I[内容系统] --> J[民谣故事]
I --> K[音乐人专栏]
L[运营系统] --> M[推荐算法]
L --> N[数据统计]
三、数据库设计(关键表结构)
1. 歌曲表 (song)
CREATE TABLE `song` (
`id` BIGINT PRIMARY KEY COMMENT '雪花ID',
`title` VARCHAR(100) NOT NULL COMMENT '歌曲名称',
`artist_id` BIGINT NOT NULL COMMENT '艺人ID',
`album` VARCHAR(100) COMMENT '专辑名称',
`duration` INT COMMENT '时长(秒)',
`lyrics` TEXT COMMENT 'LRC歌词',
`oss_url` VARCHAR(255) NOT NULL COMMENT 'OSS地址',
`play_count` INT DEFAULT 0 COMMENT '播放量',
INDEX `idx_artist` (`artist_id`)
);
2. 用户行为表 (user_behavior)
CREATE TABLE `user_behavior` (
`user_id` BIGINT NOT NULL,
`song_id` BIGINT NOT NULL,
`behavior_type` ENUM('PLAY', 'LIKE', 'COLLECT', 'SHARE') NOT NULL,
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`, `song_id`, `behavior_type`)
);
四、核心接口设计示例
1. 分页获取推荐歌单
@GetMapping("/recommend")
public Result<Page<SongVO>> getRecommendSongs(
@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer size,
@AuthenticationPrincipal User user) {
// 基于用户画像的推荐逻辑
return songService.getRecommendations(user.getId(), PageRequest.of(page-1, size));
}
2. 音乐播放接口
@GetMapping("/play/{songId}")
public void playSong(@PathVariable Long songId,
HttpServletResponse response) throws IOException {
Song song = songService.getById(songId);
InputStream audioStream = ossService.getFileStream(song.getOssUrl());
response.setContentType("audio/mpeg");
IOUtils.copy(audioStream, response.getOutputStream());
}
五、前端关键技术实现
1. 播放器组件封装
<template>
<a-player
:music="currentSong"
:list="playlist"
@play="handlePlay"
@pause="handlePause"
:showLrc="true"
/>
</template>
<script setup>
const store = usePlayerStore();
const { currentSong, playlist } = storeToRefs(store);
const handlePlay = (song) => {
store.recordPlay(song.id);
};
</script>
2. 虚拟滚动歌单列表
<template>
<RecycleScroller
:items="songs"
:item-size="72"
key-field="id"
v-slot="{ item }"
>
<SongItem :song="item" @click="playSong(item)"/>
</RecycleScroller>
</template>
六、推荐算法实现思路
# 基于内容的协同过滤(伪代码示例)
def recommend_songs(user_id):
# 获取用户历史行为
user_history = get_user_behavior(user_id)
# 提取歌曲特征向量
song_features = {
song.id: [genre_vec, artist_vec, lyric_tfidf]
for song in all_songs
}
# 计算余弦相似度
similarities = []
for song_id in user_history:
for candidate_id in candidate_songs:
sim = cosine_similarity(
song_features[song_id],
song_features[candidate_id]
)
similarities.append((candidate_id, sim))
# 返回TopN推荐
return sorted(similarities, key=lambda x: -x[1])[:10]
七、部署架构
graph LR
A[客户端] --> B[Nginx]
B --> C[前端静态资源]
B --> D[API网关]
D --> E[用户服务]
D --> F[歌曲服务]
D --> G[推荐服务]
H[MySQL] --> E
H --> F
I[Redis] --> E
J[Elasticsearch] --> F
K[MinIO] --> F
八、性能优化策略
- 音频文件处理:
- 使用FFmpeg进行音频转码(统一为MP3格式)
- HLS分片传输大文件
- 缓存策略:
@Cacheable(value = "songs", key = "#songId",
unless = "#result == null")
public Song getSongById(Long songId) {
return songMapper.selectById(songId);
}
- 搜索优化:
- Elasticsearch IK分词器+拼音插件
- 搜索结果高亮显示
九、扩展功能规划
- UGC内容:
- 用户原创故事投稿
- 线下演出信息发布
- 社交功能:
- 音乐心情动态
- 歌单分享到社交媒体
- 商业化功能:
- 数字专辑售卖
- 音乐人打赏系统
该方案结合了现代Web开发的最佳实践,可扩展性强。建议采用敏捷开发模式,分阶段迭代实现核心功能。