ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Spring Boot + 微信小程序农产品商城:从登录到库存扣减全解析

2026/10/6 9:29:55 拓冰建站 浏览量
Spring Boot + 微信小程序农产品商城:从登录到库存扣减全解析 简介这是一份面向计算机相关专业学生的毕业设计论文资源完整呈现了基于微信小程序的云浮市特色农产品交易系统的设计与实现。论文采用Java语言开发小程序前端结合Spring Boot框架与MySQL数据库搭建后端服务与数据存储针对传统农产品销售渠道受限、市场范围狭窄、信息不对称等痛点设计了集商品浏览、购物车管理、在线下单、支付与物流跟踪于一体的交易方案。文档为单个docx文件体积约1.13MB内容包含中英文摘要、目录、课题背景与意义、国内外研究现状、开发工具及技术介绍、系统设计实现等完整章节。其中不仅详细解释了Spring Boot的自动配置机制与Starter POMs对开发效率的提升还覆盖了微信开发者工具、B/S架构等关键技术并具体说明了用户端与商家后台的核心功能模块。对于需要参考毕业设计框架、技术选型论证或撰写论文的同学这份文档可作为直接模板帮助快速明确系统结构、功能划分与写作脉络。目前已有51人学习适合用于农产品电商类系统设计与开发的项目借鉴。1. 云浮市特色农产品交易的题目拆解这本质上是一个可演示的电商系统如果你拿到了“基于Spring Boot和微信小程序的云浮市特色农产品交易平台设计与实现”这个毕设题目先别急着把注意力放在“论文”两个字上。这个标题的实质是一个前后端分离的农产品商城微信小程序商城 Spring Boot 后端接口 MySQL 数据库外加一篇把设计过程讲清楚的毕业论文。它的业务场景很具体——把云浮本地的特色农产品罗定稻米、新兴凉果、郁南无核黄皮这类搬到小程序上卖买家逛商品、下单、付款卖家发货管理员管商品和订单。适合谁一个是正在选毕设题目的计算机相关专业学生另一个是想在本地做农产品线上渠道、需要一个最低成本方案的小团队。你需要交付的是一套能跑起来、能在答辩时演示的系统而不是一篇空谈架构的文档。2. 系统边界与选型先想清楚角色、数据库和工程结构这个题目容易被做成“大而全”的商城但毕设的评审老师更在意的是逻辑闭环谁能用什么功能、数据怎么流转、异常怎么处理。所以第一步不是写代码而是把系统边界画出来。2.1 三种角色和一条交易主线买家、农户、管理员各管什么云浮市特色农产品交易平台的最小可用模型是三端买家在小程序端浏览和下单农户卖家管理自己的商品和订单管理员在后台管理全平台。我一般建议论文里的用例图就按这三个角色画不要自己加一个“平台运营”之类的模糊角色。角色核心操作数据权限范围买家微信用户浏览商品、搜索、加入购物车、下单、付款、确认收货只能看到自己的订单农户卖家上架/下架商品、修改库存、发货、查看订单只能操作自己店铺的商品管理员审核商品、管理用户、查看全量订单、数据统计全平台数据交易主线是浏览商品 → 加入购物车 → 提交订单 → 支付 → 农户发货 → 买家确认收货。这条线里的每一个状态变化都要能对应到数据库里的一条记录和接口的一次调用。论文里的时序图、数据库设计、测试用例全部围绕这条主线展开其余的注册、搜索、个人中心都是辅助功能先做主线再补分支项目不会乱。2.2 技术选型Spring Boot 2.7.x、MyBatis-Plus 与原生小程序的理由这个题目不需要微服务不需要 Redis 集群不需要消息队列。常见做法是后端用 Spring Boot 2.7.x MyBatis-Plus MySQL 8.0小程序端用原生微信小程序开发管理后台如果时间紧张可以直接用若依这类脚手架生成的 Web 页面甚至只写接口再用 Postman 演示。为什么明确用 Spring Boot 2.7.x因为很多同学看到最新版本是 3.x 就装了最新版结果 Spring Boot 3 要求 JDK 17原来的 JDK 8 项目跑不起来javax 包也改成了 jakarta一堆老教程里的代码直接编译报错。用 Spring Boot 2.7.x JDK 8/11那些网上能搜到的 Spring Boot 框架教程、MyBatis-Plus 教程、Maven 依赖写法全都能用省去大量填版本坑的时间。这是这个项目第一个关键决策环境图省事选稳定版本。2.3 数据库五张表和工程骨架先把落点定死再写代码数据库设计是论文里最好写也最好被质询的部分。我建议核心业务控制在五张表用户表user、商品表product、订单表orders、订单明细表order_item、购物车表cart。加上商品分类字段而不是单独建分类表因为农产品种类有限一个 category 字段就能撑住。表名关键字段说明userid, openid, nickname, avatar, role, phone, addressopenid 唯一role 区分买家/农户productid, seller_id, category, name, price, stock, image, statusstatus 控制上下架seller_id 关联农户ordersid, order_no, buyer_id, seller_id, total_amount, status, create_timestatus0待支付 1待发货 2待收货 3已完成 4已取消order_itemid, order_id, product_id, product_name, price, count快照字段防止商品改名影响历史订单cartid, user_id, product_id, count小程序端可用本地缓存替代工程结构方面Maven 项目里按 controller / service / mapper / entity 分包具体代码在下一章展开。这里先给一个最小可启动的配置骨架我用的是 Spring Boot 2.7.x 的经典配置数据源换成你自己的云浮本地 MySQL 即可。dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdcom.auth0/groupId artifactIdjava-jwt/artifactId version3.19.4/version /dependencyserver: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/yunfu_agri?useUnicodetruecharacterEncodingutf8 username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 jwt: secret: yunfu-agri-secret-key expire-minutes: 10080配置里几个点说明一下。jwt.secret 是签发票据用的密钥用于微信登录后给小程序端返回 token有效期设成 7 天10080 分钟这样用户不用天天重新登录。MyBatis-Plus 的逻辑删除配置让删除操作变成更新操作商品下架不删数据论文里写“数据可追溯”就有依据。日期格式统一成 yyyy-MM-dd HH:mm:ss 是为了让小程序端直接显示不用再做一次时间格式化。启动这个工程前先在 MySQL 里建好库和五张表然后跑一个最简单的 health 接口确认 Spring Boot 能起来再往下加业务代码。3. 后端核心实现登录、商品、订单与库存的代码路径后端是整个系统的“黑匣子”评审老师最常追问的就是登录怎么做的、订单状态怎么流转的、库存怎么防超卖。这一章把四条核心代码路径讲透。3.1 微信登录换取 openidcode2session 与 JWT 签发小程序端调用wx.login()拿到一个临时 code后端拿这个 code 去微信服务器换 openid。openid 是用户在小程序里的唯一身份标识拿到它之后查库如果没有就自动注册然后签发 JWT 返回给前端。Service public class WeChatAuthService { Value(${wx.appid}) private String appid; Value(${wx.secret}) private String secret; private final UserMapper userMapper; private final JwtUtil jwtUtil; public WeChatAuthService(UserMapper userMapper, JwtUtil jwtUtil) { this.userMapper userMapper; this.jwtUtil jwtUtil; } public LoginResult login(String code, String nickname, String avatar) { // 1. 用 code 换 openid String url https://api.weixin.qq.com/sns/jscode2session?appid appid secret secret js_code code grant_typeauthorization_code; String response HttpUtil.get(url); JSONObject json JSONObject.parseObject(response); String openid json.getString(openid); if (openid null) { throw new BusinessException(微信登录失败请检查 appid 和 secret); } // 2. 查库不存在则自动注册 User user userMapper.selectOne(new LambdaQueryWrapperUser() .eq(User::getOpenid, openid)); if (user null) { user new User(); user.setOpenid(openid); user.setNickname(nickname ! null ? nickname : 微信用户); user.setAvatar(avatar); user.setRole(1); // 1买家, 2农户 userMapper.insert(user); } // 3. 签发 JWT过期时间 7 天 String token jwtUtil.createToken(user.getId(), user.getRole()); LoginResult result new LoginResult(); result.setToken(token); result.setUserId(user.getId()); result.setRole(user.getRole()); return result; } }这段代码是这个平台所有业务的前提。注意第 1 步里 jscode2session 的调用有频率限制所以前端不能每次进页面都走 wx.login而是只在本地没有 token 或者 token 过期时才调。第 2 步的自动注册是毕设常见的简化做法论文里可以说“用户无感注册”但如果要做到农户身份需要在个人中心里提供“切换为农户”的身份申请入口。第 3 步签发的 JWT 建议把 userId 和 role 放进去后续每个需要鉴权的接口都从 token 里拿当前用户信息不用再查一次数据库这也是答辩时能讲清楚的优化点。3.2 商品分页与分类筛选列表接口要有边界商品列表是用户打开小程序看到的第一个页面接口设计上注意两点分页和字段裁剪。毕设里最常见的翻车是直接把整表查出来返回给前端数据量大了小程序端渲染会卡网络传输也慢。我一般用 MyBatis-Plus 的分页插件每次只取一页。RestController RequestMapping(/api/product) public class ProductController { private final ProductService productService; public ProductController(ProductService productService) { this.productService productService; } GetMapping(/list) public ResultIPageProductVO list( RequestParam(defaultValue 1) Integer page, RequestParam(defaultValue 10) Integer size, RequestParam(required false) String keyword, RequestParam(required false) String category) { PageProduct pageParam new Page(page, size); LambdaQueryWrapperProduct wrapper new LambdaQueryWrapper(); wrapper.eq(Product::getStatus, 1) // 只看上架商品 .like(StringUtils.hasText(keyword), Product::getName, keyword) .eq(StringUtils.hasText(category), Product::getCategory, category) .orderByDesc(Product::getCreateTime); IPageProduct productPage productService.page(pageParam, wrapper); IPageProductVO voPage productPage.convert(p - { ProductVO vo new ProductVO(); BeanUtils.copyProperties(p, vo); return vo; }); return Result.ok(voPage); } }这里的关键参数是 page 和 size。defaultValue 1 和 10 表示默认取第一页十条小程序端滚动到底部时把 page 加一再请求一次对应“微信小程序页面列表加载更多”的场景。status 1 的过滤条件必须由后端做不能只靠前端隐藏下架商品否则用户直接改接口参数就能看到下架货。keyword 用 like 查询农产品名称短这种模糊匹配够用但如果论文里想写“搜索优化”可以提一句“本项目使用 MySQL 的 LIKE 实现关键字搜索数据量增大后可替换为 ElasticSearch”点到为止即可。VO 转换是为了不把 price 的 BigDecimal 格式问题、库存字段暴露给前端这也是可写进论文的一个设计细节。3.3 订单状态机从待支付到已完成超时关单用定时任务兜底订单模块是整个系统里最容易被问垮的地方。很多学生把状态流转写散在各处支付接口改一次状态、取消接口改一次状态、发货接口再改一次结果没有任何统一约束状态说变就变。正确的做法是先定义一个状态机用一个 Service 统一处理所有状态迁移。public enum OrderStatus { WAIT_PAY(0, 待支付), WAIT_DELIVERY(1, 待发货), WAIT_RECEIVE(2, 待收货), COMPLETED(3, 已完成), CANCELLED(4, 已取消); private final int code; private final String desc; OrderStatus(int code, String desc) { this.code code; this.desc desc; } public static boolean isAllowedTransition(int from, int to) { // 允许的状态迁移表 if (from WAIT_PAY.code) { return to WAIT_DELIVERY.code || to CANCELLED.code; } if (from WAIT_DELIVERY.code) { return to WAIT_RECEIVE.code; } if (from WAIT_RECEIVE.code) { return to COMPLETED.code; } return false; } }配合这个状态机订单 Service 里的每个方法在更新前先校验isAllowedTransition不合法直接抛业务异常。这能挡住一个常见场景待支付订单被用户连续点击两次“取消”按钮第二次请求进来时订单已经是已取消如果没有校验就会把状态再改一遍导致状态错乱。还有个细节是超时关单我建议用 Spring 的定时任务或 xxl-job 每分钟扫一次超过 30 分钟未支付的订单把它改成已取消并回滚库存。Component public class OrderCloseTask { private final OrderMapper orderMapper; private final ProductMapper productMapper; Scheduled(fixedDelay 60000) public void closeExpiredOrders() { LocalDateTime deadline LocalDateTime.now().minusMinutes(30); LambdaQueryWrapperOrder wrapper new LambdaQueryWrapper(); wrapper.eq(Order::getStatus, OrderStatus.WAIT_PAY.getCode()) .lt(Order::getCreateTime, deadline); ListOrder expiredOrders orderMapper.selectList(wrapper); for (Order order : expiredOrders) { order.setStatus(OrderStatus.CANCELLED.getCode()); orderMapper.updateById(order); // 回滚库存 for (OrderItem item : orderItemMapper.selectList(...)) { productMapper.rollbackStock(item.getProductId(), item.getCount()); } } } }fixedDelay 60000 表示任务结束后 60 秒再跑下一次不是从启动开始每分钟固定执行这样不会出现上一次任务没跑完而下一次又启动的并发覆盖问题。30 分钟超时阈值建议放进配置里而不是写死在代码中论文里的“可配置参数”章节就能多一个可以讲的点。定时关单配合状态机把订单模块的边界彻底锁死了。3.4 库存扣减的原子 SQL高并发超卖问题要提前交代库存扣减是面试和答辩都喜欢问的点。最朴素的做法是先查库存、判断是否大于 0、再减库存但并发请求下这一步极易超卖——两个请求同时查到库存还剩 1都通过判断都执行了扣减库存变成 -1。解决的这个问题的核心其实就一句话把查询和扣减合并成一条原子 SQL。public interface ProductMapper extends BaseMapperProduct { Update(UPDATE product SET stock stock - #{count} WHERE id #{productId} AND stock #{count} AND status 1) int deductStock(Param(productId) Long productId, Param(count) Integer count); }mysql 里UPDATE ... WHERE stock #{count}的写法本身就是原子操作InnoDB 会在执行更新时对行加锁天然防止两个事务同时扣减同一行。返回值 int 是受影响的行数等于 1 说明扣减成功等于 0 说明库存不足或商品已下架业务层根据这个返回值决定是创建订单还是提示“库存不足”。这条 SQL 能挡住大多数并发场景论文里写“采用乐观锁思路通过条件更新保证库存扣减的原子性”就站稳了。加 Redis 预减库存属于进阶方案毕设系统不需要提前讲清楚反而显得你知道边界在哪里。4. 小程序端实现请求封装、登录态与列表加载优化小程序端是用户直接面对的“门面”实现它的核心不是页面好看而是稳住三个点网络请求不出错、登录态不丢失、列表加载不卡顿。这一章按这三个点展开。4.1 原生微信小程序还是 uni-app先想清楚要不要跨端这个题目里写着“微信小程序”没有跨端需求我建议直接原生开发。理由很现实原生语法就是 WXML、WXSS、JS 三件套网上的教程和代码片段最多遇到问题直接在官方文档里就能找到答案uniapp 的语法是 Vue 风格如果你没学过 Vue还要先补 Vue 的基础知识性价比太低。但如果你的论文想顺带提一句“后续可扩展为 uni-app 一套代码多端打包”那也无可厚非只是开发阶段不要给自己加复杂度。原生项目首页上只需要三个页面文件index、category、cart、order、me够演示买家和农户核心流程即可。4.2 请求层封装token 注入与 401 统一处理所有小程序页面的网络请求都走同一个封装好的 request 方法不要在页面里裸写wx.request否则你会在几十个页面里重复处理 token 过期逻辑改一个参数要翻遍整个项目。我写的是封装在 utils/request.js 里的一套通用请求。const BASE_URL http://localhost:8080/api; function request(method, path, data) { return new Promise((resolve, reject) { wx.request({ url: BASE_URL path, method: method, data: data, header: { Content-Type: application/json, Authorization: wx.getStorageSync(token) || }, success(res) { if (res.statusCode 200 res.data.code 200) { resolve(res.data.data); } else if (res.statusCode 401) { wx.removeStorageSync(token); wx.navigateTo({ url: /pages/login/login }); reject(new Error(登录状态已过期)); } else { wx.showToast({ title: res.data.msg || 请求失败, icon: none }); reject(new Error(res.data.msg)); } }, fail(err) { wx.showToast({ title: 网络请求失败, icon: none }); reject(err); } }); }); } module.exports { get: (path, data) request(GET, path, data), post: (path, data) request(POST, path, data) };请求层里最容易被忽略的是 BASE_URL。微信开发者工具里跑本地联调没问题但真机预览时 localhost 指向的是手机自己必须改成电脑的局域网 IP。上线前还要注意微信要求请求地址必须是 HTTPS 且在小程序后台配置合法域名否则真机会拦截请求。Authorization 头里塞 token后端从 JWT 里取 userId这样每个接口都天然带有用户信息。401 统一处理会清掉本地 token 并跳回登录页用户重新走一次微信登录就能恢复会话不用重启整个小程序。4.3 登录页的三种状态首次授权、静默登录、token 过期登录流程是微信小程序特有的逻辑。用户第一次进来需要点击“微信一键登录”按钮触发wx.login拿到 code 后走后端接口换取 token第二次再进来本地已有 token 就直接进首页token 过期时由请求层拦截并引导重新登录。三种状态对应三个分支代码里要分别处理。Page({ onLoad() { this.checkLogin(); }, checkLogin() { const token wx.getStorageSync(token); if (token) { wx.switchTab({ url: /pages/index/index }); } }, handleLogin() { wx.login({ success: async (res) { const loginRes await request.post(/auth/login, { code: res.code, nickname: 云浮用户, avatar: }); wx.setStorageSync(token, loginRes.token); wx.setStorageSync(userId, loginRes.userId); wx.switchTab({ url: /pages/index/index }); } }); } });注意这里的 wx.login 拿到的是临时 code不是用户昵称和头像。如果你要展示用户头像昵称得用wx.getUserProfile单独再写一套授权逻辑但很多毕设直接放弃获取头像昵称统一显示“微信用户”省时省力论文里把“用户可通过个人中心补充昵称和头像”写进功能清单就行。登录后跳转要用wx.switchTab而不是wx.navigateTo因为首页一般配置在 tabBar 里navigateTo 只能跳非 tabBar 页面这算小程序新手最常见的报错之一。4.4 商品列表页加载更多onReachBottom 与防抖回到商品列表页。页面触底时自动加载下一页对应微信小程序页面列表加载更多这个经典场景实现注意到两个细节页面滚动条到触发区以及防止连续触底重复请求。Page({ data: { productList: [], page: 1, size: 10, hasMore: true, loading: false }, onReachBottom() { this.loadNextPage(); }, async loadNextPage() { if (this.data.loading || !this.data.hasMore) return; this.setData({ loading: true }); const res await request.get(/product/list, { page: this.data.page, size: this.data.size, keyword: , category: }); const newList this.data.productList.concat(res.records); this.setData({ productList: newList, page: this.data.page 1, hasMore: res.records.length this.data.size, loading: false }); } });loading 标志位是这个逻辑的“保险丝”。onReachBottom 在手指快速滑动时可能被触发多次如果没有 loading 判断同一页数据会被请求好几遍列表里出现重复商品。hasMore 判断通过当前返回条数是否等于页面大小来推断还有没有下一页这是最简单可靠的分页判断方式而不是前端猜一个总页数。配合 WXML 里wx:for渲染商品卡片列表滚动加载就完整了。注意下拉刷新和触底加载会用同一套分页参数如果做了刷新page 要重置成 1列表清空否则刷新后会把老数据叠加进来。5. 毕设最常踩的五个坑从 Spring Boot 版本到支付资质照着排查这一章是血泪经验汇总。我见过太多项目在最后一周因为环境或配置问题推倒重来下面这五条是按出现频率排的建议每一条都对着自己项目过一遍。5.1 Spring Boot 3.x 编译报错javax 不存在问题是 springboot 版本太高现象从网上下了一个老项目的源码导入 IDEA 后大量 import 报错javax.servlet、javax.annotation全部标红项目根本编译不过。原因你装的是 Spring Boot 3.x它要求 JDK 17并且把 javax 包替换成了 jakarta 包网上绝大多数教程和源码都是基于 Spring Boot 2.x 的接口名和注解路径全对不上。解决把 pom.xml 里的 parent 版本改成 Spring Boot 2.7.xJDK 降到 8 或 11重新导入 Maven编译即通过。这条排桌面最高如果你刚起步直接固定用 2.7.x别给自己找麻烦。5.2 真机预览发不出请求合法域名和“不校验”选项现象模拟器里一切正常用微信扫码在真机预览首页空白Network 面板里请求全部 fail。原因默认情况下真机强制校验接口域名是否在微信公众平台配置的合法域名清单里而你的后端地址是http://localhost:8080微信根本不认。解决开发调试阶段在微信开发者工具的“详情 → 本地设置”里勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”发布上线前把你的域名配置成 HTTPS 并加入小程序后台的 request 合法域名列表。这里还有个隐藏成本微信小程序认证费用 300 元一年由主体承担如果只是毕设演示认证不是必须项但上线就必须走这一步论文里可以把“部署成本”写进可行性分析。5.3 订单状态串了状态机没有统一收口现象测试时发现已取消的订单还能发货已收货的订单还能再取消数据乱成一团。原因前端页面里多个入口都在调用订单状态变更接口每个接口各自写一套更新 SQL没有统一的合法性校验。解决按第 3 章的做法在后端维护一个状态机枚举在所有订单状态变更的 Service 方法开头调用OrderStatus.isAllowedTransition(from, to)非法迁移直接抛异常。这条解决成本很低但在论文的“系统测试”章节里非常好写你列出状态迁移表再写几个非法操作的测试用例测试结论一目了然。5.4 商品图片显示空白临时文件路径和上传域名是两回事现象图片上传成功数据库里存的路径也能看到但商品列表里图片就是裂开。原因小程序端wx.chooseImage拿到的是本地临时文件路径如wxfile://tmp_xxx这个路径只有当前会话有效其他用户拿到这个路径自然无法访问。解决图片要先通过wx.uploadFile把文件传到后端由后端保存到本地目录或云存储返回一个可访问的 URL 存入数据库。注意云开发环境的存储域名也需要在小程序后台配置为 downloadFile 合法域名否则同样会被拦截。如果你论文里选了“文件存储在本地磁盘”的简单方案记得给 Spring Boot 配一个静态资源映射让/upload/**能访问到文件目录。5.5 库存超卖并发下单时库存变成负数现象用两个账号同时下单同一件只剩 1 件库存的商品两个订单都创建成功商品库存变成 -1。原因代码是先SELECT stock判断大于 0 再UPDATE stock stock - 1两个请求先后读到相同的库存值各自扣减后写回最后库存被覆盖成 -1。解决把扣减改为UPDATE product SET stock stock - #{count} WHERE id #{productId} AND stock #{count}用受影响行数判断是否成功。这条是实验中很容易给评委演示的“亮点式”问题你甚至可以写一段 JUnit 测试模拟多线程并发下单证明修正前后库存结果的差异放在论文测试章节里很加分。6. 答辩前怎么验证接口文档、状态推演和真机演示顺序毕设评审实际上是一场“可信度”的考验。评委看的不只是你能跑而是你能讲清楚“为什么这么设计”。答辩前我会做三件事。第一接入 knife4j 或 Swagger 生成接口文档把登录、商品、订单、库存这组接口的请求响应示例整理成 PDF 放进论文附录演示现场就算网络不给力评委看接口文档就能理解系统全貌。第二在测试数据里准备一个完整的交易链路——从买家注册、下单、支付、农户发货到确认收货每个节点截一张图状态变更时间要能对上这组截图同时用于论文的“系统实现”和“系统测试”两章。第三真机演示时按固定顺序操作先展示登录用微信扫体验版二维码然后搜一款云浮本地特产比如郁南无核黄皮加购、支付可用模拟支付开关、查看订单状态变化、农户端发货、买家确认收货一口气走完这条主链比临时翻代码页更有说服力。最后说一个经验之谈我接手过几个类似题目的改动最后悔的都是前期没把订单状态机和库存扣减这两块硬骨头放在前列等界面都做完了再补状态逻辑牵一发动全身。这套系统真正能打动答辩老师的地方也恰恰在于这两块的严谨性界面简洁不是减分项。先把主链跑通再考虑多商户、消息推送、数据大屏这些加分项。希望帮到你。本文还有配套的精品资源点击获取