1. 项目背景与核心价值
家政服务行业近年来呈现爆发式增长态势,传统电话预约模式已经无法满足现代家庭的多元化需求。这个Java家政服务平台的设计初衷,就是通过技术手段解决三个行业痛点:服务供需匹配效率低、服务过程缺乏透明度、用户与服务人员双向评价体系缺失。
我选择Java作为开发语言主要基于三点考虑:首先,Java的Spring Boot框架能快速构建高可用的后端服务;其次,Java生态中有大量成熟的家政行业解决方案可供参考;最后,院校教学中Java仍是主流技术栈,方便后续功能扩展和毕业答辩演示。平台采用微服务架构设计,各模块可独立部署,这在后期添加智能调度算法时体现出了明显优势。
2. 系统架构设计解析
2.1 技术栈选型
后端采用Spring Boot 2.7 + MyBatis Plus组合,数据库使用MySQL 8.0。这里特别说明选择MyBatis Plus而非JPA的原因:家政业务涉及大量复杂查询(如按服务类型、距离、评分等多维度筛选),MyBatis Plus的Wrapper条件构造器比JPA的Specification更直观。前端选用Vue 3 + Element Plus,打包工具升级为Vite,实测项目冷启动时间比Webpack快3倍。
消息队列用RabbitMQ处理订单状态变更通知,这里有个实际教训:最初用Redis的Pub/Sub实现,但在服务人员APP频繁断线重连场景下会出现消息丢失。支付模块对接微信支付官方API时,要注意服务商模式和直连模式的区别,我们平台因为涉及服务人员分成,必须用服务商模式。
2.2 数据库关键设计
用户表采用垂直分表设计,将基础信息与扩展信息分离。订单表的核心字段包括:
sql复制CREATE TABLE `service_order` (
`order_id` varchar(32) NOT NULL COMMENT '雪花算法ID',
`service_type` tinyint(4) NOT NULL COMMENT '服务类型枚举值',
`geohash` varchar(12) NOT NULL COMMENT '用于LBS查询的GeoHash值',
`dynamic_price` decimal(10,2) DEFAULT NULL COMMENT '动态加价金额',
`status_log` json DEFAULT NULL COMMENT '状态变更日志',
PRIMARY KEY (`order_id`),
SPATIAL KEY `idx_geohash` (`geohash`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
特别注意geohash字段的空间索引,这是实现3公里内服务人员快速筛选的关键。status_log采用JSON类型存储完整状态机流转记录,这在处理投诉纠纷时特别有用。
3. 核心业务模块实现
3.1 智能调度算法
家政服务的特殊之处在于必须考虑服务人员的技能矩阵(如月嫂需要育婴师证)和实时位置。算法核心逻辑:
- 基于GeoHash的初步筛选(3公里范围内)
- 技能标签匹配度计算
- 服务评分权重调整(新用户加权)
- 接单率动态平衡(避免头部服务人员过载)
实现代码片段:
java复制public List<WorkerVO> matchWorkers(OrderDTO order) {
// 获取GeoHash前缀范围
String geoPrefix = GeoHashUtils.getPrefix(order.getLat(), order.getLng(), 3);
// 构建查询条件
LambdaQueryWrapper<Worker> wrapper = new LambdaQueryWrapper<>()
.apply("LEFT(work_location_geohash, {0}) = {1}", geoPrefix.length(), geoPrefix)
.eq(Worker::getServiceType, order.getServiceType())
.gt(Worker::getCertScore, 60);
// 加入权重计算
return workerMapper.selectList(wrapper).stream()
.map(w -> {
WorkerVO vo = new WorkerVO();
BeanUtils.copyProperties(w, vo);
vo.setMatchScore(calculateMatchScore(w, order));
return vo;
})
.sorted(Comparator.comparing(WorkerVO::getMatchScore).reversed())
.limit(20)
.collect(Collectors.toList());
}
3.2 动态定价策略
周末/节假日的价格浮动采用策略模式实现:
java复制public interface PricingStrategy {
BigDecimal calculate(BasicPriceInfo info);
}
@Service
public class HolidayStrategy implements PricingStrategy {
@Override
public BigDecimal calculate(BasicPriceInfo info) {
return info.getBasePrice().multiply(new BigDecimal("1.3"));
}
}
在订单创建时通过策略上下文自动应用对应规则:
java复制public BigDecimal getFinalPrice(OrderCreateDTO dto) {
PricingStrategy strategy = strategyFactory.getStrategy(dto.getServiceTime());
return strategy.calculate(buildPriceInfo(dto));
}
4. 典型问题排查实录
4.1 微信支付签名失败
错误现象:调试时频繁出现"签名验证失败"错误。根本原因是微信支付APIv3的签名规则与v2完全不同,必须严格按照以下步骤:
- 获取平台证书列表(GET /v3/certificates)
- 使用平台公钥验证应答签名
- 构造请求时注意URLEncode处理
关键代码:
java复制String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
String nonceStr = UUID.randomUUID().toString();
String body = JSON.toJSONString(paymentRequest);
String signStr = buildSignStr(method, url, timestamp, nonceStr, body);
String signature = signer.sign(signStr);
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization",
"WECHATPAY2-SHA256-RSA2048 " +
"mchid=\"" + mchId + "\"," +
"nonce_str=\"" + nonceStr + "\"," +
"timestamp=\"" + timestamp + "\"," +
"serial_no=\"" + serialNo + "\"," +
"signature=\"" + signature + "\"");
4.2 高并发下的订单状态冲突
使用分布式锁+乐观锁双重保证:
java复制public boolean acceptOrder(String orderId, Long workerId) {
String lockKey = "order:accept:" + orderId;
try {
// 分布式锁防止重复操作
boolean locked = redisLock.tryLock(lockKey, 10, TimeUnit.SECONDS);
if (!locked) return false;
// 乐观锁更新
int updated = orderMapper.updateOrderStatus(
orderId,
OrderStatus.PENDING,
OrderStatus.ACCEPTED,
workerId);
return updated > 0;
} finally {
redisLock.unlock(lockKey);
}
}
5. 演示系统构建要点
5.1 测试数据生成
使用Java Faker库构造真实场景数据:
java复制Faker faker = new Faker(Locale.CHINA);
Worker worker = new Worker();
worker.setRealName(faker.name().fullName());
worker.setMobile(faker.phoneNumber().cellPhone());
worker.setServiceType(faker.number().numberBetween(1, 5));
worker.setWorkLocationGeoHash(GeoHashUtils.encode(
faker.number().randomDouble(6, 39, 41),
faker.number().randomDouble(6, 116, 118)
));
5.2 PPT制作技巧
- 架构图使用Draw.io绘制,导出为矢量图
- 数据库ER图用PowerDesigner生成后转为PPT可编辑格式
- 关键代码截图要保持风格统一(推荐VS Code Dark+主题)
- 性能对比数据用组合图表展示(柱状图+折线图双Y轴)
6. 毕业设计避坑指南
- 需求分析阶段务必制作原型图,避免后期频繁修改
- 技术选型要准备备选方案(如Redis不可用时降级到本地缓存)
- 答辩演示前必须完整跑通主流程三次以上
- 视频录制建议采用分段录制+后期剪辑的方式
- 源代码注释率要达到80%以上,重点算法需有详细说明
在数据库连接池配置方面,我们最终采用HikariCP而非Druid,因为在压力测试中(JMeter模拟100并发),HikariCP的平均响应时间比Druid低23%。这个选择过程应该在论文中详细说明测试方法和数据。