做鲜花电商这个项目之前,我其实有点轻视它——市面上商城类的开源项目一抓一大把,换个商品类目而已,能玩出什么花?真正把需求理完、把代码写起来之后,我才发现自己错得离谱。鲜花的商品属性跟数码、服饰、图书完全是两套逻辑:库存有时效,配送有温度要求,用户买的不是一件商品而是一种情绪。这些业务上的特殊性,会直接逼着你把SpringBoot后端、Vue前端、AI大模型能力重新做一轮针对性设计。
这篇文章把整个「在线鲜花电商平台系统」的从0到1全过程拆开讲,覆盖业务建模、技术选型、数据库设计、订单状态机、AI大模型集成、四项创新扩展功能,以及我在开发过程中踩过的坑。适合正在做SpringBoot+Vue毕业设计的同学、想转型电商开发方向的从业者,以及想了解AI大模型怎么跟业务系统真实结合的团队参考。整个项目技术栈围绕标题里的三个关键词展开:SpringBoot负责后端服务与AI接入,Vue负责用户端与商家端界面,AI大模型则嵌进货架推荐、花语助理、库存预警和质检四个具体场景里。
1. 为什么鲜花电商和普通商城项目根本不是一回事
1.1 鲜花SKU的“时令性损耗”直接改变库存设计
普通电商的商品可以屯在仓库里慢慢卖,一件羽绒服放三年不会坏。鲜花不行。切花从花田采下来之后,寿命以天计算:玫瑰通常7天左右,百合5到7天,绣球和郁金香更短,有时3天就开始打蔫。这就带来一个普通商城完全不需要考虑的问题:库存不仅仅是“有没有”的数字,还是一个“还剩多久会报废”的倒计时。
这个特性直接决定了几个后端设计决策。第一,库存表不能只存总数,还要记录每一批花材的入库时间和预计失效日期;第二,前端商品列表需要根据剩余生命周期动态打标,比如“今日空运到店”和“花期还剩2天,特价处理”其实是同一种商品在不同时间点的两种展示;第三,下单时的锁库存策略要支持批次优先——系统先扣寿命最短的那批货,把新鲜货留到后面卖。这个“近效期优先”的库存策略,我把它实现成了SpringBoot里一个独立的StockAllocator组件,它接收花材SKU和数量,返回具体扣哪些批次,这样订单模块和库存模块的职责就分清楚了。
1.2 配送时效为什么是鲜花电商的命门
鲜花的典型消费场景是当天送:生日订一束、纪念日订一束、约会前订一束。用户从下单到收货,心理预期是按小时算的,不是按天。所以这个系统的配送模块不能沿用普通电商的“下单后48小时发货”逻辑,而要拆成两类:同城即时配送(接单后2到3小时内送达)和预约配送(指定未来某天某个时段送达)。
在代码层面,我做的第一件事是给订单表增加了两个关键字段:期望送达时间段和配送类型。预约单在用户下单那一刻不会立刻推送给门店,而是进入一个延迟队列,在送达时间前2小时自动触发“备货+配送”流程。同城单则直接进入门店工作台的待处理列表。这套机制看起来不复杂,但它决定了整个订单状态的流转节奏,也是后面AI助手的配送类知识库必须覆盖清楚的内容。
1.3 用户买的不是花,是“被正确表达的心意”
鲜花是典型的情感消费品。用户在商品详情页停留时间长、犹豫率高,经常反复比较:送女朋友和送妈妈选的花不一样,生日花束和道歉花束风格不一样,预算100和预算500的搭配逻辑也不一样。如果系统只能提供“搜索-加购-下单”这条冷冰冰的路径,转化率一定会很难看。
这一点是我决定引入AI大模型的核心原因。系统的兜底体验不是靠更细的商品分类,而是靠一个能听懂自然语言的推荐助手:用户输入“闺蜜搬家,想送一束明亮点的花,预算200以内”,大模型结合花语知识库返回推荐结果和解释。这个能力在普通商城里是加分项,在鲜花场景里几乎是刚需——因为大多数用户根本不知道自己该买什么花。
1.4 需求清单:先弄清楚要给谁做、做哪些端
我把系统拆成三个端口来规划功能边界:用户端(小程序风格H5)、门店端(商家管理与接单)、管理后台(平台运营与数据看板)。用户端核心流程是浏览花束、按场景筛选、AI花语助手、下单支付、订单追踪、售后申请;门店端包括商品上下架、花材库存管理、接单出餐、上传配送信息;管理后台负责全局商品审核、订单总览、营销活动配置、AI知识库管理、保鲜损耗统计。
这么一分,开发顺序就清晰了:先用户端主流程,打通下单闭环;再门店端接单履约;最后管理后台兜底。AI能力则穿插在用户端的推荐、售前问答,以及门店端的文案生成和损耗预警里,不单独做成一个孤零零的“AI聊天页面”。
2. 技术选型的底层逻辑:SpringBoot + Vue 的组合为什么是这个项目的最优解
2.1 单体架构 + 模块化包结构,而不是一上来就拆微服务
很多同学做毕设或者个人项目时有个误区:听到“平台系统”四个字就想上微服务,注册中心、网关、配置中心全套安排上。我的观点很明确:这个项目的业务复杂度远没到需要分布式拆分的地步。鲜花电商的核心链路是商品、订单、库存、配送、支付,这些模块强耦合,拆成独立服务反而引入网络开销和数据一致性问题。更现实的一点是,单体能跑明白的同学,拆微服务的坑往往不是技术问题,而是运维成本和调试成本。
所以我选择SpringBoot单体工程,但包结构按业务域做模块化隔离:controller层只负责任务分发,service层承载业务逻辑,domain层统一放实体和值对象。具体包划分是:core(通用工具与配置)、user(用户与认证)、product(商品与花材库存)、order(订单与购物车)、ai(大模型接入与知识库)、marketing(营销与优惠券)、admin(后台管理接口)。这么一摆,代码结构跟微服务一样有边界,但部署还是一个大Jar包,省心得多。
技术版本上,我用了SpringBoot 3.x配合JDK 17——这个组合已经是当前主流,而且SpringBoot 3全面支持虚拟线程,后续要做并发性能优化有空间。数据库用MySQL 8,ORM选了MyBatis-Plus。可能有人会问为什么不用JPA,我的理由很实际:MyBatis-Plus的分页和条件构造器写起来直接,国内相关教程和方言支持也完善,团队新成员上手成本低;而且后面复杂SQL需要手写XML时,MyBatis体系本来就比JPA好控制。
2.2 Vue 3 + Element Plus + Pinia:前端为什么不选 React
前端选了Vue 3全家桶,具体是Vite构建、Vue Router管理路由、Pinia管理状态、Element Plus做管理后台的UI组件库。用户端H5部分没有用重型组件库,而是自己写了一套轻量样式,保证页面在手机端加载快。选择Vue而不是React,纯粹从项目匹配度考虑:Vue的模板语法对后端开发者更友好,上手曲线平缓,而且Element Plus这种开箱即用的后台组件库能大幅缩短管理端的开发时间。如果你是一个人同时写前后端,Vue的性价比明显高于React。
前端架构分两层:用户H5端和管理后台。用户端路由为懒加载模式,图片走MinIO的预签名URL,状态管理用Pinia存购物车和登录态。管理后台直接站在Element Plus的表格、表单、弹窗组件上搭,很多页面其实就是配置化的增删改查,开发效率极高。
2.3 前后端交互协议与认证方案:无状态JWT为什么合适
前后端分离后,认证方案我选了JWT而不是Session。原因不复杂:H5端可能同时对接微信公众号和小程序端,未来还可能要出App,服务端无状态认证天然适配多端场景;JWT把用户ID和角色直接编码在Token里,网关或拦截器解析即可,不需要依赖Redis保存会话;配合过期时间和刷新Token机制,安全性也够用。具体实现上,后端用拦截器统一校验Authorization头,解析出的用户信息放入ThreadLocal,业务代码里直接通过UserContext.getUserId()取当前操作人,不用每个Controller重复解析。
文件存储这块,我选了MinIO而不是直接把图片丢服务器硬盘或云OSS。MinIO是开源的对象存储,Docker一条命令就能起起来,兼容S3 API,上传下载走预签名URL可以避免把AccessKey暴露在前端。商品图、花材图、用户头像、质检照片统一都放这里。后面在踩坑部分我会专门讲MinIO的一个大坑——预签名URL的有效期问题。
2.4 技术选型没写进PPT但必须知道的事
这里补几个选型时容易被忽略的点。定时任务用的是Spring自带的@Scheduled,没引入Quartz,原因是项目里的定时任务场景都比较简单——每天凌晨算库存损耗、每10分钟清一次过期订单,单机部署下Spring自带的定时器足够稳定。消息推送没有引入RocketMQ或Kafka,直接在订单状态变更时保存站内消息,同时用WebSocket给门店端推送新订单。AI大模型的流式输出走了SSE(Server-Sent Events),没有用WebSocket全双工,因为AI回复是单向推流,SSE实现更简单、断线重连机制也更成熟。
| 技术组件 | 选型 | 选择理由 |
|---|---|---|
| 后端框架 | SpringBoot 3.x + JDK17 | 主流稳定,虚拟线程与jakarta生态升级 |
| ORM | MyBatis-Plus | 分页与条件构造器开发效率高,SQL可控 |
| 前端框架 | Vue3 + Vite + Pinia | 上手快,生态完善,配套管理后台组件齐全 |
| 数据库 | MySQL 8 | 通用稳定,事务支持可靠 |
| 对象存储 | MinIO | 私有化部署可控,S3协议兼容,学生项目友好 |
| 认证 | JWT | 无状态、多端适配、部署简单 |
| AI接入 | 云厂商大模型API + SSE流式 | 生成质量高,接入成本低 |
| 实时推送 | WebSocket + SSE | 新订单用WS,AI回复用SSE,各取所长 |
3. 数据库设计与订单状态机:先把地基的每一块砖看清楚
3.1 核心表结构:普通商城表 + 四张AI专属表
项目表数量最终是22张。普通电商必备的user、order_master、order_item、cart_item、address、product_sku、product_category、banner、coupon这些都有,但有几个表设计跟普通商城不一样,需要重点说明。
第一张是flower_batch,也就是花材批次表。它记录了某次采购入库的花材SKU、数量、入库时间、预计失效时间、存储条件(冷藏还是常温)。它的存在让“库存”这个概念从静态数字变成了动态批次队列。第二张是delivery_slot,配送时段表,把每天按小时切成若干可预约的时段,保证用户在前端选配送时间时不会出现门店无法履约的情况。第三张是bot_conversation和bot_message,这是AI对话的会话表和消息表,用来落地上线后的多轮会话。第四张是knowledge_doc,AI知识库文档表,存花语、配送政策、售后规则这些语料的原始文本和向量化状态。
普通商城可能会忽略的一个字段是order_master里的intended_time和delivery_type,前者存用户期望送达时间,后者区分即刻送和预约送。这两个字段承载了整个鲜花履约的核心逻辑。
3.2 订单状态机的流转与边界处理
订单状态流转是这个项目里业务逻辑最密集的地方。我定义的状态包括:待支付、已支付待备货、备货中、配送中、已完成、已取消、售后申请中。其中待支付订单超时30分钟自动关闭,备货中状态只有门店端可以操作确认出餐,配送中状态需要同城配送人员上传送达时间才能翻转到已完成。
状态机的实现没有引入复杂的工作流引擎,就在OrderService里用一组状态流转方法加状态校验来处理。关键点有两个:第一,每个状态变更操作必须是幂等的,防止前端重复点击或接口重试导致重复处理;第二,所有状态变更都写入一张order_status_log表,记录操作人、操作时间和变更前后状态。这张日志表在产品上线后排障时价值极高,用户说“我订单怎么莫名其妙取消了”,查一下日志立刻定位是超时关闭还是门店拒单。
关于库存扣减,我是放在支付成功后执行的。用户下单但未支付时只锁定Redis里的预占数量,支付回调成功后才真实扣减MySQL里对应花材批次的数量。如果扣减失败,订单回滚并触发退款。为了防超卖,扣减SQL写成条件更新:UPDATE flower_batch SET quantity = quantity - #{need} WHERE id = #{batchId} AND quantity >= #{need},受影响行数为0就说明批次库存不足,返回友好提示。
3.3 前端路由与页面结构:H5和后台分开跑
前端工程两个:一个是用户H5(mobile-web),一个是管理后台(admin-web)。H5的主路由包括首页、分类页、商品详情、购物车、下单确认、订单列表、订单详情、AI花语助手对话页、个人中心。管理后台的路由按权限分两块:门店角色的路由有接单台、花材库存、商品管理;平台角色的路由有全局商品审核、订单总览、知识库管理、营销配置、损耗报表。
路由级别的权限控制用了Vue Router的全局前置守卫,配合动态路由注册。用户登录后拿到角色信息,前端基于角色动态添加对应权限路由;没有权限的路由即使手动输入URL也会被拦截回登录页。这里踩过的坑后面会讲,history路由模式在刷新页面时如果后端没配回退规则,会出现404。
3.4 数据库索引与事务边界的一点实操心得
写电商项目最容易被忽略的就是索引和事务。我在订单表建了复合索引(user_id, status),支撑“我的订单”列表按状态过滤;flower_batch表建了(sku_id, status, expire_time)索引,支撑近效期优先的库存分配查询。事务边界上,我的原则是“一个业务用例一个事务”,比如说创建订单方法加@Transactional,但里面如果调用了远程AI接口,绝对不能放在同一个事务里——AI响应的延迟会长时间占用数据库连接,高并发下连接池直接被打爆。我的做法是把AI调用放到事务提交之后的业务事件里,或者干脆在Controller层先调AI再进Service层落库事务。
4. AI大模型集成:不是接个API就完事,得先想清楚模型能力边界
4.1 大模型在这个系统里该干什么、不该干什么
AI大模型接入项目之前,最重要的一件事是画清楚能力边界。我的划分方式是这样:大模型只处理文本理解和生成类任务,包括售前的花束推荐对话、售后的客诉应答辅助、商品描述的批量改写、配送问题的语义理解;而所有数值预测和强逻辑判断,比如库存损耗率计算、销量趋势预测、优惠券门槛校验,都交给传统算法和业务规则,不让大模型碰。
举个具体的反例。最开始我试过让大模型根据历史销量预测未来一周哪种花材需要补货,效果非常不稳定,同一个问题不同轮次会给出差异很大的答案,而且模型不具备时间序列计算能力,给出来的补货量完全不可信。后来我把这个功能改成用加权移动平均算法做,基于近30天销量和花材寿命基线计算建议补货量,结果稳定又可控。所以做AI集成时一定要认清:大模型是“语义引擎”不是“计算引擎”,把这两者的边界擦清楚,项目才不会翻车。
4.2 云端API还是本地部署:论32G内存能不能跑起来
标题里提到了AI大模型本地部署。说实话我也认真评估过本地部署方案。本地部署的核心优势是数据不出域、没有按量计费,但代价是硬件门槛和推理速度。一台32G内存的机器,用Ollama跑7B或14B参数量级的量化模型是可行的,Q4量化后7B模型大概占5GB左右内存,能流畅做对话生成。但换成更大的模型,比如34B甚至70B,32G内存就比较吃力了,要么换更激进的量化策略牺牲质量,要么干脆靠CPU慢速推理,用户体验很差。
结合这个项目的实际场景,我最终的方案是:开发调试阶段用云端API(选择国产大模型服务商的API),主要是质量稳定、接入快;如果团队有内部部署需求,再在Linux服务器上用Ollama部署一套Qwen系列的量化模型作为备选推理通道。在SpringBoot代码里我把模型调用封装成一个ChatModelClient接口,云端和本地是同一套接口的两套实现,切换时只改配置项不需要动业务代码。
4.3 RAG架构落地:知识库让模型不再胡编乱造
直接扔一个大模型接口给用户问“这个花多久能送到”,它大概率会编一个答案出来,因为模型没有你系统的实时数据。所以必须用RAG(检索增强生成)架构:先把系统里的静态知识——花语大全、配送政策、退换货规则、不同花材生命周期——切块后向量化存起来;用户提问时,先从知识库里检索出最相关的片段,拼进Prompt,再交给大模型生成回答。
我采用的向量库是开源的Milvus Lite(本地文件模式),Embedding用的BGE中文模型,文本块按300字左右切分、重叠50字,目的是保住段落语义的完整性。SpringBoot端做了一个KnowledgeService:知识文档上传后自动解析、切片、向量化入库;对话时先向量检索TopK=5的候选片段,加上系统提示词一起发给大模型。这套流程跑通之后,AI助手的回答准确率明显提升,涉及配送时效的问题会引用配送政策原文,而不是凭空发挥。
4.4 SSE流式输出的一个完整实现:从浏览器到SpringBoot再到模型API
AI对话体验的关键是流式输出。用户发完问题后,如果界面等3秒才一次性吐全部文字,感知上会非常卡;流式输出能做到字字蹦出,用户从心理上觉得响应很快。
前端实现用Fetch API读取ReadableStream,解析SSE数据格式,逐片追加到对话界面的消息气泡里。这里的核心SSE后端实现,我用SseEmitter封装:
@PostMapping("/api/ai/chat-stream") public SseEmitter chatStream(@RequestBody ChatRequest request, HttpServletResponse response) { SseEmitter emitter = new SseEmitter(120000L); // 2分钟超时 // 异步执行,避免阻塞Tomcat线程 CompletableFuture.runAsync(() -> { try { // 1. 检索知识库,拿到参考片段 List<String> contexts = knowledgeService.search(request.getQuestion()); // 2. 构造Prompt String prompt = buildPrompt(request.getQuestion(), contexts); // 3. 调用大模型接口,拿到流式响应 chatModelClient.streamChat(prompt, new StreamCallback() { @Override public void onToken(String token) { emitter.send(token); } @Override public void onError(Throwable t) { emitter.completeWithError(t); } @Override public void onComplete() { emitter.complete(); } }); } catch (Exception e) { emitter.completeWithError(e); } }); return emitter; }SSE要正常穿透网关和代理服务器,有几个关键配置要处理好。开发阶段我用Vite的代理转发SSE流,需要在proxy里配置关闭缓冲;生产环境如果放在Nginx后面,必须把proxy_buffering设为off,否则流式内容会被Nginx缓冲到全部结束后才一次性推给浏览器,流式效果直接失效。
4.5 Prompt模板怎么设计才稳定
Prompt模板设计是AI集成中投入产出比最高的环节。我总结的经验是:系统级提示词负责定角色和边界,对话期提示词负责任务和上下文,两者分开管理。系统提示词我放在SpringBoot的配置中心里,大致内容就是:“你是鲜花电商平台的花语助手,你的任务是帮助用户选购合适的花束。回答要简洁、专业、有温度。只能基于提供的知识库内容回答,未知信息明确说明不确定。推荐花束时需提供花材构成、参考价格区间和花语含义。”
对话期Prompt的核心是让大模型通过JSON结构输出推荐结果,方便前端结构化渲染。我会要求模型在回答中携带一个建议花束列表,格式为JSON数组,每个元素包含name、flowers、meaning、priceRange四个字段。效果稳定之后,前端对话页会展示推荐卡片,点击直接跳转对应商品详情页,整个推荐链路就闭环了。
5. 四项创新扩展功能的完整拆解
5.1 鲜花保鲜时间轴:让每束花都有自己的“倒计时”
这是我觉得整个项目最有区分度的功能。用户在订单详情页能看到一个时间轴,上面标注了这束花的期望送达时间、最佳观赏期起始、预计凋谢时间,不同时间段的卡片背景色会从鲜绿渐变到淡黄再偏暗,直观传递“花正在老去”的信息。它解决的是鲜花消费中一个很微妙的需求:用户想在最合适的日子收到最饱满的花。
实现逻辑分两块。第一块是计算服务:每束花的预计凋谢时间 = 送达时间 + 花材寿命基线天数 × 环境系数(冷藏配送环境系数1.2,常温配送系数0.8,夏季高温系数再打七折)。花材寿命基线存在flower_batch表的expire_time里。第二块是展示服务:用户端订单详情页和商品详情页通过一个FlowerLifespanService实时计算剩余花期天数,如果剩余花期不足2天,商品卡片自动打上“临期特惠”标并调整价格展示。刚开始我准备把这段逻辑塞进大模型里做“智能预测”,后来想明白了——固定的规则计算能做的事情,永远不要交给随机性强的模型。
5.2 AI花语助理:多轮对话里的推荐闭环
AI花语助理是用户端的核心交互入口,入口放在首页的悬浮按钮和商品分类页顶部的搜索框旁。用户典型的提问方式是:“明天是情人节,想给女朋友送花,她喜欢郁金香,预算300左右。”系统会走一遍RAG检索:查花语知识库、查当前在售商品列表、查配送规则,然后生成一个带推荐卡片的结构化回答。
这里有个关键设计:推荐的商品必须来自数据库实时数据,不能由模型凭空生成。所以我的Prompt里会拼接一段当前在售且库存充足的商品摘要列表(ID、花束名、价格、花材构成),明确要求模型只能从这个列表中选择推荐。这样模型负责语义理解和文案生成,商品真实性和库存有效性由系统把关,既保证了体验又避免了推荐出不存在的商品。
5.3 门店智能备货助手:大模型生成文案,算法决定数量
门店端有一个“智能备货”面板,做两件事。第一件事是补货建议,用加权移动平均算法算每种花材未来三天的建议备货量,算法输入是近30天销量和花材寿命系数,输出是一个带置信度区间的数字。第二件事是自动生成促销文案:针对即将进入近效期的花材批次,大模型会根据剩余花期、当前库存和基础促销规则,生成类似“还剩3天花期的香槟玫瑰,原价129现价79,适合追求性价比的自用客户”这样的说明文案,门店一键确认后直接推送到用户端特惠专区。
这个组合的好处是,算法给了数字的依据,大模型给了文字的温度,各干各擅长的活。
5.4 收货质检照片分析:把视觉模型用在不显眼但实用地方
鲜花电商的售后纠纷很多时候是“公说公有理”:用户说收到的花蔫了,门店说发货时候明明是新鲜的。传统的处理办法是人工审核照片,效率低且标准不一。我在售后模块里加了一个AI照片质检功能:用户上传收货照片后,系统调用多模态大模型API,分析花材的色泽、挺立度、花瓣状态,输出一个新鲜度评分和文字描述,比如“花瓣边缘轻微焦枯,五朵玫瑰中两朵呈明显萎蔫状态”。这个结果作为售后审核的参考证据,结合配送时长(超时配送自动加权)自动给出处理建议:全额退款、部分补偿或驳回。
这个功能实际落地时效果超出预期,不是因为模型判断有多么精确,而是它把售后的处理效率从平均15分钟缩短到了1分钟以内,售后客服只需要看模型输出再点确认就行。
6. 开发中的踩坑记录:这些坑不写出来,后面的人还得再踩一遍
6.1 SpringBoot 3.x的jakarta迁移:老教程代码直接编译失败
用SpringBoot 3之后,最明显的坑是javax.servlet包全部迁移到了jakarta.servlet。网上一半以上的老教程代码直接搬过来会编译报错,很多人第一反应是自己环境有问题,其实是规范命名空间的迁移。解决办法只有一个:查资料认准SpringBoot 3.x和JDK17以上版本,写代码时引入的依赖统一用jakarta前缀,遇到老帖子的javax代码要手动替换。另一个关联问题是SpringCloud版本必须选适配SpringBoot 3的版本,不要用旧版本硬顶,否则无限报错会让你生无可恋。
6.2 Maven依赖冲突:spring-boot-starter-web和webflux你死我活
我踩过实打实的一个坑是同时引入了spring-boot-starter-web和spring-boot-starter-webflux,结果应用启动后部分路由返回406。原因是两个starter都会注册DispatcherServlet相关的自动配置,Spring MVC和WebFlux在同一个上下文里互相抢占。这个问题的根源是我想引入WebClient做AI接口的异步HTTP调用,结果直接拉进来一个webflux全家桶。解决方式是把WebClient相关代码独立成模块,或者干脆用Java 17自带的HttpClient;在实际项目中,我用的是Spring的RestClient配合虚拟线程发起AI请求,既顺滑又不带额外依赖。
6.3 Vue打包进SpringBoot的细节:base路径和history路由
H5端开发完要部署上线,我的做法是前端build后把dist目录的东西拷到SpringBoot的src/main/resources/static下面。这里两个大坑必须注意。第一个是资源路径,前端打包时要把base配置改成'./',否则所有静态资源会从根路径加载,部署到子路径时全部404。第二个是Vue Router的history模式,刷新某个子路由会直接404,因为后端找不到这个路径对应的Controller。生产环境最省事的做法是用hash模式,或者在后端加一个转发规则:对非/api开头的路径统一转发到index.html。我为了路由美观选了后者,配置一个WebMvcConfigurer来解决。
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/{spring:\\w+}") .setViewName("forward:/index.html"); registry.addViewController("/**/{spring:\\w+}") .setViewName("forward:/index.html"); } }6.4 MinIO预签名URL的过期时间:用户看图一半裂了
MinIO接入后遇到的坑比较隐蔽:图片直传后展示还好,但预签名URL默认有效期太短,用户打开商品列表后停留一会儿,再点开详情页时图片URL已经过期,前端直接裂图。这个问题的原因是预签名URL带的是临时token,过期时间由你生成时指定。解决办法是把商品图、花材图这些静态图片的预签名URL有效期设置成足够长(我设成了7天),动态生成的临时上传URL才用短时效。同时在上传接口里对文件类型做校验,防止绕过前端直接传可执行文件。
6.5 本地部署大模型的量化和内存配置
本地部署路线我试过Ollama跑Qwen系列模型。32G内存的机器上,7B模型用Q4_K_M量化,大概需要6GB内存加4GB左右开销,能流畅跑;14B模型需要10GB以上,推理速度明显下降;34B级别就基本不推荐了。另外要把Ollama的并发请求数调小,默认配置下同时来多个推理请求会直接OOM。我实际跑下来发现,响应速度在3到5秒之间,对于开发调试够用。如果将来要做高并发生产环境,建议直接走云端API,本地部署只适合数据敏感型项目。
7. 关于部署、测试和上线的一些个人体会
项目整体跑通之后,部署上线的流程其实非常简单直接。后端打成Jar包扔到服务器,MySQL和MinIO用Docker Compose起服务,前端两个工程build完塞进后端静态目录,再在宿主机配一个Nginx做访问转发和SSL终止,一套单机部署就能把所有端跑起来。如果想要更规范,可以把前后端拆开部署,前端用Nginx独立服务,后端通过反向代理暴露API,这个看团队的运维习惯。
测试环节我的经验是,先集中精力把主链路的端到端用例跑透:注册登录、选花下单、支付回调、门店接单、配送完成、售后申请,这条链路是系统的心脏,任何一环出问题都掉链子。AI功能单独做一轮评测,准备一批典型的用户提问,记录回答的准确率和推荐商品的可购买率,指标跑不上去就去优化知识库切分和Prompt模板,而不是盲目换大模型。
最后说一点个人体会。做完这个项目,我最大的感触是:技术栈本身没有新鲜事,SpringBoot和Vue都是成熟工具,AI大模型平台都在卷接口接入,真正决定项目质量的,是你对业务的理解深度和把这些技术嵌进业务场景的能力。鲜花电商的特殊性——时令库存、配送时效、情感属性——逼着我在每个模块上都做针对性设计,这些设计才是项目真正的亮点所在。如果只是把普通商城的代码换个皮肤,技术上再炫,也只是一个作业;而当你把AI助手嵌进选花链路、把保鲜时间轴做成可视化的订单体验、把模型能力用在售后质检的真实单据上,这个系统才真正有了属于自己的灵魂。如果你也在做类似的项目,我建议你别着急动手写代码,先花一整个白天把业务特殊性梳理清楚,这会让你后面的每一步都走得特别踏实。