1. 项目背景与核心价值
疫情物资捐赠与分配系统是近年来在公共卫生事件中发挥重要作用的信息化平台。这个基于SpringBoot+Vue的前后端分离项目,完整实现了从物资捐赠、库存管理到智能分配的全流程数字化解决方案。作为Java Web方向的毕业设计选题,它既贴合实际应用场景,又涵盖了主流技术栈的综合运用。
我在实际开发中发现,这类系统最核心的挑战在于解决三个矛盾:捐赠方快速登记与物资严格审核的矛盾、库存实时变动与分配公平性的矛盾、多角色协同与数据一致性的矛盾。本项目通过以下技术方案有效应对:
- 采用SpringBoot的异步处理机制实现高并发捐赠登记
- 基于Redis的分布式锁保证库存操作的原子性
- 使用加权算法实现按需智能分配
- 通过WebSocket实现各终端数据实时同步
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构解析
2.1 后端技术栈设计
SpringBoot 2.7.x作为核心框架,其技术选型考虑如下:
- 数据持久层:MyBatis-Plus + 多数据源配置
- 主库:MySQL 8.0(事务型操作)
- 从库:MongoDB(物资图片等非结构化数据)
- 缓存方案:Redis 6.x
- String类型:存储实时库存量
- Hash类型:记录物资流转日志
- ZSet类型:实现分配优先级队列
- 安全控制:
- JWT + Spring Security OAuth2
- 细粒度权限控制到API级别
- 接口文档:Knife4j增强版Swagger
- 自动生成带示例的接口文档
- 支持离线文档导出
2.2 前端技术方案
Vue 3.x + Element Plus的组合方案优势明显:
- 状态管理:Pinia替代Vuex
- 路由方案:动态路由表+权限过滤
- 特色功能实现:
- 物资地图展示:集成腾讯地图JS SDK
- 数据看板:ECharts 5.x
- 文件上传:分片上传+MD5校验
- 性能优化:
- 路由懒加载
- 组件按需引入
- Gzip压缩
3. 核心业务实现
3.1 捐赠流程实现
捐赠模块采用分布式事务保证数据一致性:
java复制// 伪代码示例
@Transactional
public DonationResult submitDonation(DonationDTO dto) {
// 1. 保存捐赠记录
donationMapper.insert(dto);
// 2. 更新物资库存(Redis原子操作)
String lockKey = "stock_lock_" + dto.getMaterialId();
try {
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
if (!locked) throw new RuntimeException("操作频繁");
// 库存操作
Integer current = redisTemplate.opsForValue()
.decrement("stock_" + dto.getMaterialId(), dto.getCount());
if (current < 0) {
redisTemplate.opsForValue()
.increment("stock_" + dto.getMaterialId(), dto.getCount());
throw new RuntimeException("库存不足");
}
} finally {
redisTemplate.delete(lockKey);
}
// 3. 记录操作日志
logService.asyncSaveLog(dto);
return new DonationResult(true);
}
3.2 智能分配算法
物资分配采用动态权重算法:
-
基础权重因子:
- 申请机构等级(三甲医院=5,社区医院=3)
- 疫情严重程度(高风险区=1.5倍权重)
- 历史分配记录(近期已分配量反向加权)
-
计算公式:
code复制W = (机构等级 × 疫情系数) / (历史分配量 × 衰减因子) -
实现代码片段:
java复制public List<DistributionPlan> calculatePlan(List<Applicant> applicants) {
return applicants.stream()
.map(app -> {
double weight = (app.getLevel() * app.getEpidemicFactor())
/ (app.getHistoryAmount() * 0.8);
return new DistributionPlan(app, weight);
})
.sorted(Comparator.comparing(DistributionPlan::getWeight).reversed())
.limit(maxDistribution)
.collect(Collectors.toList());
}
4. 系统部署方案
4.1 开发环境配置
推荐使用Docker Compose搭建本地环境:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
ports:
- "3306:3306"
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/init:/docker-entrypoint-initdb.d
redis:
image: redis:6-alpine
ports:
- "6379:6379"
command: redis-server --appendonly yes
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
frontend:
build: ./frontend
ports:
- "80:80"
4.2 生产环境建议
-
后端集群部署:
- 使用Nginx做负载均衡
- 配置Keepalived实现高可用
- 建议最少2个实例互为备份
-
数据库方案:
- MySQL主从复制+读写分离
- Redis哨兵模式
- 每日全量备份+binlog增量备份
-
监控方案:
- Prometheus + Grafana监控体系
- ELK日志分析系统
- 关键业务指标埋点
5. 常见问题解决方案
5.1 接口文档无法显示响应参数
问题现象:Knife4j无法显示复杂泛型返回值
解决方案:
- 在返回对象上添加@ApiModel注解
- 泛型类需要明确类型:
java复制@GetMapping("/list")
@ApiOperation("物资列表")
public Result<List<MaterialVO>> getMaterialList() {
//...
}
5.2 Vue地图组件内存泄漏
问题现象:频繁切换含腾讯地图的页面导致内存增长
优化方案:
javascript复制onBeforeUnmount(() => {
if (this.map) {
this.map.destroy()
this.map = null
}
})
5.3 库存超卖问题
典型场景:高并发下库存出现负数
终极解决方案:
sql复制UPDATE material_stock
SET count = count - #{reduce}
WHERE id = #{id} AND count >= #{reduce}
6. 项目扩展方向
- 区块链存证:将物资流转记录上链
- 智能预测:基于历史数据预测需求
- 移动端适配:开发微信小程序版本
- 物联网集成:通过RFID自动登记物资
- 大数据分析:使用Spark处理捐赠画像
关键提示:毕业设计答辩时应重点展示技术难点解决方案,建议准备以下材料:
- 数据库ER图(PowerDesigner格式)
- 接口测试用例(Postman集合)
- 压力测试报告(JMeter测试结果)
- 算法流程图(Visio绘制)
在实际开发过程中,我发现物资分类的树形结构处理是个易错点。推荐使用MP的@TableField(typeHandler = JacksonTypeHandler.class)处理JSON树结构,比递归查询效率提升5倍以上。另外,前端表格渲染大量数据时,采用虚拟滚动技术可显著提升性能,Element Plus的
