1. 项目背景与核心价值
蛋糕订购小程序是当前烘焙行业数字化转型的典型应用场景。随着移动互联网的普及,传统蛋糕店面临着线上获客难、订单管理效率低、客户粘性不足等痛点。这个基于SpringBoot+uni-app的解决方案,恰好解决了以下行业痛点:
- 线上订单占比提升:烘焙行业线上订单已从2019年的12%增长至2023年的37%(数据来源:中国烘焙行业协会)
- 多端适配需求:商家需要同时覆盖微信、支付宝、H5等多渠道客户
- 运营效率提升:传统手工记录订单方式错误率高达8%,而数字化系统可降至0.5%以下
我在实际开发中发现,采用SpringBoot+uni-app的技术组合具有独特优势:
-
后端采用SpringBoot可快速实现:
- 订单状态机管理(待支付/已支付/制作中/配送中/已完成)
- 分布式锁防止超卖(特别是节日高峰期)
- 微信支付/退款全流程对接
-
前端使用uni-app可实现:
- 一套代码多端发布(微信+支付宝小程序+App)
- 原生体验的交互效果(通过条件编译实现平台差异化)
- 热更新能力(避免频繁审核)
特别提示:小程序审核时最容易被打回的三个点:类目选择(必须选"餐饮-烘焙")、支付协议(需要《食品经营许可证》)、用户隐私协议(必须明确说明数据收集范围)
2. 技术架构详解
2.1 后端SpringBoot设计
采用经典的三层架构,但针对蛋糕业务做了特殊优化:
java复制// 订单服务核心逻辑示例
@Transactional
public Order createOrder(OrderDTO dto) {
// 分布式锁防止重复下单
String lockKey = "order_lock:" + dto.getUserId();
try {
boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
if (!locked) throw new BusinessException("操作太频繁");
// 库存校验(重点!)
cakeService.checkInventory(dto.getItems());
// 订单流水号生成(日期+店铺ID+Redis自增序列)
String orderNo = generateOrderNo(dto.getShopId());
// 持久化订单
Order order = convertToEntity(dto);
order.setOrderNo(orderNo);
orderMapper.insert(order);
// 扣减库存(采用最终一致性方案)
sendInventoryMessage(order);
return order;
} finally {
redisTemplate.delete(lockKey);
}
}
关键设计点:
- 库存管理采用"预扣减+异步确认"模式,避免超卖
- 订单号生成融合店铺ID,便于后期分库分表
- 分布式锁使用Redis+自动过期,防止死锁
2.2 前端uni-app实现
通过自定义组件实现关键业务流程:
vue复制<!-- 蛋糕选择组件 -->
<template>
<view class="cake-picker">
<size-selector
:sizes="sizes"
@change="handleSizeChange"
/>
<flavor-selector
:flavors="flavors"
:disabled="!selectedSize"
@change="handleFlavorChange"
/>
<decoration-options
v-if="selectedFlavor"
:options="decorations"
@change="handleDecorationChange"
/>
</view>
</template>
<script>
export default {
data() {
return {
sizes: ['6寸', '8寸', '10寸'],
flavors: ['巧克力', '草莓', '榴莲'],
decorations: ['水果', '鲜花', '卡通造型']
}
},
methods: {
handleSizeChange(size) {
this.$emit('size-change', size)
// 根据尺寸更新价格
this.fetchPrice(size)
}
}
}
</script>
性能优化技巧:
- 图片使用webp格式+CDN加速
- 长列表采用虚拟滚动
- 接口数据做本地缓存(特别适合商品信息)
3. 核心业务实现
3.1 定制化订单流程
针对蛋糕行业的特殊需求,我们设计了五步定制流程:
-
基础选择阶段
- 尺寸选择(带价格实时计算)
- 口味选择(关联库存校验)
- 糖度选择(0%/30%/50%/100%)
-
装饰定制阶段
- 上传参考图片(采用微信临时路径处理)
- 选择装饰元素(联动显示附加费用)
- 祝福语输入(敏感词过滤)
-
收货信息确认
- 地图API集成(配送范围校验)
- 时间选择器(区分工作日/节假日)
- 联系人信息(脱敏存储)
-
支付处理
- 微信支付签名处理
- 支付超时自动取消(30分钟)
- 支付结果异步通知
-
订单状态追踪
- 制作进度可视化
- 配送轨迹地图展示
- 完成后的评价引导
3.2 支付系统对接
支付环节的坑最多,这里分享几个关键点:
java复制// 微信支付回调处理
@PostMapping("/pay/notify")
public String handleNotify(HttpServletRequest request) {
// 1. 验证签名
Map<String, String> params = WxPayUtil.parseNotify(request);
if (!WxPayUtil.isSignatureValid(params, apiKey)) {
return WxPayUtil.generateFailXml("签名失败");
}
// 2. 处理重复通知(幂等设计)
String orderNo = params.get("out_trade_no");
if (orderCache.hasProcessed(orderNo)) {
return WxPayUtil.generateSuccessXml();
}
// 3. 金额校验(防止小数点位问题)
BigDecimal paidAmount = new BigDecimal(params.get("total_fee"))
.divide(new BigDecimal(100));
if (!orderService.validateAmount(orderNo, paidAmount)) {
return WxPayUtil.generateFailXml("金额不一致");
}
// 4. 更新订单状态
orderService.paySuccess(orderNo, params.get("transaction_id"));
orderCache.markProcessed(orderNo);
return WxPayUtil.generateSuccessXml();
}
支付环节必须注意:
- 金额单位转换(微信以分为单位)
- 异步通知可能多次触发
- 网络超时需要自动补单查询
4. 部署与运维实践
4.1 后端部署方案
推荐使用Docker Compose部署:
yaml复制version: '3'
services:
app:
image: openjdk:11-jre
container_name: cake-app
ports:
- "8080:8080"
volumes:
- ./logs:/app/logs
environment:
- SPRING_PROFILES_ACTIVE=prod
- REDIS_HOST=redis
depends_on:
- redis
- mysql
mysql:
image: mysql:5.7
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=yourpassword
volumes:
- ./mysql-data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
volumes:
- ./redis-data:/data
4.2 小程序发布要点
- 分包加载配置
json复制{
"subPackages": [
{
"root": "pages/order",
"pages": [
"create/index",
"detail/index"
]
}
]
}
- 隐私协议配置
xml复制<!-- 必须在小程序根目录添加 -->
<privacy-description>
我们收集您的地址信息用于配送,手机号用于订单通知...
</privacy-description>
5. 常见问题排查
5.1 微信登录失败
典型错误代码与解决方案:
| 错误码 | 原因 | 解决方案 |
|---|---|---|
| 40029 | code无效 | 检查appsecret是否正确,code是否重复使用 |
| 45011 | API调用太频繁 | 增加失败重试间隔,使用本地缓存 |
| 40163 | code已被使用 | 确保code一次性使用,实现请求幂等 |
5.2 图片上传问题
uni-app中处理微信临时路径的技巧:
javascript复制// 转换微信临时路径为可上传路径
function getRealPath(tempFilePath) {
return new Promise((resolve) => {
if (tempFilePath.startsWith('http')) {
resolve(tempFilePath)
} else {
plus.io.resolveLocalFileSystemURL(
tempFilePath,
(entry) => resolve(entry.toLocalURL()),
(error) => console.error(error)
)
}
})
}
6. 项目扩展方向
在实际运营中,可以考虑以下增值功能:
-
会员积分系统
- 消费积分计算
- 积分兑换设计
- 生日特权设置
-
智能推荐算法
- 基于购买历史的推荐
- 季节限定款自动置顶
- 搭配购买建议
-
配送优化
- 骑手轨迹实时追踪
- 预计到达时间算法
- 温控配送提醒
这个项目最让我有成就感的是解决了蛋糕尺寸与配料的组合定价问题。通过设计一套规则引擎,商家可以在后台自由配置:
code复制当选择【8寸】+【榴莲口味】时:
- 基础价增加30%
- 需要额外选择【加固包装】
- 配送范围缩小到5公里内
这种灵活性让系统可以适配各种特色蛋糕店的个性化需求
