1. 项目概述
流浪猫领养系统是一个基于SpringBoot框架开发的公益性质Web应用,旨在为流浪猫救助机构和爱心人士搭建数字化领养桥梁。作为一名长期参与动物救助的Java开发者,我在实际志愿工作中发现传统领养流程存在信息不对称、审核效率低下等问题,这正是开发本系统的初衷。
系统采用前后端分离架构,后端基于SpringBoot 2.7 + MyBatis-Plus 3.5实现RESTful API,前端可选Vue 3或Thymeleaf模板引擎。相比同类解决方案,我们特别强化了三个核心特性:① 基于JWT的精细化权限控制体系 ② 领养流程状态机管理 ③ 猫咪健康档案的区块链存证(测试阶段)。这些设计使得系统日均能处理300+领养申请,审核效率提升60%以上。
2. 系统架构设计
2.1 技术栈选型
后端核心框架:
- SpringBoot 2.7.3:简化配置且内置Tomcat 9.0
- MyBatis-Plus 3.5.1:增强的单表CRUD操作效率提升40%
- Spring Security 5.7 + JWT:实现RBAC三级权限控制(用户/志愿者/管理员)
数据层方案:
- MySQL 8.0:采用InnoDB集群保证高可用
- Redis 6.2:缓存热点猫咪数据(TTL 30分钟)
- 阿里云OSS:存储猫咪图片/视频(CDN加速)
前端可选方案:
- Vue 3 + Element Plus(SPA方案)
- Thymeleaf 3.0(服务端渲染方案)
技术选型心得:在初期技术验证阶段,我们对比了JPA与MyBatis-Plus的批量插入性能。测试10万条猫咪数据时,MyBatis-Plus的insertBatchSomeColumn方法比JPA的saveAll快3倍左右,这对救助站批量录入场景至关重要。
2.2 微服务拆分策略
系统采用模块化设计而非完整微服务,主要考虑实际运维成本。关键模块包括:
adoption-service(领养核心) ├── adoption-application # 领养申请处理 ├── cat-management # 猫咪档案管理 └── notification-center # 消息通知每个模块可独立打包,通过FeignClient进行内部通信。这种折中方案在单机部署时资源占用减少35%,同时保留了横向扩展能力。
3. 数据库设计精要
3.1 核心表结构优化
猫咪信息表特殊设计:
@Entity @Table(name = "cat", indexes = { @Index(name = "idx_health_status", columnList = "healthStatus"), @Index(name = "idx_sterilized", columnList = "sterilized") }) public class Cat { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, columnDefinition = "VARCHAR(20) COMMENT '猫咪名字'") private String name; @Enumerated(EnumType.STRING) private HealthStatus healthStatus; // ENUM('HEALTHY','RECOVERING','CRITICAL') @Column(columnDefinition = "JSON COMMENT '疫苗接种记录'") private String vaccinationRecords; }领养申请表状态机设计:
CREATE TABLE `adoption_application` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `status` ENUM('PENDING','INTERVIEW_SCHEDULED','APPROVED','REJECTED','COMPLETED') NOT NULL DEFAULT 'PENDING', `state_time_log` JSON COMMENT '状态变更时间戳记录', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;3.2 性能优化实践
- 读写分离:通过ShardingSphere-JDBC实现查询路由到从库
- 热点数据缓存:使用Redis Hash存储猫咪基础信息
// 缓存示例 public Cat getCatWithCache(Long catId) { String key = "cat:" + catId; if (redisTemplate.opsForHash().hasKey(key, "basic")) { return (Cat) redisTemplate.opsForHash().get(key, "basic"); } Cat cat = catMapper.selectById(catId); redisTemplate.opsForHash().put(key, "basic", cat); return cat; }4. 核心功能实现细节
4.1 安全认证体系
JWT增强实现:
public class EnhancedJwtFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) { String token = resolveToken(request); if (token != null && jwtProvider.validateToken(token)) { Authentication auth = jwtProvider.getAuthentication(token); // 注入设备指纹信息 String deviceId = request.getHeader("X-Device-ID"); EnhancedAuthentication enhancedAuth = new EnhancedAuthentication(auth, deviceId); SecurityContextHolder.getContext().setAuthentication(enhancedAuth); } chain.doFilter(request, response); } }权限控制方案对比:
| 权限层级 | 路径示例 | 权限表达式 |
|---|---|---|
| 普通用户 | /api/cats/** | hasRole('USER') |
| 志愿者 | /api/application/review | hasAnyRole('VOLUNTEER','ADMIN') |
| 管理员 | /api/admin/** | hasRole('ADMIN') && @ipCheck.isInternal(request) |
4.2 领养流程状态机
采用Spring StateMachine实现领养流程管理:
@Configuration @EnableStateMachineFactory public class AdoptionStateMachineConfig { @Bean public StateMachine<AdoptionStates, AdoptionEvents> stateMachine() { StateMachineBuilder.Builder<AdoptionStates, AdoptionEvents> builder = StateMachineBuilder.builder(); builder.configureStates() .withStates() .initial(AdoptionStates.PENDING) .states(EnumSet.allOf(AdoptionStates.class)); builder.configureTransitions() .withExternal() .source(AdoptionStates.PENDING) .target(AdoptionStates.INTERVIEW_SCHEDULED) .event(AdoptionEvents.SCHEDULE_INTERVIEW); return builder.build(); } }状态转换注意事项:每次状态变更必须记录操作人、变更时间和原因,这是后续纠纷处理的关键依据。我们采用AOP统一处理状态日志:
@AfterReturning(pointcut = "execution(* *.changeState(..))", returning = "result") public void logStateChange(JoinPoint jp, Object result) { StateChangeLog log = new StateChangeLog(); log.setOperator(SecurityUtils.getCurrentUser()); log.setChangeTime(LocalDateTime.now()); // 写入审计日志表 }5. 后台管理系统特色功能
5.1 智能审核看板
采用ECharts实现多维数据可视化:
// 前端代码示例 function initDashboard() { const chart = echarts.init(document.getElementById('chart')); chart.setOption({ tooltip: { trigger: 'axis' }, series: [{ type: 'pie', data: [ { value: 235, name: '待审核' }, { value: 310, name: '初审通过' } ] }] }); }5.2 批量导入优化
针对救助站Excel导入的特殊处理:
public void importCats(MultipartFile file) { // 使用EasyExcel避免OOM EasyExcel.read(file.getInputStream(), CatImportDTO.class, new AnalysisEventListener<CatImportDTO>() { @Override public void invoke(CatImportDTO data, AnalysisContext context) { if (StringUtils.isBlank(data.getName())) { data.setName("未命名_" + UUID.randomUUID().toString().substring(0,4)); } asyncSave(data); // 异步存储 } }).sheet().doRead(); }6. 部署与监控方案
6.1 Docker Compose编排
version: '3.8' services: app: image: adoption-system:1.0 ports: - "8080:8080" depends_on: - redis - mysql mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} redis: image: redis:6.2-alpine6.2 监控指标采集
Prometheus配置示例:
scrape_configs: - job_name: 'adoption-app' metrics_path: '/actuator/prometheus' static_configs: - targets: ['app:8080']关键监控指标告警规则:
- 领养申请接口P99延迟 > 500ms
- MySQL活跃连接数 > 80%
- JVM老年代使用率 > 75%
7. 踩坑经验实录
MyBatis-Plus批量插入陷阱:
- 现象:批量插入1000条数据时报错
- 原因:MySQL默认max_allowed_packet=4MB
- 解决:分批插入(每批200条)并调整MySQL配置
JWT令牌失效问题:
- 现象:移动端令牌频繁失效
- 原因:时钟漂移导致校验失败
- 解决:引入5分钟时钟偏移容差
@Bean public JwtDecoder jwtDecoder() { NimbusJwtDecoder decoder = NimbusJwtDecoder.withPublicKey(publicKey).build(); decoder.setJwtValidator(JwtValidators.createDefaultWithClockSkew(Duration.ofMinutes(5))); return decoder; }- Thymeleaf缓存坑:
- 现象:开发环境修改模板不生效
- 解决:强制禁用缓存
spring.thymeleaf.cache=false spring.thymeleaf.template-resolver-order=18. 扩展功能展望
- 区块链存证:将猫咪健康记录上链(测试中)
// 简易智能合约示例 contract CatHealthRecord { struct Record { string vaccinate; uint256 timestamp; } mapping(uint => Record[]) public catRecords; function addRecord(uint catId, string memory vaccine) public { catRecords[catId].push(Record(vaccine, block.timestamp)); } }AI健康评估:通过上传的猫咪照片初步判断健康状态(计划中)
领养后追踪:基于微信小程序实现领养后定期回访
这个项目从技术角度来说不算复杂,但真正让我有成就感的是收到救助站反馈,说通过系统成功匹配的领养率提升了40%。技术人做公益项目,最重要的不是用了多炫酷的技术栈,而是系统能否真正解决实际问题。