1. 项目背景与核心价值
流浪动物救助一直是个社会痛点问题。我在参与本地动物保护组织志愿活动时,发现他们还在用Excel表格手工记录救助信息,经常出现信息丢失、重复登记的情况。领养匹配更是全靠工作人员记忆,效率极低。这促使我开发了这套基于SpringBoot+Vue3的救助平台系统。
这个系统的核心价值在于:
- 标准化救助流程:从发现动物到最终领养的全生命周期管理
- 资源整合平台:连接救助站、志愿者和潜在领养人
- 数据可视化:实时统计各区域流浪动物数量、救助成功率等关键指标
2. 技术架构设计
2.1 为什么选择SpringBoot+Vue3
后端选型考虑:
- SpringBoot的自动配置特性特别适合快速迭代的公益项目
- 内置Tomcat简化部署,志愿者组织通常没有专业运维
- Actuator监控确保系统稳定运行
前端选型理由:
- Vue3的Composition API使复杂表单逻辑更易维护
- Pinia状态管理完美适配多角色权限体系
- Vite构建速度对志愿者使用的低配电脑更友好
2.2 数据库设计要点
MySQL表设计遵循几个原则:
- 所有表必须包含create_time/update_time
- 状态字段统一使用TINYINT类型
- 关联查询频繁的字段建立组合索引
sql复制-- 典型表示例
CREATE TABLE `animal_info` (
`animal_id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`animal_type` VARCHAR(20) NOT NULL COMMENT '猫/狗/其他',
`health_status` TINYINT DEFAULT 0 COMMENT '0-健康 1-需治疗',
`rescue_location` POINT NOT NULL COMMENT 'GIS位置',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
KEY `idx_type_status` (`animal_type`,`health_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 核心功能实现
3.1 救助工单系统
救助申请处理流程:
- 公众提交表单(包含动物照片、位置等)
- 系统自动生成工单编号
- 分配最近的志愿者现场核实
- 状态变更触发微信通知
关键技术点:
- 使用Hutool生成带校验位的工单号
- 腾讯地图API解析位置信息
- 使用MinIO存储动物图片
java复制// 工单分配逻辑示例
public void assignVolunteer(RescueTask task) {
// 1. 查询5公里内的活跃志愿者
List<Volunteer> candidates = volunteerMapper.selectNearby(
task.getLatitude(),
task.getLongitude(),
5,
VolunteerStatus.ACTIVE
);
// 2. 按任务量均衡分配
candidates.sort(Comparator.comparingInt(v -> v.getTaskCount()));
// 3. 更新任务状态
task.setVolunteerId(candidates.get(0).getId());
task.setStatus(TaskStatus.ASSIGNED);
taskMapper.updateById(task);
// 4. 发送微信通知
wxPushService.sendTemplateMsg(
candidates.get(0).getOpenId(),
"新救助任务通知",
Map.of("location", task.getAddress())
);
}
3.2 智能领养匹配
匹配算法考虑因素:
- 领养人居住环境(是否有院子)
- 养宠经验
- 动物性格测试结果
- 地理位置就近原则
实现方案:
- 使用Elasticsearch存储动物特征
- 基于BM25算法实现相似度匹配
- 人工审核后完成匹配
4. 典型问题解决方案
4.1 并发领养冲突
当多个用户同时申请同一只动物时:
- 使用Redis分布式锁
- 数据库乐观锁(version字段)
- 加入等待队列机制
java复制// 领养申请代码示例
@Transactional
public Result applyAdoption(Long userId, Long animalId) {
// 获取Redis锁
String lockKey = "adopt_lock:" + animalId;
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
if (!locked) {
return Result.fail("当前申请人数过多,请稍后再试");
}
try {
// 查询动物当前状态
Animal animal = animalMapper.selectById(animalId);
if (animal.getStatus() != AnimalStatus.WAITING) {
return Result.fail("该动物已被领养");
}
// 更新状态
animal.setStatus(AnimalStatus.RESERVED);
animalMapper.updateById(animal);
// 创建领养记录
AdoptionRecord record = new AdoptionRecord();
record.setUserId(userId);
record.setAnimalId(animalId);
record.setStatus(AdoptionStatus.PENDING);
adoptionMapper.insert(record);
return Result.success();
} finally {
redisTemplate.delete(lockKey);
}
}
4.2 志愿者调度优化
遇到的坑:
- 初期简单按距离分配,导致部分志愿者任务过载
- 未考虑志愿者可用时间段
改进方案:
- 建立志愿者能力模型(可处理动物类型、空闲时段等)
- 引入负载均衡算法
- 增加任务拒接/转派功能
5. 部署实践建议
5.1 服务器配置
最低配置要求:
- 2核4G云服务器(公益组织可申请企业优惠)
- 推荐使用Docker Compose部署:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql-data:/var/lib/mysql
backend:
image: rescue-backend:latest
depends_on:
- mysql
ports:
- "8080:8080"
frontend:
image: rescue-frontend:latest
ports:
- "80:80"
5.2 性能优化经验
- 动物列表页添加Redis缓存
- 使用HikariCP连接池配置:
properties复制spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.idle-timeout=30000
- 前端开启gzip压缩
6. 扩展方向
- 微信小程序接入:方便公众随时上报流浪动物
- 疫苗提醒功能:对接宠物医院系统
- 捐赠物资管理模块
- 动物行为分析(使用TensorFlow识别攻击倾向)
这个项目在本地救助站运行半年后,救助效率提升了60%,领养率提高了45%。最大的收获是技术真的可以改变公益事业的运作方式。如果你也在开发类似系统,建议重点考虑移动端适配和离线操作支持,很多救助场景发生在网络信号不好的郊区。