作为一名经历过多次企业物资管理混乱局面的开发者,我深知中小企业在物资管理上的痛点。传统Excel表格+微信报单的模式,往往导致库存数据滞后、责任划分不清、重复采购等问题频发。这次分享的SSM+Vue物资管理系统,正是为了解决这些实际问题而设计的轻量级解决方案。
系统采用前后端分离架构,后端基于Spring+SpringMVC+MyBatis框架组合,前端使用Vue.js实现响应式界面。特别针对10-200人规模的中小企业设计,覆盖从采购申请到最终归还的完整物资生命周期管理。与市面上常见的ERP系统相比,我们的方案更注重:
系统采用经典的三层架构:
code复制表现层(Vue.js前端) → 业务逻辑层(Spring) → 数据访问层(MyBatis)
前后端通过RESTful API交互,数据格式统一为JSON。这种设计使得后期扩展小程序端或APP端时,可以复用90%的后端接口。
提示:选择Tomcat7而非更高版本,是考虑到企业实际环境中旧版本服务器仍广泛使用,确保系统有更好的兼容性。
采用RBAC(基于角色的访问控制)模型,实现四级权限划分:
权限控制通过Spring Security实现,前端菜单根据权限动态渲染。特别注意处理了"部门数据隔离"问题,确保财务部只能看到本部门物资记录。
创新性地采用"树形结构+属性模板"双重分类:
java复制// 分类实体类示例
public class MaterialCategory {
private Long id;
private String name;
private Long parentId; // 树形结构
private String attributes; // JSON格式的属性模板
// 电子类示例属性模板
// {"voltage":"电压","wattage":"功率"}
}
前端使用Vue的递归组件渲染树形选择器,属性表单则根据模板动态生成。
采购流程状态机设计(使用Camunda引擎):
code复制申请 → 部门审批 → 财务复核 → 生成PO → 供应商确认 → 物流跟踪 → 到货质检
关键实现技巧:
java复制// 审批策略接口
public interface ApprovalStrategy {
String getApprover(double amount);
}
实测发现当并发入库超过200QPS时,MySQL出现明显性能下降。最终采用双缓冲方案:
java复制@Transactional
public void batchImport(List<Material> materials) {
// 获取分布式锁
String lockKey = "import_lock_" + warehouseId;
try {
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
if (!locked) throw new RuntimeException("操作太频繁");
// 分批处理
Lists.partition(materials, 50).forEach(batch -> {
materialMapper.insertBatch(batch); // 自定义批量方法
updateStock(batch); // 更新库存
});
} finally {
redisTemplate.delete(lockKey);
}
}
物资状态变更是个典型的前后端一致性问题。我们的解决方案:
前端状态管理使用Vuex,结构设计如下:
javascript复制const store = new Vuex.Store({
state: {
materials: {
// 使用对象存储便于快速查找
byId: {
'm001': {id:'m001', status:'IN_STOCK', ...}
},
// 状态变更记录
statusLogs: []
}
},
mutations: {
updateStatus(state, {id, newStatus}) {
// 记录旧状态
const oldStatus = state.materials.byId[id].status;
state.materials.statusLogs.push({
id, oldStatus, newStatus, time: new Date()
});
// 更新当前状态
state.materials.byId[id].status = newStatus;
}
}
})
推荐服务器配置:
关键JVM参数:
code复制-Xms2048m -Xmx4096m -XX:+UseG1GC
-XX:MaxGCPauseMillis=200
通过JMeter压测发现的三个性能瓶颈及解决方案:
物资查询接口响应慢(>2s)
xml复制<!-- 使用关联查询替代多次查询 -->
<select id="selectWithCategory" resultMap="materialResult">
SELECT m.*, c.name as category_name
FROM material m LEFT JOIN category c ON m.category_id=c.id
WHERE m.id=#{id}
</select>
添加二级缓存:java复制@Cacheable(value = "material", key = "#id")
public Material getById(Long id) { ... }
导出Excel内存溢出
java复制SXSSFWorkbook workbook = new SXSSFWorkbook(100); // 保留100行在内存
// ... 写入数据
workbook.dispose(); // 清理临时文件
首页加载资源过多
跨部门数据权限问题
初期设计时忽略了跨部门数据可见性需求,导致财务部需要查看全公司物资数据时无法实现。最终解决方案:
java复制@Intercepts(@Signature(type= Executor.class, method="query",
args={MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
public class DataPermissionInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 自动添加部门ID条件
if (needDataFilter()) {
BoundSql boundSql = ms.getBoundSql(parameterObject);
String newSql = boundSql.getSql() + " AND dept_id IN ("+getDeptIds()+")";
resetSql(invocation, newSql);
}
return invocation.proceed();
}
}
Excel导入功能兼容性问题
企业提供的Excel文件格式五花八门,导致导入失败率高。最终实现方案:
二维码生成优化
java复制Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
hints.put(EncodeHintType.MARGIN, 1); // 边距
BitMatrix matrix = new QRCodeWriter().encode(
content, BarcodeFormat.QR_CODE, width, height, hints);
库存预警实现技巧
java复制// 记录操作
redisTemplate.opsForHyperLogLog().add("material_op:"+materialId, userId);
// 获取操作次数
Long count = redisTemplate.opsForHyperLogLog().size("material_op:"+materialId);
老系统迁移策略
这套系统在实际部署后,客户反馈库存准确率从原来的82%提升到99.6%,月度盘点时间从8小时缩短到2小时。特别是在防疫物资管理场景下,二维码扫码功能大大减少了接触感染风险。