Java项目实战:从零构建企业级制造执行系统(MES)——含完整架构设计与源码解析
适用人群:Java 中高级开发者、工业软件工程师、智能制造领域从业者、希望深入理解制造业数字化转型的在校生或转行者
关键词:Java、Spring Boot 3、MyBatis-Plus、MES系统、生产工单、设备管理、OEE分析、JWT、Vue 3、工业物联网(IIoT)、项目实战
前言:为什么 MES 是智能制造的“神经中枢”?
在“中国制造2025”与“工业4.0”浪潮下,制造执行系统(Manufacturing Execution System, MES)已成为连接企业计划层(ERP)与控制层(PLC/SCADA)的关键桥梁。如果说 ERP 是企业的“大脑”,负责战略规划与资源调度;那么 MES 就是企业的“神经系统”,实时监控、调度、反馈并优化车间现场的每一台设备、每一道工序、每一个物料批次。
传统工厂依赖纸质工单、人工报工、Excel统计,导致:
- 生产进度不透明:管理层无法实时掌握订单完成率;
- 质量追溯困难:产品缺陷无法定位到具体设备、操作员或原材料批次;
- 设备效率低下:停机原因不明,OEE(设备综合效率)长期低于60%;
- 数据孤岛严重:ERP中的计划与车间实际执行脱节。
而一个现代化的 Java MES 系统,不仅能打通“计划—执行—反馈”闭环,更能通过实时数据采集、智能预警、可视化看板,驱动精益生产与持续改进。
本文将带你从业务建模 → 架构设计 → 核心模块开发 → 设备对接 → 数据分析,完整实现一个基于Spring Boot 3 + MyBatis-Plus + Vue 3的轻量级但功能完备的企业级 MES 系统,并提供可运行的开源代码。
一、项目全景:目标、价值与技术选型
1.1 MES 解决的核心问题
| 制造痛点 | MES 解决方案 |
|---|---|
| 订单进度靠问 | 实时工单状态看板(待排产 / 生产中 / 已完成) |
| 质量问题频发 | 全流程质量检验点 + 不合格品隔离 + 根本原因分析(RCA) |
| 设备频繁停机 | OEE自动计算 + 停机原因分类(故障/换模/缺料) |
| 物料混用错用 | 条码/RFID 扫描绑定物料批次与工单 |
| 报工效率低下 | 移动端扫码报工 + 自动计件工资 |
💡小贴士:MES 不是 ERP 的子集,而是其延伸。ERP管“做什么”,MES管“怎么做”和“做得怎样”。
1.2 技术栈深度解析
我们采用高内聚、低耦合、易扩展的技术组合,兼顾开发效率与生产稳定性:
| 类别 | 技术 | 版本 | 选型理由 |
|---|---|---|---|
| 后端框架 | Spring Boot | 3.2+ | 快速启动、Actuator健康监控、WebFlux响应式支持 |
| 持久层 | MyBatis-Plus | 3.5.15 | LambdaQueryWrapper 简化复杂查询、自动分页 |
| 数据库 | PostgreSQL | 15+ | JSONB 支持结构化存储工艺参数、GIS 扩展支持车间布局 |
| 消息中间件 | RabbitMQ | 3.12+ | 异步解耦设备数据上报、报警通知 |
| 安全框架 | Spring Security + JWT | - | 无状态认证、细粒度权限(按车间/产线授权) |
| 前端框架 | Vue 3 + TypeScript | 3.4+ | Composition API 提升逻辑复用性 |
| UI组件库 | Naive UI / Element Plus | - | 工业风主题、高性能表格支持万级数据渲染 |
| 部署运维 | Docker + Prometheus + Grafana | - | 容器化部署、指标监控、OEE可视化看板 |
⚠️注意:Spring Boot 3 要求 JDK 17+,且不再支持 javax.* 包,请使用 jakarta.* 替代。
二、核心业务模块设计
MES 系统聚焦于车间现场管理,我们设计以下六大核心模块:
2.1 基础数据管理(制造主数据)
- 产品BOM:成品与原材料的层级关系(支持多版本)
- 工艺路线:工序顺序、标准工时、所需设备、质检要求
- 工作中心:产线、班组、设备组
- 设备档案:设备编号、型号、所属产线、保养周期
🔐一致性原则:所有生产活动必须引用基础数据ID,禁止冗余存储名称!
2.2 生产工单管理
- 工单创建:来自ERP的生产计划或手动创建
- 工单排产:指定产线、开始/结束时间、优先级
- 工单下发:推送至车间终端或移动端
- 工单状态跟踪:待开始 → 生产中 → 暂停 → 完成/报废
2.3 设备管理与 OEE 分析
- 设备状态监控:运行 / 停机 / 故障 / 保养
- 停机原因登记:操作员选择预设原因(如“换模”、“缺料”)
- OEE 自动计算:
- 时间开动率= 运行时间 / 计划生产时间
- 性能开动率= 实际产量 / (运行时间 × 理论节拍)
- 合格品率= 合格数 / 总产量
- OEE = 时间开动率 × 性能开动率 × 合格品率
2.4 质量管理
- 首件检验:每班次/换型后首件确认
- 过程巡检:按工艺设定抽检频率
- 终检判定:整批合格/不合格
- 不合格品处理:返工 / 报废 / 降级,并记录原因
2.5 物料追踪(批次/序列号)
- 投料扫码:绑定原材料批次号到工单
- 在制品流转:工序间交接扫码
- 成品入库:生成唯一序列号,关联所有投入物料
- 正反向追溯:输入成品序列号 → 查所有原料;输入原料批次 → 查所有产出成品
2.6 系统管理(RBAC + 操作日志)
- 用户/角色/权限:如“车间主任”可看全车间,“操作员”仅看本工位
- 操作审计:记录关键操作(如修改工单数量、跳过质检)
- 数据权限:按“所属车间”自动过滤数据
三、数据库深度设计
3.1 核心 ER 图(简化)
3.2 关键表结构
工单主表work_order
CREATETABLEwork_order(id BIGSERIALPRIMARYKEY,order_noVARCHAR(50)UNIQUENOTNULL,-- 格式: WO20260223001product_idBIGINTNOTNULL,planned_qtyINTNOTNULL,-- 计划数量completed_qtyINTDEFAULT0,-- 已完成数量statusVARCHAR(20)DEFAULT'CREATED',-- CREATED/RUNNING/COMPLETED/CANCELLEDline_idBIGINTNOTNULL,-- 产线IDstart_timeTIMESTAMP,end_timeTIMESTAMP,created_atTIMESTAMPDEFAULTNOW());工序作业表wo_operation
CREATETABLEwo_operation(id BIGSERIALPRIMARYKEY,wo_idBIGINTNOTNULL,step_idBIGINTNOTNULL,-- 工艺步骤IDequipment_idBIGINT,-- 使用设备operator_idBIGINT,-- 操作员start_timeTIMESTAMP,end_timeTIMESTAMP,actual_cycle_timeINT,-- 实际节拍(秒)statusVARCHAR(20)DEFAULT'PENDING'-- PENDING/RUNNING/DONE);设备状态日志equipment_status_log
CREATETABLEequipment_status_log(id BIGSERIALPRIMARYKEY,equipment_idBIGINTNOTNULL,statusVARCHAR(20)NOTNULL,-- RUNNING/STOPPED/FAULTreason_codeVARCHAR(50),-- 停机原因编码start_timeTIMESTAMPNOTNULL,end_timeTIMESTAMP-- NULL 表示当前状态);✅最佳实践:
- 使用
BIGSERIAL自增主键,兼容高并发插入;end_time IS NULL表示当前活跃状态,便于实时查询。
四、后端核心逻辑实现
4.1 工单排产与下发
@Service@TransactionalpublicclassWorkOrderService{publicvoidscheduleWorkOrder(LongwoId,LonglineId,LocalDateTimestartTime){WorkOrderwo=woMapper.selectById(woId);if(!"CREATED".equals(wo.getStatus())){thrownewBusinessException("工单状态不可排产");}// 更新工单wo.setLineId(lineId);wo.setStartTime(startTime);wo.setStatus("SCHEDULED");woMapper.updateById(wo);// 创建工序作业List<RouteStep>steps=routeStepMapper.selectByRouteId(wo.getRouteId());for(RouteStepstep:steps){WoOperationop=newWoOperation();op.setWoId(woId);op.setStepId(step.getId());op.setStatus("PENDING");woOperationMapper.insert(op);}// 异步通知车间终端mqProducer.send("mes.wo.scheduled",woId);}}4.2 OEE 实时计算(定时任务)
@ComponentpublicclassOeeCalculator{@Scheduled(fixedRate=60000)// 每分钟计算publicvoidcalculateOee(){List<Equipment>equipments=equipmentMapper.selectAll();for(Equipmenteq:equipments){OeeResultoee=computeOeeFor(eq.getId(),LocalDateTime.now().minusHours(1));oeeMapper.saveOrUpdate(oee);// 覆盖最新值}}privateOeeResultcomputeOeeFor(LongeqId,LocalDateTimesince){// 1. 获取计划生产时间(从班次配置)longplannedTimeSec=shiftService.getPlannedSeconds(eqId,since);// 2. 获取实际运行时间longrunningTimeSec=logMapper.sumRunningTime(eqId,since);// 3. 获取理论产量 = 运行时间 / 标准节拍inttheoreticalQty=(int)(runningTimeSec/standardCycleTime);// 4. 获取实际合格产量intactualGoodQty=woOpMapper.countGoodOutput(eqId,since);doubleavailability=(double)runningTimeSec/plannedTimeSec;doubleperformance=(double)actualGoodQty/theoreticalQty;doublequality=(double)actualGoodQty/totalProduced;// 需查总产量returnnewOeeResult(eqId,availability,performance,quality);}}📊可视化建议:将 OEE 结果写入 InfluxDB,通过 Grafana 展示趋势图。
4.3 物料追溯(递归查询)
@ServicepublicclassTraceabilityService{/** * 正向追溯:成品 → 原料 */publicList<MaterialBatch>traceForward(StringfinishedGoodsSn){FinishedGoodsfg=fgMapper.selectBySn(finishedGoodsSn);returnmaterialConsumeMapper.selectBatchesByWoId(fg.getWoId());}/** * 反向追溯:原料 → 成品(递归) */publicList<String>traceBackward(StringbatchNo){List<Long>woIds=materialConsumeMapper.selectWoIdsByBatch(batchNo);List<String>result=newArrayList<>();for(LongwoId:woIds){result.addAll(getFinishedGoodsSnByWo(woId));// 递归:如果该工单产出是半成品,则继续追溯if(isIntermediateProduct(woId)){StringsemiSn=getIntermediateSn(woId);result.addAll(traceBackward(semiSn));// 递归调用}}returnresult;}}⚠️性能提示:反向追溯可能涉及多层递归,建议限制最大深度(如5层),并添加缓存。
五、前端交互与可视化
5.1 车间看板(Vue 3 + ECharts)
<template> <div class="dashboard"> <h2>产线 {{ lineName }} 实时状态</h2> <div class="cards"> <StatCard title="今日计划" :value="planQty" /> <StatCard title="已完成" :value="completedQty" /> <StatCard title="OEE" :value="oee.toFixed(1) + '%'" /> </div> <div class="chart-container"> <IEcharts :option="oeeTrendOption" /> </div> <el-table :data="activeOrders" height="300"> <el-table-column prop="orderNo" label="工单号" /> <el-table-column prop="product.name" label="产品" /> <el-table-column label="进度"> <template #default="{ row }"> <el-progress :percentage="row.progress" /> </template> </el-table-column> </el-table> </div> </template> <script setup lang="ts"> import { ref, onMounted } from 'vue'; import { fetchLineDashboard } from '@/api/mes'; const planQty = ref(0); const completedQty = ref(0); const oee = ref(0); const activeOrders = ref([]); onMounted(async () => { const data = await fetchLineDashboard('LINE_01'); planQty.value = data.planQty; completedQty.value = data.completedQty; oee.value = data.oee; activeOrders.value = data.orders; }); </script>🎨工业UI建议:使用深色主题减少屏幕反光,关键指标用红/黄/绿颜色编码。
六、设备对接与 IIoT 集成
MES 的价值在于连接物理世界。我们通过以下方式集成设备:
6.1 协议支持
- Modbus TCP:通用工业协议,读取PLC寄存器
- OPC UA:跨平台、安全的数据交换标准
- MQTT:轻量级物联网协议,适合传感器数据上报
6.2 设备网关设计
// 设备数据接收服务@ServicepublicclassEquipmentGateway{@RabbitListener(queues="equipment.data")publicvoidhandleEquipmentData(Stringpayload){EquipmentDatadata=JsonUtils.parse(payload,EquipmentData.class);// 1. 更新设备实时状态equipmentStatusService.updateRealtime(data.getEqId(),data.getStatus());// 2. 触发OEE计算(异步)oeeTaskExecutor.submit(()->oeeCalculator.recalc(data.getEqId()));// 3. 异常报警if("FAULT".equals(data.getStatus())){alarmService.send("设备["+data.getEqId()+"]发生故障!");}}}🔌硬件建议:在车间部署边缘计算网关(如树莓派+协议转换模块),预处理数据后再上传。
七、安全与扩展
7.1 权限控制
// 仅允许查看本车间工单@PreAuthorize("@auth.hasWorkshop(#workshopId)")@GetMapping("/orders")publicResult<List<WorkOrderVO>>getOrders(@RequestParamLongworkshopId){returnResult.success(workOrderService.getByWorkshop(workshopId));}7.2 可扩展方向
- 微服务化:拆分为
order-service、equipment-service、quality-service - AI预测:基于历史数据预测设备故障(LSTM模型)
- 数字孪生:3D可视化车间布局,实时映射设备状态
- 移动端:开发 UniApp 应用,支持扫码报工、异常上报
八、总结
通过本项目,你不仅掌握了 MES 系统的核心业务逻辑(工单、设备、质量、物料),更实践了工业软件特有的技术挑战:实时数据处理、设备协议集成、复杂追溯算法、OEE计算等。这套架构虽为简化版,但已具备生产环境部署的基础能力,可作为中小型制造企业数字化转型的起点。
如果你觉得本文对你有帮助,欢迎点赞、收藏、评论!也欢迎关注我,后续将持续更新更多 Java 工业软件实战系列!💡