做音乐平台这类项目,最难的不是某个功能写不出来,而是整个技术栈串起来之后,各种版本、配置、跨域、播放器兼容的问题一起冒出来,让人怀疑人生。基于javaweb和mysql的springboot精美网上音乐平台,前后端分离架构,用的是一套最经典的组合:SpringBoot做后端服务,SSM(Spring+SpringMVC+MyBatis)做业务底座,Vue搭建前端页面,MySQL存数据,Maven管理整个构建流程。这几乎是Java全栈项目里最标准的一条技术路线,也是很多课程设计和毕业设计的首选,因为它覆盖面够广、难度适中、能展示的东西足够多。这篇文章我会把这个项目从架构设计到表结构、从后端接口到前端页面、从部署上线到问题排查整个过程完整梳理一遍,想自己动手做一个音乐平台项目的朋友,可以对照着走,能少踩不少坑。
1. 项目整体设计与架构拆解
1.1 前后端分离的本质
先把前后端分离这个概念掰开揉碎说清楚。传统JavaWeb项目是JSP页面直接渲染数据,后端既要处理业务逻辑又要输出HTML,前后端代码搅在一起,一旦页面结构调整,后端代码跟着动,维护成本极高。前后端分离则把两端彻底切开:后端只提供JSON格式的RESTful接口,前端通过Ajax或Axios去调用这些接口,各自独立开发、独立部署。
在这个音乐平台里,后端跑在8080端口,前端由Vue开发,开发阶段跑在5173或8081端口,上线后把前端打包成静态文件放到Nginx里,再由Nginx做反向代理,把 /api 开头的请求转发给后端服务。两层应用通过HTTP协议通信,数据格式统一用JSON,这就带来了一个关键优势——两边的开发完全可以并行,后端不用等前端页面做完,前端也可以用Mock数据先把页面效果调出来。
但分离也带来了额外的问题,最典型的就是跨域。前端在5173端口,后端在8080端口,浏览器会认为这不是同一个源,直接请求会被拦截。解决办法有几种:后端加CORS配置、前端用代理转发、或者生产环境靠Nginx反代。我在这个项目里采用的是后端全局CORS加前端开发环境代理的双保险方案,开发调试时走Vue的代理,不会出现跨域问题,打包上线走Nginx代理,也不会有跨域问题。
1.2 技术栈选型的底层逻辑
为什么用SpringBoot而不是直接裸用SSM?最直接的原因是配置量。传统SSM项目需要大量XML配置,数据源、事务管理器、MyBatis映射都要手工声明,SpringBoot把这些全部自动化,开箱即用,而且提供了一套非常完善的自动配置机制。但注意,SpringBoot本身并没有替代SSM,它只是把Spring核心、SpringMVC和MyBatis整合到了一起,所以这个项目的技术栈叫“SpringBoot+SSM”才是准确的。
Vue选型方面的考虑也是一样的。Vue的核心优势是组件化,一个页面拆成组件树,每个组件有自己的模板、样式和逻辑,互不干扰。音乐平台这种交互密集的项目,歌单列表、播放器、搜索框、评论区域,每个模块独立成组件,后续维护只需要定位到对应组件,不用在几百行的HTML里翻找。Vue还支持单文件组件(SFC),模板、脚本、样式写在一个 .vue 文件里,结构非常清晰。
MySQL在这个项目里承担了全部数据持久化的职责,音乐信息、用户账号、歌单关联、评论记录、收藏关系都落在关系型表里。这类业务数据之间的关联性强,用MySQL的事务保证数据一致性完全够用,没必要引入非关系型数据库增加复杂度。
Maven的作用则是把整个构建流程标准化,依赖管理、生命周期控制、项目打包全部交给它。SpringBoot项目的依赖数量非常多,版本兼容问题也极其容易踩雷,比如SpringBoot 2.x和3.x的差异就很大,Maven能统一管住这些依赖,哪个版本出问题,改一下 pom.xml 就能解决。
1.3 功能模块规划
一个完整的音乐平台需要哪些功能?我按使用者的视角把需求拆成了两大块:
普通用户端:注册登录、浏览歌单、搜索歌曲、试听歌曲、收藏歌曲、发布评论、查看排行榜、管理个人中心。
管理员端:歌曲信息管理(增删改查)、歌手管理、歌单管理、用户管理、评论审核。
做课程设计或毕业设计的时候特别容易犯一个错误——上来就写代码,功能东一榔头西一棒子。正确的做法是先画功能导图,把每个模块的页面、接口、数据表对应起来,形成一张清晰的开发地图。在这个项目里,我先把页面路由定出来,再把每个页面需要的接口列出来,接口需要的表和字段标出来,最后才动手建项目和数据库,整个开发过程顺畅了很多。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据库设计与持久层实现
2.1 核心表结构拆解
音乐平台的数据库设计,核心是搞清楚实体之间的关系。我用的是InnoDB引擎,字符集utf8mb4,排序规则utf8mb4_unicode_ci。utf8mb4非常关键,如果只用utf8,用户评论里输入一个Emoji表情,数据库会直接报错,因为Emoji是四字节字符,utf8存不了。这个细节在这个项目里几乎必然遇到,因为音乐软件的评论区怎么可能没有表情。
核心表大概七八张:
用户表(t_user):用户ID主键、用户名、密码(MD5加盐存储)、头像地址、注册时间。密码不能明文存,这一点没有商量的余地。
歌手表(t_singer):歌手ID、姓名、性别、头像、简介、地区。一首歌必须关联到歌手,这样在歌手详情页才能拉出该歌手的全部作品。
歌曲表(t_song):歌曲ID、歌曲名、歌手ID(外键)、专辑名、歌曲时长、歌曲文件地址、封面图地址、播放量、歌词内容。音频文件不要直接存数据库的BLOB字段,存文件路径,文件本身放在服务器或者OSS上,数据库只存URL,否则数据库体积会爆炸。
歌单表(t_song_list):歌单ID、歌单名称、创建用户ID、封面、描述。歌单是音乐平台最有粘性的模块,用户自己创建歌单,往歌单里添加喜欢的歌。
歌单歌曲关联表(t_song_list_detail):ID、歌单ID、歌曲ID。为什么要单独的关联表?因为歌单和歌曲是多对多关系,一首歌可以出现在多个歌单里,一个歌单也可以包含多首歌,这必须有中间表来解耦。
收藏表(t_favorite):ID、用户ID、歌曲ID、收藏时间。收藏功能本质上是用户和歌曲的映射关系。
评论表(t_comment):ID、歌曲ID、用户ID、评论内容、评论时间、点赞数。评论区的实现要点是最近评论优先,并在歌曲详情页按歌曲ID分页查询。
这七八张表之间的外键关系,用一把关联查询就串起来了。我建议表字段设计阶段就统一命名规范,主键统一叫 id,表名统一加 t_ 前缀,字段名用小写加下划线,这样后续写SQL和Java实体映射的时候心里有数,不会混乱。
2.2 MyBatis与数据访问层的细节
持久层我选用的是MyBatis而不是Spring Data JPA。原因很简单,MyBatis的SQL是手写的,虽然多了些工作量,但完全可控,尤其是多表关联查询和动态SQL,写起来非常灵活,性能也容易把控。JPA虽然省事,但遇到复杂查询需要拼接JPQL,调试起来远没有直接看SQL方便。
MyBatis的使用要点有几个:
第一个是配置。在SpringBoot中引入 mybatis-spring-boot-starter,然后在 application.yml 里配置Mapper接口扫描路径和XML文件位置:
yaml复制mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.music.entity
configuration:
map-underscore-to-camel-case: true
map-underscore-to-camel-case 这个配置一定要开,它能把数据库字段下划线自动映射到Java实体类的驼峰属性,比如 song_name 映射到 songName,省掉一堆 resultMap 的重复配置。
第二个是XML中的SQL,得避免经典的 #{} 和 ${} 写错的问题。#{} 是预编译参数,传值安全可靠,能防止SQL注入;${} 是字符串拼接,直接把值替换进SQL,虽然个别场景需要它,比如动态排序字段,但正常业务查询一律用 #{},不要给黑客留机会。
第三个是分页。查歌曲列表、评论列表、歌单列表都需要分页,我用的PageHelper插件,引入依赖后在Mapper接口的查询方法前加一行 PageHelper.startPage(pageNum, pageSize),它会在SQL执行前自动拼接LIMIT语句,非常方便。但有个巨坑——PageHelper做多表关联查询时,统计总数的SQL偶尔会出错,尤其是带GROUP BY的查询。遇到这种情况,要么手写 count 查询,要么用 PageHelper 的 countSql 属性自定义计数SQL。
2.3 数据库初始化与实际数据插入
建库建表之后还得有数据,不然前端页面全是空的,联调效果感人。我当时的做法是写了一个数据初始化脚本,插入十几个歌手、几十首歌,覆盖流行、民谣、电子、古典几种风格,这样播放器、歌单、搜索、评论全都有验证数据。
这里要提一下歌曲文件怎么处理。开发阶段,我把MP3文件放在后端的 static/music/ 目录下,数据库里存相对路径,比如 /music/xxx.mp3,播放器直接拼上后端域名就能播放。这种做法简单直接,适合课程设计和个人项目。但如果你打算上线到云服务器,建议把音频放到对象存储里,数据库存完整URL,不然服务器的带宽和磁盘会被拖垮。
关于MySQL安装的问题,顺手也提一句,因为几乎每个新手都会在这卡住。Windows用户尽量下载MySQL Installer版本,它会帮你把服务注册、环境变量、配置文件都处理好。安装过程中如果出现“net start mysql 服务名无效”的错误,大概率是服务名不对,先用管理员权限打开命令行,执行 mysqld --install 把服务装上,再 net start mysql 启动。MySQL 5.7和8.0的安装方式有些差异,8.0默认加密插件是caching_sha2_password,如果你的JDBC驱动版本太旧,连接会报认证错误,需要把驱动升级到 mysql-connector-java 8.0以上版本。
3. 后端API设计与业务闭环
3.1 REST接口的规范实践
后端接口用RESTful风格设计,资源用名词定义,操作靠HTTP方法体现。用户资源对应 /api/user,歌曲资源对应 /api/song,歌单是 /api/songlist,评论是 /api/comment。查询用GET,新增用POST,修改用PUT,删除用DELETE,语义非常清晰。
实际的接口清单大概是这样的:
| 功能 | 请求方法 | 接口路径 | 说明 |
|---|---|---|---|
| 用户注册 | POST | /api/user/register | 用户名查重+密码加密入库 |
| 用户登录 | POST | /api/user/login | 校验账户密码,签发Token |
| 获取歌曲列表 | GET | /api/song/page | 分页+按类型筛选 |
| 获取歌曲详情 | GET | /api/song/ | 单曲详情+歌手信息 |
| 搜索歌曲 | GET | /api/song/search | 按歌名或歌手模糊搜索 |
| 创建歌单 | POST | /api/songlist | 当前用户创建歌单 |
| 歌单添加歌曲 | POST | /api/songlist/detail | 维护歌单和歌曲关系 |
| 收藏歌曲 | POST | /api/favorite | 收藏/取消收藏合一 |
| 发表评论 | POST | /api/comment | 登录后才允许评论 |
| 获取排行榜 | GET | /api/song/rank | 按播放量取Top10 |
统一响应结构这一点一定要做。我定义了一个Result类,包含三个字段:code(200成功/500失败/401未登录)、message(提示信息)、data(实际数据)。所有接口都返回这个结构,前端拿到之后先判断code,再取data。好处是异常状态可控,前端不用解析各种奇形怪状的返回体。
3.2 登录鉴权与核心业务实现
登录功能是项目的门面,也是安全性的第一道关口。密码存储用MD5加盐,盐值可以取用户名或随机字符串,跟密码拼接后再做摘要,配合加盐让彩虹表攻击基本失效。登录成功后,我用JWT签发一个Token返给前端,前端存到localStorage里,后续每次请求在请求头加上 Authorization: Bearer xxx,后端的拦截器拦截所有需要登录的接口,校验Token有效性。
JWT的实现有两种方式:自己手写解析逻辑,或者用Interceptors加一个框架工具类。我建议用SpringBoot的HandlerInterceptor做统一鉴权拦截,配置类里注册拦截器,放行登录、注册、歌曲列表这些公开接口,其余接口全部校验Token。这里要提个很多新手都会犯的错误——JWT的密钥不要硬编码在业务代码里,放到 application.yml 作为配置项,后续要更换密钥只需要改配置,不用重新编译。
核心业务里比较有意思的是搜索和排行榜。搜索用一条模糊查询搞定,SQL大概长这样:
sql复制SELECT s.*, sg.singer_name
FROM t_song s
LEFT JOIN t_singer sg ON s.singer_id = sg.id
WHERE s.song_name LIKE CONCAT('%', #{keyword}, '%')
OR sg.singer_name LIKE CONCAT('%', #{keyword}, '%')
排行榜则很简单,按播放量倒序排序取前十条。关键点是每次播放接口被调用时,要对歌曲的播放量字段做自增更新。我在播放接口里专门做了这个动作:前端点击播放按钮时,向后端发一个记录播放量的请求,后端执行 UPDATE t_song SET play_count = play_count + 1 WHERE id = #{id},把统计和业务解耦,不会因为统计失败导致播放功能异常。
3.3 事务与异常处理
音乐平台里哪些操作需要事务?最典型的是歌单添加歌曲,需要同时关联歌单和歌曲的关系。如果有人恶意传一个不存在的歌曲ID,或者歌单ID失效,加歌曲这个操作就得整个回滚。我在Service层加了 @Transactional(rollbackFor = Exception.class) 注解,一旦执行过程中抛出任何异常,数据库自动回滚,不会出现歌单记录存在但关联记录缺失的脏数据。
异常处理这块,我做了全局异常处理器,用 @RestControllerAdvice 配合 @ExceptionHandler 统一捕获异常,返回统一的Result结构。好处很多:首先,数据库查询异常、参数校验异常、业务逻辑异常,前端拿到的都是合法JSON结构,不会出现HTML错误页;再者,日志统一记录在AOP层,排查问题方便。
4. 前端Vue项目搭建与页面实现
4.1 环境配置与项目初始化
前端这块我用的是Vue 3加Vite来搭项目,相比Vue 2的webpack方案,Vite开发服务器启动速度简直天壤之别。环境准备阶段,先把Node.js装好,再装Vite。Node版本要注意一下,Vite 3以上版本要求Node.js 14.18+以上,如果你本机还是Node 12的老版本,跑 npm run dev 会直接报语法错误。
安装依赖的坑主要集中在版本不兼容上。Vue 3项目里,路由用Vue Router 4,状态管理用Pinia而不是Vuex 4,UI组件库如果用Element Plus,注意它只兼容Vue 3。我见过太多人把Vue 2时代的Element UI装进Vue 3项目,然后控制台刷一片红色报错,还搞不清楚为什么。
项目结构我按功能模块划分,src/api 放接口请求,src/router 放路由配置,src/store 放全局状态,src/views 放页面组件,src/components 放通用组件。这样划分的好处是结构清晰、职责单一,后续新成员接手代码,扫一遍目录结构就能知道每个文件是干什么的。
前端工程化里有一个所有人都绕不开的痛处——造了一个项目,想发给朋友或导师运行的时候怎么办。直接把项目文件夹发过去肯定不行,因为庞大的 node_modules 文件夹没人愿意传。正确的做法是把node_modules 和 dist 加入 .gitignore,只发送源码。对方拿到手后先 npm install 安装依赖,再 npm run dev 启动。如果你的项目有代理配置,记得把 vue.config.js 或 vite.config.js 里的代理一起发过去,不然朋友本地联调后端直接跨域。
js复制// vite.config.js 核心配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
server: {
port: 5173,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
})
这个代理配置的作用是:前端开发服务器收到 /api/xxx 的请求后,自动转发到 http://localhost:8080/api/xxx,浏览器看到的还是同源请求,完美解决开发阶段跨域。
4.2 路由设计与页面组件规划
音乐平台的页面结构大概是这样:首页展示推荐歌单和热门歌曲,歌单列表页展示全部歌单,歌单详情页展示歌单包含的歌曲列表,歌曲排行页按播放量排序,搜索页,用户登录注册页,个人中心页。
Vue Router配置路由时,我用了一套动态导入的懒加载方式:
js复制const routes = [
{ path: '/', component: () => import('../views/Home.vue') },
{ path: '/songlist/:id', component: () => import('../views/SongListDetail.vue') },
{ path: '/search', component: () => import('../views/Search.vue') },
{ path: '/login', component: () => import('../views/Login.vue') }
]
动态导入让路由对应的组件在访问时才加载,首屏会快不少。路由传参用 /:id 形式,组件里用 route.params.id 获取。切歌单详情页的时候,监听 route.params.id 的变化重新发起请求,这样同一个页面不会被重复渲染,数据还能实时刷新。
组件设计上最重要的全局组件是底部播放器。播放器的播放状态、歌曲列表、当前播放歌曲的索引这些数据,需要跨组件共享,传统写法是props多级透传,能传到人崩溃。我用了Pinia建了一个播放器Store,所有组件通过Store读写播放状态,播放按钮组件直接调用Store的 playSong 方法,歌曲列表和底部播放器自动同步,数据流非常清爽。
Vue插槽在这个项目里也派上了用场。歌单卡片这个组件在不同页面长得有细微差异,首页展示封面加名字,排行榜需要加排名数字徽标,歌单搜索需要加匹配关键词高亮。我在歌单卡片组件里预留了插槽,把这些差异的部分丢给父组件去填,组件自身只负责公共布局,一个组件吃遍所有页面。
4.3 音频播放器实现与媒体格式问题
音频播放是整个项目体验的重头戏,也是坑最多的地方。我用原生的 audio 标签配合HTML5 Audio API实现播放功能,没有引入重量级播放器库。核心逻辑是:Store里维护一个全局音频对象,所有组件共享同一个Audio实例,切换歌曲时更新Audio的src并调用play方法,同时监听播放时间、播放结束事件更新当前进度。
关于播放格式,有一个无数人踩坑的问题——浏览器原生播放支持MP3、WAV、OGG,但如果你接的视频或音频地址是M3U8格式的,浏览器不原生支持,需要引入hls.js库才能播放。音乐平台的音频文件基本都是MP3格式,直接播放没问题,但如果你顺手做视频预览功能,放了M3U8的链接,就会遇到播放不了的问题。我看到热搜里有 vue播放欢乐谷m.3u8 这个词,说明很多人都在这个坑里扑腾过。我的建议是,M3U8这类HLS流媒体格式,前端必须依赖 hls.js 做解析,并且要注意视频服务端要配好CORS,留本地文件是播不起来的。
播放进度条的显示,要通过 timeupdate 事件实时更新 currentTime,然后用 Math.floor(currentTime / duration * 100) 计算百分比绑定到遮罩宽度上。进度条拖动则要处理 change 事件,设置 audio.currentTime 为拖拽位置,这里要注意数据类型转换,别把字符串时间传给Audio对象。
播放按钮的图标切换也是个细节逻辑。不要直接用event监听播放状态来切换图标,因为音频加载中、缓冲中等状态下播放状态不可靠,要监听 play 和 pause 事件后再更新Store里的状态,UI才能准确反映真实播放情况。
4.4 接口对接与搜索交互
页面做好后跟后端对接接口,我用axios封装了一个统一请求模块,设置基础URL和请求拦截器。请求拦截器里从localStorage取出Token,添加到请求头;响应拦截器里统一处理状态码,401时跳转登录页,500时弹出错误消息提示。这样业务代码里就不用反复写错误处理逻辑。
前端调用接口的核心代码像这样:
js复制const api = axios.create({
baseURL: '/api',
timeout: 10000
})
api.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
搜索框的实时搜索体验要处理好。每敲一个字符就发一次请求太激进,键盘输入期间频繁切换关键词会不停刷新接口。我用防抖函数处理:用户停止输入300毫秒后才真正发起请求,既保证响应速度又避免了大量无效请求。
5. 常见问题与排查技巧实录
5.1 启动失败与应用报错速查
SpringBoot版本相关的坑。SpringBoot 2.7和3.x有一个重大分水岭。3.x是基于JDK 17的,改动了大量自动配置类的包名,如果你的JDK版本是8,老老实实用2.7版本,不要一上来就下载官网最新的SpringBoot 4,因为版本太高意味着你的JDK、Maven可能全部不满足要求,项目根本启动不了。新建项目时我建议直接用Spring Initializr,把JDK版本和SpringBoot版本选匹配好,SpringBoot 2.7对应JDK 8,3.x对应JDK 17。
数据库连接失败。报错 Communications link failure 或 Access denied for user,第一步检查MySQL服务有没有启动,Windows下执行 net start mysql 确认。第二步检查连接串的用户名密码和实际数据库是否匹配,特别注意 application.yml 里的密码不能有特殊字符,如果密码带 & 或 #,要做URL编码。第三步检查数据库连接池配置,SpringBoot 2.7默认的HikariCP连接超时时间较短,数据库启动速度慢会导致初始化失败,调大 connection-timeout 能解决。
前端报 tsconfig not found。这个错误出现在Vue 3 + TypeScript项目,本质是项目引用的 @vue/tsconfig 依赖没有正确安装,执行 npm install -D @vue/tsconfig 重新装一遍即可,Windows上常见原因是node_modules被误删或者路径过长导致安装中断。
5.2 跨域与Token过期的处理
跨域处理是前后端分离项目最容易卡住人的地方。前端启动后页面能加载,但一调接口就报跨域错误。排查思路按顺序来:先看浏览器控制台报错信息,是CORS错误还是404;是CORS错误就检查后端是否配置了CorsFilter或 @CrossOrigin,以及 allowedOriginPatterns 是否覆盖了前端地址。开发环境记得前端代理转发优先,后端CORS兜底。生产环境把前后端都挂在同一个域名下,用Nginx做路径分流,不存在跨域问题。
Token过期导致页面数据全挂也是高频问题。用户登录后Token有效期内一切正常,过期之后请求接口返回401,前端响应拦截器直接跳登录页。但如果在空白页面静默过期,突然跳登录页体验非常差。我的方案是后端在Token即将过期的时间段内,允许前端携带Token调用刷新接口拿到新Token,实现无感续期。课程设计做到这一步算加分项,但前面的基本功能全部跑通之后再优化这个点,优先级不要放太高。
5.3 数据库大小写与排序问题
MySQL表名和字段名在Windows上默认大小写不敏感,但在Linux服务器上区分大小写。我在本地Windows开发时表名全用小写,传到Linux上没问题的原因是在建表语句中都统一了小写。但是如果你在本地表名叫 User,Linux上报错找不到表,就是大小写不敏感和敏感的差异导致的。项目的表命名统一小写和双引号,可以避免这个问题。
搜索排序问题也值得一提。歌名模糊搜索按匹配度排序最优,最简单的做法是对SQL的匹配结果加上权重条件:完整匹配排最前面,以关键词开头次之,包含关键词排最后。用ORDER BY FIELD或CASE WHEN实现。不做这一步,搜索结果杂乱无章,搜索“可能”时先出来“不可能”,用户会觉得系统很傻。
5.4 部署上线的完整流程
本地开发调试通过后,部署上线又是一轮新的考验。后端打包执行 mvn clean package -DskipTests,生成 jar 包后用 java -jar 启动,生产环境注意把配置文件里的数据库地址改为服务器上的地址,日志路径改成绝对路径,端口按需调整。
前端打包执行 npm run build,生成 dist 目录,把dist里的静态文件扔到Nginx的 html 目录下,Nginx配置大致是这样:
nginx复制server {
listen 80;
server_name music.example.com;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://127.0.0.1:8080/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
这里有个关键点,前端路由用了history模式,刷新页面时Nginx需要把所有路径都指向 index.html,否则刷新某个子路由页面会404。try_files $uri $uri/ /index.html 就是干这个的。很多人前端访问首页没事,一刷新子页面就404,基本都是因为少了这一行配置。
结尾
做这个音乐平台项目,我个人体会最深的一点是:前后端分离的复杂度不在任何一个单一技术点上,而在所有技术点协同工作时的摩擦上。Vue组件写得再漂亮,后端接口返回的数据结构不规范,对接阶段照样抓狂;后端的接口再完善,前端请求拦截器的错误处理没写好,用户照旧看到白屏或一堆看不懂的报错。
如果让我给你的建议就一条:开发初期,先定一个简单的接口文档规范,把返回结构、状态码、错误信息的约定写清楚,前后端都照着它开发,对接过程的痛苦能减少八成。这个项目的代码、数据库脚本和环境配置,我建议你放在Git仓库里做好版本管理,每次解决一个棘手问题都写一句commit说明。从一个能跑的Demo到一个成熟的作品,就是在这一次次commit之间长出来的。
