做毕设选到这个题目,算是选到了“天胡开局”。Spring Boot + Vue这套前后端分离组合,是当前Java方向毕业设计里最稳、最主流、最容易出活儿的技术栈之一,而二手手机销售系统这个业务场景,又比那些烂大街的“图书管理”“学生管理”更有商业味道,需求很容易说圆,Demo演示也有看点。这篇文章不搞虚的,我会把整个项目的核心设计思路、数据库怎么建、后端怎么写、Vue怎么调、答辩怎么讲、以及调试时容易踩的坑,全部按实操顺序捋一遍。源码、SQL脚本、文档这些配套材料基础好的同学可以直接跑,但我建议大家一定把自己扔进代码里走一遍,把每个模块为什么这么设计讲清楚,这才是拿高分的关键。
1. 项目整体设计思路与技术选型
1.1 为什么选Spring Boot + Vue组合,它到底好在哪
可以先明确一个结论:在毕业设计这个尺度上,Spring Boot + Vue几乎就是最优解,没有之一。
先看后端。Spring Boot不是一个新的框架,它是对Spring全家桶的一次“封装革命”。传统SSH(Struts + Spring + Hibernate)或SSM(Spring + SpringMVC + MyBatis)时代,最折磨人的是那一堆web.xml、applicationContext.xml配置文件,光是让一个HellWorld跑起来都要折腾半天。Spring Boot把自动配置(AutoConfiguration)做到了极致,你只需要一个spring-boot-starter-web依赖,加一个@SpringBootApplication注解,一个内嵌的Tomcat就帮你把HTTP服务跑起来了。这对毕设来说太关键了——时间要花在业务代码上,不是花在“让服务器起来”上。
再看前端。Vue的核心优势是“渐进式”和“组件化”。vue-cli或vite一行命令就能拉出一个标准工程,Element UI或Element Plus组件库让你不用自己写CSS就能拼出后台管理界面。做毕设的人最怕的就是前端样式写得像“上世纪的政府网站”,用Vue + Element这套组合,颜值分基本稳了。
加上MySQL做数据持久化,这套技术栈的学习资料、踩坑记录、开源项目多到看不完。哪怕你某个点卡住了,搜索引擎随便一翻就能找到答案。这种“生态红利”是你在答辩时能蒙混过关(不是)……是能高效解决问题的基础。
1.2 系统核心需求拆解:你必须说清楚“做的是什么东西”
很多同学拿到题目的第一反应是“不就是商品增删改查嘛”,这个理解太浅了。二手手机销售系统,核心不是手机,是交易流程。
站在用户(买家)角度:要能浏览在售手机、看详情(成色、价格、配置)、加入购物车、下单购买。站在卖家(管理员)角度:要能发布手机信息、管理库存、处理订单、审核上下架。还有一层容易被忽略的是用户角色——如果整个系统只有一个大而全的界面,那答辩时老师说一句“你这个没有权限区分”,你就很难受了。
所以,我给这个系统定下的核心模块是:
- 前台用户模块:注册登录、浏览商品、商品搜索、购物车、订单管理、个人信息维护
- 后台管理模块:商品管理(发布/编辑/上下架)、用户管理、订单管理、公告/新闻管理
- 公共模块:轮播图、分类导航、系统数据统计
这样拆分后,一个标准的“前台展示 + 后台管理”双子系统就出来了。技术栈上对应的是Vue Router做路由分离,Spring Boot按Controller层做模块划分。后面的数据库设计、接口设计、页面设计都围绕这个结构展开。
1.3 技术栈版本选择:别用太老也别用太新
选版本这件事看着不起眼,实际坑很多。我的建议是:
| 角色 | 推荐版本 | 说明 |
|---|---|---|
| JDK | 1.8 或 11 | 很多公司的老项目还在用JDK8,毕设用JDK8兼容性最好,别上17/21给自己找麻烦 |
| Spring Boot | 2.7.x | 稳定,第三方教程多,很多开源项目都是这个版本 |
| Vue | 2.6.x + Element UI 或 3 + Element Plus | 如果你不熟Vue,选2更稳,教程多到爆炸;想折腾可以上3 |
| MySQL | 5.7 或 8.0 | 5.7最经典,8.0也行,注意驱动依赖不一样 |
| MyBatis | MyBatis-Plus 3.5.x | 强烈建议用Plus,代码量直接少一半 |
| Node.js | 14/16/18 | 运行Vue工程用,装LTS版本就行 |
有人问为什么不用MyBatis而用MyBatis-Plus,因为后者在CRUD上太友好了:BaseMapper里已经有selectById、selectList、insert这些方法,你连SQL都不用写就能完成80%的单表操作。毕设的重心在业务逻辑上,不在写重复的<insert>标签上。这点想清楚,后面效率完全不一样。
2. 数据库设计:二手手机交易系统的地基
2.1 核心表结构规划
数据库表设计决定了系统的上限。毕设评分的重点之一,就是看你的ER图是否合理、表之间关联是否清楚、字段命名是否规范。二手手机销售系统的表不需要太多,但每张表都得“有话说”。
我建议的核心表如下:
用户表(sys_user):
id,username,password,phone,email,avatar,role,status,create_time。其中role区分管理员和普通用户,可以用0/1或ROLE_ADMIN/ROLE_USER。手机商品表(phone_info):
id,title,brand,model,price,original_price,condition_level(成色等级,例如99新/95新/有划痕),description,cover_image,detail_images,stock,sales_volume,shelf_status,create_time,update_time。这是整个系统的信息中心,字段尽量给全,图片路径用URL字符串存储。购物车表(cart_item):
id,user_id,phone_id,quantity,checked,create_time,update_time。这里注意一点,购物车要不要建表取决于你的设计理念,用localStorage也能做购物车,但既然要做数据库设计亮点,还是建表更规范,而且方便后续扩展订单逻辑。订单表(order_info):
id,order_no(唯一订单号),user_id,phone_id,quantity,total_amount,status(0待付款/1已付款/2已发货/3已完成/4已取消),create_time,pay_time,deliver_time,complete_time。建议再拆出一个订单明细表来记录商品快照(商品名称、下单时价格、图片),因为商品信息会变,但订单得保留下单那一刻的真实数据。公告/新闻表(news_info):
id,title,content,cover,create_time。后台发布公告用,前台首页展示。轮播图表(banner_info):
id,image_url,link_url,sort,status。前台首页轮播图数据。
这六张表已经能撑起整个系统了。如果想让功能更丰满,可以再加收货地址表、手机品牌分类表、收藏表。但核心记住一个原则:表不在多,而在于能否支撑核心业务流程闭环。
2.2 关系设计中的关键考量与反范式技巧
设计表关系时要讲得清“为什么”,这是答辩加分点。
用户表和订单表是1:N;购物车表和用户表是1:N;订单表和商品表本质上是N:M,通过订单明细表来解除。这个逻辑绝大多数同学都懂,但有一个细节容易被忽略——商品表要不要存冗余字段sales_volume。
我的建议是:存。因为每次查询都去订单表COUNT(*)太浪费性能了,而且对毕设系统来说,数据量根本达不到需要严格规范化的级别。稍微冗余一点,换查询效率,这叫“反范式设计”,可以在文档里专门写一节,评委看到你懂这个会很加分。
另一个容易忽略的地方是订单明细表为什么要存商品快照。二手手机价格波动大,同一个型号的手机可能今天卖1500明天卖1400,如果订单只关联商品表的id,用户打开历史订单时看到的却是当前价格,这就出问题了。快照字段虽然在表结构上看着“重复”,但它是交易系统的基本常识。
2.3 建表SQL关键写法参考
CREATE TABLE `phone_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL COMMENT '商品标题', `brand` varchar(50) DEFAULT NULL COMMENT '品牌', `model` varchar(50) DEFAULT NULL COMMENT '型号', `price` decimal(10,2) NOT NULL COMMENT '售价', `original_price` decimal(10,2) DEFAULT NULL COMMENT '原价', `condition_level` varchar(20) DEFAULT '99新' COMMENT '成色等级', `description` text COMMENT '商品描述', `cover_image` varchar(500) DEFAULT NULL COMMENT '封面图', `detail_images` text COMMENT '详情图,可存多张逗号分隔', `stock` int(11) DEFAULT '0' COMMENT '库存', `sales_volume` int(11) DEFAULT '0' COMMENT '销量', `shelf_status` tinyint(1) DEFAULT '1' COMMENT '上架状态 1上架 0下架', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='二手手机商品表';两个细节:一是price用decimal(10,2)而不是float,金额字段用浮点类型会出现精度丢失的问题,这在支付场景是绝对的禁忌。二是字符集用utf8mb4而不是utf8,因为utf8在MySQL里存不了emoji和部分生僻字,虽然毕设里不一定用到,但这是一个专业习惯。
3. 后端核心实现:Spring Boot业务落地
3.1 项目分层结构与代码组织
后端工程结构给人的第一印象很重要。推荐这样建包:
com.example.secondhand ├── controller # 接收前端请求,返回JSON ├── service # 业务逻辑层,接口+实现 ├── mapper # MyBatis数据访问层 ├── entity # 数据库实体类 ├── common # 统一返回结果、异常处理、常量 └── config # 配置类(跨域、拦截器等)分层的目的不是为了好看,而是为了降低耦合。Controller不写SQL,Service只处理业务,Mapper只管数据访问。答辩被问“你系统怎么保证可维护性”的时候,直接说“我严格按照分层架构设计,每层职责单一”,就是及格线以上的回答。
统一返回结构是后端设计里很加分的细节。我习惯于定义这样一个返回体:
{ "code": 200, "message": "操作成功", "data": { ... } }前端Axios拦截器统一处理code,当code不是200时弹出错误提示。这么做之后,Controller每一层返回数据都不需要再自己包一层Result.ok(data)之外的特殊逻辑,代码整洁度立刻上了一个档次。
3.2 登录鉴权:JWT还是Session
做毕设时最纠结的往往不是业务,而是“登录状态怎么保存”。
两种主流方案:Session和JWT。Spring Security + JWT在真实项目中很常见,但配置过程偏复杂,对毕设来说有点重。我的建议是:用拦截器 + Token(或简单Session)的方案。
如果用的是JWT,核心流程是:
- 用户登录时后端校验用户名密码,成功后生成一个带过期时间的Token返回给前端;
- 前端把Token存到
localStorage,每次请求时在Authorization请求头带上; - 后端写一个
LoginInterceptor,拦截除了登录接口以外的请求,校验Token有效性。
public class JwtInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { // 放行预检请求 if ("OPTIONS".equals(request.getMethod())) { return true; } String token = request.getHeader("Authorization"); if (token == null || !JwtUtil.verify(token)) { response.setStatus(401); response.getWriter().write("{\"code\":401,\"message\":\"未登录或登录已过期\"}"); return false; } return true; } }这个方案的优点是:前端能明确感知登录失效,接口安全性在毕设层面绝对够用。讲项目的时候你可以提一句“用户凭证无状态校验,服务端不保存会话状态,天然支持水平扩展”——这比“我用Session”听起来专业得多。
3.3 商品与订单模块的业务闭环设计
商品模块没什么特殊的,无非是Controller接收分页参数,Service调用MyBatis-Plus的分页查询,返回给前端。真正考验业务设计能力的是订单模块。
一个完整的“立即购买”接口,后端要走这些步骤:
- 校验用户登录状态,获取
userId; - 根据
phoneId查出商品,校验是否上架、库存是否大于0; - 生成唯一订单号(可用时间戳+随机数,或数据库雪花ID),把商品信息写入订单明细快照;
- 扣减库存,增加销量;
- 返回订单号和待支付金额。
这里我强烈建议把“创建订单”和“扣库存”放到一个@Transactional事务里。因为如果扣库存成功后订单创建失败,会导致数据不一致——商品库存没了,但订单却不存在。一旦出现问题,事务回滚让两边数据都复原。
这个细节看起来简单,但很多同学的代码里根本没加事务注解。我见过太多“库存莫名其妙少了”的案例,最后发现是并发下事务缺失导致的。@Transactional非常轻量,但它在答辩时价值极高,因为老师一定会问“你如何保证数据一致性”。
3.4 后端与前端联调时不得不说的跨域问题
每个做前后端分离项目的同学,100%会遇到跨域(CORS)报错。具体现象是:前端Vue启动在localhost:8080,后端Spring Boot启动在localhost:8081,前端发请求过去,浏览器拦截说“No 'Access-Control-Allow-Origin' header is present on the requested resource”。
这是浏览器的同源策略导致的。解决方案有两种:
一种是在后端加全局CORS配置:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }另一种是前端配合后端配置代理。Vue CLI项目的vue.config.js里:
module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:8081', changeOrigin: true } } } }这两种方案各有利弊。后端CORS配置简单粗暴,适合快速联调;前端代理是生产环境的常见做法之一,但需要前端去适应。我个人的建议是:开发阶段用第一种,打包部署后你其实不需要CORS配置了,因为前端静态文件会被Spring Boot托管到同一个端口下,同源就不存在跨域问题。
4. 前端核心实现:Vue页面与交互
4.1 工程目录设计与路由划分
Vue前端工程,我见过太多人把所有页面堆在一个views文件夹里,毫无结构。问题在于:你做个毕设无所谓,但答辩老师问“你前端怎么组织”时,你说“随便放的”就尴尬了。
一个清晰的前端结构长这样:
src ├── api # 所有请求接口定义 ├── assets # 静态资源(图片、样式) ├── components # 公共组件(轮播图、商品卡片、分页组件) ├── router # 路由配置 ├── store # Vuex状态管理 ├── views │ ├── home # 前台首页 │ ├── goods # 商品列表、详情 │ ├── cart # 购物车 │ ├── order # 订单确认、订单列表 │ ├── user # 个人中心、登录注册 │ └── admin # 后台管理页面路由配置上,前台和后台建议分开。后台管理页面用meta: { requiresAuth: true }标记需要登录才能访问,配合Vue Router的beforeEach导航守卫做登录拦截:
router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (to.matched.some(record => record.meta.requiresAuth) && !token) { next({ path: '/login' }) } else { next() } })4.2 Axios封装与接口调用的正确姿势
直接在每个页面里写axios.get('/api/phone/list')也能跑,但一旦接口地址变动或需要统一处理登录过期,你就会痛苦到想砸电脑。我把Axios封装成一个request.js模块,统一处理三件事:请求头加Token、响应拦截、错误提示。
import axios from 'axios' import { Message } from 'element-ui' const request = axios.create({ baseURL: '/api', timeout: 10000 }) request.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers['Authorization'] = token } return config }) request.interceptors.response.use( response => { const res = response.data if (res.code !== 200) { Message.error(res.message || '请求失败') return Promise.reject(new Error(res.message)) } return res.data }, error => { if (error.response && error.response.status === 401) { localStorage.removeItem('token') router.push('/login') } Message.error('网络异常,请稍后重试') return Promise.reject(error) } ) export default request这样封装后,页面里调用接口就非常干净了:
import request from '@/utils/request' export function getPhoneList(params) { return request({ url: '/phone/list', method: 'get', params }) }页面里直接getPhoneList({ page: 1, size: 10 }).then(res => { this.list = res.rows }),所有公共逻辑全部收敛。写的时候多花10分钟,后面一整个项目的开发体验都会起飞。
4.3 商品列表、购物车与订单流程的页面实现要点
前台页面的核心场景有三个,做得好不好直接决定演示效果。
商品列表页:用卡片网格布局展示手机商品,每个卡片显示封面图、标题、成色、价格。顶部加分类筛选和关键词搜索框。分页用Element组件的el-pagination。这里一个小细节:图片建议用固定比例裁剪好的图,否则卡片会忽高忽低,看上去非常业余。
商品详情页:头部是图片轮播(用el-carousel),下面是商品信息、成色描述、库存数量、购买按钮。购买按钮有两种逻辑:直接下单和加入购物车。建议这两个按钮都做,形成完整业务链路。
购物车与结算页:购物车列表用表格或卡片展示,右侧是结算栏(合计金额、去结算按钮)。点击结算后跳转订单确认页,需要填写收货人信息,然后提交订单。
后端交互上,购物车加减数量后要及时调用更新接口;提交订单成功后清空购物车对应项;订单列表页按状态Tab切换(待付款/已发货/已完成)。
4.4 后台管理界面的搭建思路
后台管理页面重点不是炫酷,是“功能完整 + 操作顺手”。
左侧菜单用el-menu,顶部是标题栏和退出按钮。内容区嵌套路由切换不同管理页面。
商品管理页:表格展示所有商品,支持上下架切换、编辑、删除。新增/编辑商品用el-dialog弹窗,里面用el-form做表单校验——手机名称必填、价格必须大于0、图片上传用Element的上传组件,上传成功后把返回的URL存到表单字段里。
订单管理页:表格展示所有订单,按订单状态筛选。管理员可以发货(将订单状态从“已付款”变成“已发货”)。
用户管理页:表格展示注册用户,支持禁用/启用账号。禁用后该用户登录要提示“账号已被禁用”。
如果想让后台更亮眼,可以在首页加一个简单的统计面板:商品总数、用户总数、订单总数、今日新增订单数,别看只是几个COUNT(*)查询,视觉加分非常明显。
5. 部署调试流程:从源码到可演示Demo
5.1 本地开发环境搭建全流程
这一节写给那些第一次在自己电脑上跑项目就心态爆炸的同学。
第一步:装JDK。下载JDK 8,配置JAVA_HOME环境变量,在命令行运行java -version验证成功。
第二步:装MySQL。Windows下直接用安装包,记住你设置的root密码。如果对安装没有把握,可以用集成环境PhpStudy或小皮面板,一键启动MySQL服务。安装完成后用Navicat新建一个数据库,然后导入项目里附带的.sql文件。
第三步:装Maven。把Maven解压后配置MAVEN_HOME环境变量,配置阿里云镜像源(在conf/settings.xml里改),这样下载依赖会快很多。然后打开后端工程,IDEA会自动识别Maven项目并下载依赖。如果下载慢,检查镜像是否配置正确。
第四步:装Node.js。同样LTS版本一路下一步。然后在Vue项目根目录执行:
npm install如果npm install太慢,设置淘宝镜像源:
npm config set registry https://registry.npmmirror.com依赖装完后执行npm run serve启动开发服务器。正常情况下终端会显示App running at: http://localhost:8080。
第五步:改配置。打开后端工程的application.yml,把MySQL的用户名密码改成自己的,数据库名改成你导入时的库名。然后启动后端Application类。看到“Started Application in X seconds”就是成功了。
5.2 代码打包与联合部署(前端放进后端)
开发阶段是前后端两个服务独立跑,但最终提交或演示时通常要打包成一个整体。
先在前端工程目录执行:
npm run build执行完后会生成一个dist目录,里面是index.html和static/静态资源。把dist目录里的所有文件复制到后端工程的src/main/resources/static目录下。重新打包后端:
mvn clean package -DskipTests生成的.jar文件在target目录下,执行:
java -jar second-hand.jar这个时候Spring Boot已经把前端页面当作静态资源托管了,直接访问http://localhost:8080就能看到系统首页,前后端完全同源,没有任何跨域问题。这个部署方式非常好讲,也是真实项目中最常见的“单体外壳”部署方案。
5.3 十分钟跑通演示的核心链路检查清单
每年答辩,总有人现场演示时翻车:“登录进去了但列表加载不出来”、“图片裂了”、“点下单没反应”。大部分问题都能提前排查。我提供一个自检清单,演示前按顺序过一遍:
- 后端是否启动成功,
application.yml数据库密码是否正确 - 前端是否已打包并放进后端
static目录,还是前端单独跑在8080端口 - 数据库是否已导入,三个业务基础数据(管理员账号、普通用户账号、至少5条商品数据)是否存在
- 图片路径是否能访问,如果图片存在本地,确认目录路径是否存在
- 浏览器控制台是否有红色报错,确认所有接口返回
code: 200
这套清单跑完,基本能保障演示时不会出大问题。
6. 常见问题与排查技巧实录(踩坑合集)
6.1 依赖下载失败或IDEA报红
最经典的问题。pom.xml里的依赖全部标红,或者在Maven面板里一直报Cannot resolve symbol 'springframework'。
排查顺序是:IDEA的Maven设置里检查是否用了自己配置的settings.xml->检查settings.xml里镜像是否配好->点击IDEA右侧Maven面板的刷新按钮强制重新加载->删掉本地仓库中对应依赖的文件夹重新下载。绝大多数情况是网络问题,配好阿里云镜像就解决了。
6.2 数据库连接报错:Access denied or Unknown database
“Access denied for user 'root'@'localhost'”说明用户名密码不对;“Unknown database 'xxx'”说明指定的数据库不存在。前一个去改application.yml,后一个去重新导入SQL文件。还有一个很隐蔽的问题:MySQL 8.0的驱动类名和5.7不一样,8.0要用com.mysql.cj.jdbc.Driver,并且URL需要指定时区参数serverTimezone=Asia/Shanghai。
6.3 前端页面空白或404
npm run serve启动成功但页面空白,按F12看控制台报错。如果是Cannot find module 'xxx',说明缺依赖,npm install重装;如果是路由404,检查后端接口前缀和前端baseURL是否匹配。一个常见的前坑:后端Controller映射是/phone/list,前端请求却是/api/phone/list,这时需要在后端加server.servlet.context-path=/api或前端把baseURL改成空。
6.4 MyBatis-Plus分页查不出数据
selectPage返回的total为0或者records为空,但数据库明明有数据。多数原因有两个:一是分页拦截器没配置,二是表名或字段名对不上。MyBatis-Plus默认开启驼峰映射,但数据库字段如果叫condition_level而实体属性叫conditionLevel是可以自动映射的,前提是字段命名规范。分页插件配置如下:
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }少加这个是高频问题,一定要检查。
6.5 上传的图片无法显示
检查是不是防盗链问题,图片URL能不能在浏览器直接访问。如果前端页面和图片服务不同端口,有些本地图片会被浏览器拦截。最简单的做法是:图片上传后通过后端接口返回,统一存到一个磁盘目录,后端配置静态资源映射:
spring: web: resources: static-locations: file:D:/upload/,classpath:/static/6.6 修改端口号的正确姿势
开发阶段想改后端端口,在application.yml加:
server: port: 8081改前端端口在vue.config.js:
module.exports = { devServer: { port: 3000 } }改完之后重启各自服务即可。注意改了前端端口后,后端CORS配置里的allowedOriginPatterns要对应加上新端口,否则会跨域。
7. 答辩讲解加分点:从“做了系统”到“讲透系统”
7.1 演示节奏建议
我见过很多人演示时“唰唰唰”把页面点完,老师还没看清界面,演示就结束了。错误的演示方式等于自废武功。建议按这样的节奏:先讲背景与需求(30秒)-> 讲系统架构与角色(1分钟)-> 演示前台“用户视角”完整买手机流程(3分钟)-> 演示后台“管理员视角”商品管理与订单处理(3分钟)-> 最后讲技术亮点(1分钟)。
7.2 老师最爱问的问题清单
提前把这几个问题想好,答辩基本稳了一大半:
- “你这个系统的角色权限是怎么控制的?” 答:登录后签发Token,Token里包含用户角色,后端拦截器校验接口权限,前端路由做页面权限控制。
- “购物车和订单的数据一致性怎么保证?” 答:创建订单和扣减库存放在同一个事务里,失败会回滚。
- “你的数据库为什么这么设计?” 答:按业务模块拆表,订单明细做了快照冗余,商品表加了销量冗余字段提升查询效率。
- “项目里你觉得最难的点是什么?” 答:可以说前后端联调时的跨域问题、订单模块事务问题、多个状态流转的订单设计问题。
7.3 设计文档的配合要点
文档不是给老师看的摆设,是你答辩时的提词器。在文档里一定要含:系统架构图、功能架构图、业务流程图(特别是购物和订单流程)、ER图、数据库表设计说明、核心接口说明。每个图在答辩前自己对着讲一遍,讲顺了,整个演示基本不会卡壳。
8. 写在最后的一点经验
做完这个项目,我最大的体会是:二手手机销售系统这个选题,真正考验人的不是技术,而是对业务链路的完整理解。很多人的系统只做到了“商品CRUD”就停了,根本没走到订单闭环。但恰恰是这个从“浏览商品”到“提交订单”再到“后台发货”的完整流程,才让整个系统显得成熟、有商业价值。
从0到1把项目做一遍,比对着视频敲十遍代码有用得多。我强烈建议你拿一份源码之后,先从数据库脚本开始看,搞清楚每张表的作用;然后跑起来,对着代码断点走一遍“用户下单”的完整链路;最后再自己动手改几个功能——哪怕只是给商品加一个“品牌筛选”,你也会对这套前后端交互有完全不同的理解。
如果你在搭建环境或者跑通项目的过程中遇到实在绕不过去的坑,欢迎把这篇文章翻出来再对照一遍。我踩过的坑,你大概率还能再踩一遍——但至少现在,你已经知道每个坑长什么样了。