1. 项目概述
作为一名长期从事Java全栈开发的工程师,最近完成了一个基于Spring Boot的流浪猫管理系统。这个项目源于我在社区做志愿者时的亲身经历——看到救助站还在用Excel表格管理上百只流浪猫的信息,经常出现重复记录、信息丢失的情况。于是决定用技术手段解决这个问题。
系统采用前后端分离架构,后端基于Spring Boot 3.0 + MyBatis-Plus,前端使用Vue 3 + Ant Design Vue,数据库选用MySQL 8.0。核心功能包括流浪猫信息管理、救助记录追踪、领养申请处理和科普教育四大模块。特别在数据安全方面做了重点设计,通过RBAC权限模型和AES加密保障敏感信息,所有救助关键节点都上链存证。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 后端技术选型
选择Spring Boot 3.0作为基础框架主要考虑三点:
- 自动配置机制能快速集成各类组件
- 内嵌Tomcat简化部署
- 丰富的starter依赖降低整合难度
数据库访问层采用MyBatis-Plus而非JPA,因为:
- 项目涉及复杂查询(如多表联查流浪猫健康记录)
- 需要精细控制SQL性能
- Lambda表达式让动态查询更直观
java复制// 示例:使用MyBatis-Plus实现动态查询
LambdaQueryWrapper<StrayCat> query = new LambdaQueryWrapper<>();
query.eq(StrayCat::getIsSterilized, true)
.between(StrayCat::getFoundDate, startDate, endDate)
.orderByDesc(StrayCat::getHealthLevel);
2.2 前端技术方案
Vue 3的组合式API更适合这个管理系统的开发:
- 逻辑关注点分离更清晰
- TypeScript支持完善
- 与Ant Design Vue的按需引入特性完美配合
地图模块选用高德地图API而非百度地图,因其:
- 流浪猫位置标注API更稳定
- 热力图渲染性能更好
- 移动端适配更完善
3. 核心功能实现
3.1 流浪猫信息管理
数据模型设计
sql复制CREATE TABLE stray_cats (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
breed VARCHAR(30) COMMENT '品种',
age INT COMMENT '月龄',
health_status ENUM('HEALTHY','SICK','CRITICAL') NOT NULL,
is_sterilized BOOLEAN DEFAULT false,
location POINT SRID 4326 COMMENT 'WGS84坐标',
found_date DATE,
cover_image VARCHAR(255)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 空间索引加速位置查询
ALTER TABLE stray_cats ADD SPATIAL INDEX(location);
关键实现细节
- 使用MySQL的GIS功能存储坐标点
- 采用七牛云OSS存储猫咪照片
- 实现Elasticsearch双写保证搜索性能
踩坑提醒:MySQL GIS函数在MyBatis中需要自定义TypeHandler处理,建议直接使用
org.mybatis:mybatis-typehandlers-jsr310扩展包
3.2 救助记录模块
设计亮点:
- 医疗发票OCR识别采用阿里云服务
- 区块链存证使用Hyperledger Fabric私有链
- 规则引擎使用Drools实现医疗方案校验
java复制// Drools规则示例
rule "Post-Sterilization Antibiotics"
when
$record: RescueRecord(procedure == "STERILIZATION",
medications not contains "Antibiotic")
then
throw new MedicalRuleException("绝育手术后必须使用抗生素");
end
4. 领养系统实现
4.1 智能匹配算法
采用改进的协同过滤算法:
- 领养人特征向量化(居住环境、养宠经验等)
- 猫咪特征向量化(性格、健康状态等)
- 使用余弦相似度计算匹配度
python复制# 算法原型示例(实际用Java实现)
def calculate_similarity(user_vec, cat_vec):
dot_product = np.dot(user_vec, cat_vec)
norm_user = np.linalg.norm(user_vec)
norm_cat = np.linalg.norm(cat_vec)
return dot_product / (norm_user * norm_cat)
4.2 电子合同签署
技术要点:
- 使用CFCA数字证书服务
- 合同模板采用Freemarker动态生成
- 签署日志上链存证
5. 性能优化实践
5.1 缓存策略
采用多级缓存架构:
- 本地Caffeine缓存热点猫咪信息
- Redis集群缓存查询结果
- MySQL查询优化
yaml复制# 缓存配置示例
spring:
cache:
type: redis
redis:
time-to-live: 30m
cache-null-values: false
redis:
host: redis-cluster.example.com
port: 6379
5.2 数据库优化
- 读写分离:使用ShardingSphere-JDBC
- 索引优化:为所有查询条件建立复合索引
- 连接池:HikariCP配置
java复制// HikariCP推荐配置
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://master.db.example.com:3306/cat_db");
config.setUsername("app_user");
config.setPassword("securePassword123");
config.setMaximumPoolSize(20);
config.setConnectionTimeout(30000);
return new HikariDataSource(config);
}
6. 安全防护措施
6.1 权限控制
RBAC模型设计:
- 角色:超级管理员、救助站管理员、领养审核员、普通用户
- 权限细粒度到按钮级别
- 操作日志审计
java复制@PreAuthorize("hasRole('RESCUE_ADMIN') || hasPermission(#catId, 'EDIT')")
public void updateCatInfo(Long catId, CatDTO dto) {
// 业务逻辑
}
6.2 数据加密
敏感字段加密方案:
- 领养人身份证号:AES-256加密
- 联系方式:数据库字段级加密
- 密码:BCrypt哈希存储
7. 部署方案
7.1 容器化部署
Docker Compose编排:
yaml复制version: '3.8'
services:
app:
image: cat-system:1.0.0
ports:
- "8080:8080"
depends_on:
- redis
- mysql
redis:
image: redis:7.0-alpine
ports:
- "6379:6379"
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: cat_db
7.2 监控方案
- Prometheus + Grafana监控JVM指标
- ELK收集业务日志
- SkyWalking做分布式追踪
8. 典型问题排查
8.1 并发领养冲突
解决方案:
- 使用数据库乐观锁
- 引入Redis分布式锁
- 前端防重复提交
java复制public AdoptionResult adoptCat(Long catId, Long userId) {
String lockKey = "adopt_lock:" + catId;
try {
// 获取分布式锁
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
if (!locked) {
throw new BusinessException("当前猫咪正在被其他用户申请");
}
// 业务处理
} finally {
redisTemplate.delete(lockKey);
}
}
8.2 地图漂移问题
处理经验:
- 统一使用GCJ-02坐标系
- 前端做坐标转换
- 后端存储WGS84原始坐标
9. 项目心得
在实际开发中,有几个特别值得分享的经验:
- 批量导入优化:初期使用MyBatis的逐条插入,导入1000条记录需要2分钟。改为批量插入后缩短到3秒:
java复制@Transactional
public void batchImport(List<Cat> cats) {
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
CatMapper mapper = session.getMapper(CatMapper.class);
cats.forEach(mapper::insert);
session.commit();
}
- 缓存穿透防护:对不存在的猫咪ID查询,使用布隆过滤器拦截:
java复制public Cat getById(Long id) {
if (!bloomFilter.mightContain(id)) {
return null;
}
return catMapper.selectById(id);
}
- 文档自动生成:集成Swagger时,建议用分组展示API:
java复制@Bean
public GroupedOpenApi publicApi() {
return GroupedOpenApi.builder()
.group("public-apis")
.pathsToMatch("/api/public/**")
.build();
}
