很多朋友一开始做JavaWeb项目,都会选“音乐播放器”这个方向,毕竟人人都听歌,需求清晰,演示起来也直观。但真正动手之后才会发现,这个题目想做得像个样子,牵扯到的技术点远比想象中多:用户登录注册怎么串进来、歌曲文件存在哪、播放时怎么处理音频流、前端怎样优雅地拿到歌曲列表、最后怎么把整个项目发布到Windows服务器上跑起来。这篇文章我就把自己从零搭建一个JavaWeb音乐播放器的完整过程记录下来,包含MySQL表结构设计、Servlet三层架构、流式音频播放、VSCode开发配置,以及Apache+Tomcat在Windows Server上的部署方案。内容适合刚学完JavaSE和MySQL基础、准备做第一个完整Web项目的同学,也适合临近期末或找工作需要整理项目经验的开发者参考。
1. 为什么用JavaWeb而不是一上来就上Spring Boot:项目定位与选型思路
1.1 这个项目到底在训练什么能力
很多人问我,现在企业里都用Spring Boot,做个音乐播放器为何还要抱着Servlet和JSP不放?我的回答是:因为练手项目和真实业务项目的目标根本不同。你最终要获得的不是“我会用Spring Boot写增删改查”,而是“我理解一个Web系统从请求到响应的完整链路”。纯Servlet项目里,请求怎么被Tomcat接收、Servlet如何匹配URL、Session怎么维持登录状态、JDBC连接如何获取和释放、JSP怎么渲染动态页面,每一个环节都暴露在你面前。用上Spring Boot之后,这些东西大部分被封装进框架,初学者反而失去了感知底层的机会。
换句话说,JavaWeb音乐播放器这个题目,本质上是把你之前学的Java语法、集合框架、IO流、多线程、JDBC、MySQL、HTML/CSS/JavaScript全部串起来的一次综合演练。第一次做完整项目的人,最大的收获不是播放功能本身,而是理解分层思想——Controller层负责接收请求,Service层负责业务逻辑,Dao层负责数据访问。这个思想一旦建立,后面学框架、做分布式、看微服务源码,都会轻松很多。
1.2 具体选型清单与取舍理由
这里给出我实际使用的技术栈清单,每一行都附上选择理由,方便你评估自己项目是否能直接复用。
| 组件 | 选型 | 理由 |
|---|---|---|
| Web容器 | Tomcat 9.x | Servlet规范标准实现,JavaWeb课程最常用,资料丰富 |
| 服务端语言 | Java 8+ | 主流稳定,流式播放相关IOAPI成熟 |
| 前端页面 | JSP + Bootstrap + jQuery | 无需额外构建工具,JSP可直接读取后端数据,Bootstrap保证颜值 |
| 数据存储 | MySQL 8.x | 大众化、教程多、Navicat可视化方便 |
| 音频文件存储 | 本地磁盘路径 | 对比数据库BLOB字段,更适合流式加载,减少数据库压力 |
| 构建工具 | Maven | 依赖管理方便,后续移植Spring Boot省事 |
| 开发工具 | VSCode + Java插件包 | 轻量、免费、调试Tomcat项目方便,避免破解IDEA的麻烦 |
| 部署环境 | Windows Server + Apache + Tomcat | 热搜词里出现最多的发布方案,适合没有Linux基础的场景 |
这套组合最大的特点是:每个组件都能让你看到它存在的必要性。比如选Maven,是因为Servlet离不开javax.servlet-api依赖,如果不引入构建工具,拷Jar包会非常痛苦;选JSP而不是前后端分离,是因为这个阶段你还不熟悉跨域和JSON接口设计,JSP在服务端渲染页面可以直接拿到User对象,不用手动拼接口文档。
1.3 哪些功能应该做,哪些功能不该碰
项目功能边界一定要提前划清楚,不然会陷入无休止的“加需求”状态。以音乐播放器来说,我做的是这些功能:用户注册登录、歌曲列表展示、歌曲详情页、在线播放、歌词展示、收藏歌曲、播放历史、搜索歌曲。这些功能覆盖了JavaWeb的核心考点:表单提交、Session、JDBC查询、外键关联、模糊搜索、文件上传下载、流式响应。至于那些与核心学习目标无关的功能,比如随机播放算法、评论区的敏感词过滤、推荐系统,我建议第一版全部砍掉。它们要么属于算法范畴,要么需要额外中间件,放到第二期再扩展完全来得及。
选好定位之后,接下来从数据库设计开始落地。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. MySQL表结构设计:歌曲数据与用户行为的建模
2.1 核心表的职责划分
数据库设计是这个项目里最不能跳过思考的环节。我第一次做的时候,想着“不就是几张表吗”,结果建了三张表就发现逻辑互相矛盾:用户在“歌曲表”里直接加了收藏字段,播放历史又不知道存到哪。正确的做法是,把数据按业务主体拆分。我的项目最终保留了四张表:用户表,存储账号信息;歌曲表,存储歌曲元数据和文件路径;收藏表,记录用户跟歌曲之间的多对多关系;播放历史表,记录“谁在什么时间听了什么歌”。
这四张表实际上对应了三种业务角色:用户、资源、关系。记住一个原则:用户和歌曲之间的行为关系,永远不应该以字段形式挂在用户表或歌曲表上,而应该单独建一张关系表。哪怕你现在只需要“收藏”一个功能,也要用独立的收藏表来承载,这样后续加“我喜欢”“最近播放”“歌单”时,不需要重新设计数据库。
2.2 歌曲表设计中的关键字段:文件路径还是BLOB
歌曲文件的存储策略是个值得展开讲的点。最初我纠结过:把MP3文件直接以二进制对象存进MySQL的BLOB字段行不行?答案是技术上可行,但实践上不要这么干。原因有两点:第一,BLOB字段会让数据库表变得无比庞大,备份、查询、索引优化全都受影响;第二,播放器加载音频时,需要按照字节范围分段读取,直接把BLOB取出来再写流,实现起来非常别扭。正确的方案是:歌曲文件上传到服务器磁盘的某个目录(比如D:/music_files/),数据库里只存文件的相对路径或访问URL。播放请求到达时,后端根据路径定位文件,以流的形式写给前端。
这样设计的好处是:数据库保持轻量,文件管理和迁移都方便;同时前端audio标签可以直接请求一个play?id=xxx的Servlet地址,由后端控制音频流输出,后续做权限校验、防盗链都很容易。以下是歌曲表的实际建表SQL,我加了注释,方便你对照理解。
sql复制CREATE TABLE `t_song` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '歌曲ID',
`song_name` varchar(100) NOT NULL COMMENT '歌曲名称',
`singer` varchar(100) DEFAULT NULL COMMENT '歌手',
`album` varchar(100) DEFAULT NULL COMMENT '专辑',
`duration` int(11) DEFAULT NULL COMMENT '音频时长(秒)',
`lyric` text COMMENT 'LRC歌词文本',
`file_path` varchar(255) NOT NULL COMMENT '音频文件服务器路径',
`cover_path` varchar(255) DEFAULT NULL COMMENT '封面图片路径',
`play_count` int(11) DEFAULT '0' COMMENT '播放次数',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '上传时间',
PRIMARY KEY (`id`),
KEY `idx_song_name` (`song_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='歌曲信息表';
2.3 用户表、收藏表与播放历史表的关联设计
用户表相对简单,但有一个关键点要提醒:密码字段不能存明文。第一次做项目的人最容易在这里偷懒,直接INSERT INTO t_user VALUES('admin', '123456'),这等于把用户账号裸奔在数据库里。我的做法是使用JDK自带的MessageDigest做SHA-256加盐哈希,盐值取用户名加固定前缀,虽然比不上BCrypt专业,但作为教学项目已经足够说明安全意识。建表时注意密码字段长度至少要64个字符,因为SHA-256摘要固定是64位十六进制字符串。
收藏表和播放历史表都属于关联表,结构大同小异。收藏表的唯一约束是`(user_id, song_id)
