Vue + SpringBoot + MyBatis 音乐网站
一、前言
本文梳理音乐网站从设计到落地的完整思路,重点讲清数据如何从数据库一步步流到前端页面。先建立整体流程感,再逐个击破接口、组件等细节——无论是照着做一遍,还是迁移到其他项目,都会顺手得多。
项目源码:github.com/Yin-Hongwei/music-website

二、项目架构
仓库分为三个子项目:前台 music-client、管理端 music-manage、后端 API music-server。前台与管理端均为 Vue 应用,通过 Axios 调用 Spring Boot 接口;后端按 Controller → Service → Mapper 分层访问 MySQL。结合下图,后文将从数据库到页面,沿这条链路逐层拆解。
三、开发环境
本节只列从零起步所需的基本开发环境,先把后端、数据库和前端跑通即可。随着项目后期功能增多、架构变复杂,Redis 等依赖再按需引入。
| 环境 | 版本 |
|---|---|
| 操作系统 | macOS |
| JDK | 8+(如 jdk-8u141) |
| MySQL | 8.0+ |
| Node.js | 14+ |
| IDE | IntelliJ IDEA / VS Code |
四、后端项目开发
1、创建数据库表
开发后端之前,先把业务里要持久化的东西想清楚。音乐网站至少需要这几类数据:
- 用户侧:前台用户(
user)、后台管理员(admin) - 内容侧:歌手(
singer)、歌曲(song)、歌单(song_sheet) - 展示侧:首页轮播(
banner) - 互动侧:收藏(
collect)、评论(comment)
表之间的关系可以这样理解:
- 歌手和歌曲是一对多:一首歌对应一个歌手,所以在
song里放singer_id - 歌单和歌曲是多对多:一首歌可以出现在多个歌单里,所以用
song_sheet_song做中间表 - 收藏和评论都可能是针对「歌曲」或「歌单」,所以在
collect、comment里同时保留song_id、song_sheet_id,再用type区分目标类型

2、创建项目
在 IntelliJ IDEA 中新建项目,选择 Spring Initializr,并按需勾选依赖:Web → Spring Web Starter,以及 SQL → MySQL Driver、MyBatis Framework。一路 Next 完成后,将得到如下项目结构(典型三层架构):

3、配置文件
3.1、application.properties
在 src/main/resources/application.properties 中配置数据库连接,起步阶段只需以下几项:
# 服务端口 |
3.2、generatorConfig.xml
MyBatis Generator(MBG) 可以根据已有数据库表,自动生成 实体类、Mapper 接口 和 Mapper.xml。项目起步阶段通常只需执行一次;生成完成后,建议在 pom.xml 里注释掉 MBG 插件,避免每次构建重复覆盖代码。
在 src/main/resources 下新建 generatorConfig.xml,需要配置三块内容:
- JDBC 连接:库地址、账号、密码(与
application.properties保持一致) - 生成路径:实体类、Mapper 接口、Mapper.xml 分别输出到哪个包/目录
- 目标表:用
<table>列出要生成的表名
示例(包名、表名按项目修改):
|
3.3、pom.xml
pom.xml 负责两块:依赖(dependencies)和 插件(plugins)。用 Spring Initializr 建项目时,Web、MySQL、MyBatis 等基础依赖已经带上了,再按需补充下面几项:
| 依赖 | 说明 |
|---|---|
| mybatis-spring-boot-starter | MyBatis 与 Spring Boot 集成 |
| mysql-connector-java | MySQL JDBC 驱动 |
| fastjson | JSON 与 JavaBean 互转 |
MBG 插件配合上一节的 generatorConfig.xml,在 plugins 中加入:
<plugin> |
执行 ./mvnw mybatis-generator:generate 生成 dao、domain、mapper 及对应文件:

