ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SpringCloud+Vue+小程序:校园外卖配送系统微服务架构全栈实战解析

SpringCloud+Vue+小程序:校园外卖配送系统微服务架构全栈实战解析 1. 项目概述1.1 这是一套什么系统这是一个面向校园场景的外卖美食配送平台技术栈是SpringBoot SpringCloud Vue 微信小程序。用户端通过小程序下单点餐商家端在后台管理菜品和订单配送端由骑手快递员接单取餐送餐。整个系统采用微服务架构不是传统的一体化单体应用而是把用户、订单、商家、配送、支付这些核心模块拆成独立服务各跑各的进程通过注册中心、网关、消息队列串联起来。很多读者看到微服务三个字就有点发怵觉得只有大厂才用得上。但校园外卖这个场景其实非常适合用微服务来讲清楚问题业务链路长用户下单、商家接单、骑手配送、订单状态流转、并发有明显峰值饭点是集中流量、角色多学生、商家、骑手、平台管理员、终端多小程序、管理后台、骑手App端。这些特征刚好是微服务能发挥优势的地方比单纯做个Demo有意义得多。这个项目的直接价值有两个层面。对学生开发者或初中级工程师来说它是一套完整的、可落地的全栈微服务实战范本能帮你把SpringCloud全家桶里那些零散组件——Nacos、Gateway、OpenFeign、Sentinel——串成一条真实的业务线。对学校或园区运营方来说它是一个可以直接二次开发上线的配送平台基础版本连骑手调度这种最容易踩坑的模块都预留了设计空间。1.2 这套系统要解决的三个核心问题校园外卖平台表面上看起来就是外卖App的简化版但真正动手做起来有三个问题决定了项目的成败。第一微服务拆分的粒度怎么定。拆太细比如把菜品和库存都拆成独立服务带来的问题是服务间通信频繁、事务一致性难保证对一个小团队来说运维成本直接压垮开发进度。拆太粗比如只拆一个业务服务加一个用户服务那微服务就名存实亡了。这个项目采用的拆分思路是业务域优先——按用户、商家、订单、配送四个核心业务域拆辅助以网关、认证等基础设施服务这个粒度对校园场景来说是相对稳妥的选择。第二订单状态在多个服务之间怎么流转。一个订单从待支付到已支付到商家已接单到骑手已取餐到已完成这中间涉及用户服务扣款、订单服务改状态、商家服务通知、配送服务派单。如果不做细致的状态机设计和消息通知机制订单状态很容易错乱。后面我会详细讲这一块的实现方案。第三骑手配送这个环节怎么设计才不鸡肋。很多外卖项目的骑手端只是做个简单的列表页面接单按钮一写就完事了。但实际上骑手端涉及抢单、配送中位置更新、订单状态回传、收益统计等多个交互而且要考虑到骑手手机网络不稳定的场景。这个项目里我对骑手端的定位是轻量但完整核心闭环必须跑通。2. 技术选型与架构设计2.1 为什么是SpringCloud而不是SpringBoot单体先回答一个最容易被问的问题一套校园外卖系统用SpringBoot单体应用做两三个星期就能上线为什么要引入SpringCloud全家桶徒增复杂度我的回答是看你的目标是交付一个软件还是掌握一套方法论。如果纯粹是想快速搞个外卖站单体确实够了。但这个项目的定位是分布式架构实践SpringCloud的核心价值不在能不能跑通功能而在业务规模扩大之后系统还能不能优雅地演进。用单体应用举一个具体例子用户下完单之后订单服务要扣库存、要通知商家、要记录配送信息。如果库存和商家功能都在同一个进程里方法调用就行很爽。但等到促销活动来了订单量一涨你得水平扩展部署多个实例。这个时候问题就来了——单体应用里所有功能耦合在一个进程你只能整体扩容而整个系统里最吃资源的可能是订单模块用户模块根本没压力。微服务把这个痛点解决得很干脆订单服务单独部署三副本用户服务单副本按需扩容互不干扰。另外微服务对团队协作也有实际价值。开发时用户端、订单端、配送端的代码仓库是分开的不同人负责不同模块合并冲突少了很多。我记得做这个项目的时候三个人并行开发用户服务只跟订单服务有OpenFeign接口约定商家服务跟订单和配送服务有接口约定只要把接口定义好各写各的基本不用互相等。2.2 核心技术组件选型与理由整个系统的组件选型遵循一个原则——生产环境验证过的、生态成熟的、资料多的。毕竟不是造轮子项目没必要选冷门技术来彰显个性。组件选型核心理由注册中心与配置中心Nacos同时搞定服务发现和配置管理不用额外引入两套组件中文文档全遇到问题好排查微服务网关Spring Cloud Gateway官方出品路由能力、过滤器机制、限流配置都比较完善性能比Zuul好一截远程调用OpenFeign声明式HTTP客户端写接口调用就像写本地方法维护成本低服务熔断降级Sentinel配置控制台可视化流控规则实时生效比Hystrix的维护状态更有优势认证鉴权JWT Spring Security无状态认证适合微服务场景网关统一校验Token前端后台Vue 3 Element Plus组件库成熟表格/表单等后台常用组件开箱即用用户端微信小程序校园场景学生高频使用微信小程序免安装、分享方便数据库MySQL 8.x RedisMySQL存储业务数据Redis处理热点与缓存消息队列RabbitMQ订单状态变更、通知推送削峰填谷轻量不重这里重点说一下Nacos的选择。早期微服务项目里Eureka作为注册中心很常见但Eureka已经进入维护模式而且它只是个注册中心配置中心还得另外搭Spring Cloud Config。Nacos一个组件同时解决两个问题服务启动后既能注册也能拉配置控制台还带命名空间管理不同环境dev、prod切换配置很方便。对中小型项目来说少一个组件就少一份运维负担这是很实在的好处。2.3 微服务拆分边界与服务间协作拓扑本项目的微服务划分从业务域和复用角度出发拆成以下核心服务用户服务处理C端用户注册、登录、地址管理、用户余额。校园场景可以加一个学生认证的字段不过初期版本用微信OpenId做账号主体就够。商家服务管理商家入驻信息、店铺信息、菜品分类、菜品上架下架。商家后台需要的所有数据都从这个服务出。订单服务整个系统的核心服务承担下单、订单查询、订单状态流转、订单超时处理。这个服务的并发压力最大也是分布式事务和缓存策略最集中的地方。配送服务负责订单与骑手的匹配、骑手接单、配送位置轨迹上报。校园场景配送范围小距离计算直接用经纬度球面距离公式就行不需要引入高德地图API的路径规划。网关服务所有请求的统一入口负责路由转发、JWT Token校验、接口限流。这些服务之间的协作方式就是通过OpenFeign进行同步调用通过RabbitMQ进行异步解耦。同步调用用于必须立刻知道结果的场景比如商家服务查询菜品详情用户服务扣减余额。异步消息用于可以稍后处理的场景比如订单创建之后通知配送服务创建配送单、通知商家服务有新的订单提醒。这么一拆边界就清晰了订单服务不直连商家表商家服务不直连用户余额表所有跨服务的数据都通过接口或消息获取。这避免了微服务架构中最常见的分布式单体问题——服务没拆干净A服务直接操作B服务的数据库表。3. 小程序端与Vue后台的落地实现3.1 微信小程序端从页面结构到接口联调很多做小程序的开发者一开始会纠结用原生微信小程序还是用uni-app这个项目里我选择原生写法。原因很简单——项目里的小程序端只服务一个场景学生点餐没有多端复用需求用uni-app反而多一层编译转换开销。不过如果你后续要把骑手端也做成小程序或者考虑支付宝小程序那uni-app是更好的选择。小程序的页面结构围绕用户核心动线设计pages/ ├── index/ // 首页轮播图、商家列表、平台公告 ├── shop/ // 店铺页店铺信息、菜品列表、商品规格弹窗 ├── cart/ // 购物车页已选菜品、合计价格、结算入口 ├── order/list/ // 订单列表页待付款、待收货、已完成等状态Tab ├── order/detail/ // 订单详情页订单状态、商家信息、骑手信息 ├── address/ // 地址管理页学校地址列表、新增编辑 └── profile/ // 个人中心用户信息、余额、联系客服订单列表页的加载更多这个功能是所有小程序初学者最容易写崩的地方。核心逻辑是这样的请求订单列表时带上pageNum和pageSize两个参数后端返回数据时分页查询。小程序端用一个onReachBottom事件页面滚动到底部时自动触发下一页加载同时用loading状态防止重复请求。我在这个项目里的做法是在data里维护一个loading字段和finished字段每次请求前判断请求完成后如果返回的list长度小于pageSize就说明没有更多数据了把finished置为true不再发请求。这个逻辑看着简单但如果不加防重复请求的判断用户在页面底部快速滚动时一次能触发三四次重复请求订单列表会明显出现卡顿和重复数据。接口联调阶段要注意小程序的域名校验问题。本地开发时在开发工具里勾选不校验合法域名就行但上线前必须配置request合法域名。提前把后端网关的地址规划好很有必要比如所有接口统一走https://api.xxx.com/order/...这样的前缀小程序端只需要封装一个request工具函数自动拼接baseURL和处理Token。3.2 Vue管理后台商家与平台管理如何兼顾管理后台用Vue 3 Element Plus实现这里有一个设计取舍值得说一下——后台要同时满足两种角色平台管理员和商家经营者。两个角色看到的界面有交集但也有差异。平台管理员要看所有商家、所有订单、平台总流水可以审核商家入驻申请、下架违规菜品。商家经营者只能看自己的店铺数据、订单和菜品。实现这种权限模型的方案是这样的后台登录接口返回的JWT Token里包含role字段前端路由守卫根据角色做动态路由注册。平台管理员登录后注册全部路由商家登录后只注册商家相关的路由。接口层面网关会再次校验角色权限只有roleadmin的请求才允许访问/admin/**路径防止有人直接拼URL越权访问。后台的订单管理页面我做了几个实用功能按订单状态筛选、按时间段筛选、订单金额合计。表格里展示订单编号、用户昵称、商品明细摘要、实付金额、下单时间、当前状态。订单详情页用抽屉组件展开能看到完整的菜品列表、收货地址、配送信息和时间线记录。时间线记录这个功能很重要后端在订单状态每次变更时都写入一条日志后台按时间正序展示这对排查订单为什么卡在某一状态非常有帮助。Vue后台的环境配置也有值得记录的经验。开发环境用vue.config.js配置devServer的proxy代理把/api前缀的请求转发到网关地址避免跨域问题。生产环境则通过gateway统一配置跨域前端直接把请求发到网关域名。这里有个坑生产环境前后端分离部署后如果网关没有配置CORS浏览器会直接拦截请求。在网关的全局CORS过滤器里加好Access-Control-Allow-Origin和Access-Control-Allow-Headers一个下午就能搭好后端联调环境。3.3 小程序端常见问题定位、登录态与缓存小程序端做下来有三个高频问题值得展开写一写。第一个是微信登录的临时code换OpenId流程。小程序的wx.login()拿到的code是临时凭证有效期只有几分钟必须通过后端接口去微信的接口服务换取OpenId和SessionKey。正确的流程是前端拿到code后传给后端user服务user服务用code调微信接口换OpenId然后查数据库——如果OpenId存在就返回登录成功不存在就自动注册新用户再返回。前端把后端返回的自定义Token存在storage里后续请求带上这个Token。整个流程不要在前端处理AppId和Secret这些敏感信息必须放在后端否则小程序代码包被解包后密钥直接泄露。第二个是收货地址定位不准。校园场景的地址主要是宿舍楼、教学楼、食堂这种POI点直接用微信的wx.chooseLocation选择地址是可以的但返回的经纬度是百度系坐标如果后端用的是高德地图或者自己的距离计算坐标系不统一会导致位置偏移几十米甚至几百米。实际项目里我的处理方式是用户选择位置后前端用微信的wx.translateCoordinate做坐标转换再传给后端存储。如果后端直接用腾讯地图SDK那就不需要转换因为微信授权位置返回的本来就是腾讯系坐标。第三个是小程序包体积优化。校园WiFi环境下包体积太大影响加载速度也是真实痛点。整个小程序包尽量不要超过2MB超过之后微信会要求分包加载。我把常用的图标做成字体图标或CDN图片链接而不是放在本地静态资源里图片全部走CDN商品图片链接存在数据库里不打包进小程序代码。购物车和订单列表的图片用懒加载image组件加上lazy-load属性页面滚动时再加载图片资源。4. 核心业务流程与关键实现4.1 从下单到支付一次完整订单的流转整个系统最核心的业务流程就是用户从浏览商家到下单支付完成的过程。这条链路跨越了三个微服务状态流转极其容易出错我把每一步的细节拆开讲。Step 1浏览店铺与菜品用户进入首页小程序端调用网关的GET /api/shop/list接口网关路由转发到商家服务商家服务返回店铺列表包含起送价、配送费、评分、月销量。用户点击店铺后调用GET /api/shop/{shopId}/menu返回菜品分类和菜品详情。这里菜品列表需要实时展示已售罄状态所以每次请求都会实时查询库存表不走缓存。菜品图片走CDN详情里包含规格大份/中份/小份价格和库存都挂在规格下面。Step 2加入购物车与提交订单购物车在小程序端是本地维护的用Storage存储已选菜品和数量不调后端接口这样用户体验最流畅。点击结算时前端把购物车数据组装成订单创建请求调用POST /api/order。这个请求经过网关转发到订单服务订单服务的核心逻辑是验证商家是否营业、菜品是否在售、库存是否充足。从购物车数据中计算总金额加上配送费生成订单金额。调用用户服务接口扣减用户余额或校验支付能力在扣减之前先查余额是否足够。扣减库存——注意这里是关键点库存不在订单服务里所以要通过OpenFeign调用商家服务的扣库存接口。订单状态置为PENDING_PAYMENT返回订单ID和预支付参数。Step 3发起支付这个版本里我接的是模拟支付的流程。订单创建成功后前端弹出支付确认框点击确认后调用POST /api/order/{orderId}/pay。订单服务收到支付请求后调用支付中心接口模块内部模拟支付成功后把订单状态改为PAID。Step 4异步通知商家和创建配送单这里就是前面提到的事件驱动的用武之地。订单服务在订单状态变成已支付后发布一个OrderPaidEvent到RabbitMQ的消息队列。商家服务监听这个事件给商家管理后台推送一条新订单待接单提醒。配送服务同时监听事件创建一条配送任务记录状态为WAITING_RIDER等待骑手抢单。这个设计的好处是订单服务不需要同步等待商家服务和配送服务的处理结果把一次支付请求的响应时间降到了最低。哪怕配送服务当时出了故障暂时不可用订单也已经成功支付等配送服务恢复后再补发配送任务也不会导致丢单。4.2 状态机设计订单状态如何保证不乱整个流程中订单状态有PENDING_PAYMENT待支付、PAID已支付、ACCEPTED商家已接单、PICKED_UP骑手已取餐、DELIVERED已送达、COMPLETED已完成、CANCELLED已取消。这些状态不是随意流转的我在订单服务里用枚举 状态流转表做了严格约束。实现方式不复杂定义一个OrderStatusChange的Mapkey是当前状态value是允许的下一状态集合。每次状态变更时先校验——如果当前状态不允许直接跳到目标状态就抛异常。举个例子PENDING_PAYMENT状态允许跳转到PAID或CANCELLED但PAID状态不能直接跳COMPLETED必须经过ACCEPTED和PICKED_UP。这套约束在分布式环境里尤其重要。因为订单状态变更的接口可能被多个角色触发用户主动取消、商家接单、骑手取餐。如果没有状态机校验可能会出现用户取消订单和商家接单两个并发请求同时到达后到的操作覆盖了先到的导致一个已取消的订单变成了已接单状态。除了状态机校验我还在订单操作接口上加了乐观锁版本号机制防止并发更新时出现脏写。4.3 骑手接单与配送闭环位置与轨迹骑手端是这个项目里功能性很强的模块骑手角色跟普通用户不一样核心动线是抢单 → 到店取餐 → 确认取餐 → 送达完成。这四步对应四个状态操作每个操作都要调配送服务更新订单配送状态。骑手接单这个环节我设计的是主动抢单模式。配送服务在订单支付成功后被消息队列触发创建配送任务。骑手端进入配送大厅请求GET /api/delivery/tasks?statusWAITING_RIDER拿到当前待接单的配送任务列表。每个任务卡片上显示商家地址、用户收餐地址、预计配送费、配送距离。骑手点击接单时调POST /api/delivery/task/{taskId}/take配送服务会做并发控制——这个任务只允许一个骑手接单。我用Redis的setnx指令实现了分布式锁锁的key就是任务ID接单成功后立即删除锁。如果没有这个锁两个骑手同时点击接单都可能请求成功导致一单两送。用Redis分布式锁在这个场景里效果很明显而且是标准的做法不是土办法。配送过程中的位置轨迹上报我采用了一个比较轻量的方案。骑手端每10秒调一次POST /api/delivery/reportLocation接口上报告当前经纬度和订单ID。配送服务把最近的位置写入Redis的delivery:location:{orderId}保留最近20条记录。小程序端用户查看配送进度时调用GET /api/delivery/order/{orderId}/location从Redis里查出最近的几个点前端在地图上标出。这个方案不用WebSocket也不依赖高德图SDK的位置上报虽然实时性比那种官方配送App会差一点但对于校园这种1公里范围内的配送场景足够用了。这里有一个细节需要注意位置上报接口的请求频率高如果每次都写MySQL数据库压力很大。我的做法是只把最新一条位置信息写入MySQL的delivery_track表其他历史轨迹缓存在Redis里保留时间设1小时超过后自动失效。因为用户只看当次订单的实时配送进度历史轨迹没有长期保留价值。4.4 订单超时与库存扣减分布式事务怎么处理分布式环境下最容易出问题的就是多个服务的数据要同时更新成功这个需求。这个项目里有两个典型场景第一个是创建订单时库存扣减和订单创建的一致性。如果订单创建了但库存扣减失败会导致超卖如果库存扣减了但订单创建失败会导致库存凭空减少。我的处理方案是订单服务创建订单记录状态为待支付后通过OpenFeign调用商家服务的扣库存接口。如果扣库存成功继续走支付流程如果扣库存失败订单服务立即把订单标记为CANCELLED并返回错误信息。这样虽然不能保证两个操作同时成功但能保证业务结果正确——要么订单创建且库存扣减要么订单取消且库存不变。这里用的是补偿事务的思想先做主要操作如果附带操作失败通过置状态的方式把已做的操作回滚。不要在这个场景里硬上Seata分布式事务框架因为扣库存接口是在线同步调用失败率本身很低用框架引入的成本比收益大。第二个是高并发下单时的超卖问题。我在扣库存SQL上做了条件限制UPDATE dish_stock SET stock stock - #{quantity} WHERE dish_id #{dishId} AND stock #{quantity}。这个SQL利用MySQL的行锁保证并发环境下的原子性——同一时刻只有一个请求能更新成功其他请求因为条件不满足而更新0行。配合受影响行数的判断扣减失败的请求直接返回库存不足简单高效。这个方案比先查库存再扣减要安全得多也是业内电商系统的主流做法。5. 高可用设计缓存、限流与容灾5.1 Redis在微服务中的缓存策略微服务架构里的缓存策略如果没有整体规划很容易出现三个服务各自访问同一份数据然后缓存不一致的情况。这个项目里我理清了缓存的使用边界。热点数据的缓存场景店铺列表和店铺详情。校园外卖的特点就是饭点集中每到中午11点到12点大量用户同时打开小程序商家列表接口的QPS会突然暴涨。我用Redis缓存店铺列表key是缓存时间5分钟。店铺详情和菜品列表因为数据变更频率低商家一般一天改一次菜品缓存时间设15分钟。菜品售罄状态不缓存实时查数据库因为售罄是动态变化的缓存了反而误事。库存缓存要不要做这里我做了个取舍库存不直接缓存在Redis里做预扣减而是直接操作数据库。原因很简单校园外卖商家的库存量级小并发扣减频率没有那么极端数据量也远远没到MySQL单表千万级的程度。在这个业务量下直接操作数据库反而更可靠避免Redis和MySQL数据不一致的问题。5.2 Sentinel限流规则怎么配网关层是整个系统的流量入口我在Spring Cloud Gateway上集成了Sentinel对关键接口配置了流控规则。具体来说主要针对下单接口POST /api/order和首页店铺列表接口GET /api/shop/list。单机QPS阈值分别设置为100和300超出阈值的请求直接返回系统繁忙请稍后再试。这里的阈值是结合校园用户规模估算的假设学校2万人高峰期同时在线点餐2000人下单接口单机100的QPS部署两个实例就是200留出50%的冗余差不多够用。除了QPS限流网关还要防刷单。在网关的GlobalFilter里做了一个简单的IP维度的频控同一个IP在1分钟内调用下单接口超过5次直接拒绝。虽然校园场景下同一WiFi出口IP都是同一个但这个校验还是能拦截掉绝大多数脚本刷单行为。5.3 服务容灾熔断降级与兜底逻辑微服务调用链中任何一个下游服务挂了都会对上游产生连锁影响。比如用户下单时如果商家服务当时不可用订单服务的OpenFeign调用会一直超时积累大量等待线程最终把订单服务自身的线程池耗尽。这就需要用Sentinel做熔断降级。我给关键调用链路都加了降级规则。拿订单服务调用商家服务的扣减库存接口举例设置最大调用时长为3秒如果3秒内没有响应就判定为调用失败走降级逻辑。降级逻辑里不直接抛异常而是把订单标记为支付待确认同时发出告警。等商家服务恢复后再做库存核对和补偿处理。这样用户体验上是支付成功等待确认而不是直接报错订单失败。实际做项目时很多人忽略的一点是超时时间一定要设置。OpenFeign默认连接超时10秒、读超时60秒这在微服务里太长了。如果下游服务真的挂了一个请求等60秒超时上游线程池迅速被打满整个服务就雪崩了。我建议所有服务间的OpenFeign超时时间统一设置成连接2秒、读超时3秒宁可请求失败走降级也不能让超时拖垮整个系统。6. 常见问题与排查技巧实录6.1 服务间调用出现循环依赖微服务拆分后最容易遇到的经典问题就是两个服务互相调用形成循环依赖。这个项目里我就遇到过订单服务需要调用用户服务查用户配送地址信息同时用户服务在初始化时需要调用订单服务查历史订单数量。两边互相依赖启动时Nacos注册中心里两个服务都显示注册成功但实际调用时接口互相等对方数据直接超时。解决办法是梳理调用链把其中一条调用换成异步消息或者把公共数据抽出来。我的处理是把用户服务查询历史订单数量这个需求改为订单服务在用户下单时主动发送消息给用户服务去更新统计数据而不是用户服务每次去查订单服务。这样调用链就变成单向的了用户服务 → 订单服务订单服务 → 消息队列 → 用户服务不再有同步循环。6.2 Nacos配置变更不生效开发中遇到的另一个问题是修改了Nacos里的配置比如数据库连接池大小、订单超时时间但服务不生效。排查后发现原来需要在配置类上加上RefreshScope注解配置中心推送后Spring容器才能重新加载配置。另外要注意Nacos配置文件的dataId必须和服务的spring.application.name严格一致后缀写成-dev.yaml对应开发环境如果用默认的application.yaml多个服务拉到同一个配置直接互相覆盖。6.3 小程序真机预览时接口请求失败这个坑出现得非常多。本地开发工具里接口都能通但手机预览时全部请求失败。排查步骤按顺序来第一确认手机和开发机在同一个局域网开发模式下的请求地址不能是localhost必须是开发机的局域网IP。第二如果接口地址是HTTP而不是HTTPS在小程序后台开发管理-开发设置里配置服务域名而且微信要求正式环境必须HTTPS本地开发可以用不校验合法域名来绕过但真机预览时这个选项是失效的需要在预览页面勾选。第三检查网关的CORS配置是否放行了小程序端的请求。小程序请求不同于浏览器请求没有预检请求但如果网关设置了基于浏览器的CORS拦截也可能影响。6.4 骑手接单时分布式锁失效怎么办前面提到用Redis的setnx做分布式锁但在高并发抢单时发现偶尔还是会出现两个骑手都接单成功的情况。排查下来发现是锁的过期时间设置太短接单逻辑还没执行完锁就自动过期释放了另一个骑手趁虚而入获取了锁。解决办法是把锁的过期时间设为10秒同时接单逻辑里加了SETEX和SETNX的原子性改进——用Redis官方推荐的SET key value EX 10 NX命令一步完成设置值和过期时间。如果接单逻辑耗时较长还可以用一个后台线程做锁续期不过校园场景10秒足够没必要过度设计。6.5 热词搜索与接口设计的对应关系顺着这次项目里搜索到的热词最后再串一下各个高频需求点在这个项目中的落点方便你对照自己项目查漏补缺热词本项目落点springcloud入门简洁网关 Nacos Feign三个组件跑通即可不必贪多vue安装及环境配置Node 16、Vue CLI 5npm config set registry换国内镜像小程序页面列表加载更多订单列表、配送大厅列表均实现分页下拉加载微信小程序顶部导航栏高度自定义导航栏时用wx.getMenuButtonBoundingClientRect()取顶部胶囊位置springboot配置多环境配置通过Nacos管理本地开发用application-local.yml小程序抓包Charles代理 微信开发者工具不校验域名组合vue路由动态路由配合角色权限控制springboot整合flink订单统计报表后续扩展可以走这个方向initial版本直接查MySQL7. 项目复盘与可扩展方向项目完整跑通之后我最大的感受是微服务架构真正的难点不在写代码而在约束和规范。服务一多接口文档、异常码定义、日志打点、参数校验规则这些看不见的东西反而决定项目能不能顺利推进。我在这套系统中把所有服务之间的接口约定都收到了一个单独的api-docs模块里定义好统一响应体ResultT、统一异常码枚举、分页请求参数格式每个服务的Feign接口都引用这个公共模块。这样三个服务并行开发时没人会因为响应格式不统一而对字段。后续可以扩展的方向我列几个自己觉得高性价比的一是引入分布式事务框架Seata用于支付和订单创建这种强一致场景替代一直以来的手动补偿方案更适合对数据一致性要求更高的商用版本。二是做骑手位置实时推送WebSocket代替现在的轮询上报方案用户端体验会好很多但需要额外处理连接状态的容灾。三是把订单统计报表做成一个数据异步处理链路——订单服务发消息统计服务消费消息写入ES和报表中间表报表查询从ES里出。这套路不算复杂但很实用是很多毕业设计或者项目升级都会走的路径。四是接入高德地图的路径规划和配送范围圈选商家端在地图上维护1.5公里配送范围超出范围自动提示用户超出配送距离。这个功能对校园外卖来说很加分但前期版本我用的是经纬度直线距离判断够用就好。最后说一个很多人容易忽略的点做完整项目最重要的是把日志链路追踪ID带上。我现在每个服务在启动时生成一个traceId在网关生成并传递到后续所有调用链的服务遇到问题在日志平台上直接按traceId把整个请求的日志串起来排查效率提升几个档次。这个点建议所有做微服务的同学都提前接上不要等技术债积累到排查报错找不到问题时再回头补。
返回列表