资讯动态

Spring Boot+微信小程序商城系统源码解析与部署指南

发布时间:2026/8/29 3:56:25 来源:尧图企业网站定制
简介Spring Boot与微信小程序是当前全栈开发的热门组合前者提供稳定高效的后端服务后者为C端用户带来轻便的交互体验二者通过RESTful API协同工作广泛应用于毕业设计、课程设计及中小型电商实战项目。本文从技术原理入手讲解前后端分离架构、登录态管理、商品浏览、购物车与订单流转等核心机制并深入解读商城系统源码的模块划分与数据流向。同时提供从环境配置、数据库初始化到小程序联调的完整部署步骤以及常见启动异常与调试方法帮助开发者快速跑通项目建立对全栈商城开发的整体认知并为后续功能扩展如多规格商品、微信支付打下基础。 很多朋友拿到基于Spring Boot和微信小程序网上商城系统.zip这类源码包之后第一反应是解压、用IDEA打开、然后一脸懵。要么是后端启动报错要么是前端小程序白屏折腾一天最后感叹“这源码是不是有问题”。其实大部分情况下不是源码有问题而是你还没建立起对这套系统的整体认知。这篇内容我打算用一整个项目的复盘视角把网上商城系统从Spring Boot后端到微信小程序前端完整拆开讲一遍。包括源码包里的目录结构怎么看、后端核心模块如何组织、小程序端如何跟后端对上话、订单和购物车的数据流转是怎么回事以及我实际跑通这个项目时踩过的坑。适合正在做毕业设计、课程设计或者想快速上手Spring Boot小程序全栈开发的朋友。1. 先别急着敲代码读懂源码包的整体结构与技术选型拿到一个源码zip最忌讳的就是双击打开、满屏乱点。我习惯先把整个项目的骨架摸清楚知道每一层是干什么的再去跑代码出了问题也能快速定位。这一点在实际开发中也很重要接手老项目的第一步永远是看结构而不是读每一行业代码。1.1 后端项目的分层结构与包名阅读技巧Spring Boot项目的源码包通常遵循标准的Maven目录结构。src/main/java下面一般会有controller、service、mapper、entity或pojo/domain、config这几个包。这个网上商城系统也不例外我在拿到源码包后第一件事是展开这几个目录看一下类名就能大致猜出功能边界。com.example.mall ├── controller # 接口层接收前端参数、返回JSON ├── service # 业务逻辑层处理具体业务规则 ├── mapper # 数据访问层对应MyBatis的Mapper接口 ├── entity # 数据库实体类一张表对应一个类 ├── dto # 数据传输对象接口入参/出参封装 ├── config # 配置类如拦截器、跨域、微信配置 └── common # 公共类如统一返回结果、异常处理拿商城系统举例controller下面通常会有UserController、ProductController、OrderController、CartController、CategoryController这几个类。看到这几个类名你基本就知道这套系统的核心业务是用户、商品、购物车、订单、分类管理。如果还多了AddressController说明支持收货地址管理如果有CouponController那说明还做了优惠券功能。application.yml或者application.properties是后端配置的入口。商城系统一般会配置数据源MySQL、端口、MyBatis的mapper-locations、微信小程序的appid和secret。这里我要提醒一句源码里带的微信小程序appid和secret大概率是别人的或者说根本不能用的测试值。你拿到代码后第一件要改的就是这两个配置项换成自己的小程序账号信息。1.2 数据库初始化脚本先导数据再谈运行源码包里的sql目录或db目录通常放着初始化脚本命名可能是mall.sql或者schema.sql。商城系统的表结构一般会有这么几张核心表user用户表、category商品分类表、product商品表、cart购物车表、order订单表、order_item订单明细表。我拿到mall.sql之后会先打开看一眼不需要全看重点看两张表product和order。product表能看出商品字段设计得是否完整order表能看出订单状态是怎么管理的。如果这两张表字段设计得清晰那后面写业务逻辑会顺手很多。商城系统的状态字段通常是int类型比如status字段0表示待付款1表示待发货2表示待收货3表示已完成。这个状态定义会在后端代码里反复用到建议你在阅读源码前先记住这几个数字的含义。1.3 技术栈的配套关系为什么是Spring Boot MyBatis-Plus 小程序这套系统的后端是基于Spring Boot 2.x版本做的持久层用的是MyBatis-Plus。MyBatis-Plus在商城这类CRUD密集型项目里特别常见因为它内置了通用的增删改查方法写代码效率高。源码里你会看到很多ServiceImpl类直接继承ServiceImplMapper, Entity这就是MyBatis-Plus的用法不需要自己写BaseMapper的基础SQL。微信小程序端的技术栈则是原生小程序框架不是uni-app。原生小程序有一个好处微信开发者工具直接导入就能跑不需要额外的框架编译步骤。不过原生小程序也有个问题就是不能直接使用npm包封装请求、管理全局用户信息只能自己写公共JS文件。这套技术栈的组合在今天仍然是很多企业级项目的标配Spring Boot做后端API小程序做C端入口MySQL存数据。搞清楚了这个组合的优缺点你再去读源码会顺畅很多。2. Spring Boot后端三个核心模块撑起整个商城网上商城系统的后端逻辑如果不看源码你会觉得电商很复杂但真正拆解下来核心模块其实就三个用户登录态、商品浏览、订单流转。这三个模块搞定商城的主流程就通了。其他像分类、轮播图、收货地址都是锦上添花。2.1 用户登录态微信小程序登录的两次请求是怎么设计的小程序登录和传统网页登录最大的区别是小程序端不需要用户输入用户名密码而是通过微信的code换openid来实现。这套系统的UserController里一定有一个login接口接收小程序端传过来的code然后后端拿这个code去微信的接口换openid。RestController RequestMapping(/api/user) public class UserController { Autowired private UserService userService; PostMapping(/login) public Result login(RequestBody LoginDTO loginDTO) { String code loginDTO.getCode(); // 1. 用code换取openid String openid userService.getOpenidByCode(code); // 2. 根据openid查用户查不到就注册 User user userService.getOrCreateUser(openid); // 3. 生成登录令牌返回给前端 String token JwtUtil.generateToken(user.getId()); return Result.success(token); } }这里有个关键的设计点小程序端调用wx.login()拿到的是临时凭证code这个code有效期只有5分钟且只能用一次。后端每次用code去微信接口换openid返回的json里会有openid、session_key、unionid如果有绑定开放平台。源码里的逻辑一般是只取openid作为用户的唯一标识。需要注意的是session_key不要返回给前端这个是敏感信息。如果小程序端需要解密手机号或者用户信息才需要用到session_key而且这个解密操作必须放在后端做。我见过不少初学项目把session_key直接返回给前端这是一个安全隐患。拿到openid之后后端的逻辑是查数据库如果用户不存在就自动注册一条新记录。这个设计很符合小程序商城的场景用户不需要手动注册打开小程序就是游客一旦发起登录后台就帮你创建了一个账号。注册时系统会给用户生成默认昵称和头像比如“微信用户123456”。登录后怎么保持状态这套系统用的是token机制。后端用JWT生成一串令牌存到Redis或者直接返回给前端小程序端把它存到storage里后面的请求都带上这个token。我在源码里看到的是JWT方案JwtUtil类负责生成和解析tokenLoginInterceptor拦截器负责校验请求头里的token。如果拦截器校验失败会返回401状态码前端收到之后跳转到登录页或者重新发起登录。2.2 商品浏览分类、轮播图、商品列表的接口设计方式商城首页通常由三块内容组成顶部轮播图、商品分类导航、推荐商品列表。对应到后端就是三个接口/api/banner/list、/api/category/list、/api/product/page。轮播图和分类的接口设计比较简单直接查表返回列表数据。这里我比较关注的是商品列表接口因为它涉及分页和条件查询。源码里用的MyBatis-Plus的分页插件Page通过PageProduct和LambdaQueryWrapper构建查询条件。GetMapping(/page) public Result getProductPage(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(required false) Integer categoryId, RequestParam(required false) String keyword) { PageProduct page new Page(pageNum, pageSize); LambdaQueryWrapperProduct wrapper new LambdaQueryWrapper(); wrapper.eq(categoryId ! null, Product::getCategoryId, categoryId) .like(StringUtils.hasText(keyword), Product::getName, keyword) .eq(Product::getStatus, 1); productService.page(page, wrapper); return Result.success(page); }这个接口的设计很典型categoryId非空的时候按分类过滤keyword非空的时候按商品名称模糊搜索status1表示只查上架商品。小程序端首页分类和搜索页都可以复用这个接口只需要传不同的参数就行。商品详情接口一般是/api/product/info/{id}返回商品的完整信息包括轮播图列表、详情富文本、库存、价格、销量等。小程序端在商品详情页启动时请求这个接口把内容渲染到页面上。2.3 购物车与订单事务和状态机如何保证数据一致性购物车的设计有两种思路一种是纯前端缓存把购物车数据存在小程序本地另一种是后端存储每个用户的购物车数据存在数据库里。这套系统用的是后端存储方案cart表里记录了user_id、product_id、quantity这几个核心字段。购物车接口的设计很直接/api/cart/add、/api/cart/list、/api/cart/update、/api/cart/delete。添加购物车的时候后端会先查一下该用户购物车里是否已有这个商品如果有就直接增加数量没有就新增一条记录。这个逻辑用SQL表达就是先select再insert或update源码里一般是在CartServiceImpl中做这个判断。订单模块是整个商城系统的核心也是比较难啃的部分。创建订单的接口通常会涉及多张表的操作插入订单主表、插入订单明细表、扣减商品库存、清空购物车。这四件事要么全部成功要么全部失败所以源码里这个方法一定加了Transactional注解。Transactional(rollbackFor Exception.class) public Order createOrder(OrderCreateDTO dto) { // 1. 生成订单号 String orderNo generateOrderNo(); // 2. 根据购物车记录批量扣库存 // 3. 插入订单主表 // 4. 批量插入订单明细表 // 5. 清空购物车 return order; }这里要特别注意的是扣库存的操作。如果在select库存之后、update库存之前有两个用户同时下单就可能出现超卖问题。源码如果是在update语句里带上库存条件比如UPDATE product SET stock stock - #{num} WHERE id #{productId} AND stock #{num}那么是安全的。如果只是先查再改没有加库存校验那就存在并发安全风险。订单状态流转也是我读源码时关注的重点。上面提到的status字段从0到3的流转是有规律的用户提交订单后状态为0待付款支付回调成功后变为1待发货商家发货后变为2待收货用户确认收货后变为3已完成。源码里的OrderController会有对应的pay、deliver、confirm接口来更新这些状态。小程序端的不同操作会改变订单的状态同时前端页面也会根据状态显示不同的按钮。3. 微信小程序端从app.js到商品列表的数据链路后端接口梳理清楚之后再来看小程序端就轻松多了。小程序端的核心在于搞清楚页面怎么调接口、数据怎么绑定、登录态怎么维持。这套源码的小程序端在miniprogram目录或者wechat目录下用微信开发者工具导入后就能看到完整结构。3.1 小程序目录结构与工具函数封装原生小程序项目的标准结构包含app.js全局逻辑、app.json全局配置、pages页面目录、utils工具函数目录、components自定义组件目录。商城系统的小程序端还会多一个api目录专门放接口请求的封装。app.js里通常会放全局数据比如globalData对象中记录用户信息、后端接口的baseURL、token。在小程序启动时onLaunch生命周期里会读取本地缓存的token如果没有token就调用wx.login()获取code然后请求后端登录接口换取token。// app.js App({ globalData: { baseUrl: http://localhost:8080/api, userInfo: null, token: }, onLaunch() { const token wx.getStorageSync(token); if (token) { this.globalData.token token; } else { this.login(); } }, login() { wx.login({ success: (res) { wx.request({ url: this.globalData.baseUrl /user/login, method: POST, data: { code: res.code }, success: (response) { wx.setStorageSync(token, response.data.data); this.globalData.token response.data.data; } }); } }); } })utils/request.js是对wx.request的二次封装。因为原生小程序的wx.request用起来比较繁琐每次都要写url、method、header所以源码里几乎都会封装一个request函数。这个函数内部会做几件事自动拼接baseURL、自动带上token请求头、统一处理HTTP状态码和业务状态码、统一处理错误提示。3.2 首页与商品列表的动态数据绑定小程序首页通常由swiper轮播图组件、scroll-view分类导航、商品卡片列表组成。页面JS通过onLoad生命周期请求后端接口拿到数据后setData到页面数据源模板里通过wx:for循环渲染。// pages/index/index.js Page({ data: { banners: [], categories: [], products: [] }, onLoad() { this.loadBanners(); this.loadCategories(); this.loadProducts(); }, loadBanners() { request.get(/banner/list).then(res { this.setData({ banners: res.data }); }); }, loadCategories() { request.get(/category/list).then(res { this.setData({ categories: res.data }); }); }, loadProducts() { request.get(/product/page, { pageNum: 1, pageSize: 10 }).then(res { this.setData({ products: res.data.records }); }); } })这里有一个小程序开发里常见的坑wx.request的返回数据结构和浏览器里Axios的不一样小程序默认不会自动解析JSON你需要根据res.statusCode来判断请求是否成功然后通过res.data拿到后端返回的JSON。如果后端返回的是Result统一封装体{ code: 200, data: ..., msg: success }那你还要再取一层res.data.data这也是很多新手刚接触小程序时经常搞混的地方。商品卡片组件通常会被抽成一个自定义组件product-card在首页和搜索页复用。组件内通过properties接收商品对象模板里显示商品图片、名称、价格、销量。点击卡片跳转商品详情页时可以通过navigateTo传id参数也可以借助全局数据或缓存传递更复杂的对象。4. 交易主链路商品加购、提交订单、模拟支付完整走通商城主链路如果只在代码层面读懂还不够直观我建议你实际把系统跑起来然后在微信开发者工具里走一遍流程登录 - 浏览商品 - 加入购物车 - 提交订单 - 支付 - 查看订单状态。这个过程中你会看到后端接口的调用顺序和前端页面的跳转逻辑比光看代码理解深得多。4.1 购物车数量变化时前端如何与后端同步购物车页面加载时小程序端会调用/api/cart/list接口拿到当前用户的购物车列表。用户点击加号或减号修改数量时前端会调用/api/cart/update接口把cartId和新的quantity传给后端。这里有一个细节值得注意数量修改接口返回后前端可能需要重新拉取购物车列表或者用后端返回的最新购物车数据局部更新页面否则会出现不同步的问题。我在源码里看过一种做法是直接把整个购物车数组重新setData虽然简单粗暴但在商品数量多的时候会产生频繁的数据传输。更好的做法是只更新被修改的那个商品条目。不过对于学习项目来说全量刷新也够用了。购物车页面还有一个常用交互勾选商品计算总价。但要注意这套系统的购物车勾选状态一般只存在于前端本地不会提交到后端。用户点击“去结算”时前端会把自己勾选的商品ID数组传给后端后端再根据ID数组去数据库查商品最新价格重新计算订单金额。为什么这样设计因为本地显示的价格可能不是最新的后端应该以数据库价格为准防止用户篡改请求参数把价格改低了。4.2 提交订单到模拟支付的流程走读点击“去结算”后小程序端跳转到订单确认页。用户在这里选择收货地址、确认商品清单后点击“提交订单”前端调用/api/order/create接口传入商品ID列表、数量、地址ID。后端经过事务处理后返回订单号前端拿到订单号后跳转到支付页面。支付这块如果是真实商城会对接微信支付流程是后端调用微信支付统一下单API得到payment参数小程序端用wx.requestPayment拉起支付面板。但作为学习项目或毕设源码里通常做的是模拟支付也就是界面上有个假的支付按钮点击后直接调用后端的/api/order/pay接口把订单状态从0改为1。模拟支付的流程虽然简单但能帮我们把订单状态机完整走一遍。从订单确认页到支付成功页再到订单列表页看到状态变为“待发货”这个过程和真实电商的交互体验是基本一致的。改造成真实支付时只需要替换pay接口的内部实现前端的跳转逻辑基本不用动。4.3 订单列表与订单详情的状态化展示订单列表页通常会有几个Tab全部、待付款、待发货、待收货、已完成。小程序端的实现方式是在页面顶部放几个Tab按钮点击不同的Tab请求/api/order/list接口时传不同的status参数。后端根据这个参数查对应状态的订单列表。订单卡片上会根据状态显示不同的操作按钮待付款显示“去支付”和“取消订单”待发货显示“提醒发货”待收货显示“确认收货”已完成显示“删除订单”。前端代码中通常用wx:if或wx:elif配合status字段来判断显示哪个按钮。因为支付、取消、确认收货这些操作都会调用后端接口所以前端要绑定对应的点击事件并调用相应接口。我在跑这个流程时特别关注了一点订单取消后商品库存是否回滚。因为取消订单意味着用户不再买这几个商品了如果库存不回滚后面就无法下单购买了。源码里如果是简单设计可能忽略了这一点考虑得周全一点的会在取消订单的接口里恢复库存。这是一个很不错的改进切入点面试时也可以作为亮点讲。5. 把项目跑起来的完整步骤与常见启动异常说实话跑通一个Spring Boot小程序的电商项目难度通常不在代码本身而在环境配置上。我见过太多人卡在一开始的启动环节。这一部分我会把从零跑通项目的步骤细化然后列出我实际遇到的几个异常及解决办法。5.1 环境搭配与参数修改清单你需要准备的工具有IDEA或Eclipse、JDK 1.8、Maven、MySQL 5.7、微信开发者工具、Redis如果项目用到了Redis缓存。如果源码里用了Redis那你本机需要安装并启动Redis服务如果没有用到就省去这一步。拿到源码后按顺序做这几件事创建数据库导入mall.sql脚本。注意MySQL的字符集最好设置为utf8mb4否则商品名称里的特殊字符可能存不进去。修改application.yml里的数据源配置改成你本机的数据库地址、用户名、密码。示例里的配置通常是jdbc:mysql://localhost:3306/mall?useSSLfalseserverTimezoneAsia/Shanghai。检查微信小程序的appid和secret配置。如果源码里没有或者你不需要真实登录可以先留空系统大概率会报登录接口错误但不影响其他功能如果要完整测试登录流程就去微信公众平台注册小程序账号拿到自己的appid和secret。启动后端的Application类注意看控制台日志出现Started Application in x.xxx seconds字样说明启动成功。启动微信开发者工具导入项目时选择源码包里的miniprogram目录AppID可以选择测试号但登录需要真实AppID配合后端配置。5.2 后端启动失败端口占用、数据库连接、Redis未启动我在跑Spring Boot项目时最容易遇到的第一个异常就是端口被占用。默认端口是8080如果你本机有其他程序占用控制台会报Port 8080 was already in use解决办法很简单改端口或找到占用端口的进程关掉。server: port: 8081第二个常见异常是数据库连不上报错信息类似Cannot create PoolableConnectionFactory或者Access denied for user rootlocalhost。这种问题九成是数据库URL、用户名、密码写错了去application.yml里对一遍就好。后缀的serverTimezoneAsia/Shanghai很重要MySQL 8.x版本不设置时区会报时间相关的错误。第三个异常是Unable to connect to Redis。Spring Boot项目如果引入了spring-boot-starter-data-redis启动时会自动配置Redis连接。本机没启动Redis就会启动失败。解决方法是启动Redis服务或去掉Redis相关依赖。在源码里如果Redis只用作缓存而不用作JWT存储去掉依赖对主流程影响不大。5.3 小程序端白屏与接口不通的排查方法小程序端最常见的几个问题如下第一个是接口请求失败。开发者工具中如果出现request:fail或ERR_CERT_COMMON_NAME_INVALID多半是域名的问题。本地调试时后端跑在http://localhost:8080而小程序的wx.request默认只允许HTTPS和已备案域名。解决办法是在微信开发者工具的“详情” - “本地设置”里勾选“不校验合法域名、web-view业务域名、TLS版本以及HTTPS证书”。这个只用于本地开发上线时必须换成HTTPS的正式域名。第二个是数据渲染不出来但接口有数据。这种情况大概率是数据层级路径没写对。比如接口返回的是res.data.data.records你模板里写的是item.name但实际数据在item.productName字段。最简单的调试方法是在页面JS里console.log打印接口返回的数据对照着看字段名。第三个是页面白屏控制台报Component is not found in path。这通常是因为组件路径写错了或者组件目录结构不对。检查app.json和页面JSON里的usingComponents配置确保路径和组件文件名完全一致。5.4 使用Postman或Apifox单独调试后端接口如果你不确定问题是在后端还是小程序端我建议先用接口调试工具单独测后端。启动后端服务后用Postman或Apifox发一个GET请求到http://localhost:8080/api/product/page如果返回JSON数据说明后端没问题问题出在小程序端。如果后端直接报错根据错误信息去排查代码或配置。接口调试工具的好处是你可以直观地看到后端返回的JSON结构方便和小程序里的数据结构做对比。这也是我每次读源码必做的步骤——先把所有核心接口通过工具跑一遍确认数据正确后再看前端代码。这个顺序能省去很多重复排查的时间。6. 源码改进与常见坑读代码时我顺手记下的优化点读这套源码的过程中我发现了一些可以优化的地方也踩过一些坑。这些点虽然不是运行报错级别的bug但如果你后续要在这个项目基础上做扩展非常值得关注。6.1 并发扣库存与超卖问题就像前面提到的如果源码中的扣库存SQL没有带stock #{num}条件那么高并发下可能出现超卖。你可以把Mapper里的更新语句改成下面这种UPDATE product SET stock stock - #{num} WHERE id #{productId} AND stock #{num}这样即使两个请求同时进来数据库的行锁也会保证只有一个请求能成功更新。这个改动虽然只有一句话但对系统健壮性的提升非常明显。6.2 商品SKU与多规格扩展源码如果只支持单规格商品即一个商品ID对应一个价格、一个库存那么在面对“红色/大码”“黑色/中码”这类多规格商品时就无能为力了。如果要扩展需要新增product_sku表存储商品的规格名、规格值、价格、库存同时cart和order_item表里要增加sku_id字段。这个改造属于比较大的结构性变动但它在面试或课程设计答辩时是一个很好的技术亮点。你可以先明确说明当前系统只支持单规格然后给出多规格扩展的设计思路会显得你考虑得比较全面。6.3 图片上传与静态资源映射商品图片的存储方式源码里一般有两种做法一种是直接存图片URL比如图床地址另一种是把图片上传到后端项目的静态目录下。后端项目中通常会配置一个WebMvcConfig来实现静态资源映射把/images/**映射到本地目录。如果你要新增商品时上传图片就要确认这个映射路径是否正确。另外要注意的是如果后端图片是通过相对路径返回的比如/images/product/1.png那小程序端在显示图片时需要拼接上后端域名否则图片无法加载。这是一个很容易被忽略的小细节但影响面很大首页商品图全部裂开的话体验非常差。6.4 代码规范与可读性改进建议最后提一点代码规范方面的建议。源码里如果类名都是XxxController、XxxServiceImpl说明作者基本遵守了阿里编码规范。但可能有部分方法没有加注释或者接口没有统一的鉴权处理。你可以根据自己的实际需求把一些核心方法加上注释或者在common包里补充统一的异常处理类RestControllerAdvice让接口在异常时返回更友好的JSON信息。统一的异常处理对小程序端尤其友好。比如用户未登录时后端返回401小程序端在request.js里统一拦截做跳转登录页后端抛业务异常时返回{ code: 500, msg: 库存不足 }前端就弹个toast提示。有了这个统一出口前后端联调会顺畅很多。7. 我跑通这套源码后的几点体会在我自己跑完这套Spring Boot微信小程序商城系统之后最大的感触是一个项目值不值得学不在于它用了多新的技术而在于它的业务链路是不是完整的。从登录到商品浏览从加购到下单支付再到订单状态流转每一条链路都走通了你才能真正理解电商系统是怎么运转的。最后分享一个我在调试时常用的技巧如果改动了后端代码需要重启而你觉得每次重启太慢可以在pom.xml里引入spring-boot-devtools依赖它能在代码变更后自动重启应用。这个工具对开发阶段的效率提升非常明显。另外如果小程序端和后端不在同一台机器上调试比如用手机预览localhost就不管用了。你需要把后端接口地址改成你电脑的局域网IP比如http://192.168.1.100:8080/api同时保证手机和电脑在同一个WiFi下。这个细节也是很多初学者卡了很久的问题。这套源码的完整流程走完之后建议你再做两件事第一尝试新增一个功能模块比如“我的收藏”从前端页面到后端接口全链路做一遍第二把模拟支付改成接入真实的微信支付理解前后端的对接流程。当你把这两件事都做完你就已经具备了独立开发一个全栈商城项目的能力了。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价