1. 项目背景与核心需求
在传统洗衣店运营中,订单管理往往依赖纸质单据和人工记录,这种模式存在三个显著痛点:一是订单信息容易丢失或混淆,二是顾客无法实时追踪洗衣进度,三是店家与顾客之间缺乏有效沟通渠道。针对这些问题,我们开发了一套基于Spring Boot的洗衣店订单管理系统,实现从接单到交付的全流程数字化管理。
系统设计遵循"角色分离"原则,为三类用户提供差异化功能:
- 管理员:拥有最高权限,可管理系统基础数据、审核店铺资质、处理投诉纠纷
- 店家:管理自有店铺的订单流,包括衣物分类、价格设置、进度更新等
- 顾客:通过移动端完成线上下单、进度查询、在线支付等操作
实际开发中发现,洗衣行业对订单状态变更的实时性要求极高。我们在数据库设计中特别加入了状态变更日志表,记录每个订单从创建到完成的所有状态变化时间点,这对后续的纠纷处理提供了数据依据。
2. 技术架构设计
2.1 后端技术选型
采用Spring Boot 2.7作为核心框架,主要基于以下考量:
- 自动配置:通过starter依赖快速集成MyBatis、Redis等组件
- 内嵌容器:默认Tomcat支持,无需额外部署WAR包
- 健康检查:Actuator端点提供系统监控能力
- 配置管理:多环境配置分离(application-dev.yml/prod.yml)
数据库选用MySQL 8.0,关键优化包括:
sql复制-- 订单表添加复合索引
CREATE INDEX idx_order_status ON laundry_order(store_id, status);
-- 使用JSON类型存储衣物明细
ALTER TABLE order_detail ADD clothes_items JSON COMMENT '衣物明细';
2.2 前端技术方案
Vue 3组合式API带来以下优势:
- 响应式更新:基于Proxy的订单状态自动同步
- 组件复用:封装通用的订单卡片组件
- 状态管理:Pinia替代Vuex管理全局状态
典型页面数据流示例:
javascript复制// 订单列表页逻辑
const loadOrders = async () => {
const { data } = await axios.get('/api/orders', {
params: {
status: activeTab.value,
page: currentPage.value
}
});
orders.value = data.items;
total.value = data.total;
}
2.3 系统安全设计
采用五层防护体系:
- 认证层:JWT + Spring Security
- 权限层:RBAC模型控制接口访问
- 数据层:MyBatis参数预编译防SQL注入
- 传输层:HTTPS + 敏感字段加密
- 日志层:AOP记录所有管理操作
安全配置示例:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/store/**").hasRole("STORE")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()));
}
}
3. 核心功能实现
3.1 订单状态机设计
洗衣订单包含典型状态流转:
code复制待接单 → 已接单 → 清洗中 → 待取件 → 已完成
↘ 已取消 ↗
使用状态模式实现业务逻辑:
java复制public interface OrderState {
void handle(OrderContext context);
}
@Component
@Scope("prototype")
public class WashingState implements OrderState {
@Override
public void handle(OrderContext context) {
if (!context.getOrder().getPaid()) {
throw new IllegalStateException("未支付订单不能开始清洗");
}
// 更新洗衣进度...
}
}
3.2 微信支付集成
支付流程关键节点:
- 前端调起JSAPI支付接口
- 后端生成预付单并签名
- 微信回调验证处理
- 订单状态同步更新
防重复支付处理:
java复制@Transactional
public String createPayment(Order order) {
if (order.getPaid()) {
throw new BusinessException("订单已支付");
}
// 生成支付流水记录
Payment payment = new Payment()
.setOrderId(order.getId())
.setNonceStr(IdUtil.fastUUID());
paymentMapper.insert(payment);
// 调用微信统一下单API
return wechatPayService.createOrder(payment);
}
3.3 消息推送机制
采用混合推送方案:
- 模板消息:重要状态变更(如订单完成)
- WebSocket:实时聊天沟通
- 短信备份:支付提醒等关键操作
消息队列配置:
yaml复制spring:
rabbitmq:
host: mq.prod.com
virtual-host: /laundry
listener:
simple:
retry:
enabled: true
max-attempts: 3
4. 性能优化实践
4.1 缓存策略设计
三级缓存体系:
- 本地缓存:Caffeine缓存店铺基础信息
- 分布式缓存:Redis存储热点订单数据
- 数据库缓存:MySQL查询缓存
缓存注解示例:
java复制@Cacheable(value = "stores", key = "#id", unless = "#result == null")
public Store getStoreById(Long id) {
return storeMapper.selectById(id);
}
@CacheEvict(value = "stores", key = "#store.id")
public void updateStore(Store store) {
storeMapper.updateById(store);
}
4.2 数据库优化
实施以下优化措施:
- 读写分离:主库写,从库读
- 分表策略:按月份拆分订单表
- 索引优化:为常用查询字段建立覆盖索引
分页查询优化:
sql复制-- 避免使用OFFSET
SELECT * FROM laundry_order
WHERE store_id = ? AND status = ?
ORDER BY create_time DESC
LIMIT 10;
4.3 压力测试结果
使用JMeter模拟100并发:
- 订单创建API:平均响应时间238ms
- 订单查询API:平均响应时间156ms
- 支付回调API:平均响应时间89ms
优化前后对比:
| 指标 | 优化前 | 优化后 | 提升幅度 |
|---|---|---|---|
| 最大QPS | 120 | 350 | 192% |
| 99线延迟 | 1.2s | 480ms | 60% |
| 错误率 | 2.3% | 0.1% | 95% |
5. 部署与运维
5.1 容器化部署
Docker Compose编排方案:
yaml复制version: '3'
services:
app:
image: laundry:1.0
ports:
- "8080:8080"
depends_on:
- redis
- mysql
redis:
image: redis:6-alpine
ports:
- "6379:6379"
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
5.2 监控方案
集成Prometheus + Grafana监控:
- 应用指标:JVM内存、线程池状态
- 业务指标:订单创建量、支付成功率
- 系统指标:CPU负载、磁盘IO
关键告警规则示例:
yaml复制- alert: HighErrorRate
expr: rate(http_server_requests_errors_total[1m]) > 0.1
for: 5m
labels:
severity: critical
annotations:
summary: "High error rate on {{ $labels.instance }}"
5.3 持续交付流程
GitLab CI/CD流水线:
yaml复制stages:
- test
- build
- deploy
unit-test:
stage: test
script:
- mvn test
package:
stage: build
script:
- mvn package -DskipTests
artifacts:
paths:
- target/*.jar
deploy-prod:
stage: deploy
only:
- master
script:
- scp target/app.jar user@prod:/opt/laundry
- ssh user@prod "systemctl restart laundry"
6. 典型问题解决方案
6.1 并发订单冲突
使用乐观锁避免超卖:
java复制@Transactional
public boolean acceptOrder(Long orderId, Long storeId) {
Order order = orderMapper.selectById(orderId);
if (order.getVersion() != inputVersion) {
throw new OptimisticLockException("订单已被修改");
}
order.setStatus(OrderStatus.ACCEPTED);
order.setStoreId(storeId);
return orderMapper.updateById(order) > 0;
}
6.2 微信支付回调处理
保证幂等性的方案:
java复制@PostMapping("/notify")
public String paymentNotify(@RequestBody String xmlData) {
// 1. 验签
if (!wechatPayService.verifySignature(xmlData)) {
return "FAIL";
}
// 2. 解析支付结果
PaymentNotifyDTO notify = parseXml(xmlData);
// 3. 检查是否已处理
if (paymentService.isProcessed(notify.getOutTradeNo())) {
return "SUCCESS";
}
// 4. 处理业务逻辑
paymentService.handlePaymentSuccess(notify);
return "SUCCESS";
}
6.3 跨店数据隔离
多租户实现方案:
java复制@Aspect
@Component
public class TenantFilterAspect {
@Before("execution(* com.laundry.mapper.*.*(..)) && args(..,tenantId)")
public void beforeQuery(JoinPoint jp, Long tenantId) {
if (tenantId != null) {
TenantContext.setCurrentTenant(tenantId);
}
}
}
public class TenantInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
String tenantId = request.getHeader("X-Tenant-ID");
TenantContext.setCurrentTenant(tenantId);
return true;
}
}
在项目上线后,我们发现店家用户对移动端操作便捷性有更高要求。后续计划开发微信小程序版本,重点优化以下方面:
- 增加拍照识别衣物功能
- 实现LBS就近店铺推荐
- 完善售后评价体系
- 接入智能客服系统
系统目前已在本地3家连锁洗衣店试运行,订单处理效率提升40%,顾客投诉率下降65%。这个项目给我的深刻启示是:传统行业的数字化转型,不仅需要技术实现,更要深入理解行业特有的业务流程和用户习惯。