三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

SpringBoot甜品店管理系统开发实战

SpringBoot甜品店管理系统开发实战

1. 项目概述:甜品店管理系统的核心价值

去年帮朋友改造一家连锁奶茶店的运营系统时,我深刻体会到传统手工记账的痛点:每天打烊后要花2小时核对订单,新品上市时手写菜单要重印三次,会员积分总是对不上账。这正是我们开发这套甜品店管理系统的初衷——用SpringBoot技术栈为中小型餐饮门店打造轻量级数字化解决方案。

这套系统主要解决三个核心问题:一是多终端订单统一管理(堂食扫码点餐+外卖平台接单+收银台现金订单),二是动态库存预警(鲜果、奶油等原料的保质期监控),三是经营数据分析(爆品识别、时段销量统计)。特别适合日均订单量在50-300单的独立甜品店、社区奶茶店和小型蛋糕工坊。

2. 技术架构设计解析

2.1 为什么选择SpringBoot

在技术选型阶段,我们对比了传统的SSM框架和SpringBoot。某连锁品牌的技术总监分享过他们的教训:用SSM搭建的旧系统,启动一个模块就需要配置7个XML文件,而SpringBoot的约定优于配置特性,让我们的开发效率提升了40%。特别是自动装配机制,使得整合MyBatis和Redis等组件时,只需添加starter依赖就能开箱即用。

系统采用经典的三层架构:

  • 表现层:Thymeleaf模板引擎+响应式布局
  • 业务层:Spring MVC+自定义注解实现权限控制
  • 数据层:MyBatis-Plus配合多数据源切换

2.2 数据库设计要点

甜品行业的业务特殊性决定了数据库设计的几个关键点:

  1. 商品表的组合属性字段(如奶茶要记录糖度、冰度、加料等20多种组合)
  2. 原料批次管理(动物奶油开封后保质期只有72小时)
  3. 时段促销策略(下午茶时段第二杯半价)

我们采用MySQL 8.0的JSON类型字段存储商品定制选项,配合触发器实现库存实时扣减。这里有个踩坑经验:最初使用字符串拼接存储定制选项,导致促销活动时WHERE条件无法命中索引,后来改用JSON_EXTRACT函数才解决性能问题。

3. 核心功能实现细节

3.1 智能订单处理模块

订单状态机设计是核心难点,我们采用Spring StateMachine实现以下流程:

// 订单状态定义 public enum OrderStates { INITIAL, PAID, MAKING, DELIVERING, COMPLETED, CANCELLED } // 状态转换配置 @Configuration @EnableStateMachine public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStates, OrderEvents> { @Override public void configure(Transitions<OrderStates, OrderEvents> transitions) { transitions .withExternal() .source(OrderStates.INITIAL) .target(OrderStates.PAID) .event(OrderEvents.PAY) .and() .withExternal() .source(OrderStates.PAID) .target(OrderStates.MAKING) .event(OrderEvents.START_MAKE); } }

特别注意:甜品订单存在"反悔期"——顾客支付后5分钟内可免费取消。我们通过Redis的过期键通知实现:

@Bean RedisMessageListenerContainer container(RedisConnectionFactory factory) { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(factory); container.addMessageListener(new OrderCancelListener(), new PatternTopic("__keyevent@0__:expired")); return container; }

3.2 库存预警系统

原料管理采用双维度监控:

  1. 数量预警:当库存低于安全库存时触发补货提醒
  2. 时效预警:对开封原料启动倒计时提醒

核心SQL示例:

-- 临期原料查询 SELECT material_name, DATEDIFF(expire_date, NOW()) AS remain_days FROM material_stock WHERE store_id = ? AND status = 'OPENED' AND DATEDIFF(expire_date, NOW()) < 3;

我们在实际部署中发现,频繁的全表扫描会导致高峰期系统卡顿。最终解决方案是给expire_date和status字段添加联合索引,并在业务低峰期执行批量检查。

4. 典型问题排查实录

4.1 订单超卖问题

在促销活动期间,出现同一份杨枝甘露被卖出5次的严重BUG。排查过程:

  1. 先检查@Transactional注解是否生效
  2. 确认MySQL隔离级别为REPEATABLE_READ
  3. 最终发现是缓存不一致导致:
// 错误写法:先删缓存再更新数据库 public void deductStock(Long itemId, int num) { redisTemplate.delete("stock:" + itemId); // 步骤1 itemMapper.reduceStock(itemId, num); // 步骤2 } // 正确做法:先更新再删缓存(或使用CAS方案) public void deductStock(Long itemId, int num) { int affected = itemMapper.reduceStockWithVersion(itemId, num, version); if(affected > 0) { redisTemplate.delete("stock:" + itemId); } }

4.2 打印小票乱码

热敏打印机出现中文乱码的解决方案:

  1. 确认打印机字符集支持GB18030
  2. 在SpringBoot中强制指定响应编码:
spring: thymeleaf: encoding: GB18030 servlet: content-type: text/plain;charset=GB18030
  1. 使用Esc/Pos指令集时,注意发送初始化序列:
byte[] init = new byte[]{0x1B, 0x40}; // ESC @ printerOutputStream.write(init);

5. 部署优化实践

5.1 多环境配置技巧

我们采用Profile区分开发、测试和生产环境:

# application-dev.properties spring.datasource.url=jdbc:mysql://localhost:3306/dessert_dev # application-prod.properties spring.datasource.url=jdbc:mysql://prod-db:3306/dessert_prod

启动时通过VM参数指定环境:

java -jar dessert-system.jar --spring.profiles.active=prod

5.2 健康检查端点

为满足容器化部署需求,暴露关键健康指标:

@RestController @RequestMapping("/actuator") public class HealthCheckController { @GetMapping("/db") public ResponseEntity<?> checkDB() { try { jdbcTemplate.queryForObject("SELECT 1", Integer.class); return ResponseEntity.ok().build(); } catch (Exception e) { return ResponseEntity.status(503).build(); } } }

在Kubernetes中配置存活探针:

livenessProbe: httpGet: path: /actuator/db port: 8080 initialDelaySeconds: 60 periodSeconds: 15

这套系统在某网红奶茶店上线后,其订单处理时间从平均3分钟缩短到40秒,原料损耗率下降了28%。特别提醒:甜品行业有很强的季节性波动,建议在系统设计时预留300%的流量余量,比如夏季水果茶销量可能是冬季的5倍以上。

← 返回列表