恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Spring Boot+Vue微信小程序购物系统:从搭建到答辩全流程指南
首页
资讯中心
/
Spring Boot+Vue微信小程序购物系统:从搭建到答辩全流程指南
Spring Boot+Vue微信小程序购物系统:从搭建到答辩全流程指南
发布时间:2026/10/9 17:59:12
简介一套面向毕业设计场景的Java微信小程序购物系统完整可运行项目基于Springboot与Vue实现前后端分离适合计算机专业学生用于课题设计、期末作业或二次开发学习也可作为微信小程序开发的进阶参考。项目已通过导师指导与答辩评审并获得98分高分在Windows 10/11环境调试通过下载后可按部署文档直接运行稳定性有保障。资源包共1033个文件、约22.17MB涵盖Java源码、Vue组件、微信小程序页面文件、数据库脚本、论文、答辩PPT及详细使用说明其中143个vue组件、142个java类、46个wxml等对应前后端核心实现55个json用于配置179个png等素材辅助界面展示。压缩包内目录结构清晰有序包含数据库脚本shoppingsystemdb.sql及部署命令等文件便于快速搭建环境。目前已有66人学习下载是兼顾学习参考与直接运行的毕业设计资料也可为同类购物系统开发提供完整范式。1. 购物小程序不是代码凑齐就完事先搞懂这套SpringBootVue组合微信小程序购物系统这几年在毕业设计选题里出镜率极高而 Spring Boot 做后端、Vue 做小程序前端是其中最保守也最稳的组合Java 负责业务接口和数据库操作Vue 负责页面渲染和交互两边通过 HTTP 接口传 JSON。很多人拿到这套代码的第一反应是先把后端跑起来再打开开发者工具看页面结果往往卡在联调环节——请求发不出去、token 校验不过、商品图片全挂。这个资源包把后端源码、小程序前端、MySQL 数据库脚本、论文、答辩 PPT 和使用说明文档一次带齐相当于给了一份已经调通的前后端分离基线代码。适合两类人一是想在毕设里少走弯路、直接拿完整案例改业务的二是代码能跑但要补论文和演示逻辑需要参考整体结构的。后面按架构→部署→功能→排错→答辩的顺序把它拆透。2. 系统全景前后端分离架构与数据库设计2.1 为什么是 Spring Boot Vue这种搭配到底解决了什么先聊一个基础问题毕业设计里为什么普遍选 Spring Boot 而不是 SSH 或者纯 Servlet关键在约定优于配置。Spring Boot 把 Spring MVC、内嵌 Tomcat、自动配置全揉在一起你在 pom.xml 里加一个spring-boot-starter-web依赖启动类写三行代码一个可运行的 Web 服务就成了。相比以前要配一堆 XML 的时代这个学习成本低很多。对购物系统这种业务逻辑偏 CRUD 的项目Spring Boot 的 RestController Service Mapper 三层结构几乎是最省事的组织方式。Vue 这边同理。微信小程序的页面无非是数据展示、事件绑定和请求发送而 Vue 的模板语法、生命周期、组件化思想恰好能覆盖这些需求。更关键的是不少人的毕设课件和论文里画系统架构图都喜欢画一个小程序端 后端服务 数据库的三层结构Spring Boot Vue 的分离式开发正好能让这张图落到实际代码上答辩时每层都能讲出内容。反向对比一下如果用 JSP 做前端页面和后端强耦合小程序端就得再单独写一套如果用原生微信小程序配 Java Servlet也不是不行但登录、拦截器、统一返回结构这些代码都要自己重复造。Spring Boot 的拦截器和 Vue 的请求封装能省掉大量重复工作这就是选型的直接收益。2.2 六张核心表订单与明细为什么要拆开购物系统最重要的不是页面是数据库表之间的关系。资源包里如果用规范设计至少会包含六张核心表用户表、商品分类表、商品表、购物车表、订单表、订单明细表。它们的关联关系如下表名核心字段作用与关联useropenid, nickname, avatar存微信用户被 cart、order 引用categoryname, sort_order商品分类goods_info 通过 category_id 关联goods_infoname, price, stock, status, category_id商品主表status 控制上下架cartuser_id, goods_id, num, create_time购物车用户与商品的多对多桥接表order_infouser_id, total_price, status, address订单主表一个订单对应多条明细order_itemorder_id, goods_id, price, num订单明细保证订单级字段和商品级字段分开用户表和商品表没有直接关系用户通过购物车表和商品发生关联一个用户对应多个购物车记录购物车表里保存 goods_id 和 user_id外加数量。用户下单后购物车记录变成订单表和订单明细表的数据来源。这里一个常见的错误设计是把订单里的商品直接以 JSON 字符串塞进订单表的一个字段里省了明细表但后面写订单详情页面时又要解析 JSON增大了代码复杂度甚至会因为字符串拼接格式不一致导致统计出错。订单表和订单明细表拆开的具体价值在于一个订单的总额需要统计而明细行数是可变的。如果每次都从 JSON 字符串里解析并汇总容易出数据一致性问题。拆表之后订单表只管总金额、订单状态、收货人、下单时间这些订单级字段明细表只管 goods_id、单价、数量、小计。以待发货订单查商品列表就是 order_item 表按 order_id 过滤再关联商品表拿图片和名称。这个结构也方便管理员后台对每个订单分别发货、改状态。设计表时还有两个容易忽略的点。第一用户表里 openid 和自增主键 id 必须同时存在。微信登录时先用 openid 查找或创建用户但购物车、订单这些业务表的外键一律用自增 id。如果你把 openid 直接当外键用每个业务表都要存一个很长的字符串索引和查询都会变慢而且一旦用户更换微信号登录历史订单归属就乱了。第二商品表最好预留下架状态字段。后端做商品列表查询时默认只查状态为上架的商品不然管理端把商品下架后用户那边还能看到并下单。2.3 订单状态机与事务边界下单接口的正确写法把订单状态定义清楚是购物系统可维护性的分水岭。常见的一种定义0 表示待付款1 表示待发货2 表示已发货3 表示已完成4 表示已取消。前端我的订单页面按这个数值渲染 tab 标签后端管理端修改订单状态时也写同一个数字。如果资源包里状态定义不同动手改代码之前先在常量类里统一避免页面显示待发货而数据库里存的是1却不匹配。下单是购物系统里最需要谨慎处理的业务操作因为它涉及三处数据变更扣减商品库存、写入订单和订单明细、清空购物车。这三步必须在一个事务里完成。常见做法是在 Service 方法上加Transactional注解方法执行过程中任何一步抛异常数据库整体回滚。有一个经常被忽视的点如果这个方法内部还有自调用同一个类里另一个方法调它Transactional是会失效的因为 Spring 的代理只拦截外部调用。所以下单逻辑不要写在 Controller 里也不要写成同类的内部私有方法调用最好单独放在 OrderService 里。Service public class OrderService { Transactional(rollbackFor Exception.class) public Order createOrder(Long userId, CreateOrderDTO dto) { // 1. 锁定商品并校验库存 Goods goods goodsMapper.selectByIdForUpdate(dto.getGoodsId()); if (goods.getStock() dto.getNum()) { throw new BusinessException(库存不足); } // 2. 计算订单金额以后端查到的单价为准 int totalPrice goods.getPrice() * dto.getNum(); // 3. 扣减库存 goodsMapper.decreaseStock(dto.getGoodsId(), dto.getNum()); // 4. 生成订单与明细 Order order new Order(); order.setUserId(userId); order.setTotalPrice(totalPrice); order.setStatus(0); orderMapper.insert(order); OrderItem item new OrderItem(); item.setOrderId(order.getId()); item.setGoodsId(goods.getId()); item.setPrice(goods.getPrice()); item.setNum(dto.getNum()); orderItemMapper.insert(item); // 5. 清空购物车中对应商品 cartMapper.deleteByUserIdAndGoodsId(userId, dto.getGoodsId()); return order; } }三个细节值得说透。rollbackFor Exception.class是为了让运行时异常和检查型异常都触发回滚否则默认只回滚 RuntimeException一部分业务异常的抛出会导致库存扣了但订单没生成。selectByIdForUpdate是加行级锁防止两个用户同时买最后一件商品时出现库存扣成负数。totalPrice完全以后端查到的单价为准前端传过来的价格只作为展示参考不参与计算。答辩时能把这三条说清楚就是一个有效的加分点这比堆页面数量更有说服力。事务写好之后随手在代码里埋一个测试把库存改成 1用两个账号同时下单同一商品看最终是否一个成功一个报库存不足。能过这个测试下单模块一般就稳了。3. 启动与部署从源码压缩包到本地可运行项目3.1 环境准备与版本选择先别急着解压防坑在开始前拿到 zip 之后解压前先过一遍环境清单。JDK 建议用 1.8 或 8Maven 3.6 以上MySQL 5.7 或 8.0Node.js 16微信开发者工具稳定版。为什么强烈不建议 JDK 开 17因为 Spring Boot 2.x 的老依赖里有一部分用的反射和字节码库是基于 JDK 8 编译的很多老项目说明文档也不会注明不支持更高 JDK这回事。如果本地环境必须用高版本 JDK那启动报错时第一反应应该是检查 JDK 是否与项目依赖兼容而不要先怀疑代码有问题。环境装好后用三条命令做快速自检java -version mvn -v mysql --versionjava 能正确打印版本号说明 JDK 生效mvn 能打印出 Maven 版本说明 PATH 里能找到 mvnmysql 客户端能连接数据库说明 MySQL 服务已启动。项目跑不起来时先用这三条命令排除环境变量层面的低级失误再去翻日志通常能省下不少时间。3.2 初始化数据库与后端配置把 application.yml 改成你的机器解压后先打开数据库目录一般叫 sql 或 db 或 docs。用命令行执行 SQL 文件之前先建库mysql -u root -p CREATE DATABASE shop DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;注意字符集用 utf8mb4 而不是 utf8。utf8mb4 才能保留 Emoji 和生僻字商品名、收货地址里一旦出现特殊符号utf8 会直接落库变问号。数据库建好之后回到后端目录修改 application.yml最常改的是数据源配置server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/shop?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver这几个参数各管一件事useUnicode 和 characterEncoding 负责中文不乱码serverTimezone 负责日期字段正确显示不加它会发现订单时间和本地时间差八小时useSSLfalse 是为了在本地开发时关闭无谓的 SSL 握手allowPublicKeyRetrievaltrue 只对用 caching_sha2_password 认证的 MySQL 8 用户有意义不加会报 Public Key Retrieval 错误。driver-class-name 不要写错MySQL 8 对应 com.mysql.cj.jdbc.DriverMySQL 5.7 对应 com.mysql.jdbc.Driver写错会直接抛 ClassNotFound 启动失败。3.3 启动后端并验证接口日志和 Postman 缺一不可后端的启动方式一般两种打开 IDE 直接运行主类或者命令行执行mvn spring-boot:run。用命令行启动有个好处日志输出和实际部署环境更接近排查问题时不容易被 IDE 的编译缓存干扰。cd 后端目录 mvn spring-boot:run启动过程要看两类关键日志第一类是 Spring Boot 启动横幅出现并且后面跟着Tomcat started on port(s): 8080第二类是 MyBatis 或 JPA 的初始化语句没有报错。两者都正常后用 Postman 或 curl 验证一个公开接口例如商品列表curl http://localhost:8080/api/goods/list返回 JSON 数组且 HTTP 状态码是 200说明后端、数据库、ORM 映射整条链路已经打通。如果返回 500优先看后台打印的异常堆栈是数据库连接问题、表前缀问题、还是实体类字段映射问题。很多时候报错信息本身就是线索比如Table shop.goods_info doesnt exist说明 SQL 脚本没执行成功Unknown column name in field list说明实体类字段和表字段没对齐大概率是驼峰转下划线配置没开。3.4 小程序开发工具导入前端域名校验和 baseURL后端通了接下来处理小程序端。用微信开发者工具导入前端目录导入时选择不使用云服务。本地开发阶段需要在详情→本地设置里勾选不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书不然 wx.request 访问 http://localhost 会直接报url not in domain list。导入之后把前端请求的基础路径 baseURL 配置指向后端地址。常见配置文件路径是utils/request.js或config/index.js。// utils/request.js const BASE_URL http://localhost:8080/api export function request(url, method, data) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL url, method: method || GET, data: data || {}, header: { Content-Type: application/json, Authorization: wx.getStorageSync(token) || }, success: (res) { if (res.statusCode 200 res.data.code 0) { resolve(res.data.data) } else { reject(res) } }, fail: reject }) }) }这段封装做了两件事一是统一为每个请求附加 Authorization 头这样后端拦截器能识别登录态二是统一解析后端返回结构前端业务代码只管拿 data不用每个页面都判断一次状态码。baseURL 在开发者工具模拟器里可以写 http://localhost:8080但如果用手机真机预览localhost 会失效必须把 localhost 改成电脑的局域网 IP比如 http://192.168.1.100:8080同时确保手机和电脑在同一个局域网并且电脑防火墙放行 8080 端口。到这里后端能返回 JSON、小程序能发请求一个最小可运行闭环就建立了。4. 核心功能模块拆解登录、下单、商品管理与后台联动4.1 微信登录链路code 换 openidopenid 换 token购物系统的第一道关口是登录。小程序端调用wx.login()拿到一个临时凭证 code后端拿这个 code 加上 AppID、AppSecret 去微信的接口换 openid。code 的有效期只有五分钟而且是一次性使用所以必须把换 openid 的逻辑放在后端不能在前端缓存。// pages/login/login.js wx.login({ success: (res) { request(/auth/login, POST, { code: res.code }).then((data) { wx.setStorageSync(token, data.token) wx.switchTab({ url: /pages/index/index }) }) } })后端收到 code 后做三件事调微信接口换 openid、查用户表决定登录还是自动注册、生成 token 返回前端。PostMapping(/auth/login) public Result login(RequestBody LoginDTO dto) { String openid wxService.code2Session(dto.getCode()); User user userMapper.selectByOpenid(openid); if (user null) { user new User(); user.setOpenid(openid); user.setNickname(微信用户); userMapper.insert(user); } String token UUID.randomUUID().toString().replace(-, ); tokenRedis.set(token, user.getId(), 7, TimeUnit.DAYS); return Result.success(token); }代码里的关键点是把 token 和 userId 绑定并设置有效期。毕业设计里用 Redis 存 token 是一个加分写法token 可以过期用户退出或管理员强制下线时也可以主动删除。如果资源包没引入 Redis退一步用数据库表存 token 也可以但要在查 token 时判断过期时间。不要把 token 直接设置为 openid 或者 userId 的明文否则拦截器验证就形同虚设任何拿到该值的人都能冒充用户。4.2 商品浏览与购物车Vue 页面的数据流商品列表页拿到商品 JSON 后小程序端的渲染逻辑是把每个商品渲染成卡片。购物车这边的加购请求是把商品 id 和数量 POST 到后端接口// pages/goods/detail.js addToCart() { const goodsId this.data.goods.id request(/cart/add, POST, { goodsId, num: 1 }).then(() { wx.showToast({ title: 已加入购物车, icon: success }) }) }后端加购接口不会真的在这里扣库存只在 cart 表里存一条记录。如果购物车里该商品已存在就更新数量而不是插入新行这需要一张 user_id goods_id 的联合唯一索引来兜底。商品详情页能做的优化是把 create_time 或 update_time 作为排序字段让购物车列表最新加入的排前面这是一个小体验点但论文里能写成基于时间排序的购物车管理策略也算一个小的自我亮点。购物车列表页需要注意的数据流是前端不做任何价格计算顶多在展示时把单价乘数量得到小计。真正的价格校验必须在下单接口里做这一点在 4.3 会细说。如果前端在购物车页自行修改商品单价再传后端在不做校验的后端实现里就会变成漏洞。4.3 下单与订单列表前端确认订单后端二次校验下单流程一般拆成两个页面确认订单页→订单提交页。确认订单页显示的商品单价快照、数量小计在提交前都可以变真正落库时以后端重新读取的价格为准。前端每次发起下单请求时把购物车项的 id 列表传过去而不是传计算好的总金额这是最安全的设计。submitOrder() { const cartIds this.data.selectedItems.map(item item.id) request(/order/create, POST, { cartIds, address: this.data.address }).then((res) { wx.redirectTo({ url: /pages/order/detail?id res.id }) }) }后端下单接口的核心逻辑刚才在第 2 章讲了事务边界这里补充一个容易漏掉的管理行为订单创建之后要处理支付环节。支付功能在毕业设计里通常做模拟不做真实微信支付常见的做法是订单状态先置为待付款前端页面显示模拟支付按钮点击后把状态改为待发货。这个模拟支付的过程对完整购物流程的演示是必须的——不然演示到用户下单就卡住了后面管理员发货、用户收货都没法闭环。订单列表接口要考虑分页和状态筛选。小程序端我的订单页有一个状态栏包含全部/待付款/待发货/已发货/已完成实质就是GET /order/list?status0page1size10这样的查询。后端返回对象里要带上总条数前端做触底加载时用总条数判断是否还有下一页。如果接口没有分页一次把所有订单返回给小程序数据量过千后会明显卡顿而且翻页逻辑完全没法写这不是一个好的设计。4.4 管理端商品上下架与订单状态更新资源包里的管理端一般是 Vue 的后台项目单独一个目录和后端通过不同的前缀路由交互。商品管理的主要操作是上架、下架、编辑库存和价格。这里尽量在管理端的商品列表接口里加上状态筛选方便演示时快速找到一个下架商品再上架。订单管理这一块是前后端联动的关键管理员在后台修改订单状态为已发货用户端我的订单页在刷新后应立即显示状态变化。如果你打算把代码改造得更完整可以考虑给商品表加一个 merchant_id让管理端按店铺过滤商品这样系统就可以讲多商家入驻的故事。但要注意资源包和配套论文如果都是单店模型这种改造会牵扯到商品查询、订单归属、库存逻辑等多处关联改动工作量远超你一开始的预想。动手前先在论文里把模型改成多商家再改代码避免两边对不上。5. 遇到这些问题别慌启动与联调的五组高频排查5.1 小程序请求不通后端baseURL 和域名校验的双重陷阱现象开发者工具里点击登录或加载商品一直转圈控制台报request:fail或者url not in domain list。原因两个常见因素叠加。一是不校验合法域名的开关没有打开本地请求 http 地址被微信侧拦截二是 baseURL 写成了 localhost模拟器能访问但真机预览时手机根本访问不到电脑本机地址。解决开发阶段在微信开发者工具的详情→本地设置里勾选不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书真机调试时把 baseURL 改为电脑的局域网 IP并确认手机和电脑在同一网段。后端如果开了防火墙先放行对应端口再试。改完 baseURL 记得在开发者工具里清除缓存重新编译有时候旧的请求缓存会覆盖新地址。5.2 MySQL 版本切换引发的启动失败现象后端一启动就报Cannot create PoolableConnectionFactory或者Public Key Retrieval is not allowed。后者在 MySQL 8 里低频出现。原因pom.xml 中的 MySQL 驱动版本和本地数据库版本不匹配。MySQL 8 默认用 caching_sha2_password 认证老版本的驱动不支持这种认证方式于是出现Public Key Retrieval is not allowed。另一个高频原因是连接 URL 里没有加serverTimezone报错信息指向时区无法识别。解决确认 pom 里驱动版本。如果本地是 MySQL 8驱动依赖用mysql-connector-j8.xurl 里加serverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrueuseSSLfalse。改完配置清理 Maven 缓存再启动IDE 里记得刷新依赖。dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId version8.0.33/version /dependency改完再跑一次mvn clean spring-boot:run一般能看到数据源初始化成功。5.3 商品图片不显示静态资源映射缺失现象小程序商品列表能拉到数据但图片全裂控制台请求图片返回 404。原因后端把商品图片存放在本地磁盘 upload 目录但 Spring Boot 没有把/upload/**映射到本地磁盘路径所以请求被默认的静态资源处理器拒掉了。另一个变体开发环境下localhost能访问真机用 IP 访问后图片仍无法加载通常是图片 URL 写成了绝对地址或者带上了哪个机器的路径。解决在配置类里加静态资源映射把本地磁盘目录和 URL 前缀绑定。Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceLocations(file: System.getProperty(user.dir) /upload/); } }如果图片最终要上真机演示最好把 upload 目录改成相对稳定路径或者直接把图片路径存成完整 URL。不要在代码里把图片地址写死成D:/xxx/upload/...演示时换了台电脑就白瞎。5.4 下单后库存没扣事务未生效的三种可能现象点击下单订单表多了一条记录但商品表库存数不变。原因大概率是三种情况之一。第一Service 方法没加Transactional第二加了但方法被同类内部调用——Spring 的Transactional只拦截外部代理调用同类的 A 方法调 B 方法时注解失效第三异常被 try-catch 吞掉事务感知不到异常自然没法回滚。解决把下单逻辑放在独立的 OrderService 里方法上写Transactional(rollbackFor Exception.class)。不要在 Service 内部 try-catch 后吞掉异常让异常正常抛给上层事务才能正确回滚。检查库存扣减是否生效用一个库存为 1 的商品做两个并发会话同时下单测试这是最直接的验证方式。5.5 端口占用和依赖冲突启动日志没到 Tomcat现象运行mvn spring-boot:run后日志推到Web server failed to start. Port 8080 was already in use就停了。原因本地另一个 Java 进程占用了 8080或者上一次运行的后端进程没有关掉。另一种少见情况是 pom.xml 里引入了多个版本冲突的依赖启动时直接抛NoSuchMethodError。解决先用命令查端口占用。# Linux / macOS lsof -i:8080 # Windows netstat -ano | findstr :8080找到占用进程 PID 后 kill 掉或者把后端端口改成 8081 再启动。依赖冲突用mvn dependency:tree排查重点看同一个依赖是否存在两个版本。改完端口记得同步改小程序端 baseURL不然前端仍然请求 8080后端日志确实起来了但接口全超时。6. 把资源包从能运行变成能答辩演示顺序与论文自检的最后一公里代码能跑通只是第一步毕业设计答辩的现场表现关键在演示是否有逻辑。资源包里的论文和 PPT 不是装饰品而是你的演示脚本。我一般会把模拟项目X 的演示固定为五步。第一步小程序端正常启动进入首页展示商品列表并指出列表数据来自后端接口而非写死的 JSON。第二步用微信登录模拟流程进入个人中心讲明 code 换 openid 再换 token 的链路。第三步选一件商品加入购物车再下单在确认订单页展示收货地址然后模拟支付成功。第四步切到管理端把刚下的订单状态改成已发货。第五步切回小程序端刷新订单列表显示状态同步。这五步一次走完整个系统的前后端协作和数据库流转全部得到验证。论文自检也值得花时间。把资源包论文里的接口列表和代码里的实际 Controller 路径对着核对一遍常见问题是论文写/api/goods/add代码里实际路径是/api/goods/save或者字段名不一致。统一返回结果的 code 和 message 也要一致这能省掉答辩老师临时翻代码找对不上的尴尬。PPT 里的系统架构图、用例图、ER 图最好和代码实现保持同一种命名风格图里叫goods_info代码里也必须是goods_info别一个下划线一个驼峰。有一个习惯让我从那次模拟项目X 的答辩里学到很多任何代码资源包拿到手先从配套的使用说明文档开始按它的步骤在干净环境里重新跑一遍验证通过再改需求。从那以后我每次拿到同类资源都强制自己先走完这遍说明书验证再打开代码目录。这能让资源里的环境坑提前暴露而不是积累到答辩前夜。如果你正准备拿这套 SpringBoot Vue 的购物系统做底稿建议把演示流程、接口核对和使用说明检查也放进计划里这套包值得按这个顺序吃透。希望帮到你。本文还有配套的精品资源点击获取