从零搭建校园二手交易系统:Vue2 + SpringBoot 4.x 全栈实战 文章目录 前言 项目介绍核心功能界面预览 技术栈 系统架构项目结构 数据库设计user 用户表product 商品表orders 订单表 关键技术点1. 组件化开发2. Vue Router 路由守卫3. Axios 二次封装4. Spring Data JPA 方法名自动生成 SQL5. 统一响应结果6. 全局异常处理 踩坑记录坑 1SpringBoot 4.x 不支持 MyBatis-Plus坑 2MySQL 保留字 order坑 3Git 子模块问题坑 4Vue Router 部署到 Pages 后刷新 404坑 5JPA 分页页码从 0 开始 部署方案后端前端 项目总结完成度学到的后续计划 项目地址 前言最近花了一周时间做了一个校园二手交易系统从数据库设计到前端 UI从后端接口到部署上线完整走了一遍前后端分离的开发流程。这篇文章记录一下整个项目的技术选型、架构设计和踩坑经验希望能给做类似项目的同学一些参考。项目地址 GitHubhttps://github.com/dxiangwiki/campus-trade 在线演示https://dxiangwiki.github.io/campus-trade/ 项目介绍一个面向校园场景的二手物品交易平台支持用户注册登录、商品发布、在线下单、订单管理等功能。核心功能用户模块注册、登录、个人中心商品模块发布商品、商品列表、关键词搜索、分页展示订单模块在线下单、订单列表、状态管理权限控制Vue Router 路由守卫未登录自动跳转界面预览 技术栈分类技术前端框架Vue 2.6 Vue Router 3UI 组件库ElementUI 2.15HTTP 客户端Axios 1.x后端框架SpringBoot 4.1 Spring Data JPA数据库MySQL 9.4工具库Lombok部署GitHub Pages GitHub Actions 系统架构┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 浏览器 │ HTTP │ SpringBoot │ JPA │ MySQL │ │ (Vue2 SPA) │ ──────► │ 后端服务 │ ──────► │ 数据库 │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ ElementUI │ Controller │ Vue Router │ Service │ Axios │ Repository项目结构campus-trade/ ├── campus-trade-backend/ # 后端 │ └── src/main/java/com/campus/trade/ │ ├── common/ # 通用Result、异常处理 │ ├── config/ # 配置跨域 │ ├── controller/ # 接口层 │ ├── dto/ # 数据传输对象 │ ├── entity/ # 实体类 │ ├── repository/ # 数据访问层 │ └── service/ # 业务逻辑层 └── campus-trade-frontend/ # 前端 └── src/ ├── api/ # 接口封装 ├── components/ # 复用组件 ├── router/ # 路由配置 ├── utils/ # 工具Axios 封装 └── views/ # 页面 数据库设计user 用户表字段类型说明idBIGINT主键usernameVARCHAR(50)用户名唯一passwordVARCHAR(100)密码nicknameVARCHAR(50)昵称phoneVARCHAR(20)手机号create_timeDATETIME注册时间product 商品表字段类型说明idBIGINT主键titleVARCHAR(100)商品标题descriptionVARCHAR(500)描述priceDECIMAL(10,2)价格categoryVARCHAR(50)分类statusTINYINT0在售 1已售seller_idBIGINT卖家 IDcreate_timeDATETIME发布时间orders 订单表字段类型说明idBIGINT主键order_noVARCHAR(50)订单号唯一product_idBIGINT商品 IDbuyer_idBIGINT买家 IDseller_idBIGINT卖家 IDamountDECIMAL(10,2)金额statusTINYINT0待付款 1已付款 2已完成create_timeDATETIME下单时间踩坑订单表名用orders而不是order因为order是 MySQL 保留字用 JPA 会报错。 关键技术点1. 组件化开发前端拆分为 7 个页面 1 个复用组件views/ # 页面级组件 ├── Layout.vue # 主布局顶栏 内容区 ├── Login.vue # 登录页 ├── Register.vue # 注册页 ├── ProductList.vue # 商品列表 ├── ProductPublish.vue # 发布商品 ├── OrderManage.vue # 订单管理 └── UserCenter.vue # 个人中心 components/ # 复用组件 └── ProductCard.vue # 商品卡片ProductCard.vue通过props接收商品数据通过$emit触发购买事件在多处复用。2. Vue Router 路由守卫router.beforeEach((to,from,next){constuserlocalStorage.getItem(user)constpublicPaths[/login,/register]if(!publicPaths.includes(to.path)!user){next(/login)// 未登录跳登录}else{next()}})3. Axios 二次封装统一处理请求拦截、响应错误、Loading 状态// 请求拦截开启 Loading 带用户 IDservice.interceptors.request.use(config{loadingInstanceLoading.service({fullscreen:true})constuserJSON.parse(localStorage.getItem(user)||null)if(user)config.headers[X-User-Id]user.idreturnconfig})// 响应拦截统一处理错误 解包 dataservice.interceptors.response.use(res{loadingInstanceloadingInstance.close()constdatares.dataif(data.code!200){Message.error(data.msg)returnPromise.reject(newError(data.msg))}returndata.data})4. Spring Data JPA 方法名自动生成 SQLRepository 只需声明方法名JPA 自动生成 SQLpublicinterfaceProductRepositoryextendsJpaRepositoryProduct,Long{// 自动生成SELECT * FROM product WHERE status? ORDER BY create_time DESC LIMIT ...PageProductfindByStatusOrderByCreateTimeDesc(Integerstatus,Pageablepageable);// 自动生成SELECT * FROM product WHERE status? AND title LIKE %?% ORDER BY create_time DESCPageProductfindByStatusAndTitleContainingOrderByCreateTimeDesc(Integerstatus,Stringtitle,Pageablepageable);}一行 SQL 都不用写方法名就是 SQL 语义。5. 统一响应结果DatapublicclassResultT{privateIntegercode;privateStringmsg;privateTdata;publicstaticTResultTsuccess(Tdata){ResultTrnewResult();r.code200;r.msgsuccess;r.datadata;returnr;}publicstaticTResultTerror(Stringmsg){ResultTrnewResult();r.code500;r.msgmsg;returnr;}}6. 全局异常处理RestControllerAdvicepublicclassGlobalExceptionHandler{ExceptionHandler(RuntimeException.class)publicResult?handleRuntime(RuntimeExceptione){returnResult.error(e.getMessage());}}Service 层直接throw new RuntimeException(商品不存在)前端收到的就是{code: 500, msg: 商品不存在}。 踩坑记录坑 1SpringBoot 4.x 不支持 MyBatis-Plus现象用 Spring Initializr 生成项目时最低只能选 SpringBoot 4.x但 MyBatis-Plus 3.5.x 只支持到 SpringBoot 3.x。解决改用Spring Data JPASpringBoot 官方亲儿子比 MyBatis-Plus 更贴合 4.x。坑 2MySQL 保留字 order现象实体类Table(name order)启动报错。解决表名改成orders实体类用Table(name orders)。坑 3Git 子模块问题现象在 monorepo 里推送后GitHub Actions 报No url found for submodule path。原因子目录里残留了.git文件夹被 Git 误判为子模块。解决删除子目录的.git并git rm --cached后重新git add。坑 4Vue Router 部署到 Pages 后刷新 404解决路由模式改成hashURL 带#Pages 静态托管就能正确处理。坑 5JPA 分页页码从 0 开始现象前端传pageNo1JPA 显示的还是第一页其实是第 0 页。解决Service 层做pageNo - 1前端始终从 1 开始用户无感。 部署方案后端SpringBoot 打包成 jarjava -jar xxx.jar运行或部署到云服务器。前端GitHub Pages GitHub Actions 自动化部署每次git push到 main 分支GitHub Actions 自动检出代码安装依赖npm run build上传 dist 到 Pages工作流配置.github/workflows/deploy-pages.ymlname:Deploy to GitHub Pageson:push:branches:[main]jobs:build:runs-on:ubuntu-lateststeps:-uses:actions/checkoutv4-uses:actions/setup-nodev4with:{node-version:18}-run:npm installworking-directory:./campus-trade-frontend-run:npm run buildworking-directory:./campus-trade-frontend-uses:actions/upload-pages-artifactv3with:path:./campus-trade-frontend/distdeploy:needs:buildruns-on:ubuntu-latestenvironment:name:github-pagessteps:-uses:actions/deploy-pagesv4 项目总结完成度✅ 用户注册 / 登录✅ 商品发布 / 列表 / 搜索 / 分页✅ 在线下单 / 订单管理✅ 统一异常处理✅ 跨域配置✅ GitHub Pages 自动化部署学到的前后端分离RESTful API 设计Axios 统一封装Vue 组件化props 传递 $emit 事件JPA 方法命名优雅地避免写 SQLGitHub ActionsCI/CD 自动化部署Monorepo前后端一个仓库管理方便后续计划JWT 登录态替代 localStorage 明文图片上传本地磁盘 / 阿里云 OSS订单状态流转付款 / 收货 / 完成WebSocket 实时消息通知卖家视角我的发布 / 卖出订单ECharts 数据看板 项目地址GitHubhttps://github.com/dxiangwiki/campus-trade在线演示https://dxiangwiki.github.io/campus-trade/技术栈Vue2 ElementUI Axios SpringBoot 4.x JPA MySQL如果这个项目对你有帮助欢迎给个 ⭐ Star也欢迎在评论区交流。作者dxiangwiki日期2026-10