1. 项目概述与核心价值
这个宠物诊所管理系统是我去年为一个本地连锁宠物医院开发的实战项目,当时他们正面临纸质档案混乱、预约排班冲突频发、药品库存盘点困难三大痛点。系统上线后,诊所的日均接诊量提升了40%,药品损耗率从15%降到3%以下。这个基于Java技术栈的解决方案,特别适合5-20人规模的中小型哺乳类宠物诊所(猫、狗、兔等),相比市面上的通用系统,在宠物病历模板、疫苗提醒、品种特异性用药等方面做了深度定制。
技术选型上采用SpringBoot 2.7 + MyBatis-Plus 3.5的组合,前端用Vue2+ElementUI(客户预算有限),数据库是MySQL 8.0。特别要说明的是没有用更流行的SpringCloud架构,因为诊所没有微服务需求,单体架构反而减少了运维复杂度。系统包含7个核心模块:挂号预约、病历管理、药品库存、财务统计、会员管理、医生排班和系统设置,接下来我会重点拆解其中最具行业特性的三个模块实现细节。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 宠物病历管理模块深度实现
2.1 病历数据结构设计
宠物病历和人类医疗最大的区别在于要记录品种特性。我们设计的病历表结构包含几个关键字段:
sql复制CREATE TABLE `pet_medical_record` (
`id` bigint NOT NULL AUTO_INCREMENT,
`pet_id` bigint NOT NULL COMMENT '宠物ID',
`pet_breed` varchar(50) NOT NULL COMMENT '品种(英短猫/金毛犬等)',
`body_weight` decimal(5,2) DEFAULT NULL COMMENT '体重(kg)',
`temperature` decimal(3,1) DEFAULT NULL COMMENT '体温(℃)',
`symptom` text NOT NULL COMMENT '症状描述',
`diagnosis_result` text COMMENT '诊断结果',
`treatment_plan` text COMMENT '治疗方案',
`is_vaccine` tinyint DEFAULT '0' COMMENT '是否疫苗注射',
`next_checkup_date` date DEFAULT NULL COMMENT '下次复查日期',
`attending_doctor_id` bigint NOT NULL COMMENT '主治医生ID',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_pet_id` (`pet_id`),
KEY `idx_doctor_id` (`attending_doctor_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
特别注意:
- 体重字段用decimal而非float,避免计算用药量时的精度问题
- 专门记录品种信息,用于后续的用药剂量计算(不同体型动物用药量差异大)
- 体温字段预留1位小数,猫狗正常体温范围38-39℃
2.2 品种特异性用药计算
在药品管理模块,我们实现了基于品种的自动剂量计算算法:
java复制public BigDecimal calculateDosage(PetBreed breed, Medicine medicine, BigDecimal weight) {
// 获取基础剂量(mg/kg)
BigDecimal baseDose = medicine.getBaseDose();
// 品种系数(小型犬1.0,中型犬0.8,大型犬0.6,猫1.2)
BigDecimal breedFactor = getBreedFactor(breed);
// 计算最终剂量 = 基础剂量 × 品种系数 × 体重
return baseDose.multiply(breedFactor)
.multiply(weight)
.setScale(2, RoundingMode.HALF_UP);
}
实际使用中发现,布偶猫等大型猫的系数需要单独设置,不能简单套用普通猫的系数,这是我们在测试阶段通过临床数据调整的重要经验。
2.3 疫苗提醒功能实现
系统会自动扫描next_checkup_date字段,在到期前3天触发提醒。核心SQL如下:
sql复制SELECT r.pet_id, p.pet_name, p.owner_phone,
r.next_checkup_date, v.vaccine_name
FROM pet_medical_record r
JOIN pet_info p ON r.pet_id = p.id
JOIN vaccine_info v ON r.vaccine_id = v.id
WHERE r.is_vaccine = 1
AND r.next_checkup_date BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 3 DAY)
重要提示:疫苗提醒必须考虑闰年情况,我们最初用简单的+365天计算,结果在2020年2月出现大量错误提醒,后改为使用Java 8的LocalDate.plusYears()方法。
3. 预约挂号模块的并发处理
3.1 排班表的锁机制设计
宠物诊所经常出现多个客户同时抢热门医生号源的情况。我们采用乐观锁解决并发冲突:
java复制@Transactional
public boolean makeAppointment(Long scheduleId, Long petId) {
// 1. 查询当前版本号
DoctorSchedule schedule = scheduleMapper.selectById(scheduleId);
// 2. 检查剩余号源
if (schedule.getRemainCount() < 1) {
return false;
}
// 3. 更新带版本检查
int updated = scheduleMapper.updateRemainCount(
scheduleId,
schedule.getVersion(),
schedule.getRemainCount() - 1);
// 4. 更新成功才创建预约记录
if (updated > 0) {
Appointment appt = new Appointment();
appt.setScheduleId(scheduleId);
appt.setPetId(petId);
appt.setStatus(0); // 0-待就诊
appointmentMapper.insert(appt);
return true;
}
return false;
}
3.2 高峰期性能优化
在双十一等促销日(宠物医院也会搞体检套餐活动),我们通过以下措施保障系统稳定:
- 对
/api/appointment/**接口启用Redis缓存 - 使用Hystrix实现熔断降级
- 预约列表接口添加二级缓存(Caffeine + Redis)
实测优化前后对比:
| 场景 | QPS | 平均响应时间 | 错误率 |
|---|---|---|---|
| 优化前 | 120 | 850ms | 15% |
| 优化后 | 300 | 230ms | 0.2% |
4. 药品库存管理特殊处理
4.1 批次管理与效期预警
宠物药品对批次管理要求严格,我们设计了双维度库存表:
sql复制CREATE TABLE `drug_inventory` (
`id` bigint NOT NULL AUTO_INCREMENT,
`drug_id` bigint NOT NULL,
`batch_number` varchar(50) NOT NULL COMMENT '批次号',
`production_date` date NOT NULL,
`expiry_date` date NOT NULL,
`quantity` int NOT NULL COMMENT '当前库存量',
`location` varchar(20) DEFAULT NULL COMMENT '货架位置',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_drug_batch` (`drug_id`,`batch_number`),
KEY `idx_expiry` (`expiry_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
效期预警Job每天凌晨3点执行:
java复制@Scheduled(cron = "0 0 3 * * ?")
public void checkDrugExpiration() {
LocalDate warnDate = LocalDate.now().plusMonths(1);
List<DrugInventory> expiringSoon = drugInventoryMapper
.selectList(new LambdaQueryWrapper<DrugInventory>()
.le(DrugInventory::getExpiryDate, warnDate)
.gt(DrugInventory::getQuantity, 0));
expiringSoon.forEach(item -> {
String message = String.format("药品【%s】批次%s将在%s过期,当前库存%d",
item.getDrugName(), item.getBatchNumber(),
item.getExpiryDate(), item.getQuantity());
sendWarningNotice(message);
});
}
4.2 药品-病症关联推荐
基于历史处方数据,我们构建了药品推荐引擎:
- 使用HanLP分词处理症状描述
- 通过TF-IDF算法提取关键词
- 关联历史处方中的药品使用记录
核心算法片段:
java复制public List<DrugRecommendation> recommendDrugs(String symptom) {
// 1. 症状关键词提取
List<String> keywords = hanlpService.extractKeywords(symptom);
// 2. 查询关联药品
return drugMapper.selectRecommendations(keywords).stream()
.sorted(Comparator.comparingDouble(DrugRecommendation::getScore).reversed())
.limit(5)
.collect(Collectors.toList());
}
5. 部署与运维实战经验
5.1 诊所本地化部署方案
由于宠物诊所通常没有专业IT人员,我们提供两种部署方式:
- 一键Docker部署(推荐):
bash复制# 诊所服务器只需执行
curl -sSL https://example.com/install-petclinic.sh | bash
- 传统部署:
- JDK17环境
- MySQL 8.0+配置
- 最少2核4G服务器配置
5.2 常见问题排查
问题1:SpringBoot应用启动时报数据库连接失败
- 检查点:
- 确认application.yml中的
spring.datasource.url包含时区参数:?serverTimezone=Asia/Shanghai - 测试网络连通性:
telnet 数据库IP 3306 - 检查MySQL用户权限:
GRANT ALL ON petclinic.* TO 'username'@'%'
- 确认application.yml中的
问题2:打印处方时中文乱码
解决方案:
yaml复制# 在application.yml中添加
spring:
thymeleaf:
encoding: UTF-8
servlet:
content-type: text/html;charset=UTF-8
问题3:高峰期系统变慢
优化步骤:
- 检查慢查询日志
- 添加索引(特别是pet_id、doctor_id等关联字段)
- 配置连接池参数:
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20
connection-timeout: 30000
这个系统经过6个月的迭代开发,目前已在8家诊所稳定运行。最大的收获是认识到兽医行业的特殊性——比如宠物不能自述症状,所以病历模块要设计更详细的观察项;再比如不同品种的生理指标差异很大,需要建立完善的品种数据库。未来计划增加AI辅助诊断模块,正在试验用CNN分析宠物X光片。
