带过不少学生把这个项目从零搭到答辩通过,今天索性把整个思路和实操过程完整写出来,不论你是准备拿它当毕业设计,还是纯粹想学SpringBoot3和Vue3的前后端分离开发,这篇内容都能帮你少走很多弯路。项目本身不复杂,核心就是一套标准的前后端分离商城:前端用Vue3 + Vite + Element Plus,后端用SpringBoot3 + MyBatis-Plus + MySQL,功能覆盖用户登录注册、商品分类展示、购物车管理、订单流程,以及后台的简单管理。整套流程走下来,你对前后端交互、接口设计、状态管理、路由权限这些关键知识点的理解会扎实很多,而且每个模块都能单独拿出来在面试里讲清楚。
1. 项目整体设计与技术选型思路
1.1 这套商城系统到底解决了什么问题
很多零基础的朋友一开始都会问,商城项目为什么这么受欢迎。说白了,商城系统是一个“麻雀虽小、五脏俱全”的典型业务场景。用户端你要处理商品信息的展示、购物车的增删改查、订单的下单和状态流转;管理端你要做商品的上架下架、分类的维护、订单的审核处理。这些功能几乎涵盖了Web开发中最常用到的CRUD操作,而且业务逻辑层层递进,从简单的单表查询到复杂的事务操作,都能在一个项目里练习到。
对于SpringBoot3和Vue3这两个技术栈来说,商城系统的契合度也特别高。SpringBoot3基于JDK17,引入了新的编程模型,比如Spring AOT编译、GraalVM支持、更好的响应式编程体验,你在项目中能感受到它启动更快、配置更简洁。Vue3则带来了Composition API、Teleport、Fragment等新特性,配合Vite的开发体验,热更新几乎秒级完成,写页面的时候相当舒服。
另外,商城系统正好把前后端分离开发的完整流程串起来了。你会有清晰的接口文档,有统一的响应结构,有JWT之类的鉴权机制,有跨域处理,有状态管理等。这些内容在纯后端项目或者纯前端项目里很难接触到,但是商城系统逼着你去面对,做一遍之后印象会非常深刻。
1.2 为什么选SpringBoot3 + Vue3而不是其他组合
很多学生在动手之前都会纠结,到底用SpringBoot2还是SpringBoot3,用Vue2还是Vue3,甚至要不要直接用若依这种脚手架。我的建议是,既然做项目是为了学习和应对毕业答辩,就用最新稳定的版本,也就是SpringBoot3搭配Vue3。
SpringBoot3相比2.x版本,最大的变化是强制要求JDK17起跳,并且基于Jakarta EE 9命名空间,原来javax开头的包名全部换成了jakarta。这个变化带来的好处是长期的技术支持和生态兼容性,毕竟新项目再用旧版本,后面维护起来会越来越麻烦。你可能担心网上资料少,实际上SpringBoot3的核心用法和2.x差不多,遇到问题知道是多版本带来的兼容性即可。
Vue3也一样,现在新项目再用Vue2,技术上等于给自己挖坑。Vue3的Composition API配合<script setup>语法糖,写业务代码比Options API舒服太多,逻辑复用也方便。而且现在组件库全面支持Vue3,Element Plus就是最典型的一个。如果你用Vue2,很多组件库已经停止维护,遇到BUG都没人管。
再说为什么不直接用若依或vue-element-admin这类脚手架。脚手架适合真正做项目的人快速起步,但是对学习者和毕设党是致命的,因为里面的代码很多是自动生成的,你今天删掉两行代码,可能就触发了一个隐藏的坑,而且问你某个功能怎么实现的时候,你根本答不上来。自己从零手写一套,架构上参考了这些开源项目的设计,但是每一行都能讲清楚,这才是项目经历应有的价值。
1.3 前后端分离架构的核心理解
说过很多次,前后端分离的核心不是两个项目分开写,而是“接口契约”的建立。前端只管页面显示和交互,后端只管数据逻辑和存储,两者通过JSON格式的数据进行通信。这个模式听起来简单,但实际操作中很多人会在这里翻车。
最常见的翻车方式有两种。第一种是前端页面写完了,发现后端接口还没写好,自己随便Mock了一些假数据,等联调的时候发现字段不对,又大改一遍。第二种是后端接口写完了,但是返回的JSON结构和前端期望的不一致,比如后端返回了{code:200,data:{name:"xxx"}},前端却拿着res.name去接,页面当然什么都不显示。
所以在这个项目中,我强烈建议你先定义好统一的返回结构。比如后端所有接口都返回Result<T>,包含三个字段:code表示状态码,msg表示提示信息,data表示具体数据。前端在axios的响应拦截器里统一处理这个结构,拿到res.code === 200才继续执行业务逻辑。这样一个简单的约定,可以让前后端联调少掉一半的坑。
另外一个核心概念是接口文档。这里不要求你专门去搭建Swagger或者Knife4j,但是至少要在项目的接口定义上保持清晰,类名、方法名、参数名要见名知义。我习惯在Controller层直接把注释写好,包括接口用途、请求参数说明、返回结果说明。后面写前端的时候,对着后端代码就能把接口调对,不需要反复问别人。
2. 起步前的环境准备与工程初始化
2.1 后端工程搭建的全过程
后端我选择用Spring Initializr来创建工程,你可以直接访问start.spring.io,也可以在自己IDE里操作。这里有几个关键选项需要注意。
Java版本选择17,这是SpringBoot3的最低要求。如果本机还没装JDK17,先去Oracle官网下载安装,安装完记得在环境变量里把JAVA_HOME指到新版本。有时候你之前装过JDK8,即使JAVA_HOME改好了,项目里还是识别不出来,多半是IDE里的配置引用了旧路径,检查一下Eclipse或IDEA的Project Structure。
Spring Boot版本选择3.x的最新稳定版。在Dependencies里勾选这几个模块:Spring Web、Spring Security(如果你打算做JWT鉴权)、MyBatis框架的依赖需要手动加、MySQL Driver、Lombok、Validation。另外我习惯加上一个AOP依赖,因为后面要写统一的日志切面,虽然不是必需,但加上没坏处。
创建完成之后先做三件事。第一件事是改配置文件,把application.properties改成application.yml,后面所有的配置都用YAML格式写,更清晰也更好维护。第二件事是写一个基础的Result<T>返回类,放在common包下。第三件事是配置全局的跨域,在SpringBoot3里可以通过实现WebMvcConfigurer接口,重写addCorsMappings方法来完成。
这里提醒一下,SpringBoot3的跨域配置和SpringBoot2差别不大,但如果你开启了Spring Security,跨域配置的位置要特别注意,过滤器链里也要放行OPTIONS请求,否则前端联调时会遇到"Access-Control-Allow-Origin"报错,这个问题我在后面章节会详细讲。
2.2 前端工程搭建与Vite使用心得
前端这块直接用Vite创建,命令是npm create vite@latest,然后在交互式命令行里选择Vue框架、JavaScript语法(如果你的基础够好可以试TypeScript,但零基础的同学先用JS把流程跑通,TS后面再迭代替换)。
Vite比Webpack快非常多,原因是它基于ESModule,开发时只对修改后的文件做编译,而不是像Webpack那样打包整个项目。这个速度体验在写大项目时特别明显,基本上保存后浏览器里马上就能看到效果。
创建好之后,我需要你额外安装几个依赖。vue-router是必须的,做路由管理。pinia负责状态管理,轻量而且和Vue3的Composition API配合得很舒服。axios用来发HTTP请求。UI组件库我推荐Element Plus,它的组件丰富度在Vue3生态里是数一数二的,而且一直在维护更新。
安装命令一并写出:
npm install vue-router@4 pinia axios element-plus @element-plus/icons-vue在main.js里完成全局注册,不要每个组件单独引入,效率太低。Element Plus的中文语言包也要在入口处配置好,否则日期组件等显示的是英文。
2.3 数据库表设计
表设计是整个项目的基石,我见过太多人一上来就写代码,最后发现表结构不合理,代码写了一半推倒重来。这套酒类商城系统的数据表设计,我是按这个思路来的。
用户表sys_user是最基础的,字段包括主键id、用户名username、密码password(这里我强烈建议用BCrypt加密存储)、昵称nickname、手机号phone、头像avatar、创建时间create_time这几个字段。如果有多个角色,还要加一个role字段区分管理员和普通用户。
商品分类表category和商品表product是核心业务表。分类表有id、name、sort(排序权重)。商品表字段相对多:id、category_id、name、description、price(价格,注意用DECIMAL类型而不是DOUBLE,避免精度丢失)、stock(库存)、image(商品主图)、status(上下架状态)、sales(销量)、create_time。这里有一个重要的设计细节,商品表通过category_id和分类表关联,查询某个分类下的商品时,用where category_id = ?即可,不需要冗余存分类名称。
购物车表cart字段有id、user_id、product_id、quantity、create_time。订单相关表稍微复杂一点,我拆成了主表orders和明细表order_item。orders表记录一笔订单的整体信息,包括id、order_no(订单编号)、user_id、total_amount、status、create_time。order_item表记录这笔订单里的每项商品信息,包括id、order_id、product_id、product_name、product_image、price、quantity。为什么要冗余product_name和product_image?因为订单生成后商品信息可能会修改或下架,订单详情里保留下单时刻的快照,才能确保历史订单始终呈现正确信息。
首页轮播图表banner和系统配置表sys_config这种锦上添花的表,建议学有余力再加,初期不用追求全,先把主干跑通。
3. 后端核心功能实现
3.1 统一返回结果与全局异常处理
这套代码设计是你整个项目的门面,也是面试时最容易突出亮点的地方。先定义一个Result<T>类,放在common包下,内部维护三个字段:code、msg、data,并提供两个静态方法:Result.success(data)和Result.error(msg)。这样Controller层的代码就变成了:
@GetMapping("/list") public Result<List<Product>> list() { List<Product> list = productService.list(); return Result.success(list); }你想想,如果没有这个封装,每个接口都要单独处理ResponseBody的格式,代码重复率极高,而且前端对接时也没有一个统一的标准可循。
全局异常处理用@RestControllerAdvice来统一拦截异常。先定义一个业务异常类BizException继承RuntimeException,构造函数里接收错误信息和状态码。然后在@RestControllerAdvice标注的类里写两个方法:一个处理BizException,一个兜底处理Exception。这样做的目的是,业务逻辑里遇到参数校验失败、库存不足等情况,直接throw new BizException("库存不足"),前端就能收到格式统一的错误JSON,而不是一堆丑陋的异常堆栈。
最后一个细节是参数校验。SpringBoot3里可以用@Validated加@NotBlank这类注解来校验请求参数,省去手写一大堆if判断的代码。
3.2 用户登录注册与JWT鉴权
用户模块是第一个完整的业务闭环。注册逻辑很简单,前端提交用户名和密码,后端先检查用户名是否已存在,如果不存在就创建一个用户,密码用BCrypt加密后存入数据库。BCrypt的加密方式是单向的,每次生成的结果都不同,和原来的密码做比对用matches方法完成。
登录逻辑稍微复杂一些。验证密码通过后,需要生成一个Token返回给前端。Token方案我推荐JWT(JSON Web Token),它天然适合前后端分离的鉴权场景,服务端不需要存储会话状态,Token自包含用户信息,校验时只需要在服务端用密钥解开签名即可。
JWT的工具类建议自己封装。引入jjwt依赖后,核心方法就两个,一个是生成Token的方法:
public String generateToken(Long userId, String username, boolean isAdmin) { Date now = new Date(); Date expireDate = new Date(now.getTime() + 7 * 24 * 3600 * 1000); return Jwts.builder() .setSubject(String.valueOf(userId)) .claim("username", username) .claim("isAdmin", isAdmin) .setIssuedAt(now) .setExpiration(expireDate) .signWith(SignatureAlgorithm.HS256, secretKey) .compact(); }这里注意,不要往Token里放敏感信息,比如手机号、身份证号,因为JWT本身Base64编码后可以被解码,只有签名部分才是加密的。
鉴权过滤器是用户模块的重头戏。写一个JwtAuthenticationFilter继承OncePerRequestFilter,在doFilterInternal方法里从Header里取出Authorization字段,判断有没有Bearer前缀,如果有就解析Token,解析成功则把用户信息放入SecurityContextHolder。Spring Security的配置类里放行/api/user/login、/api/user/register以及/api/product/**的公开查询接口,其他接口全部开启鉴权。
这块代码我是按Spring Security 6的写法来的,注意SpringBoot3对应的是Security6.x,里面不少配置方法已经废弃,比如旧的WebSecurityConfigurerAdapter已经被移除,需要改用SecurityFilterChain的Bean定义。
3.3 商品分类与商品列表
商品模块看起来是最简单的CRUD,但里面有很多值得注意的设计细节。
分类接口提供一个树形结构会很加分。数据库里只有一级分类和二级分类,用parent_id字段标识隶属关系。查询时一次性把所有分类查出来,在内存中组装成树形结构返回给前端。这个逻辑虽然简单,但是能展示你对数据处理有自己的思考。
商品列表最关键的是分页和条件查询。前端请求时传pageNum、pageSize、keyword、categoryId、sortType这几个参数,后端用MyBatis-Plus的Page对象配合LambdaQueryWrapper做条件构造。LambdaQueryWrapper是MyBatis-Plus的精华,不用把SQL写在注解里,用Java方法安全的方式构建查询条件,改起来也方便。
价格排序和销量排序是最常用的两个场景。价格排序用orderByAsc("price")或orderByDesc("price"),销量排序用orderByDesc("sales")。前端下拉框选择排序方式后,把sortType传给后端,后端用switch判断后添加对应的排序条件。
商品详情接口就是根据id查出商品信息,同时把分类名称一并返回。你可以用当前表关联查询,也可以单独查一次分类表,两种方式性能差异很小,看个人习惯。
3.4 购物车加购与订单提交
购物车是一个典型的关联业务模块,加购接口接收productId和quantity,先判断购物车里是否已有该商品,有就累加数量,没有就新建。这个过程要小心库存校验,加购数量不能超过商品库存。
订单提交是整个项目里事务最复杂的模块。因为它涉及多张表的变更:新增订单主表记录、批量插入订单明细表、扣减商品库存、清空购物车对应商品。任何一个环节失败,都需要回滚,所以要在@Transactional注解保护下完成。这个注解是Spring事务管理的经典用法,面试时大概率会问,你要能讲清楚它底层用的是AOP动态代理机制,默认遇到RuntimeException回滚。
订单编号是我个人觉得容易忽略的地方。用自增Id做订单号虽然简单,但是太丑了而且容易暴露业务量。建议用时间戳加随机数的组合,格式类似202501121030001234,前面14位是年月日时分秒,后面4位随机数。如果担心并发重复,可以再加一个用户Id的尾号。
下单时还需要确认收货地址。正常的电商项目会单独有地址管理表,但作为学习项目,我建议用户在订单里直接填写收货人和手机号、收货地址。这样省去一张表打交道的复杂度,也能满足毕设需求。
4. 前端核心页面实现
4.1 路由设计与Pinia状态管理
前端路由用Vue Router的History模式,需要注意的一点是部署时后端要做路径重写,否则刷新页面会404。开发环境中不存在这个问题。
路由设计上,我建议区分三个层面。第一层是公共路由,包括首页、商品列表、商品详情。第二层是用户路由,需要登录后才能访问,比如购物车、订单页、个人中心。第三层是管理员路由,后台管理的产品列表、订单管理、用户管理等页面。这几类路由要通过路由守卫实现访问控制。
路由守卫的代码思路是,在router.beforeEach里判断目标路由的meta信息。如果meta.requiresAuth为true,检查Pinia里有没有用户信息,没有就跳转到登录页并带上redirect参数。如果meta.requiresAdmin为true,则额外检查用户角色是否为管理员。
Pinia的状态管理在这里派上大用场。我建议创建两个Store,一个useUserStore管理用户信息和登录状态,一个useCartStore管理购物车数量和悬浮窗显示。用户登录成功后,把Token存到localStorage里,同时把用户信息存到Store中。刷新页面时,通过初始化的方法来从本地恢复状态,保证页面刷新后不会掉登录态。
4.2 商品列表页与详情页的交互体验
商品列表页是从后端数据到前端展示的第一个完整场景。核心逻辑就是:
- 页面加载时调用
GET /api/product/list接口获取第一页数据 - 搜索框输入关键字时触发防抖查询
- 左侧分类菜单切换时重置分页并重新请求
- 排序下拉框变化时重新请求
在这里,防抖是必须处理的细节。如果不做防抖,用户每敲一个字母就触发一次请求,不仅后端压力大,前端页面也会频繁刷新体验很差。防抖的实现有两种,一种是自己在watch里配合setTimeout实现,另一种是用lodash-es的debounce函数。个人推荐后者,代码更简洁。
商品详情页除了展示基本信息外,主要交互是数量选择、加购和立即购买。加购成功后,最好弹出一个确认框,让用户选择继续购物还是去购物车结算,这是一个非常符合真实电商场景的细节设计,答辩时讲出来会很加分。
4.3 购物车与订单提交的联动
购物车页面展示当前用户的所有购物项,每行包括商品图、名称、价格、数量、小计金额,以及一个删除按钮。数量的增减要绑定后端接口,每改变一次就调用一次PUT /api/cart/{id}接口更新数量。
这里有一个很容易踩的坑,就是页面上的数量和数据库不同步的问题。比如用户连续快速点击加号,此时多个请求同时发出,后发先至,就会把前一个请求的结果覆盖掉,导致数量最终不对。解决办法是加一个loading状态,在请求未完成时禁用按钮,或者在请求成功后再更新本地数据,让数据轴以后端为准。
订单结算页要展示订单的商品列表以及合计金额。确认提交后调用下单接口,成功后清空购物车已下单的商品,同时跳转到订单详情页展示订单状态。整个流程的顺序是:提交订单接口返回订单编号,前端根据订单编号查询订单详情,再渲染到新页面。这里前端代码要注意接口的调用顺序,避免使用success回调后再调下一个success导致回调地狱,合理做法是用async/await。
5. 项目联调高频报错与排查实录
5.1 跨域问题的三种解法
前后端分离项目里,跨域报错是出现频率最高的问题。前端的开发服务器跑在5173端口,后端的接口跑在8080端口,浏览器的同源策略会把两者之间的请求拦截下来。解决方式有三种,按推荐程度排序。
第一种是后端开启CORS,这也是最推荐的方案。在SpringBoot里就是写一个配置类实现WebMvcConfigurer接口,重写addCorsMappings方法,允许的前端地址配置在配置文件里。好处是可以精确控制允许访问的来源。
第二种是前端Vite配置代理。打开vite.config.js文件,修改server.proxy配置,把/api前缀的请求代理到后端地址。这种方案开发时最常用,因为浏览器看到的是同源localhost:5173下的请求,根本不触发跨域。但是部署到生产环境时,代理就不起作用了,需要后端或Nginx配合。
第三种是Nginx反向代理。生产环境里这基本是标配,把所有前端路由交给Nginx处理后,/api开头的请求转发到后端服务地址。
我的建议是开发阶段两种都配置:后端CORS打开兜底,前端Vite代理设置好,生产环境由Nginx负责。实际联调时,这三种方案能覆盖绝大部分场景。
5.2 前端渲染数据为空的排查思路
前端页面白屏或者表格里没数据,这是新手最容易懵的情况。我的排查路径一般是这样。
第一步看浏览器Network面板。打开F12开发者工具,刷新页面,看对应接口的状态码。如果状态码是404,说明后端的接口路径写错了或者前端请求的URL不对。如果状态码是200,但Response返回的JSON是空数组或null,那问题可能在后端SQL或数据结构,继续往下查。如果状态码是403或401,说明鉴权机制拦截了,检查Token是否带上了。
第二步看Console面板的报错信息。Vue3开发模式下,常见的两个报错是TypeError: Cannot read properties of undefined和Cannot find module。前者通常是取了不存在的字段,比如后端返回的字段叫productName,前端却取了name;后者多半是组件路径写错了或依赖没安装完。
第三步检查Store和组件的响应式绑定。有时候接口返回的数据正常,但页面没有更新,原因可能是声明变量时没有用响应式API包起来。记住,Vue3里用ref和reactive创建的变量才是响应式的,普通变量改了不会触发页面重新渲染。
5.3 前后端常见错误速查表
| 报错信息或表现 | 可能原因 | 解决办法 |
|---|---|---|
| Access-Control-Allow-Origin 缺失 | 后端没开CORS,或前端代理没配置 | 参考5.1三种方案选一种配置 |
| 401 Unauthorized | Token缺失或过期 | 检查请求拦截器是否注入了Authorization头 |
| 403 Forbidden | 登录了但权限不够 | 检查路由守卫和用户角色判断逻辑 |
| Whitelabel Error Page | 后端接口路径错误或异常未处理 | 检查后端控制台堆栈日志 |
| Cannot find module 'xxx' | npm依赖未安装完整 | 执行npm install |
| 前端表格数据不显示 | 字段名不匹配或数据类型不对 | 打开Network面板对比返回JSON和前端代码字段 |
| Refused to display in a frame | 被X-Frame-Options拦截 | 后端在安全性允许的范围内配置frameOptions |
| 购物车数量不对 | 并发请求未加锁 | 请求前禁用按钮或请求成功后刷新数据 |
| 订单重复提交 | 前端未加锁或接口未做幂等 | 提交按钮加loading状态,后端用订单号去重 |
| 刷新页面后登录态丢失 | 未从localStorage恢复状态 | 在Store初始化时读取localStorage |
5.4 几个容易忽略的小细节
第一个是时区问题。数据库连接串上一定要加serverTimezone=Asia/Shanghai,否则用默认时区取出来的时间和本地差8小时。这个问题在部署到Linux服务器上时最常见。
第二个是Python脚本类问题,不对,这里应该说的是Node版本问题。Vite5要求Node版本18+,如果你安装依赖时报错提示版本不支持,先用node -v检查一下当前版本。很多同学下载了最新的Vite模板却报错,最后发现是Node版本太老。
第三个是配置文件编码问题。在Windows上用记事本编辑过application.yml,再放回IDE里运行,偶尔会遇到配置文件乱码导致的启动失败。编码问题很隐蔽,排查时会浪费不少时间。建议统一使用UTF-8编码,并在IDE里设置默认编码为UTF-8。
6. 给毕设、实训与自学人群的额外建议
6.1 如何把这个项目从“能跑”变成“能答辩”
很多学生拿到项目源码后,第一反应是把代码跑起来,跑通了就以为万事大吉。结果到了答辩现场,老师随便问一个问题就答不上来。为了让项目真正能扛住答辩,你需要做几件事。
第一件事是重新梳理业务流程。把用户从注册、登录、浏览、加购、下单、支付的完整链路在纸上画出来,理解每一个环节涉及哪些表、哪些接口、哪些页面。能做到闭着眼讲清楚流程,答辩时就不会慌。
第二件事是理解每个模块的“为什么”。比如为什么密码要用BCrypt加密而不是MD5,为什么订单表要冗余商品名称快照,为什么要用JWT而不是Session。这些问题不要求你回答得多深入,但至少要有自己的理解。平时在写代码时多想一步,答辩时就能多说三句。
第三件事是准备一个亮点功能。商城的核心功能大家都差不多,你需要在细节上做出差异化。比如在后台上传商品时支持图片预览并回显,订单列表支持按状态筛选,购物车支持批量删除。这些功能看似不起眼,但和“只会简单CRUD”的学生一比,立刻拉开差距。
6.2 项目扩展还能往哪些方向做
如果时间充裕,这个项目可以往三个方向扩展,每个方向对能力的提升点不同。
第一个方向是支付功能。接入支付宝沙箱或者微信支付沙箱,代码里需要处理支付回调、签名验证、订单状态同步。这能让你接触真实支付场景中的安全性设计逻辑,是电商类项目里含金量最高的部分。
第二个方向是增加管理后台的权限系统。当前项目里只有管理员和普通用户的简单区别,可以改成RBAC模型,引入角色表和菜单表,做动态路由。前端根据用户的角色来动态加载路由表,这也是企业级项目里非常常见的设计。
第三个方向是引入Redis。把首页轮播图、热门商品排行等热点数据缓存到Redis,减少数据库压力。还能用Redis做分布式Session存储,这部分的代码量不大,但讲起来非常加分。
6.3 关于版本迭代和踩坑的总结
最后再分享一个实际经历。我最早带学生做这个项目时用的还是SpringBoot2和Vue2,版本升级到SpringBoot3和Vue3之后,确实踩了一些兼容性的坑,比如Spring Security的配置方式变了,比如MyBatis-Plus的starter包名调整了,比如Element Plus的组件用法和Element UI有很多差异。
遇到这些问题时,我建议你先看清楚报错信息,再根据关键字搜索解决方案,尤其是官方文档优先看。很多报错信息贴到搜索引擎里,第一条可能就是官方GitHub的Issue,点进去就能找到权威回答。
写代码过程中还有一个小技巧,就是每一阶段跑通后再进入下一阶段。比如先把后端用户模块的所有接口写完并测试通过,再写前端用户页面。不要后端还没写完整就急着写前端,那样联调时会出现一堆问题,排查起来非常痛苦。
这套项目对我个人来说,其实也是一次技术更新过程中的完整实践记录。前前后后做了多次版本的迭代,从单一的用户登录到完整的订单流程,从简单的页面展示到后台的权限管理,积累了非常多可以复用的代码设计思路。如果你正在做类似的项目,希望在阅读完这篇文章后,能直接用这份实操记录把系统跑起来,并且在使用过程中形成自己的理解。多动手,多调试,遇到报错不害怕——这才是编程学习中最重要的能力。