基于微信小程序的家具电商平台SpringBoot实战开发

发布时间:2026/10/19 9:56:08
基于微信小程序的家具电商平台SpringBoot实战开发
1. 项目概述与需求拆解今年帮人梳理过好几个类似的题目最典型的就是“基于微信小程序的家具电商平台”这种后端要求用Java生态前端落地在微信小程序。说句实话这类题目被选作毕业设计不是因为新颖而是因为它覆盖面够广小程序端能体现移动端交互能力SpringBoot后端能体现业务接口设计能力再加上支付、订单、库存这些电商核心链路整个项目拿出来既有工程量又有深度答辨的时候可讲的东西很多。很多同学拿到这种题目容易犯一个错上来就开始敲代码结果数据库表建完之后发现根本对不上功能或者做完了用户端发现管理端完全没法用。这篇文章会把整个项目从需求拆解、技术选型、数据库设计、接口规划到实际联调逐层讲透特别适合准备开题或者已经写了一半发现乱掉的场景。内容是基于我实际带项目的经验整理的大部分方案你照着做就能跑通。1.1 系统定位与目标用户先想清楚一件事这套系统不是给“程序员展示技术”用的而是模拟一个真实的家具零售场景。家具商品的典型特征是单价高、体积大、决策周期长用户不太可能像买日用品一样直接下单更多是浏览商品、收藏对比、咨询客服、然后下单购买。所以小程序端的核心目标不是堆功能而是让用户能快速看到商品、了解详情、方便结算。基于这个定位我把系统划分为三类使用角色角色需求概括典型功能C端用户逛、选、下单、付款、查看订单商品分类浏览、搜索、详情、购物车、结算、订单追踪平台运营管商品、管订单、管活动商品上下架、库存维护、订单发货、轮播图配置系统管理员基础数据维护与权限控制用户管理、角色权限、数据统计、系统配置这个表格看起来简单但它决定了后面的表结构和接口设计。比如用户表不只是存openid还要存手机号、收货地址、积分、会员等级因为家具商城经常要做会员价和运费策略。再比如商品表必须拆出SKU和规格的概念一张沙发可能有不同的颜色、尺寸、材质这些都会影响库存和价格。1.2 核心业务流程梳理电商系统的核心链路就一条浏览商品 → 加入购物车 → 提交订单 → 支付 → 发货 → 确认收货。这句话听起来像废话但如果在设计阶段不把这条链路的数据流画清楚后面做订单表时一定会出问题。我建议先梳理订单状态的流转这是整个系统最关键的环节。我的做法是把订单状态定义为一组数字枚举0待付款1待发货已支付2待收货已发货3已完成确认收货/自动确认4已取消5退款中/已退款为什么要用数字而不是直接存中文状态因为订单状态会参与大量后端逻辑判断比如取消订单只能从待付款状态发起发货只能从待发货状态发起。如果用中文串代码里到处是字符串比较容易写错用数字枚举配合状态机校验代码更干净服务端接口也能统一做状态校验。另外要提前想清楚的是购物车数据放哪。小程序端的购物车有两种做法一是放在本地存储Storage里二是放在服务端数据库里。我的建议是毕设阶段直接做服务端购物车原因很简单本地购物车无法处理多端同步也无法支撑“登录后购物车合并”这种常见场景答辨时容易被追问。服务端购物车虽然多几个接口但对订单链路更顺后面开发起来反而轻松。2. 技术选型解析与后端框架对比很多人在技术选型上纠结半天其实毕设项目选型就一个原则稳定、好实现、能讲清楚。SpringBoot 微信小程序这个组合是近几年最常见的电商项目组合之一原因不在于它有多新而在于它刚好覆盖了从业务建模到接口交付的完整闭环。2.1 后端框架为什么不用SSM而选SpringBoot我先说后端为什么不选传统的SSMSpring SpringMVC MyBatis不是不能用而是SSM的配置太繁琐要写大量的XML配置文件很多同学光配置文件就调一两个星期。SpringBoot把自动配置做掉了你只需要关注业务代码这对毕设的时间安排非常友好。持久层我推荐用MyBatis-Plus它比原生MyBatis多了很多便捷特性内置通用Mapper、分页插件、条件构造器。实际写代码时商品列表的分页、订单条件的组合查询都能省下大量重复劳动。举个例子做一个带筛选的商品列表用MyBatis-Plus的LambdaQueryWrapper可以直接这样写public PageProduct queryProductPage(Integer current, Integer size, String category, String keyword) { LambdaQueryWrapperProduct wrapper Wrappers.lambdaQuery(); wrapper.eq(StringUtils.isNotBlank(category), Product::getCategoryId, category) .like(StringUtils.isNotBlank(keyword), Product::getName, keyword) .eq(Product::getStatus, 1) .orderByDesc(Product::getCreateTime); return productMapper.selectPage(new Page(current, size), wrapper); }这段代码的意义是不用手写XML里的动态SQL也不会出现字符串拼接导致的SQL注入风险。条件只有在非空的时候才会追加到SQL里页面参数不管传不传都安全。数据库选MySQL基本没什么争议你只需要注意两点第一使用InnoDB引擎因为电商系统的事务非常重要订单创建和库存扣减必须在一个事务里第二表字段统一加上create_time和update_time后面做数据统计、列表排序都用得上。至于Redis缓存毕设里可加可不加。如果加了就重点讲缓存商品列表、首页轮播图把缓存穿透和缓存一致性原理讲清楚这是加分项不想加也行别硬凑。2.2 小程序前端原生还是跨端框架前端方面面临的选择是原生微信小程序、uni-app、Taro。我的建议很直接如果是毕设且你的重点是后端Java那原生小程序是优先级最高的。原因有两点。第一原生小程序不依赖额外的编译框架微信开发者工具直接调试报错信息直观新手坑少第二uni-app虽然有跨端优势但它的运行机制在真机调试时反而会多一层你不太容易定位的封装问题对时间有限的毕设项目不划算。小程序端的基本目录结构大致是这样的pages下面放页面每个页面由wxml、wxss、js、json四个文件组成。pages里面我习惯拆成home首页、category分类、cart购物车、mine个人中心、goods商品详情、order订单列表这几个模块刚好对应TabBar和主流程页面。再补充一个关键点小程序的网络请求封装非常关键。不要在每个页面直接wx.request一定要封装一个request.js工具函数统一处理baseUrl、token注入、状态码拦截和错误提示。我见过太多同学在十几个页面里各写各的请求代码最后改接口域名时痛苦得想哭。这里给一个非常简化的封装思路const request (url, method GET, data {}) { return new Promise((resolve, reject) { wx.request({ url: baseUrl url, method, data, header: { Content-Type: application/json, token: wx.getStorageSync(token) || }, success: (res) { if (res.statusCode 200) { resolve(res.data); } else if (res.statusCode 401) { wx.navigateTo({ url: /pages/login/login }); reject(res); } else { wx.showToast({ title: res.data.msg || 请求失败, icon: none }); reject(res); } }, fail: (err) reject(err) }); }); };统一的header注入token、统一的状态码处理能让你调试的时候少跑很多冤枉路。3. 核心设计与数据库建模电商系统的表设计是整套系统的骨架。如果表设计乱了存储过程再怎么写都是糊的。对于这个家具商城项目我建议至少规划以下几张核心表用户表、商品分类表、商品表、购物车表、收货地址表、订单表、订单明细表、轮播图表、管理员表。下面挑几个重点讲。3.1 商品表与订单表的字段设计商品表核心字段至少包含这些id、分类id、商品名称、主图、详情图多个、价格、原价、库存、销量、状态、上架时间。对于家具商品还需要考虑“规格”问题。可以有两种设计简单方案是每个规格单独一条商品记录复杂方案是单独一张规格表。毕设我建议用简单方案把不同颜色/尺寸作为不同商品记录用名称区分例如“北欧风实木书桌-1.2米”“北欧风实木书桌-1.5米”。这样价格和库存都清晰代码也简单。订单表是整个系统的重心我的建议核心字段如下字段类型说明idbigint订单主键order_novarchar(32)订单编号展示给用户看user_idbigint下单用户total_amountdecimal(10,2)商品总金额freight_amountdecimal(10,2)运费pay_amountdecimal(10,2)实付金额statusint状态0待支付/1待发货/2待收货/3完成/4取消receiver_namevarchar(50)收货人姓名receiver_phonevarchar(20)收货电话receiver_addressvarchar(255)收货地址pay_timedatetime支付时间deliver_timedatetime发货时间create_timedatetime创建时间这里要特别强调订单号和实付金额。订单号不要用自增主键因为会暴露销量而且生成规则要可控。我生成订单号的规则一般是年月日时分秒 用户ID后四位 随机四位例如 2025061210304512345678。虽然看起来长但它在用户端展示足够友好在后台做单号查询也方便。实付金额一定要单独存一份不要查询时再去算因为支付金额涉及后续退款、对账一定不能依赖商品价格变动。3.2 接口规划与JWT权限控制数据库表确定后接口规划就顺理成章了。我一般按模块把接口分成用户端接口和管理端接口前后端通过不同的路径前缀区分比如用户端用/api/user/xxx管理端用/api/admin/xxx。这里列出核心接口清单模块接口方法说明登录/api/user/loginPOST微信登录 code2Session 换取openid并颁发token商品/api/product/listGET商品分页列表支持分类和关键字筛选商品/api/product/detail/{id}GET商品详情购物车/api/cart/listGET购物车列表购物车/api/cart/addPOST加入购物车订单/api/order/createPOST创建订单订单/api/order/listGET当前用户订单列表支付/api/pay/wxpayPOST发起微信支付管理/api/admin/product/savePOST商品新增/编辑管理/api/admin/order/deliverPOST订单发货权限控制这块我用JWTJSON Web Token来做。流程是用户用wx.login得到临时code后端拿code去向微信接口换取openid首次登录自动注册然后签发JWT返回给前端。前端每次请求把token放在header里后端用一个拦截器统一解析token并设置当前用户上下文。管理端接口则额外校验角色标识简单做法是在token里带上role字段拦截器里判断路径前缀/admin/并且role不是管理员就拒绝。这里有一个容易犯的错把openid当主键。openid只是微信用户的唯一标识但你后面要扩展手机号、积分、会员体系所以应该单独用自增id做用户主键openid作为唯一索引字段。这样以后万一需要接多个登录方式用户表不用大改。4. 实操过程从0到1实现核心流程这一章是最花时间的部分我挑几个最容易卡住的环节把流程和关键代码展开讲。4.1 微信登录与Token鉴权的落地微信登录是整个系统用户体系的基础流程并不复杂但细节很多。小程序端先调用wx.login获取一个五到十分钟有效的临时code然后把code传给后端。后端收到code后调用微信接口:https://api.weixin.qq.com/sns/jscode2session参数是appid、secret、js_code也就是code、grant_typeauthorization_code。返回结果里最核心的是openid如果小程序绑定了开放平台还会有unionid。另外还有一个session_key用来解密用户手机号、获取运动数据等毕设阶段一般用不到但你要注意服务端不要把这个值返回给前端这是微信安全接口的数据。后端核心代码大概是这样的PostMapping(/login) public Result login(RequestBody LoginRequest req) { // 1. 调用微信code2Session接口 String url https://api.weixin.qq.com/sns/jscode2session?appid appId secret secret js_code req.getCode() grant_typeauthorization_code; String result restTemplate.getForObject(url, String.class); JSONObject json JSON.parseObject(result); String openid json.getString(openid); // 2. 查询用户是否存在不存在则自动注册 User user userMapper.selectOne(new LambdaQueryWrapperUser() .eq(User::getOpenid, openid)); if (user null) { user new User(); user.setOpenid(openid); user.setNickname(微信用户 openid.substring(openid.length() - 6)); user.setCreateTime(new Date()); userMapper.insert(user); } // 3. 签发JWT并返回 String token JwtUtil.createToken(user.getId(), user.getRole()); return Result.success(token); }实际跑这个流程时最常见的问题有两个。第一个是code2Session接口返回40029意思是code无效原因往往是同一个code被用了两次或者code已经过期。排查的办法是确保前端只在登录时调用一次wx.login不要让页面onLoad和onShow都触发登录。第二个问题是网络环境导致的接口超时开发调试时如果后端部署在服务器上要确认服务器能访问微信的接口域名本地开发时本机网络没问题一般就能过。4.2 商品展示与购物车的完整链路商品展示这个模块看起来简单但要把体验做顺需要注意首页轮播图、分类Tab、商品列表三块数据来源的一致性。我的做法是首页和分类页都调用同一个商品列表接口通过categoryId参数区分。轮播图单独一张表由管理端配置图片URL和跳转商品ID。商品列表接口需要处理分页。小程序端常见的是上拉加载更多也就是每次请求第current页每页size条。后端返回的参数建议用page、total、records这种结构方便前端判断是否还有下一页。前端拿到数据后追加到列表尾部而不是整体替换。购物车这块我前面提过建议做服务端购物车。它的表结构很简单id、user_id、product_id、quantity、checked、create_time。注意一个细节同一用户加入同一个商品时不要插入新记录而是更新已有记录的quantity加1。如果不去重购物车里会出现两行一模一样的商品记录用户体验很差。下单流程是从购物车创建订单。这里我建议在创建订单时把购物车中勾选的商品一次性取出然后依次检查库存是否充足不充足则提示哪个商品库存不足。库存检查通过后生成订单主表记录和订单明细记录最后清空购物车中已下单的商品。整个过程必须放在一个事务里用Transactional注解。下面是一个简化的代码结构Transactional public String createOrder(Long userId, ListCartItem cartItems) { Order order new Order(); order.setOrderNo(generateOrderNo(userId)); order.setUserId(userId); // 逐项计算金额并检查库存 for (CartItem item : cartItems) { Product product productMapper.selectById(item.getProductId()); if (product.getStock() item.getQuantity()) { throw new BizException(product.getName() 库存不足); } // 扣减库存 product.setStock(product.getStock() - item.getQuantity()); productMapper.updateById(product); // 保存订单明细、累加金额 } orderMapper.insert(order); return order.getOrderNo(); }这里一定要强调事务如果订单创建了一半某个商品库存扣减失败整个操作必须回滚否则就会出现“订单不存在但库存少了”的脏数据。Transactional注解加上后方法内任何运行时异常都会让整个事务回滚。4.3 支付功能接入与替代方案做电商毕设支付是绕不开的点。完整接入微信支付需要企业主体资质、微信支付商户号、APIv3密钥、证书等个人开发者很难申请。我的经验是能接入真实支付最好接入不了就做一个“模拟支付”并且把流程设计得足够严谨答辨时反而可以说清楚“真实支付和模拟支付的差异”以及“支付回调安全校验”这两个加分点。微信支付的官方流程是后端调用统一下单接口获取prepay_id然后生成支付参数返回给小程序小程序端用wx.requestPayment发起支付支付完成后微信服务器会向你的后端回调地址发送支付通知后端收到通知后验签、解密然后更新订单状态为已支付。这里最关键的一步是回调处理因为回调里的订单状态判断如果写错会出现用户明明付款了订单却还是待付款的问题。模拟支付就简单很多我建议的做法是在支付接口中生成一个支付二维码或者直接写一个“模拟支付确认”按钮点击后前端模拟调用wx.requestPayment后端收到“支付成功”通知后同样更新订单状态。为了让答辨更有说服力可以把支付状态更新逻辑单独抽成一个服务类方法这样真实支付和模拟支付都调用同一个方法体现代码的可扩展性。4.4 管理后台与文件上传管理员后台我建议不要做得太重用一套Web管理界面配合简单的表格表单就能满足需求。核心功能是商品管理、订单管理、轮播图配置和简单的数据统计。如果你不想从零写管理后台可以基于某开源后台管理框架二次开发只需要把商品表和订单表的CRUD界面做出来附上订单发货操作就已经覆盖了题目要求的大部分评分点。文件上传是管理端最常出的问题。管理员上传商品图片前端用form表单提交到后端接口后端接收MultipartFile后保存到本地上传目录或云存储。本地保存的方式需要配置上传目录、静态资源映射和文件大小限制。在SpringBoot中默认单文件上传大小限制是1MB商品详情图通常都会超过这个大小所以要改配置spring: servlet: multipart: max-file-size: 10MB max-request-size: 20MB同时还要在系统里做一个映射把本地上传目录映射成可访问的URL。如果用云存储要注意访问权限和URL有效期设置否则会出现图片加载不了的情况。5. 常见问题与排查技巧实录这一部分都是我在实际开发中遇到的真实问题整理成速查表帮你少踩坑。5.1 微信开发者工具请求异常域名校验与TLS版本开发阶段最常见的问题是小程序请求后端接口时提示“url not in domain list”。这是因为微信小程序在上线后必须使用HTTPS请求而且域名必须在小程序后台配置为request合法域名。在开发调试阶段你可以在微信开发者工具的“详情”-“本地设置”里勾选“不校验合法域名”这样才能正常请求本地或测试环境。但要注意一下即使开发阶段能请求发布前也必须要有一个备案过的HTTPS域名。申请SSL证书、将证书配置到Nginx然后在小程序后台添加request、uploadFile合法域名这三个步骤是上线前必做的。我见过不少同学把功能全做完了最后卡在域名配置这步时间预算要提前留好。5.2 登录后一直无法获取用户信息小程序从2022年起对获取用户头像和昵称的接口做了调整wx.getUserProfile的返回值在部分场景下会变成默认头像和“微信用户”。所以不要依赖前端拿到的用户信息作为主要用户数据正确做法是以后端为准openid作为用户唯一标识头像昵称只作为展示用途允许用户在小程序内自行修改。某高校的一个模拟项目里就出现过这个问题后来把用户信息存储逻辑改成先登录后完善资料才彻底解决。5.3 订单金额不一致和并发库存问题订单金额不一致通常是前端把金额传给了后端后端没有重新计算。正确做法是后端根据商品库存和价格重新计算订单总金额前端传的商品ID和数量只能作为订单项依据金额的一定以后端计算为准。库存并发问题可以用乐观锁解决商品表的库存字段加一个版本号字段更新库存时带上条件stock #{quantity}如果影响行数为0说明库存不足直接返回库存不足提示。5.4 图片上传失败与加载不了图片上传失败的原因一般是这几个请求头没有设置Content-Type为multipart/form-data、小程序上传文件需要用wx.uploadFile而不是wx.request、后端上传目录没有创建导致FileNotFound、文件大小超过限制。加载不了则通常是静态资源映射没配好或者云存储的URL签名过期。建议在做管理端商品维护时先上传一张小尺寸测试图确认URL能直接访问后再继续做其他功能。5.5 时间与日期显示差8小时这是个容易被忽略的问题。服务器时区如果没设置成Asia/Shanghai或者数据库连接串里没有加serverTimezoneGMT%2B8那么订单创建时间会比本地时间少8小时。排查方法很简单在数据库连接串末尾加上serverTimezoneAsia/Shanghai同时给JVM设置时区参数-Duser.timezoneAsia/Shanghai。这个问题虽然小但被答辨老师问到就非常尴尬。6. 部署上线与答辩准备很多人把代码写完就以为结束了其实部署和答辩准备的细节反而决定了项目最终能拿到的分数。6.1 服务器环境与上线清单我建议毕设阶段买一台轻量应用服务器就够用配置选择2核4G起步操作系统选CentOS或Ubuntu。上线部署的核心流程是安装JDK、MySQL、Nginx将后端项目打成jar包用systemd或脚本守护进程运行。前端小程序不需要部署服务器只需要把后端域名配置到小程序后台即可。Nginx这里有一个关键配置把HTTP请求转发到SpringBoot的8080端口同时配置HTTPS证书。小程序要求所有request和uploadFile的域名都必须HTTPS而且不允许使用IP地址或端口访问。所以域名解析、SSL证书、Nginx反向代理这三步必须提前搞定。一个简化版的Nginx配置片段如下server { listen 443 ssl; server_name your-domain.com; ssl_certificate /etc/nginx/cert/your-domain.pem; ssl_certificate_key /etc/nginx/cert/your-domain.key; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }这个配置写完后要记得执行nginx -t测试语法然后reload。如果接口能通过https://your-domain.com/api/xxx访问小程序端的baseUrl就填这个地址。6.2 答辩准备与加分项答辩时老师最常问的问题基本围绕在这几个点订单状态如何流转、库存如何防止超卖、用户身份如何校验、为什么选择这个技术栈。这些如果你真的从头到尾做过一遍回答起来不难怕的是只看了别人的代码却没有理解。想拿高分建议额外准备两样东西第一个是项目架构图简单画一下小程序端、后端服务、数据库、微信接口之间的调用关系第二个是核心流程的时序说明比如登录流程和下单流程用口语化方式讲清楚每一步做了什么。这两个东西不需要多高级但能让老师快速判断你确实是做过项目的人。注意答辩前一定要整理一份接口文档哪怕只用表格列出接口路径、请求参数、返回结果。很多同学代码写完了却说不清楚自己做了哪些接口有文档撑场会从容很多。我实际带完这个项目最大的感受是电商类毕设赢在“完整”而不在“炫技”。与其纠结要不要上Redis、消息队列、分布式事务这些重型组件不如把登录、下单、支付、发货这一条最核心的链路跑得滚瓜烂熟把事务、缓存、接口安全这些基础点讲清楚。如果你时间充裕可以在这个基础上扩展数据分析模块或者做订单状态异步处理这些才是真正能拉开分差的地方。最后再提醒一句开发前一定先把数据库表和接口文档定好纸上画链路的半天时间能帮你省下整个项目周期里边的两周返工时间。