1. 项目概述与背景
撸猫店作为新兴的宠物经济业态,近年来在各大城市快速兴起。这种结合了猫咪互动体验与轻餐饮服务的商业模式,面临着会员管理复杂、预约时段冲突、商品库存混乱等典型运营痛点。传统手工记录或通用管理软件往往难以满足这类特色店铺的个性化需求。
我去年为本地一家网红撸猫店开发的这套管理系统,采用SpringBoot+Vue的前后端分离架构,经过半年实际运行检验,成功将店铺运营效率提升40%以上。系统核心解决了三大业务难题:动态化预约时段管理、猫咪健康档案电子化、会员积分与商品销售联动。
2. 技术选型解析
2.1 后端技术栈
选择SpringBoot 2.7作为后端框架主要基于以下考量:
- 内嵌Tomcat简化部署,适合中小型店铺的轻量级服务器环境
- 自动配置特性大幅减少XML配置,与MyBatis-Plus配合可实现零XML开发
- 完善的健康检查机制(Actuator)保障系统稳定性
数据库选用MySQL 8.0而非MongoDB的决策点:
- 撸猫店业务数据高度结构化(会员信息、订单记录等)
- 需要支持复杂的事务处理(如预约与支付的一致性)
- GIS空间数据支持(后期扩展分店地理位置查询)
2.2 前端技术栈
Vue 3组合式API的选择优势:
- 更好的TypeScript支持,避免"猫咪体重"等业务字段的类型混乱
- Composition API逻辑复用能力,适合高频出现的预约日历组件
- Vite构建速度比Webpack快5-8倍,提升开发体验
特别引入的第三方库:
- Element Plus:表单验证与表格展示
- ECharts:营收数据可视化
- Vue-Draggable:实现猫咪信息卡片拖拽排序
3. 核心业务模块实现
3.1 动态预约系统
关键技术实现:
java复制// 时段库存控制逻辑
@Transactional
public ReservationResult createReservation(ReservationDTO dto) {
// 使用SELECT FOR UPDATE实现悲观锁
TimeSlot slot = timeSlotMapper.selectForUpdate(dto.getSlotId());
if (slot.getAvailable() < dto.getCatCount()) {
throw new BusinessException("可预约猫咪数量不足");
}
// 更新库存
timeSlotMapper.reduceAvailable(dto.getSlotId(), dto.getCatCount());
// 创建预约记录
Reservation reservation = convertToEntity(dto);
reservationMapper.insert(reservation);
return convertToResult(reservation);
}
重要提示:必须使用@Transactional保证库存扣减与记录创建的原子性,实测中曾因遗漏导致超卖
3.2 猫咪健康管理
采用JSON字段存储动态健康指标:
sql复制CREATE TABLE cat_info (
id BIGINT PRIMARY KEY,
basic_info JSON NOT NULL COMMENT '体重、绝育状态等固定信息',
health_records JSON COMMENT '动态健康记录',
vaccine_records JSON COMMENT '疫苗接种记录'
);
前端使用Monaco Editor实现类IDE的健康记录编辑:
vue复制<monaco-editor
v-model="healthData"
language="json"
:options="{ minimap: { enabled: false } }"
/>
3.3 会员积分体系
积分计算规则引擎配置示例:
yaml复制rules:
- name: "基础消费积分"
condition: "amount > 0"
formula: "floor(amount)"
maxDaily: 1000
- name: "时段加成"
condition: "hour(reservationTime) >= 14 && hour(reservationTime) <= 16"
formula: "points * 1.5"
4. 典型问题解决方案
4.1 高并发预约冲突
解决方案对比:
| 方案 | 吞吐量(QPS) | 实现复杂度 | 适用场景 |
|---|---|---|---|
| 数据库悲观锁 | 120 | 低 | 中小规模店铺 |
| Redis分布式锁 | 850 | 中 | 连锁店系统 |
| 令牌桶限流 | 300 | 低 | 促销活动期间 |
最终采用Redis+Lua脚本实现:
lua复制local key = KEYS[1]
local requested = tonumber(ARGV[1])
local available = tonumber(redis.call('GET', key))
if available >= requested then
redis.call('DECRBY', key, requested)
return 1
else
return 0
end
4.2 猫咪照片存储优化
技术选型对比:
- 本地存储:开发简单但扩容困难
- 七牛云:成本低但有第三方依赖
- MinIO:自建对象存储,最终方案
MinIO配置要点:
yaml复制minio:
endpoint: http://minio:9000
accessKey: ${MINIO_ACCESS}
secretKey: ${MINIO_SECRET}
bucket-name: cat-images
前端上传组件关键代码:
vue复制<template>
<input type="file" @change="upload" accept="image/*" capture="environment">
</template>
<script setup>
const upload = async (e) => {
const file = e.target.files[0];
const filename = `${Date.now()}_${file.name}`;
const url = await minioClient.putObject(filename, file);
// 生成缩略图
const thumbnail = await imageCompression(file, { maxWidth: 300 });
};
</script>
5. 部署与运维实践
5.1 宝塔面板部署
关键步骤记录:
- 安装Java环境管理插件,选择OpenJDK17
- 配置Nginx反向代理,特别注意:
nginx复制location /api { proxy_set_header X-Real-IP $remote_addr; proxy_pass http://localhost:8080; client_max_body_size 50M; # 允许大文件上传 } - 设置MySQL内存配置(4GB服务器示例):
ini复制innodb_buffer_pool_size = 2G key_buffer_size = 256M
5.2 监控配置
Prometheus监控指标示例:
yaml复制- name: reservation_metrics
rules:
- record: reservation:failed:ratio
expr: sum(reservation_failed_total) by (reason) / sum(reservation_total)
- alert: HighFailureRate
expr: reservation:failed:ratio{reason="slot_full"} > 0.3
for: 5m
6. 项目演进方向
当前正在开发的功能迭代:
- 猫咪性格标签系统(NLP分析顾客评价)
- AR猫咪信息展示(通过手机扫描猫牌)
- 智能排班算法(根据历史客流预测人力需求)
技术债改进计划:
- 将JSON字段迁移到专门的文档集合
- 引入RabbitMQ解耦积分计算与核心业务
- 实现灰度发布能力降低更新风险
