Spring Boot+Vue全栈音乐网站实战:从零构建企业级前后端分离项目

📅 2026/8/8 3:45:33
Spring Boot+Vue全栈音乐网站实战:从零构建企业级前后端分离项目
很多Java开发者都有过这样的困惑学完了Spring Boot和Vue也做了几个小项目但简历上还是缺少一个能拿得出手的、功能完整且架构清晰的全栈项目。网上的开源项目要么过于庞大复杂要么就是“玩具级”的Demo难以体现真实开发中的技术选型和工程化思考。今天要介绍的这个“前后端分离音乐网站”项目恰恰能填补这个空白。它不是一个简单的CRUD练习而是一个涵盖了用户认证、音乐播放、歌单管理、后台数据维护等核心功能的完整应用。更重要的是它采用了当前企业级开发中最主流的Spring Boot Vue前后端分离架构代码结构清晰技术栈选型经典非常适合作为毕业设计、个人作品集或者全栈能力提升的练手项目。本文将带你从零开始手把手拆解这个项目的核心实现。我们不会只停留在“跑起来就行”的层面而是会深入探讨为什么选择这样的架构前后端如何优雅地交互播放器功能如何实现以及在实际部署和开发中你会遇到哪些“坑”以及如何避开它们。读完本文你不仅能获得一套可运行的源码更能掌握构建一个现代Web应用的完整思路和实战技能。1. 这个项目解决了什么实际问题在开始看代码之前我们首先要明确做一个音乐网站项目到底在训练哪些能力它远不止是“前端画个页面后端查个数据库”那么简单。1. 真实的全栈流程体验你需要处理从数据库设计、RESTful API构建、前端组件开发到最终部署上线的完整链路。这比单纯学习一个框架要复杂得多也更能锻炼你的工程思维。2. 核心业务逻辑的抽象音乐网站涉及“用户-歌曲-歌单-评论”等多个实体间的复杂关系。如何设计数据库表结构如何实现多对多的关联查询比如一个歌单包含多首歌一首歌属于多个歌单这直接考验你的数据建模能力。3. 前后端分离的深度实践这是本项目的重点。你将深刻理解 *前后端职责分离后端Spring Boot专注于业务逻辑、数据安全和API提供前端Vue专注于数据展示、用户交互和路由管理。 *基于Token的认证授权如何实现用户登录JWT、如何保护API拦截器/过滤器、如何管理用户状态。 *异步数据交互前端通过Axios调用后端API处理异步响应和错误状态。4. 特定场景的技术实现例如音频播放是音乐网站的核心。你将学习如何在Web端使用HTML5的audio标签或第三方库如APlayer来播放音乐并实现播放列表、进度控制、歌词同步等交互功能。5. 项目部署与协作前后端分离后开发环境、联调、打包、部署的流程都与传统单体应用不同。你需要配置跨域CORS、独立部署前端静态资源和后端服务。因此这个项目的价值在于它提供了一个贴近真实业务场景的沙盒让你在一个相对可控的复杂度内系统地演练现代Web开发的全套技能。无论是为了毕业设计、面试作品还是个人技术成长它都是一个绝佳的起点。2. 技术栈选型与项目架构解析为什么是Spring Boot Vue这个组合几乎成为了当前Java全栈开发的“标准答案”其优势在于成熟、稳定、生态丰富。2.1 后端技术栈 (Spring Boot)核心框架Spring Boot 2.x。它极大地简化了Spring应用的初始搭建和开发过程提供了自动配置、内嵌服务器等开箱即用的特性。数据持久层MyBatis-Plus。在MyBatis的基础上进行了增强提供了通用的CRUD操作无需编写简单的XML同时保留了MyBatis定制化SQL的灵活性。这对于快速开发业务逻辑非常友好。数据库MySQL。最流行的开源关系型数据库用于存储用户、歌曲、歌单等结构化数据。权限认证JJWT (Java JWT)。用于生成和解析JSON Web Token实现无状态的用户认证。其他Lombok简化Java Bean编写、Hutool工具类库、Spring Boot DevTools热部署。2.2 前端技术栈 (Vue)核心框架Vue 2.x 或 3.x。本项目通常基于Vue 2的生态系统因其生态更稳定。Vue提供了响应式数据绑定和组件化开发是构建用户界面的理想选择。构建工具Vue CLI。官方脚手架可以快速初始化项目结构、集成Webpack等构建工具。UI组件库Element UI (对应Vue 2) 或 Element Plus (对应Vue 3)。提供丰富的桌面端UI组件如表格、表单、对话框等能极大提升开发效率。路由Vue Router。管理单页面应用SPA的路由。状态管理Vuex。集中管理所有组件的共享状态如当前登录用户信息、播放器状态等。HTTP客户端Axios。用于向后端发起HTTP请求支持Promise API易于使用。音频播放可能使用原生audio或第三方播放器库如APlayer。2.3 前后端分离架构图一个典型的前后端分离音乐网站架构如下用户浏览器 | | (HTTP/HTTPS) v [Nginx / 对象存储] (部署前端静态资源: HTML, CSS, JS) | | (API请求) v [Spring Boot 应用] (运行在Tomcat/Jetty上) | | (JDBC) v [MySQL 数据库]开发阶段前端运行在localhost:8080后端运行在localhost:8888。前端通过Axios请求后端API需要配置代理解决跨域问题。部署阶段前端代码打包成静态文件dist目录可以部署到Nginx服务器或云对象存储如阿里云OSS。后端打包成可执行的JAR文件部署到云服务器。Nginx同时可以作为反向代理将API请求转发到后端服务。3. 环境准备与项目初始化在开始编码前请确保你的开发环境已就绪。3.1 后端环境准备JDK:安装 JDK 8 或更高版本推荐 JDK 11 或 17LTS版本。配置好JAVA_HOME环境变量。Maven:安装 Maven 3.6用于管理项目依赖和构建。IDE:推荐使用 IntelliJ IDEA社区版或旗舰版或 Eclipse需安装Spring插件。MySQL:安装 MySQL 5.7 或 8.0并启动服务。创建一个名为music_website的数据库字符集建议utf8mb4。3.2 前端环境准备Node.js:安装 Node.js推荐 LTS 版本如 16.x, 18.x。它自带了npm包管理器。Vue CLI:在命令行中全局安装 Vue CLI。npm install -g vue/cli # 或使用 yarn # yarn global add vue/cliIDE:推荐使用 Visual Studio Code并安装Vetur、ESLint等插件。3.3 项目结构预览从GitHub或Gitee克隆或下载项目源码后你会看到两个独立的文件夹music-website/ ├── backend/ # Spring Boot 后端项目 │ ├── src/ │ ├── pom.xml │ └── ... └── frontend/ # Vue 前端项目 ├── public/ ├── src/ ├── package.json └── ...4. 后端核心模块与数据库设计后端的核心是提供一套完整的RESTful API。我们首先从数据库设计开始。4.1 核心数据表设计简化版一个基本的音乐网站至少需要以下表user(用户表):id,username,password(加密存储),avatar,create_timesinger(歌手表):id,name,pic,birth,location,introductionsong(歌曲表):id,singer_id,name,album,duration,url(音乐文件地址),pic(封面图地址),lyric(歌词文件地址),create_timesong_list(歌单表):id,title,pic,style(风格),introduction,creator_id(关联user.id)list_song(歌单-歌曲关联表):id,song_id,song_list_id。这是一个典型的多对多关系中间表。collect(收藏表):id,user_id,type(收藏类型0歌曲1歌单),song_id/song_list_id,create_time4.2 使用MyBatis-Plus快速生成代码MyBatis-Plus的代码生成器可以极大提升效率。你需要一个CodeGenerator类。// 文件路径backend/src/main/java/com/yourname/generator/CodeGenerator.java import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.config.*; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; public class CodeGenerator { public static void main(String[] args) { // 1. 创建代码生成器对象 AutoGenerator mpg new AutoGenerator(); // 2. 全局配置 GlobalConfig gc new GlobalConfig(); String projectPath System.getProperty(user.dir); gc.setOutputDir(projectPath /src/main/java); gc.setAuthor(YourName); // 设置作者 gc.setOpen(false); // 生成后不打开文件夹 gc.setFileOverride(true); // 覆盖已生成文件 gc.setServiceName(%sService); // 去掉Service接口的首字母I gc.setIdType(IdType.AUTO); // 主键策略 gc.setSwagger2(true); // 开启Swagger注解 mpg.setGlobalConfig(gc); // 3. 数据源配置 DataSourceConfig dsc new DataSourceConfig(); dsc.setUrl(jdbc:mysql://localhost:3306/music_website?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai); dsc.setDriverName(com.mysql.cj.jdbc.Driver); dsc.setUsername(root); dsc.setPassword(yourpassword); dsc.setDbType(DbType.MYSQL); mpg.setDataSource(dsc); // 4. 包配置 PackageConfig pc new PackageConfig(); pc.setParent(com.yourname.music); // 父包名 pc.setModuleName(); // 模块名如果没有就空着 pc.setEntity(model); pc.setMapper(dao); pc.setService(service); pc.setController(controller); mpg.setPackageInfo(pc); // 5. 策略配置 StrategyConfig strategy new StrategyConfig(); strategy.setInclude(user, singer, song, song_list, list_song, collect); // 要生成的表名 strategy.setNaming(NamingStrategy.underline_to_camel); // 数据库表映射到实体的命名策略 strategy.setColumnNaming(NamingStrategy.underline_to_camel); strategy.setEntityLombokModel(true); // 使用Lombok strategy.setRestControllerStyle(true); // RestController风格 strategy.setControllerMappingHyphenStyle(true); // URL中驼峰转连字符 mpg.setStrategy(strategy); // 6. 执行生成 mpg.execute(); } }运行此生成器会在指定包下生成Entity,Mapper,Service,Controller等层的基础代码你只需要在此基础上添加业务逻辑即可。4.3 实现用户登录与JWT认证这是前后端分离项目的安全基石。1. 添加JWT依赖 (pom.xml):dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt/artifactId version0.9.1/version /dependency2. 创建JWT工具类:// 文件路径backend/src/main/java/com/yourname/music/utils/JwtUtil.java Component public class JwtUtil { // 密钥应从配置文件中读取此处为示例 private static final String SECRET_KEY your-secret-key-change-in-production; // 过期时间例如7天 private static final long EXPIRATION 604800L; public static String generateToken(String username) { MapString, Object claims new HashMap(); claims.put(username, username); return Jwts.builder() .setClaims(claims) .setSubject(username) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() EXPIRATION * 1000)) .signWith(SignatureAlgorithm.HS512, SECRET_KEY) .compact(); } public static Claims parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody(); } public static boolean validateToken(String token) { try { parseToken(token); return true; } catch (Exception e) { return false; } } }3. 创建登录接口 (LoginController.java):// 文件路径backend/src/main/java/com/yourname/music/controller/LoginController.java RestController RequestMapping(/user) public class LoginController { Autowired private UserService userService; PostMapping(/login) public Result login(RequestBody MapString, String loginForm) { String username loginForm.get(username); String password loginForm.get(password); // 1. 验证用户名密码 (密码需加密比对此处简化) QueryWrapperUser queryWrapper new QueryWrapper(); queryWrapper.eq(username, username); User user userService.getOne(queryWrapper); if (user null || !user.getPassword().equals(DigestUtils.md5DigestAsHex(password.getBytes()))) { return Result.error(用户名或密码错误); } // 2. 生成JWT Token String token JwtUtil.generateToken(username); // 3. 返回用户信息剔除密码和Token MapString, Object data new HashMap(); user.setPassword(null); data.put(user, user); data.put(token, token); return Result.success(登录成功, data); } }4. 创建JWT认证拦截器 (JwtInterceptor.java):// 文件路径backend/src/main/java/com/yourname/music/interceptor/JwtInterceptor.java Component public class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 从请求头中获取token String token request.getHeader(Authorization); // 如果是预检请求OPTIONS或登录注册等公开接口直接放行 if (OPTIONS.equals(request.getMethod())) { return true; } String uri request.getRequestURI(); if (uri.contains(/user/login) || uri.contains(/user/register)) { return true; } // 验证token if (token null || !JwtUtil.validateToken(token)) { response.setStatus(HttpStatus.UNAUTHORIZED.value()); response.getWriter().write({\code\: 401, \msg\: \Token无效或已过期\}); return false; } // 将用户信息存入请求方便后续使用 Claims claims JwtUtil.parseToken(token); request.setAttribute(username, claims.getSubject()); return true; } }5. 注册拦截器 (WebConfig.java):// 文件路径backend/src/main/java/com/yourname/music/config/WebConfig.java Configuration public class WebConfig implements WebMvcConfigurer { Autowired private JwtInterceptor jwtInterceptor; Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor) .addPathPatterns(/**) // 拦截所有请求 .excludePathPatterns(/user/login, /user/register, /song/audio/**); // 排除公开路径 } // 配置跨域重要 Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) // 生产环境应指定具体前端地址 .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }5. 前端核心功能与组件实现前端负责将后端API提供的数据呈现给用户并处理复杂的交互逻辑。5.1 项目初始化与配置使用Vue CLI创建项目并安装核心依赖。# 在 frontend 目录下 vue create . # 选择默认配置或手动选择 (Babel, Router, Vuex, CSS Pre-processors) cd frontend npm install element-ui axios vuex vue-router npm install aplayer --save # 如果使用APlayer播放器配置前端开发环境代理 (vue.config.js):解决开发时的跨域问题。// 文件路径frontend/vue.config.js module.exports { devServer: { proxy: { /api: { target: http://localhost:8888, // 你的后端地址 changeOrigin: true, pathRewrite: { ^/api: // 重写路径去掉 /api 前缀 } } } } }这样前端在开发时请求/api/user/login会被代理到http://localhost:8888/user/login。5.2 实现用户登录页面与状态管理1. 创建Vuex Store管理用户状态 (store/index.js):// 文件路径frontend/src/store/index.js import Vue from vue import Vuex from vuex import axios from axios import { Message } from element-ui Vue.use(Vuex) export default new Vuex.Store({ state: { user: JSON.parse(localStorage.getItem(user)) || null, token: localStorage.getItem(token) || }, mutations: { SET_USER(state, user) { state.user user localStorage.setItem(user, JSON.stringify(user)) }, SET_TOKEN(state, token) { state.token token localStorage.setItem(token, token) // 将token设置到axios的默认请求头 if (token) { axios.defaults.headers.common[Authorization] token } else { delete axios.defaults.headers.common[Authorization] } }, LOGOUT(state) { state.user null state.token localStorage.removeItem(user) localStorage.removeItem(token) delete axios.defaults.headers.common[Authorization] } }, actions: { async login({ commit }, loginForm) { try { const response await axios.post(/api/user/login, loginForm) if (response.data.code 200) { const { user, token } response.data.data commit(SET_USER, user) commit(SET_TOKEN, token) Message.success(登录成功) return true } else { Message.error(response.data.msg || 登录失败) return false } } catch (error) { Message.error(网络请求失败) return false } }, logout({ commit }) { commit(LOGOUT) Message.success(已退出登录) } } })2. 创建登录组件 (Login.vue):!-- 文件路径frontend/src/views/Login.vue -- template div classlogin-container el-form refloginForm :modelloginForm :rulesloginRules classlogin-form h2音乐网站登录/h2 el-form-item propusername el-input v-modelloginForm.username placeholder请输入用户名/el-input /el-form-item el-form-item proppassword el-input v-modelloginForm.password typepassword placeholder请输入密码/el-input /el-form-item el-form-item el-button typeprimary clickhandleLogin :loadingloading stylewidth:100%登录/el-button /el-form-item /el-form /div /template script export default { name: Login, data() { return { loginForm: { username: , password: }, loginRules: { username: [{ required: true, message: 请输入用户名, trigger: blur }], password: [{ required: true, message: 请输入密码, trigger: blur }] }, loading: false } }, methods: { handleLogin() { this.$refs.loginForm.validate(async (valid) { if (valid) { this.loading true const success await this.$store.dispatch(login, this.loginForm) this.loading false if (success) { this.$router.push(/) // 登录成功后跳转到首页 } } }) } } } /script style scoped .login-container { display: flex; justify-content: center; align-items: center; height: 100vh; background: #f0f2f5; } .login-form { width: 400px; padding: 40px; background: #fff; border-radius: 8px; box-shadow: 0 2px 12px rgba(0,0,0,0.1); } /style5.3 实现音乐播放器组件播放器是音乐网站的灵魂。这里以集成APlayer为例。1. 在Vue中集成APlayer:!-- 文件路径frontend/src/components/Player.vue -- template div classplayer-wrapper !-- APlayer容器 -- div idaplayer/div /div /template script import APlayer from aplayer import aplayer/dist/APlayer.min.css import { mapState } from vuex export default { name: MusicPlayer, data() { return { player: null, audioList: [] // 播放列表格式[{name: 歌曲名, artist: 歌手, url: 音频地址, cover: 封面图}] } }, computed: { ...mapState([currentSong]) // 假设从Vuex中获取当前播放歌曲 }, watch: { currentSong(newSong) { if (newSong this.player) { // 切换歌曲逻辑 this.player.list.add([{ name: newSong.name, artist: newSong.singerName, url: /api${newSong.url}, // 拼接后端API地址 cover: /api${newSong.pic} }]) this.player.play() } } }, mounted() { this.initPlayer() // 从Vuex或API初始化播放列表 this.fetchPlaylist() }, beforeDestroy() { if (this.player) { this.player.destroy() } }, methods: { initPlayer() { this.player new APlayer({ container: document.getElementById(aplayer), fixed: true, // 固定模式 autoplay: false, audio: this.audioList }) // 监听播放事件可以同步歌词等 this.player.on(play, () { console.log(播放开始) }) }, async fetchPlaylist() { // 调用API获取默认播放列表或用户歌单 try { const response await this.$axios.get(/api/song/list/recommend) if (response.data.code 200) { this.audioList response.data.data.map(song ({ name: song.name, artist: song.singerName, url: /api${song.url}, cover: /api${song.pic} })) if (this.player) { this.player.list.clear() this.player.list.add(this.audioList) } } } catch (error) { console.error(获取播放列表失败, error) } } } } /script6. 前后端联调与项目运行6.1 启动后端服务确保MySQL服务已启动并已创建music_website数据库。在backend目录下使用Maven导入依赖。修改application.yml或application.properties中的数据库连接配置。# backend/src/main/resources/application.yml spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/music_website?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: yourpassword servlet: multipart: max-file-size: 10MB # 设置文件上传大小限制 max-request-size: 10MB mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印SQL调试用找到主启动类如MusicApplication.java运行它。控制台看到Tomcat started on port(s): 8888即表示启动成功。6.2 启动前端服务在frontend目录下安装依赖npm install。运行开发服务器npm run serve。浏览器访问http://localhost:8080默认端口应该能看到前端页面。6.3 测试登录功能在前端登录页面输入用户名和密码需要先在数据库user表中插入一条测试数据密码记得用MD5加密。点击登录观察浏览器开发者工具的Network标签页。应该能看到一个POST请求发送到/api/user/login状态码为200。响应体中应包含token和user信息。后续的API请求请求头Authorization中应自动携带了这个token。登录成功后页面应跳转至首页。7. 常见问题与排查思路在开发过程中你几乎一定会遇到以下问题。这里提供清晰的排查路径。问题现象可能原因排查方式解决方案前端访问后端API报错4041. 后端服务未启动。2. 后端API路径写错。3. 前端代理配置错误。1. 检查后端控制台是否启动成功。2. 用Postman直接测试后端API (http://localhost:8888/xxx)。3. 检查vue.config.js中的proxy配置。1. 启动后端。2. 修正API路径。3. 确保代理目标地址正确。前端报跨域错误CORS1. 后端未配置跨域支持。2. 前端请求未走代理生产环境问题。1. 检查后端WebConfig中的addCorsMappings配置。2. 检查请求URL是否包含/api前缀开发环境。1. 确保后端CORS配置允许前端源。2. 生产环境需通过Nginx配置代理或后端直接配置允许生产域名。登录成功但后续请求报4011. Token未正确设置到请求头。2. Token已过期。3. 后端拦截器路径排除配置有误。1. 检查浏览器开发者工具Network看请求头是否有Authorization。2. 检查Vuex中SET_TOKENmutation是否正确设置了axios默认头。3. 检查后端拦截器逻辑。1. 确保登录后正确保存和设置Token。2. 实现Token刷新机制或提示用户重新登录。3. 检查公开接口路径是否被正确排除。文件如图片、音频无法访问1. 文件路径错误或文件不存在。2. 后端未配置静态资源映射。3. 文件上传后路径未正确保存到数据库。1. 直接浏览器访问文件URL看是否可下载。2. 检查后端是否将上传目录映射为静态资源路径。1. 在Spring Boot中配置静态资源映射spring.web.resources.static-locationsfile:/your/upload/path/2. 确保数据库存储的是相对路径或可访问的完整URL。MyBatis-Plus查询结果为空1. 数据库表字段名与实体类属性名未正确映射下划线转驼峰。2. 查询条件QueryWrapper构建错误。1. 开启MyBatis-Plus SQL日志查看实际执行的SQL。2. 检查实体类TableField注解。1. 确认全局配置map-underscore-to-camel-case: true。2. 使用QueryWrapper时注意条件字段名是数据库列名。Vue页面数据不更新1. 数据不是响应式的。2. 异步操作未正确处理。1. 检查Vue Devtools查看组件数据状态。2. 在mounted或方法中使用this.$forceUpdate()测试。1. 确保在data()中声明初始数据。2. 对于数组/对象使用Vue.set或数组的变更方法如push。3. 使用async/await或.then()处理异步请求。8. 项目部署与生产环境最佳实践将项目部署到服务器才是真正的完结。这里给出一个简单的部署思路。8.1 后端部署打包在backend目录下执行mvn clean package -DskipTests会在target目录生成一个可执行的xxx.jar文件。上传将JAR包上传到云服务器如CentOS/Ubuntu。运行在服务器上使用nohup或systemd运行Jar包。# 简单运行 nohup java -jar your-music-backend.jar --server.port8888 app.log 21 # 使用systemd管理更规范 # 创建服务文件 /etc/systemd/system/music-backend.service配置生产环境的数据库连接、JWT密钥、文件上传路径等敏感信息应使用application-prod.yml外部配置文件或环境变量管理切勿硬编码在代码中。8.2 前端部署构建在frontend目录下执行npm run build生成dist文件夹里面是压缩优化后的静态资源。上传将dist文件夹内的所有文件上传到Nginx的HTML目录如/usr/share/nginx/html或云对象存储。Nginx配置配置Nginx同时服务前端静态文件和反向代理后端API。# /etc/nginx/conf.d/music.conf server { listen 80; server_name your-domain.com; # 你的域名或IP # 前端静态资源 location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; # 支持Vue Router的history模式 } # 反向代理后端API location /api/ { proxy_pass http://localhost:8888/; # 后端服务地址 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # 代理静态资源文件如图片、音频 location /file/ { proxy_pass http://localhost:8888/; # 指向后端静态资源映射 } }重启Nginxsudo systemctl restart nginx。8.3 安全与优化建议API安全对敏感操作如删除、修改进行权限校验对用户输入进行严格的校验和过滤防止SQL注入和XSS攻击。密码存储绝对不要明文存储密码。使用BCrypt等强哈希算法加盐存储。文件上传限制上传文件类型、大小对上传的文件进行病毒扫描使用对象存储服务如OSS、COS是更好的选择能减轻服务器压力。数据库为常用查询字段建立索引定期进行数据备份。日志配置完整的日志记录便于问题排查。使用Logback或Log4j2区分不同级别和输出。监控简单的服务器监控可以使用htop,nmon。对于应用监控可以考虑Spring Boot Actuator。通过以上步骤你已经完成了一个具备核心功能的Spring Boot Vue前后端分离音乐网站从开发到部署的全过程。这个项目麻雀虽小五脏俱全涵盖了认证授权、RESTful API、数据库操作、文件处理、前端状态管理、组件化开发、第三方库集成以及生产部署等关键技能点。建议你在理解的基础上进行扩展例如添加歌曲搜索、热门推荐、用户动态、管理员后台等功能让它真正成为你技术履历中一个亮眼的作品。