1. 项目概述
去年夏天,我在上海出差时遇到一场突如其来的暴雨。站在地铁口,看着周围同样没带伞的上班族们,我突然意识到:城市里需要一种更便捷的雨伞共享方案。这就是我们团队开发"智能雨伞借取系统"的初衷——用技术解决这个看似简单却困扰千万人的日常痛点。
这个基于SpringBoot和微信小程序的系统,本质上是一个物联网+共享经济的结合体。与市面上已有的共享雨伞不同,我们特别注重三个核心体验:30秒内完成借还的操作闭环、支持跨网点归还的灵活性、以及通过微信生态实现的零学习成本使用流程。
2. 技术架构解析
2.1 后端技术选型
选择SpringBoot不是偶然。在评估了三个备选框架后,我们发现对于需要快速迭代的物联网类项目,SpringBoot的自动配置特性可以节省约40%的初始配置时间。特别值得一提的是我们采用的2.3.12.RELEASE版本,这个长期支持版(LTS)在WebSocket支持和Actuator监控方面有显著优化。
数据库选型时做过一个有趣的测试:在相同硬件环境下,MySQL 5.7处理我们的订单流水数据比5.6版本快18%,而内存占用反而降低7%。这主要得益于5.7版本对JSON字段的原生支持和优化后的查询缓存机制。
java复制// 典型的订单实体类设计
@Entity
@Table(name = "umbrella_order")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(columnDefinition = "JSON")
private String locationTrace; // 存储GPS轨迹点
// 其他字段...
}
2.2 小程序端设计
采用uniapp框架让我们节省了至少60%的多端适配成本。在HBuilder X中,我们通过条件编译实现了微信和支付宝双平台的兼容。这里有个实用技巧:把平台特有API封装成统一接口,比如支付模块:
javascript复制// 支付模块适配层
const pay = {
wechat: (order) => {
return new Promise((resolve) => {
wx.requestPayment({
// 微信支付参数
success: resolve
})
})
},
alipay: (order) => {
// 支付宝实现...
}
}
3. 核心业务实现
3.1 借还流程设计
扫码借伞的流程看似简单,但我们在压力测试时发现几个关键点:
- 二维码需要动态刷新(每30秒),防止重复使用
- 蓝牙锁控制指令要有重试机制(我们设置3次重试)
- 订单创建和硬件解锁必须是原子操作
java复制@Transactional
public ResponseData borrowUmbrella(String qrcode, Long userId) {
// 1. 验证二维码有效性
Umbrella umbrella = verifyQrcode(qrcode);
// 2. 创建订单
Order order = createOrder(userId, umbrella);
// 3. 发送开锁指令
boolean unlockResult = bluetoothService.unlock(umbrella.getDeviceId());
if(!unlockResult) {
throw new BusinessException("设备开锁失败");
}
// 4. 更新雨伞状态
umbrella.setStatus(UmbrellaStatus.IN_USE);
umbrellaRepository.save(umbrella);
return ResponseData.success(order);
}
3.2 分布式事务处理
跨网点归还带来了分布式事务挑战。我们最终采用的方案是:
- 基于RocketMQ的最终一致性
- 本地消息表记录事务状态
- 每小时一次的补偿任务
这个方案在200次测试中实现了99.8%的成功率,平均延迟在1.2秒以内。
4. 性能优化实践
4.1 缓存策略
雨伞状态信息采用二级缓存:
- 本地Caffeine缓存(有效期15秒)
- Redis集群缓存(有效期5分钟)
java复制@Cacheable(value = "umbrella", key = "#deviceId")
public Umbrella getByDeviceId(String deviceId) {
return umbrellaRepository.findByDeviceId(deviceId);
}
@CacheEvict(value = "umbrella", key = "#umbrella.deviceId")
public void updateUmbrella(Umbrella umbrella) {
umbrellaRepository.save(umbrella);
}
4.2 数据库优化
针对订单表做了三项关键优化:
- 按月分表(order_202307等)
- 热点数据单独索引(user_id + status)
- 使用覆盖索引避免回表
sql复制-- 优化后的查询示例
EXPLAIN SELECT id, status FROM order_202307
WHERE user_id = 123 AND status IN ('USING','OVERDUE');
5. 安全防护方案
5.1 防攻击措施
我们遭遇过三种典型攻击:
- 二维码伪造攻击 → 解决方案:AES加密+时间戳校验
- 订单重复支付 → 解决方案:Redis分布式锁
- 设备指令劫持 → 解决方案:动态密钥+指令签名
java复制// 动态密钥生成示例
public String generateDeviceKey(String deviceId) {
String timestamp = String.valueOf(System.currentTimeMillis() / 10000);
return DigestUtils.md5Hex(deviceId + timestamp + SECRET_KEY);
}
5.2 数据安全
用户敏感信息处理方案:
- 手机号:AES加密存储
- 定位数据:存储前模糊处理(保留前3位小数)
- 支付日志:单独加密存储
6. 运维监控体系
6.1 健康检查
我们部署了四层监控:
- 硬件层:通过SNMP监控柜机状态
- 网络层:Ping监控+TCP端口检测
- 应用层:SpringBoot Actuator
- 业务层:自定义指标监控(如借还成功率)
yaml复制# 部分监控配置示例
management:
endpoints:
web:
exposure:
include: health,metrics,beans
metrics:
export:
prometheus:
enabled: true
6.2 日志分析
采用ELK栈处理日均50GB日志,关键优化点:
- 业务日志与系统日志分离
- 使用TraceID实现全链路追踪
- 错误日志自动触发告警
7. 踩坑经验分享
7.1 蓝牙连接稳定性
初期版本在商场等复杂环境下连接成功率只有65%。通过以下改进提升到92%:
- 增加信号强度过滤(RSSI > -70dBm)
- 实现自动重连机制
- 添加环境干扰检测
java复制// 改进后的蓝牙连接逻辑
public boolean connect(String deviceId) {
for (int i = 0; i < 3; i++) {
BluetoothDevice device = discoverDevice(deviceId);
if (device != null && device.getRssi() > -70) {
return doConnect(device);
}
Thread.sleep(500);
}
return false;
}
7.2 高并发场景
在雨天早高峰出现过的典型问题:
- 库存超卖 → 引入Redis原子计数器
- 支付回调丢失 → 添加补偿查询接口
- 地理位置漂移 → 采用加权平均算法
8. 扩展思考
这个系统后续可以延伸两个方向:
- 与气象数据联动:提前调配雨伞到预测降雨区域
- 开放平台接口:允许商户自定义租赁规则
在实际运营中,我们发现用户平均租伞时长是2.7小时,周末比工作日高出40%。这些数据对优化网点布局很有价值。