1. 项目背景与核心需求
2020年以来的全球公共卫生事件让校园防疫物资管理面临前所未有的挑战。某高校后勤处王主任告诉我:"以前我们每学期采购2000个口罩就够用,现在每周就要处理5000+的物资流转,手工台账根本跟不上节奏。"这正是我们开发这套系统的现实背景。
防疫物资管理平台需要解决三个核心痛点:
- 动态库存难掌控:口罩、消毒液等消耗品进出频繁,人工记录易出错
- 调配效率低下:传统纸质审批流程平均需要3天时间
- 数据追溯困难:无法快速统计各院系物资领用情况
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型与架构设计
2.1 为什么选择SpringBoot+Vue
在技术选型阶段,我们对比了三种主流方案:
| 方案 | 开发效率 | 性能 | 学习成本 | 社区支持 |
|---|---|---|---|---|
| PHP+Laravel | 高 | 一般 | 低 | 一般 |
| Node.js+Express | 中 | 较好 | 中 | 较好 |
| SpringBoot+Vue | 高 | 优 | 中 | 极好 |
最终选择SpringBoot+Vue组合基于以下考量:
- Java生态成熟:MyBatis+MySQL组合在高校信息化系统中应用广泛
- 前后端分离优势:Vue的响应式特性特别适合动态表单场景
- 部署便捷性:SpringBoot内嵌Tomcat简化运维
2.2 系统架构详解
系统采用经典三层架构:
code复制[前端层]
└── Vue 3 + Element Plus + Axios
[服务层]
└── SpringBoot 2.7 + MyBatis-Plus
[数据层]
└── MySQL 8.0 + Redis缓存
关键设计决策:
- JWT鉴权:采用无状态token机制,解决频繁登录问题
- 分布式锁:使用Redisson防止物资超发
- Excel导出:基于Apache POI实现动态报表
3. 核心功能实现细节
3.1 物资库存管理模块
库存管理面临的最大挑战是并发修改问题。我们通过组合锁机制解决:
java复制@Transactional
public boolean deductStock(Long itemId, int num) {
// 1. 获取分布式锁
RLock lock = redissonClient.getLock("stock_" + itemId);
try {
lock.lock(5, TimeUnit.SECONDS);
// 2. 校验库存
Item item = itemMapper.selectById(itemId);
if(item.getStock() < num) {
throw new BusinessException("库存不足");
}
// 3. 扣减库存
itemMapper.updateStock(itemId, num);
// 4. 记录流水
StockLog log = new StockLog(itemId, num, "领用");
stockLogMapper.insert(log);
return true;
} finally {
lock.unlock();
}
}
实际踩坑:初期使用MySQL乐观锁导致大量重试,改为Redisson分布式锁后性能提升300%
3.2 智能预警系统
通过Spring Schedule实现三级预警机制:
- 库存预警(阈值触发)
java复制@Scheduled(cron = "0 0 9 * * ?")
public void checkStock() {
List<Item> items = itemMapper.selectLowStockItems();
items.forEach(item -> {
String msg = String.format("%s库存仅剩%d件", item.getName(), item.getStock());
wechatService.sendAlert(item.getManagerId(), msg);
});
}
- 临期预警(提前30天提醒)
- 异常消耗预警(同比波动超过50%触发)
3.3 可视化大屏
利用Vue+ECharts实现动态数据展示:
vue复制<template>
<div class="dashboard">
<el-row>
<el-col :span="12">
<echart :option="stockOption" />
</el-col>
<el-col :span="12">
<echart :option="consumptionOption" />
</el-col>
</el-row>
</div>
</template>
<script>
export default {
data() {
return {
stockOption: {
tooltip: {...},
series: [{
type: 'pie',
data: [
{value: 1048, name: '口罩'},
{value: 735, name: '消毒液'}
]
}]
}
}
}
}
</script>
4. 关键问题解决方案
4.1 高并发下的库存准确性问题
我们通过组合方案解决:
- Redis预减库存:秒杀场景先扣减Redis缓存
- MQ异步落库:使用RocketMQ实现最终一致性
- 定期对账机制:每天凌晨核对Redis与MySQL数据
4.2 复杂审批流程实现
采用状态机模式设计审批流:
java复制public class ApprovalMachine {
private static Map<ApprovalState, List<ApprovalState>> transitions = Map.of(
SUBMITTED, Arrays.asList(REJECTED, DEPARTMENT_APPROVED),
DEPARTMENT_APPROVED, Arrays.asList(REJECTED, FINANCE_APPROVED)
);
public static boolean canTransition(ApprovalState from, ApprovalState to) {
return transitions.getOrDefault(from, List.of()).contains(to);
}
}
4.3 数据权限控制
通过MyBatis插件实现动态SQL改写:
java复制@Intercepts(@Signature(type= Executor.class, method="query",
args={MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
public class DataAuthInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 获取当前用户部门ID
String deptId = SecurityUtils.getCurrentUserDeptId();
// 修改SQL添加部门过滤条件
BoundSql boundSql = ((MappedStatement)invocation.getArgs()[0]).getBoundSql();
String newSql = boundSql.getSql() + " AND dept_id = '" + deptId + "'";
resetSql(invocation, newSql);
return invocation.proceed();
}
}
5. 部署与性能优化
5.1 容器化部署方案
使用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql-data:/var/lib/mysql
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
frontend:
build: ./frontend
ports:
- "80:80"
5.2 性能调优实战
通过Arthas诊断发现的问题及解决方案:
- N+1查询问题:
bash复制[arthas@12345]$ watch com.example.mapper.ItemMapper selectById params returnObj -x 3
优化方案:启用MyBatis二级缓存
- 大文件上传超时:
调整Tomcat配置:
properties复制server.tomcat.max-swallow-size=500MB
spring.servlet.multipart.max-file-size=500MB
- 前端打包优化:
js复制// vue.config.js
module.exports = {
chainWebpack: config => {
config.optimization.splitChunks({
chunks: 'all',
maxSize: 244 * 1024 // 拆分包大小
})
}
}
6. 项目演进方向
在实际运行半年后,我们规划了三个升级方向:
- 物联网集成:通过RFID技术实现物资自动盘点
- 智能预测:基于历史数据预测未来消耗趋势
- 移动端适配:开发微信小程序版本
这个项目让我深刻体会到:好的管理系统不是功能的堆砌,而是要对业务痛点有精准把握。比如我们最初设计了复杂的审批层级,后来发现学校更关注的是"实时可见"和"一键导出"这样的基础需求