生成完成后注释掉 MBG 插件,避免后续构建重复覆盖已有代码。
4、测试(以新建一个用户为例)
MBG 生成代码后,先写一条「插入用户」的链路,确认数据库连接和 MyBatis 映射都正常。下面用 MBG 生成的 Consumer 为例,包名与第三节配置保持一致(与 项目源码 最新代码可能不同,以教程为准)。
4.1、新建 Service 层
后端采用 Controller → Service → Mapper 分层(第五节会展开)。MBG 只生成 Mapper,Service 需手动创建。这里先补上 Service,让本节测试与后续接口走同一条链路;当前 addUser 只是转发到 Mapper,等业务复杂后再在 Service 里加校验、转换等逻辑。
在 src/main/java/com/example/demo/service 下新建:
service/ |
ConsumerService 接口 — 声明 addUser 方法:
public interface ConsumerService { |

ConsumerServiceImpl 实现类 — 调用 Mapper 写入数据库:
|

4.2、补充 Mapper
MBG 默认会为每张表生成 insert、insertSelective 等通用 CRUD 方法(接口 + XML 已有,无需手写)。本节为与 4.1 的 addUser 命名一致,额外在接口和 XML 里补一条同名映射——SQL 复制默认生成的 insertSelective 即可,只改 id。
ConsumerMapper 接口(src/main/java/com/example/demo/dao/ConsumerMapper.java):
int addUser(Consumer record); |

ConsumerMapper.xml(src/main/resources/mapper/ConsumerMapper.xml)— 复制 MBG 默认生成的 insertSelective 节点,把 id 改为 addUser:
<insert id="addUser" parameterType="com.example.demo.domain.Consumer"> |

4.3、启动类扫描 Mapper
MBG 生成的 Mapper 接口不会自动注册到 Spring 容器,需要在启动类上用 @MapperScan 指定扫描包(与 3.2 中 javaClientGenerator 的 targetPackage 一致),否则注入 ConsumerMapper 时会报找不到 Bean。
在 src/main/java/com/example/demo/DemoApplication.java 上添加:
|
4.4、写单元测试
前面几步就绪后,用 @SpringBootTest 启动 Spring 容器,走一遍 Service → Mapper → 数据库 的完整链路(会连真实 MySQL,属于集成测试)。
在 src/test/java/com/example/demo/DemoApplicationTests.java 中编写:
|
右键运行 addUser 测试方法:控制台无报错,且 consumer 表里能看到新记录,说明后端链路已跑通,可以开始写接口。

5、开发接口(以返回所有用户信息为例)
第四节验证了「写入」,这里从「读取」入手,走一遍完整的 HTTP 请求链路。包名仍与第三节、第四节保持一致。
5.1、分层说明
后端按四层组织,请求自上而下、响应自下而上:
浏览器 → Controller → Service → Mapper(+ XML)→ 数据库 |
| 层次 | 目录 | 职责 |
|---|---|---|
| 实体类 | domain |
对应数据库表,MBG 已生成 |
| Mapper / DAO | dao + mapper |
接口声明数据操作,XML 编写 SQL |
| Service | service + impl |
业务逻辑,调用 Mapper |
| Controller | controller |
接收 HTTP 请求,调用 Service 并返回结果 |
5.2、实战:返回所有用户
目标:访问 http://localhost:8888/allUser 拿到全部用户。按 Controller → Service → Mapper 逐层补充 allUser 方法。
Controller 层 — 监听 /allUser,交给 Service 处理:
|

Service 层 — 接口声明方法,实现类调用 Mapper:
// ConsumerService.java |


Mapper 层 — 接口 + XML 查询数据库(SQL 写法与 4.2 类似,复制 MBG 默认生成的 select 并改 id 亦可):
// ConsumerMapper.java |
<!-- ConsumerMapper.xml --> |


启动验证 — 运行项目并在浏览器访问:
./mvnw spring-boot:run |
浏览器打开 http://localhost:8888/allUser 查看 JSON 结果。


5.3、延伸
其余接口按同样分层逐层添加方法即可。联调前端时还需注意两点:跨域(见 config 目录)和静态资源路径(歌曲、图片等文件的存放与访问)。
5.4、小结
一次 HTTP 请求的完整路径:Controller 接收请求 → Service 处理业务 → Mapper 访问数据库 → 结果沿原路返回前端。
6、最终项目结构
. |
五、客户端项目开发
前台项目位于仓库 music-client/,基于 Vue 3 + TypeScript + Pinia + Vue Router + Axios + Element Plus 实现。
1、创建项目
客户端的创建比后端简单,使用 Vue CLI 脚手架即可。进入 music-website 目录后,可参照如下方式初始化:
npm install -g @vue/cli |
依赖安装完成后进入项目目录启动:
cd music-client |
启动成功后,直接点击控制台输出的本地地址即可访问前端页面。

如果是新手,建议先阅读 Vue 3 官方文档,了解组件、路由、组合式 API 等基础概念后再动手。
2、开发思路
代码按职责拆分到不同目录,便于后期维护:
- pages:页面级视图,负责路由对应的整页展示(首页、搜索、歌手、歌单、个人中心等)
- components:可复用组件,按
auth(认证布局)、business(业务组件)、layouts(页头页脚、播放栏)、player(音频播放)分类 - api:按模块封装后端接口(歌曲、歌手、歌单、评论、用户等),统一走
utils/request.ts中的 Axios 实例 - store:Pinia 状态管理,拆分
user(用户)、player(播放器)、song(当前歌曲)、search(搜索)、configure(全局 UI 状态)等模块 - composables:抽取跨组件复用的逻辑,如导航、搜索关键词、全局操作等
- router:路由配置,
YinAppLayout.vue作为带页头/页脚/播放栏的主布局,子路由挂载各页面
开发流程建议:先搭页面骨架(可写死数据),再通过 api 层请求后端数据;前端请求后端接口需在 vue.config.js 中通过 NODE_HOST 配置后端地址(如 http://localhost:8888);遇到跨域问题可在后端配置 CORS,或在 vue.config.js 中配置 devServer 代理。
前台组件以自研为主,第三方 UI 用得较少,适合练习组件封装与状态管理。
3、最终项目结构
music-client/ |
六、管理端项目开发
后台项目位于 music-manage/,同样基于 Vue 3 + TypeScript,使用 Element Plus 快速搭建表格、表单、弹窗等管理界面,整体分层与前台一致(api / views / components / stores / router)。
1、创建与启动
cd music-manage |
启动成功后,直接点击控制台输出的本地地址即可访问。
2、开发思路
管理端以 CRUD 为主:每个 views 页面对应一类资源(Banner、用户、歌曲、歌手、歌单、评论、收藏等),列表展示与增删改查通过 Element Plus 的 Table、Form、Dialog 等组件完成。api 层按资源拆分接口;components/layouts 提供侧边栏(YinAside)、顶栏(YinHeader)和整体布局(YinLayout);stores/app.ts 用 Pinia 管理侧边栏折叠等全局状态;mixins/mixin.ts 保留部分跨页面公共方法。
3、最终项目结构
music-manage/ |
七、贡献者
感谢所有为本仓库提交过代码与改进建议的贡献者。
八、最后
希望本文对大家有所启发,如有问题欢迎交流。
- 作者: Yin-Hongwei
- 链接: http://Yin-Hongwei.github.io/2019/03/04/music/
- 版权声明: CC BY-NC-SA 4.0