1. 项目背景与技术选型
音乐播放网站管理系统作为计算机专业毕业设计的常见选题,既考验学生全栈开发能力,又能体现对现代Web技术的综合运用。这个项目采用SpringBoot+Vue的前后端分离架构,是当前企业级应用开发的主流模式。
为什么选择SpringBoot作为后端框架?我在实际项目开发中发现,相比传统的SSM框架,SpringBoot有三大优势:
- 自动配置机制大幅减少了XML配置,内置Tomcat容器让部署更简单
- Starter依赖管理让第三方组件集成变得非常便捷
- Actuator模块提供了完善的应用监控能力
前端选用Vue.js而非React或Angular,主要考虑因素包括:
- 渐进式框架特性适合中小型项目快速开发
- 单文件组件(SFC)模式让前端代码更易维护
- 与Element UI等组件库配合能快速构建美观界面
- 相比React更平缓的学习曲线适合毕业设计场景
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计
2.1 整体架构图
code复制[前端Vue层] ←HTTP→ [SpringBoot REST API] ←JDBC→ [MySQL数据库]
↑ ↑
Vue Router Spring Security
Vuex状态管理 MyBatis-Plus
Axios HTTP客户端 Redis缓存
2.2 数据库设计核心表
- 用户表(user)
sql复制CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '登录名',
`password` varchar(100) NOT NULL COMMENT '密码',
`salt` varchar(20) DEFAULT NULL COMMENT '盐值',
`avatar` varchar(255) DEFAULT NULL COMMENT '头像URL',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`phone` varchar(20) DEFAULT NULL COMMENT '手机号',
`status` tinyint DEFAULT '1' COMMENT '状态(0:禁用,1:正常)',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
- 音乐表(music)
sql复制CREATE TABLE `music` (
`id` bigint NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL COMMENT '歌曲名',
`artist` varchar(100) DEFAULT NULL COMMENT '艺术家',
`album` varchar(100) DEFAULT NULL COMMENT '专辑',
`cover_url` varchar(255) DEFAULT NULL COMMENT '封面URL',
`music_url` varchar(255) NOT NULL COMMENT '音乐文件URL',
`duration` int DEFAULT '0' COMMENT '时长(秒)',
`play_count` int DEFAULT '0' COMMENT '播放次数',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
注意:实际开发中音乐文件应当使用对象存储服务(如阿里云OSS),而非直接存储在服务器本地
3. 核心功能实现
3.1 音乐播放功能实现
前端使用vue-aplayer组件实现播放器界面:
vue复制<template>
<aplayer
:music="currentMusic"
:list="playlist"
:showLrc="true"
@ended="handleEnded"
/>
</template>
<script>
export default {
data() {
return {
currentMusic: {
title: '',
artist: '',
src: '',
pic: ''
},
playlist: []
}
},
methods: {
async loadMusic(id) {
const res = await this.$axios.get(`/api/music/${id}`)
this.currentMusic = {
title: res.data.title,
artist: res.data.artist,
src: res.data.music_url,
pic: res.data.cover_url
}
}
}
}
</script>
后端SpringBoot需要实现音乐文件流式传输:
java复制@GetMapping("/music/stream/{id}")
public void streamMusic(@PathVariable Long id, HttpServletResponse response) {
Music music = musicService.getById(id);
String filePath = music.getMusicUrl();
try (InputStream inputStream = new FileInputStream(filePath);
OutputStream outputStream = response.getOutputStream()) {
response.setContentType("audio/mpeg");
IOUtils.copy(inputStream, outputStream);
outputStream.flush();
} catch (IOException e) {
log.error("音乐流传输失败", e);
}
}
3.2 用户认证与授权
采用JWT+Spring Security实现安全控制:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/music/list").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
JWT工具类示例:
java复制public class JwtUtil {
private static final String SECRET = "your-secret-key";
private static final long EXPIRATION = 86400000L; // 24小时
public static String generateToken(UserDetails userDetails) {
return Jwts.builder()
.setSubject(userDetails.getUsername())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
}
public static String getUsernameFromToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
}
4. 项目部署与优化
4.1 前端部署配置
vue.config.js关键配置:
javascript复制module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? '/music-web/' : '/',
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}
4.2 后端性能优化
- 使用Redis缓存热门音乐数据:
java复制@Service
public class MusicServiceImpl implements MusicService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public Music getById(Long id) {
String key = "music:" + id;
Music music = (Music) redisTemplate.opsForValue().get(key);
if (music == null) {
music = baseMapper.selectById(id);
redisTemplate.opsForValue().set(key, music, 1, TimeUnit.HOURS);
}
return music;
}
}
- 数据库连接池配置(application.yml):
yaml复制spring:
datasource:
url: jdbc:mysql://localhost:3306/music_db?useSSL=false&serverTimezone=UTC
username: root
password: 123456
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
5. 毕业设计常见问题解决
5.1 跨域问题解决方案
SpringBoot后端配置:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.maxAge(3600);
}
}
5.2 文件上传大小限制
application.yml配置:
yaml复制spring:
servlet:
multipart:
max-file-size: 50MB
max-request-size: 100MB
5.3 前端路由问题
Vue Router配置(history模式):
javascript复制const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/',
component: Home
},
{
path: '/player/:id',
component: Player
}
]
})
对应Nginx配置:
nginx复制location / {
try_files $uri $uri/ /index.html;
}
6. 项目扩展方向
- 音乐推荐算法实现:
java复制// 基于用户播放历史的协同过滤推荐
public List<Music> recommendMusics(Long userId) {
// 获取用户播放记录
List<PlayHistory> histories = playHistoryMapper.selectByUser(userId);
// 找出相似用户
Set<Long> similarUsers = findSimilarUsers(histories);
// 获取相似用户喜欢的音乐
return musicMapper.selectByUsers(similarUsers);
}
- 歌词同步显示功能:
vue复制<aplayer
:music="currentMusic"
:lrc="lrcText"
/>
<script>
export default {
data() {
return {
lrcText: `[00:00.00]歌词第一行
[00:05.00]歌词第二行`
}
}
}
</script>
- 移动端适配方案:
- 使用vw/vh单位实现响应式布局
- 添加PWA支持实现离线访问
- 配置manifest.json实现添加到主屏幕
我在实际开发中发现,音乐播放网站有几个关键点需要特别注意:
- 音频文件的处理要使用流式传输,避免大文件直接加载
- 播放状态管理要使用Vuex进行全局状态维护
- 移动端和PC端的交互差异需要针对性设计
- 版权问题要特别注意,毕业设计建议使用无版权音乐或自行创作
