1. 项目概述与背景
去年参与开发了一个宠物服务综合平台,采用SpringBoot+Vue.js技术栈,完整实现了从宠物服务预约到领养管理的全流程数字化。这个项目让我深刻体会到,一个优秀的宠物服务平台不仅需要扎实的技术实现,更要深入理解宠物主和服务商的双向需求。
当前宠物服务行业存在几个典型痛点:服务信息分散在各类平台,用户需要反复切换比价;预约流程繁琐,经常出现电话沟通不畅导致的时间冲突;领养信息真实性难以验证,双方信任成本高。我们的系统正是针对这些问题,通过标准化服务流程、透明化信息展示和便捷的线上操作,为宠物主和服务商搭建了一个高效对接平台。
2. 技术架构设计
2.1 整体技术选型
后端采用SpringBoot 2.7 + MyBatis Plus组合,前端使用Vue 3 + Element Plus。这个组合经过多个项目验证,在开发效率和性能之间取得了很好平衡。特别说明几个关键选择:
-
放弃JPA选择MyBatis Plus:虽然JPA开发更快速,但宠物服务涉及复杂的多表关联查询(如预约记录需要联查用户、服务、支付状态),MyBatis Plus的Wrapper条件构造器更适合这种场景。
-
前端采用Pinia状态管理:相比Vuex,Pinia的TypeScript支持更好,在服务预约流程中需要维护复杂的临时状态(如选择的服务项、时间、优惠券等),Pinia的模块化设计让状态管理更清晰。
-
自定义权限控制方案:基于Spring Security的RBAC模型扩展,增加了服务商角色(介于管理员和普通用户之间),通过@PreAuthorize注解实现方法级权限控制。
2.2 数据库设计要点
MySQL表设计中几个值得分享的经验:
- 服务预约表的冗余设计:
sql复制CREATE TABLE `service_order` (
`id` bigint NOT NULL AUTO_INCREMENT,
`service_id` bigint NOT NULL COMMENT '服务ID',
`service_name` varchar(100) NOT NULL COMMENT '冗余存储服务名称',
`user_id` bigint NOT NULL,
`user_mobile` varchar(20) NOT NULL COMMENT '冗余用户手机号',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '0-待支付 1-已预约 2-已完成 3-已取消',
`appointment_time` datetime NOT NULL COMMENT '预约时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
关键点:存储服务名称和用户手机号等冗余字段,避免列表查询时频繁联表。这种设计在订单类系统中很常见。
- 宠物信息的标签化存储:
sql复制CREATE TABLE `pet_info` (
`id` bigint NOT NULL AUTO_INCREMENT,
`tags` json DEFAULT NULL COMMENT '存储疫苗、绝育等标签JSON数组',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
使用JSON类型存储动态标签,比传统的多对多关联表更灵活,适合宠物特征这种非结构化数据。
3. 核心功能实现
3.1 服务预约流程
预约功能的技术实现有几个关键点:
- 服务时间冲突检测:
java复制public boolean checkTimeConflict(Long serviceProviderId, LocalDateTime startTime, int duration) {
// 查询该服务商已有预约
List<ServiceOrder> orders = orderMapper.selectList(new LambdaQueryWrapper<ServiceOrder>()
.eq(ServiceOrder::getServiceProviderId, serviceProviderId)
.eq(ServiceOrder::getStatus, 1) // 已预约状态
.between(ServiceOrder::getAppointmentTime,
startTime.minusMinutes(duration),
startTime.plusMinutes(duration)));
return !orders.isEmpty();
}
- 预约状态机设计:
使用状态模式实现订单状态流转,避免复杂的if-else判断:
java复制public interface OrderState {
void cancel(ServiceOrder order);
void complete(ServiceOrder order);
// 其他操作...
}
@Component
@Scope("prototype")
public class PendingPaymentState implements OrderState {
@Override
public void cancel(ServiceOrder order) {
order.setStatus(OrderStatus.CANCELLED);
// 释放库存等操作
}
}
3.2 宠物领养信息审核
领养模块最复杂的是信息审核流程,我们实现了:
- 多级审核机制:
- 基础信息自动审核(必填项检查、敏感词过滤)
- 人工审核(志愿者后台审核照片/视频)
- 终审(管理员确认)
- 审核日志追踪:
java复制public class AdoptionAuditLog {
private Long recordId;
private AuditOperation operation; // 通过/拒绝
private String remark;
private Long auditorId;
private LocalDateTime auditTime;
@Transient
private String auditorName; // 展示用
}
4. 性能优化实践
4.1 服务列表缓存策略
服务列表采用多级缓存:
- Redis缓存热门服务(基于点击量)
- Caffeine本地缓存全量服务分类
- 数据库分页查询兜底
关键配置:
yaml复制spring:
cache:
type: caffeine
caffeine:
spec: maximumSize=1000,expireAfterWrite=10m
redis:
time-to-live: 1h
4.2 预约服务的并发控制
采用Redisson分布式锁防止超卖:
java复制public boolean createOrder(OrderDTO dto) {
RLock lock = redissonClient.getLock("service_lock:" + dto.getServiceId());
try {
if (lock.tryLock(3, 10, TimeUnit.SECONDS)) {
// 检查库存
// 创建订单
}
} finally {
lock.unlock();
}
}
5. 安全防护措施
5.1 敏感数据加密
宠物主联系方式等敏感信息使用AES加密存储:
java复制@Column
@Convert(converter = CryptoConverter.class)
private String mobile;
自定义JPA AttributeConverter实现加解密:
java复制public class CryptoConverter implements AttributeConverter<String, String> {
private static final String KEY = "...";
@Override
public String convertToDatabaseColumn(String attribute) {
return AES.encrypt(attribute, KEY);
}
}
5.2 接口防刷策略
- 预约接口限流:Guava RateLimiter
- 短信验证码:IP+手机号频率控制
- 关键操作二次验证
6. 部署与监控
6.1 容器化部署
Docker Compose编排文件示例:
yaml复制version: '3'
services:
app:
image: pet-service:1.0
ports:
- "8080:8080"
depends_on:
- redis
- mysql
redis:
image: redis:6
ports:
- "6379:6379"
6.2 Prometheus监控配置
采集SpringBoot Actuator指标:
yaml复制management:
endpoints:
web:
exposure:
include: "*"
metrics:
tags:
application: pet-service
7. 踩坑经验分享
-
时间处理时区问题:
MySQL服务器时区必须与应用一致,否则预约时间会出现偏差。建议统一使用UTC时间存储,前端按需转换。 -
Vue组件性能优化:
宠物列表页初期渲染卡顿,通过以下措施解决:
- 虚拟滚动
- 图片懒加载
- 复杂计算移至Web Worker
- MyBatis批量插入优化:
领养信息批量导入时性能差,改用BatchExecutor:
java复制@Bean
public Executor executor(DataSource dataSource) {
return new BatchExecutor(configuration, new SimpleExecutor(configuration, dataSource));
}
8. 扩展方向
已完成项目中还可以进一步优化:
- 接入支付系统(已预留支付回调接口)
- 增加宠物健康档案管理
- 实现服务智能推荐(基于用户行为分析)
- 开发微信小程序端
这个项目让我深刻认识到,一个好的系统需要不断迭代完善。技术选型要平衡当下需求和未来发展,架构设计要预留扩展性,而核心是要始终聚焦解决用户的真实痛点。