首页 / 资讯中心 / 文章详情

Spring Boot+Vue二手手机销售系统毕业设计全流程实战

Spring Boot+Vue二手手机销售系统毕业设计全流程实战 ★ FEATURED ARTICLE
做毕设选到这个题目算是选到了“天胡开局”。Spring Boot Vue这套前后端分离组合是当前Java方向毕业设计里最稳、最主流、最容易出活儿的技术栈之一而二手手机销售系统这个业务场景又比那些烂大街的“图书管理”“学生管理”更有商业味道需求很容易说圆Demo演示也有看点。这篇文章不搞虚的我会把整个项目的核心设计思路、数据库怎么建、后端怎么写、Vue怎么调、答辩怎么讲、以及调试时容易踩的坑全部按实操顺序捋一遍。源码、SQL脚本、文档这些配套材料基础好的同学可以直接跑但我建议大家一定把自己扔进代码里走一遍把每个模块为什么这么设计讲清楚这才是拿高分的关键。1. 项目整体设计思路与技术选型1.1 为什么选Spring Boot Vue组合它到底好在哪可以先明确一个结论在毕业设计这个尺度上Spring Boot Vue几乎就是最优解没有之一。先看后端。Spring Boot不是一个新的框架它是对Spring全家桶的一次“封装革命”。传统SSHStruts Spring Hibernate或SSMSpring 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 技术栈版本选择别用太老也别用太新选版本这件事看着不起眼实际坑很多。我的建议是角色推荐版本说明JDK1.8 或 11很多公司的老项目还在用JDK8毕设用JDK8兼容性最好别上17/21给自己找麻烦Spring Boot2.7.x稳定第三方教程多很多开源项目都是这个版本Vue2.6.x Element UI 或 3 Element Plus如果你不熟Vue选2更稳教程多到爆炸想折腾可以上3MySQL5.7 或 8.05.7最经典8.0也行注意驱动依赖不一样MyBatisMyBatis-Plus 3.5.x强烈建议用Plus代码量直接少一半Node.js14/16/18运行Vue工程用装LTS版本就行有人问为什么不用MyBatis而用MyBatis-Plus因为后者在CRUD上太友好了BaseMapper里已经有selectById、selectList、insert这些方法你连SQL都不用写就能完成80%的单表操作。毕设的重心在业务逻辑上不在写重复的insert标签上。这点想清楚后面效率完全不一样。2. 数据库设计二手手机交易系统的地基2.1 核心表结构规划数据库表设计决定了系统的上限。毕设评分的重点之一就是看你的ER图是否合理、表之间关联是否清楚、字段命名是否规范。二手手机销售系统的表不需要太多但每张表都得“有话说”。我建议的核心表如下用户表sys_userid,username,password,phone,email,avatar,role,status,create_time。其中role区分管理员和普通用户可以用0/1或ROLE_ADMIN/ROLE_USER。手机商品表phone_infoid,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_itemid,user_id,phone_id,quantity,checked,create_time,update_time。这里注意一点购物车要不要建表取决于你的设计理念用localStorage也能做购物车但既然要做数据库设计亮点还是建表更规范而且方便后续扩展订单逻辑。订单表order_infoid,order_no唯一订单号,user_id,phone_id,quantity,total_amount,status0待付款/1已付款/2已发货/3已完成/4已取消,create_time,pay_time,deliver_time,complete_time。建议再拆出一个订单明细表来记录商品快照商品名称、下单时价格、图片因为商品信息会变但订单得保留下单那一刻的真实数据。公告/新闻表news_infoid,title,content,cover,create_time。后台发布公告用前台首页展示。轮播图表banner_infoid,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) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4 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不写SQLService只处理业务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. 部署调试流程从源码到可演示Demo5.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 rootlocalhost”说明用户名密码不对“Unknown database xxx”说明指定的数据库不存在。前一个去改application.yml后一个去重新导入SQL文件。还有一个很隐蔽的问题MySQL 8.0的驱动类名和5.7不一样8.0要用com.mysql.cj.jdbc.Driver并且URL需要指定时区参数serverTimezoneAsia/Shanghai。6.3 前端页面空白或404npm 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.jsmodule.exports { devServer: { port: 3000 } }改完之后重启各自服务即可。注意改了前端端口后后端CORS配置里的allowedOriginPatterns要对应加上新端口否则会跨域。7. 答辩讲解加分点从“做了系统”到“讲透系统”7.1 演示节奏建议我见过很多人演示时“唰唰唰”把页面点完老师还没看清界面演示就结束了。错误的演示方式等于自废武功。建议按这样的节奏先讲背景与需求30秒- 讲系统架构与角色1分钟- 演示前台“用户视角”完整买手机流程3分钟- 演示后台“管理员视角”商品管理与订单处理3分钟- 最后讲技术亮点1分钟。7.2 老师最爱问的问题清单提前把这几个问题想好答辩基本稳了一大半“你这个系统的角色权限是怎么控制的” 答登录后签发TokenToken里包含用户角色后端拦截器校验接口权限前端路由做页面权限控制。“购物车和订单的数据一致性怎么保证” 答创建订单和扣减库存放在同一个事务里失败会回滚。“你的数据库为什么这么设计” 答按业务模块拆表订单明细做了快照冗余商品表加了销量冗余字段提升查询效率。“项目里你觉得最难的点是什么” 答可以说前后端联调时的跨域问题、订单模块事务问题、多个状态流转的订单设计问题。7.3 设计文档的配合要点文档不是给老师看的摆设是你答辩时的提词器。在文档里一定要含系统架构图、功能架构图、业务流程图特别是购物和订单流程、ER图、数据库表设计说明、核心接口说明。每个图在答辩前自己对着讲一遍讲顺了整个演示基本不会卡壳。8. 写在最后的一点经验做完这个项目我最大的体会是二手手机销售系统这个选题真正考验人的不是技术而是对业务链路的完整理解。很多人的系统只做到了“商品CRUD”就停了根本没走到订单闭环。但恰恰是这个从“浏览商品”到“提交订单”再到“后台发货”的完整流程才让整个系统显得成熟、有商业价值。从0到1把项目做一遍比对着视频敲十遍代码有用得多。我强烈建议你拿一份源码之后先从数据库脚本开始看搞清楚每张表的作用然后跑起来对着代码断点走一遍“用户下单”的完整链路最后再自己动手改几个功能——哪怕只是给商品加一个“品牌筛选”你也会对这套前后端交互有完全不同的理解。如果你在搭建环境或者跑通项目的过程中遇到实在绕不过去的坑欢迎把这篇文章翻出来再对照一遍。我踩过的坑你大概率还能再踩一遍——但至少现在你已经知道每个坑长什么样了。
阅读完成 · 觉得有帮助?
咨询建站