news 2026/9/1 7:42:55

基于Spring Boot构建工业生产计划管理系统:从核心流程到技术实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Spring Boot构建工业生产计划管理系统:从核心流程到技术实现

这类系统最值得先看的不是功能列表,而是能不能把生产计划、物料、订单、排程这些核心流程串起来,并且在实际部署时稳定运行。很多团队在选型或自研时,容易陷入两个误区:要么过度追求大而全,引入了大量用不上的复杂模块,导致维护成本飙升;要么只做了简单的增删改查,业务逻辑散落在各个角落,一旦计划调整或插单,整个系统就乱了套。

一个真正能用的工业生产计划管理系统,核心价值在于流程闭环数据驱动。它需要把销售订单、物料清单(BOM)、库存、设备产能、工时、交货期这些原本分散在Excel、邮件甚至纸质单据里的信息,通过一个统一的逻辑串联起来,让计划员能基于实时数据做决策,而不是靠经验“拍脑袋”。对于正在评估或准备动手开发的团队来说,最该关注的是:系统如何定义“计划”这个核心对象?排程算法是简单的先到先得,还是能考虑优先级、换线时间、设备约束?当紧急订单插入时,系统是推倒重来,还是能局部调整并给出影响评估?

下面,我会以一个从零开始构建的视角,拆解基于Spring Boot实现这样一个系统的关键环节、技术选型考量以及那些只有踩过坑才知道的细节。文章会避开空泛的概念,直接聚焦于环境搭建、核心表设计、排程逻辑实现、前后端协作以及生产环境部署中的具体问题。

1. 先明确系统边界:它到底管什么,不管什么

在动手写第一行代码之前,必须把系统的边界画清楚。一个“工业生产计划管理系统”听起来包罗万象,但如果试图一次性解决所有问题,项目大概率会失败。

1.1 核心管理对象:从销售订单到生产工单的转化链

系统管理的起点通常是销售订单预测订单。终点是下达给车间执行的生产工单。中间的核心转化逻辑,是这套系统的灵魂。

你需要明确以下几个实体及其关系:

  • 销售订单:客户要什么、要多少、何时要。
  • 产品:最终要交付的成品。
  • 物料清单:一个成品由哪些子部件或原材料构成(BOM),以及构成的数量关系。这是计划分解的基石。
  • 物料:具体的原材料、半成品、零部件,需要有库存信息。
  • 工作中心:可以是一台设备、一条生产线或一个班组,是执行生产任务的基本单位,需要有产能(如小时/天)和日历(工作日、休息日)信息。
  • 工艺路线:一个产品在哪些工作中心上,经过哪些工序,每个工序的标准工时是多少。
  • 生产工单:最终下达的指令,包含产品、数量、计划开始/结束时间、所需物料、工序步骤等。

很多新手系统只做到了“工单管理”,即手工创建工单并分配,这只是一个高级版的记事本。真正的计划系统,应该能根据销售订单,结合BOM库存,自动计算出需要生产或采购的物料需求(即MRP核心思想),再根据工艺路线工作中心产能,将生产任务在时间轴上排列开来(即排程)。

1.2 功能边界划分:第一期做什么,后续迭代什么

对于第一期(MVP),我建议聚焦以下核心闭环:

  1. 基础数据管理:产品、BOM、物料、工作中心、工艺路线的维护。
  2. 销售订单录入
  3. MRP运算:根据订单和现有库存,计算物料净需求。这一步可以暂时简化,例如只考虑单层BOM,不考虑在途、安全库存等复杂因素。
  4. 简单排程:根据物料齐套情况和工作中心产能,为生产任务分配一个建议的开始时间。初期可以采用无限产能排程(即假设产能无限,只按顺序排),先跑通流程。
  5. 工单下达与状态跟踪:工单创建后,可以下发,并更新状态(待生产、生产中、已完成)。

暂时不要做:

  • 复杂的有限产能优化算法。
  • 完整的供应链管理(供应商、采购订单)。
  • 车间现场数据采集。
  • 复杂的成本核算。

先让核心流程跑起来,数据能流转,再基于实际使用反馈进行迭代。这个边界意识能帮你节省大量初期开发时间,避免陷入技术细节而忘了业务目标。

2. 技术栈选型与项目初始化:不只是Spring Boot

虽然标题是“基于Spring Boot”,但一个可用的系统远不止一个框架。技术选型需要平衡开发效率、团队技能和后期维护成本。

2.1 后端技术栈:稳健为主,预留扩展

  • Spring Boot:毫无疑问是基石。版本选择上,不必追求最新。Spring Boot 2.7.x 或 3.x 的LTS版本都是稳妥的选择。新项目可以从3.x开始,注意其最低要求JDK 17。
  • 持久层
    • ORM框架:MyBatis-Plus。它比纯JPA更贴近国内开发者的SQL习惯,代码生成器能极大提升基础CRUD的开发速度,对于管理类系统非常友好。
    • 数据库:MySQL 8.0 或 PostgreSQL。生产环境务必做好主从分离和备份策略的规划。
  • 缓存:Redis。用于存储会话、热点数据(如产品信息)、以及简单的排程队列状态。Spring Boot缓存技术可以很方便地通过注解集成,但要注意缓存一致性问题。
  • 消息队列:可选,但建议预留。当工单状态变更、计划更新需要通知其他系统(如MES、WMS)时,消息队列是解耦利器。RabbitMQ或RocketMQ都是常见选择。SpringBoot整合ActiveMQ也是一种方案,但ActiveMQ在吞吐量和社区活跃度上相对弱一些。
  • 任务调度:计划系统本身可能就有定时任务需求,如每天凌晨自动运行MRP计算。Spring自带的@Scheduled注解适合简单场景,更复杂的分布式调度可以考虑XXL-JOB或Quartz集成。
  • API文档Swagger。用SpringBoot增加Swagger依赖并简单配置,可以自动生成API文档,前后端协作效率倍增。
  • 工具包:Hutool、Lombok等,能减少很多样板代码。

2.2 前端技术栈:分离部署,快速迭代

推荐前后端分离架构。后端提供RESTful API,前端独立部署。

  • Vue 3 + Element Plus:是目前管理后台类项目非常主流和高效的选择。组件丰富,生态成熟。
  • 构建工具:Vite,开发热更新速度极快。

2.3 项目初始化与关键配置

使用IDEA的Spring Initializr或阿里云的 start.aliyun.com 快速生成项目骨架。

pom.xml文件是依赖管理的核心,初期不必引入所有功能。按需添加,例如:

<dependencies> <!-- Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 数据库 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>最新版本</version> </dependency> <!-- 缓存 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- 文档 --> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.x</version> </dependency> <!-- 工具 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>

application.yml配置要点:

server: port: 8080 servlet: context-path: /api # 建议统一API前缀 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/prod_plan?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai username: root password: your_password redis: host: localhost port: 6379 database: 0 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开发阶段开启SQL日志 global-config: db-config: logic-delete-field: deleted # 逻辑删除字段 logic-delete-value: 1 logic-not-delete-value: 0 # Swagger/OpenAPI 配置 springdoc: api-docs: path: /v3/api-docs swagger-ui: path: /swagger-ui.html

注意:生产环境务必移除SQL日志打印,并妥善保管数据库密码。

3. 核心数据库设计与领域建模

数据库设计直接决定了系统的扩展性和性能。不要一上来就对着界面画表,要先理解业务实体和它们之间的关系。

3.1 核心表结构设计(简化版)

以下是最核心的几张表,用于支撑第一节描述的闭环:

  1. 产品表 (product)

    CREATE TABLE `product` ( `id` bigint NOT NULL COMMENT '主键', `code` varchar(64) NOT NULL COMMENT '产品编码', `name` varchar(255) NOT NULL COMMENT '产品名称', `spec` varchar(500) DEFAULT NULL COMMENT '规格型号', `unit` varchar(20) DEFAULT NULL COMMENT '单位', `type` tinyint DEFAULT NULL COMMENT '类型:1-成品,2-半成品,3-原材料', PRIMARY KEY (`id`), UNIQUE KEY `uk_code` (`code`) ) COMMENT='产品表';
  2. 物料清单表 (bom)

    CREATE TABLE `bom` ( `id` bigint NOT NULL, `parent_product_id` bigint NOT NULL COMMENT '父产品ID', `component_product_id` bigint NOT NULL COMMENT '子件/原材料产品ID', `quantity` decimal(12,4) NOT NULL COMMENT '单台用量', `loss_rate` decimal(5,4) DEFAULT '0.0000' COMMENT '损耗率', PRIMARY KEY (`id`), KEY `idx_parent` (`parent_product_id`) ) COMMENT='物料清单表';
    • 一个成品(parent)对应多条BOM记录。
    • type字段可以区分替代料、虚拟件等,初期可省略。
  3. 销售订单表 (sales_order)

    CREATE TABLE `sales_order` ( `id` bigint NOT NULL, `order_no` varchar(64) NOT NULL COMMENT '订单号', `customer_name` varchar(255) DEFAULT NULL COMMENT '客户', `product_id` bigint NOT NULL COMMENT '产品ID', `quantity` decimal(12,4) NOT NULL COMMENT '订单数量', `delivery_date` date NOT NULL COMMENT '要求交货日期', `status` tinyint DEFAULT '1' COMMENT '状态:1-待处理,2-已计划,3-已关闭', PRIMARY KEY (`id`) ) COMMENT='销售订单表';
  4. 物料库存表 (material_stock)

    CREATE TABLE `material_stock` ( `id` bigint NOT NULL, `product_id` bigint NOT NULL COMMENT '物料产品ID', `warehouse` varchar(100) DEFAULT NULL COMMENT '仓库', `location` varchar(100) DEFAULT NULL COMMENT '库位', `quantity` decimal(12,4) NOT NULL DEFAULT '0.0000' COMMENT '当前库存数量', `locked_quantity` decimal(12,4) DEFAULT '0.0000' COMMENT '已锁定数量(已分配未出库)', PRIMARY KEY (`id`), UNIQUE KEY `uk_product_warehouse` (`product_id`,`warehouse`) ) COMMENT='物料库存表';
    • locked_quantity用于实现简单的库存预留,防止超卖。
  5. 工作中心表 (work_center)

    CREATE TABLE `work_center` ( `id` bigint NOT NULL, `code` varchar(64) NOT NULL COMMENT '工作中心编码', `name` varchar(255) NOT NULL COMMENT '名称', `daily_capacity` decimal(10,2) DEFAULT NULL COMMENT '日产能(小时)', `efficiency` decimal(5,4) DEFAULT '1.0000' COMMENT '效率系数', `calendar_id` bigint DEFAULT NULL COMMENT '关联日历ID', PRIMARY KEY (`id`) ) COMMENT='工作中心表';
  6. 工艺路线表 (process_route) 与 工序表 (process_step)

    -- 工艺路线头 CREATE TABLE `process_route` ( `id` bigint NOT NULL, `product_id` bigint NOT NULL COMMENT '产品ID', `version` varchar(20) DEFAULT 'A' COMMENT '版本', PRIMARY KEY (`id`), UNIQUE KEY `uk_product_version` (`product_id`,`version`) ) COMMENT='工艺路线表'; -- 工艺路线明细(工序) CREATE TABLE `process_step` ( `id` bigint NOT NULL, `route_id` bigint NOT NULL COMMENT '工艺路线ID', `step_no` int NOT NULL COMMENT '工序序号', `work_center_id` bigint NOT NULL COMMENT '工作中心ID', `setup_time` decimal(8,2) DEFAULT '0.00' COMMENT '准备时间(小时)', `process_time` decimal(8,4) NOT NULL COMMENT '单件加工时间(小时/件)', `description` varchar(500) DEFAULT NULL COMMENT '工序描述', PRIMARY KEY (`id`), KEY `idx_route` (`route_id`) ) COMMENT='工序表';
  7. 生产工单表 (work_order)

    CREATE TABLE `work_order` ( `id` bigint NOT NULL, `order_no` varchar(64) NOT NULL COMMENT '工单号', `product_id` bigint NOT NULL COMMENT '产品ID', `plan_quantity` decimal(12,4) NOT NULL COMMENT '计划数量', `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态:1-已创建,2-已排程,3-已下达,4-生产中,5-已完成,6-已关闭', `plan_start_time` datetime DEFAULT NULL COMMENT '计划开始时间', `plan_end_time` datetime DEFAULT NULL COMMENT '计划结束时间', `actual_start_time` datetime DEFAULT NULL, `actual_end_time` datetime DEFAULT NULL, `priority` int DEFAULT '10' COMMENT '优先级,数字越小优先级越高', `source_order_id` bigint DEFAULT NULL COMMENT '来源销售订单ID', PRIMARY KEY (`id`) ) COMMENT='生产工单表';

3.2 领域模型与Service层设计

有了表结构,在Java中需要建立对应的实体类。使用MyBatis-Plus,可以配合Lombok简化代码。

@Data @TableName("work_order") public class WorkOrder { @TableId(type = IdType.ASSIGN_ID) // 使用雪花算法ID private Long id; private String orderNo; private Long productId; private BigDecimal planQuantity; private Integer status; private LocalDateTime planStartTime; private LocalDateTime planEndTime; private Integer priority; private Long sourceOrderId; // 其他字段... }

业务逻辑集中在Service层。例如,WorkOrderService中会包含创建工单、排程、状态变更等方法。这里的关键是事务管理。例如,创建工单并扣减物料库存,必须在一个事务内完成,否则会导致数据不一致。

@Service @Transactional(rollbackFor = Exception.class) public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder> implements WorkOrderService { @Autowired private MaterialStockService stockService; @Override public boolean createAndAllocate(WorkOrder workOrder, List<MaterialRequirement> requirements) { // 1. 保存工单 this.save(workOrder); // 2. 为工单分配物料,锁定库存 for (MaterialRequirement req : requirements) { stockService.lockStock(req.getProductId(), req.getWarehouse(), req.getQuantity()); } // 如果任何一步失败,整个事务回滚 return true; } }

4. 核心业务逻辑实现:MRP与排程

这是系统的“大脑”。初期可以简化,但逻辑必须清晰。

4.1 简化的MRP计算服务

MRP的核心是需求分解净需求计算。我们实现一个最简单的版本:只考虑一层BOM,不考虑在途、安全库存和批量政策。

@Service public class MrpService { @Autowired private SalesOrderService salesOrderService; @Autowired private BomService bomService; @Autowired private MaterialStockService stockService; /** * 为指定销售订单计算物料需求 * @param orderId 销售订单ID * @return 物料需求清单 */ public List<MaterialRequirement> calculateRequirement(Long orderId) { SalesOrder order = salesOrderService.getById(orderId); List<MaterialRequirement> result = new ArrayList<>(); // 1. 获取订单产品 Product finishedProduct = productService.getById(order.getProductId()); // 2. 获取该产品的BOM List<Bom> bomList = bomService.listByParentProductId(finishedProduct.getId()); for (Bom bom : bomList) { MaterialRequirement req = new MaterialRequirement(); req.setProductId(bom.getComponentProductId()); // 3. 计算毛需求 = 订单数量 * BOM用量 * (1 + 损耗率) BigDecimal grossReq = order.getQuantity() .multiply(bom.getQuantity()) .multiply(BigDecimal.ONE.add(bom.getLossRate())); // 4. 查询当前可用库存 (当前库存 - 已锁定库存) BigDecimal availableStock = stockService.getAvailableStock(bom.getComponentProductId()); // 5. 计算净需求 = 毛需求 - 可用库存 (如果为负则取0) BigDecimal netReq = grossReq.subtract(availableStock); if (netReq.compareTo(BigDecimal.ZERO) < 0) { netReq = BigDecimal.ZERO; } req.setQuantity(netReq); if (netReq.compareTo(BigDecimal.ZERO) > 0) { result.add(req); } } return result; } }

这个计算结果是“需要多少物料”。实际项目中,净需求还会触发采购建议或生产建议(对于半成品)。

4.2 基于有限产能的后向排程

排程算法极其复杂,工业级APS(高级计划排程)系统是另一个专业领域。我们实现一个最基本的后向排程:从交货日期倒推,考虑每个工序的标准工时和工作中心产能。

假设条件:

  1. 工作中心每天工作8小时。
  2. 工序之间没有等待时间。
  3. 排程时暂时忽略其他已排产任务(即无限产能假设)。
@Service public class SchedulingService { @Autowired private ProcessRouteService routeService; @Autowired private WorkCenterService workCenterService; /** * 为工单计算计划开始和结束时间(后向排程) * @param workOrder 工单 * @param deliveryDate 要求完工日期 * @return 排程结果 */ public ScheduleResult backwardSchedule(WorkOrder workOrder, LocalDate deliveryDate) { ScheduleResult result = new ScheduleResult(); // 1. 获取产品的工艺路线 ProcessRoute route = routeService.getByProductId(workOrder.getProductId()); List<ProcessStep> steps = routeService.getStepsByRouteId(route.getId()); // 假设最后一道工序在交货日下班前完成 LocalDateTime currentEndTime = deliveryDate.atTime(17, 0); // 下午5点下班 List<StepSchedule> stepSchedules = new ArrayList<>(); // 2. 倒序计算每道工序 for (int i = steps.size() - 1; i >= 0; i--) { ProcessStep step = steps.get(i); StepSchedule ss = new StepSchedule(); ss.setStep(step); // 计算该工序总工时 = 准备时间 + (单件时间 * 工单数量) BigDecimal totalHours = step.getSetupTime() .add(step.getProcessTime().multiply(workOrder.getPlanQuantity())); // 将工时转换为工作日(简化:按8小时/天) double daysNeeded = totalHours.doubleValue() / 8.0; // 计算计划开始时间(从结束时间往前推) LocalDateTime planStart = calculateStartTime(currentEndTime, daysNeeded); ss.setPlanStartTime(planStart); ss.setPlanEndTime(currentEndTime); stepSchedules.add(0, ss); // 按正序插入列表 // 当前工序的开始时间,是上一道工序(在循环中)的结束时间 currentEndTime = planStart; } result.setStepSchedules(stepSchedules); if (!stepSchedules.isEmpty()) { result.setPlanStartTime(stepSchedules.get(0).getPlanStartTime()); result.setPlanEndTime(stepSchedules.get(stepSchedules.size() - 1).getPlanEndTime()); } // 3. 将最终的计划时间更新到工单 workOrder.setPlanStartTime(result.getPlanStartTime()); workOrder.setPlanEndTime(result.getPlanEndTime()); workOrder.setStatus(2); // 状态更新为“已排程” // ... 保存工单 return result; } private LocalDateTime calculateStartTime(LocalDateTime endTime, double daysNeeded) { // 简化计算:不考虑节假日,直接减去所需天数 long hoursToSubtract = (long) (daysNeeded * 8); return endTime.minusHours(hoursToSubtract); } }

这个算法非常初级,但足以演示排程的核心思想:时间推算产能占用。真实的排程还需要考虑:

  • 有限产能:检查工作中心在计划时间段内是否已被占用。
  • 工序重叠:某些工序可以并行。
  • 换模时间:产品切换带来的设备准备时间。
  • 优先级规则:紧急订单插单处理。

对于初期系统,可以先使用这个简化算法,让计划员能看到一个初步的时间线,然后再手动调整。这比完全没有排程要前进一大步。

5. 前端界面与API交互:让数据流动起来

后端逻辑完成后,需要通过清晰的界面和稳定的API暴露给用户。

5.1 RESTful API设计要点

遵循RESTful风格,保持接口语义清晰。

  • GET /api/work-orders:获取工单列表(可分页、过滤、排序)。
  • GET /api/work-orders/{id}:获取单个工单详情。
  • POST /api/work-orders:创建新工单。
  • PUT /api/work-orders/{id}:更新工单信息。
  • POST /api/work-orders/{id}/schedule:为指定工单执行排程。
  • POST /api/mrp/calculate?orderId=xxx:触发MRP计算。

使用SpringBoot常用注解简化开发:

@RestController @RequestMapping("/api/work-orders") @Api(tags = "生产工单管理") public class WorkOrderController { @Autowired private WorkOrderService workOrderService; @GetMapping @ApiOperation("分页查询工单列表") public R<Page<WorkOrderVO>> list(@RequestParam(required = false) Integer status, @RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize) { Page<WorkOrder> page = new Page<>(pageNum, pageSize); LambdaQueryWrapper<WorkOrder> queryWrapper = new LambdaQueryWrapper<>(); if (status != null) { queryWrapper.eq(WorkOrder::getStatus, status); } queryWrapper.orderByDesc(WorkOrder::getId); Page<WorkOrder> resultPage = workOrderService.page(page, queryWrapper); // 转换为VO对象... return R.ok(voPage); } @PostMapping("/{id}/schedule") @ApiOperation("为工单排程") public R<ScheduleResult> schedule(@PathVariable Long id, @RequestBody ScheduleRequest request) { WorkOrder order = workOrderService.getById(id); if (order == null) { return R.failed("工单不存在"); } ScheduleResult result = schedulingService.backwardSchedule(order, request.getDeliveryDate()); return R.ok(result); } }

注意:R是一个自定义的通用响应体,包含codemsgdataVO是视图对象,用于过滤掉不必要的实体字段。

5.2 前端页面关键功能

使用Vue 3 + Element Plus,可以快速搭建以下核心页面:

  1. 基础数据维护:产品、BOM、工作中心、工艺路线的增删改查列表页。BOM维护界面最好支持树形展示和拖拽。
  2. 销售订单管理:列表页和表单页。在表单页,选择产品后,可以联动显示产品信息。
  3. MRP运算界面:提供一个操作按钮,选择销售订单后,触发后端计算,并以表格形式展示计算出的物料净需求清单。
  4. 工单管理
    • 工单列表:显示所有工单,支持按状态、产品、时间筛选。状态可以用标签(Tag)直观显示。
    • 工单详情/编辑:查看和修改工单信息。
    • 排程操作:在工单行或详情页,有一个“排程”按钮,点击后弹出对话框,让用户确认或修改要求完工日期,然后调用排程API,并将返回的计划时间展示出来。
    • 甘特图视图:这是计划系统的“仪表盘”。可以使用如dhtmlx-ganttfrappe-gantt等开源库,将工单和工序以时间条的形式展示在时间轴上。拖拽时间条可以调整计划,并同步回后端。
  5. 库存查询:查看物料的当前库存、锁定库存和可用库存。

前后端联调时,重点关注数据一致性用户体验。例如,创建工单时,前端应实时验证产品ID是否存在;排程计算可能较耗时,需要添加加载状态提示。

6. 部署、监控与生产环境考量

系统开发完成,如何在生产环境稳定运行是另一个挑战。

6.1 部署方式选择

  • 传统部署:将Spring Boot打成的可执行JAR包,放在服务器上,用nohup java -jar app.jar &或systemd服务来运行。SpringBoot 直接打jar包运行是最简单的方式。
  • 容器化部署:使用Docker。编写Dockerfile,将应用、JDK打包成镜像。Docker部署SpringBoot项目能保证环境一致性。
    FROM openjdk:17-jdk-slim VOLUME /tmp COPY target/*.jar app.jar ENTRYPOINT ["java","-jar","/app.jar"]
  • 容器编排部署:在微服务架构或需要高可用时,使用Kubernetes。k8s部署SpringBoot项目涉及Deployment、Service、Ingress等资源配置。

6.2 生产环境关键配置

  1. 数据库连接池:使用HikariCP,在application-prod.yml中调整参数。
    spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 10 connection-timeout: 30000 idle-timeout: 600000 max-lifetime: 1800000
  2. 日志:配置Logback或Log4j2,将日志按级别输出到文件,并设置滚动策略。生产环境关闭DEBUG日志。
  3. 监控:集成Spring Boot Actuator,暴露健康检查、指标等信息。可以搭配Spring Boot Admin搭建一个简单的监控面板。
  4. 异常处理:使用@ControllerAdvice实现全局异常处理器,将系统异常转换为友好的错误信息返回给前端,同时记录详细日志用于排查。
  5. 安全
    • 使用Spring Security实现认证和授权。
    • API接口做好权限控制。
    • 对用户上传的文件(如果有)进行病毒扫描和大小限制,防止恶意上传。SpringBoot解决PDF XSS攻击这类问题,本质是对所有外部输入进行严格的校验和过滤。

6.3 信创环境适配

如果项目需要适配信创环境(国产化),这是一个系统工程,不仅仅是更换应用服务器。

  • 服务器:可能从CentOS转向麒麟、统信UOS。
  • 中间件:数据库可能换为达梦、金仓、OceanBase。缓存可能换为腾讯云Tendis等兼容Redis协议的国产产品。
  • 应用服务器:Tomcat是Spring Boot内嵌的,通常没问题。如果需要外置,东方通的TongWeb、金蝶的Apusic等是常见选择。是否需要更换,取决于部署环境的具体要求。通常,Spring Boot内嵌Tomcat打成的JAR包,只要JDK是兼容的(如龙芯的Loongson JDK、华为的毕昇JDK),在国产操作系统上可以直接运行。只有在客户明确要求必须使用特定国产应用服务器时,才需要将应用打包成WAR包并部署到TongWeb中。
  • 芯片:可能运行在鲲鹏、飞腾、龙芯等架构上。关键是要使用对应架构的JDK。

适配信创的首要步骤是:在目标国产化环境上,从编译到运行,完整地走通一遍CI/CD流程,尽早发现兼容性问题。

6.4 常见问题排查清单

系统上线后,遇到问题可按此顺序排查:

  1. 应用启动失败

    • 检查java -version,确认JDK版本符合Spring Boot要求。
    • 检查application.yml配置,特别是数据库、Redis连接信息。
    • 检查端口是否被占用。
    • 查看启动日志,寻找ErrorException关键字。
  2. 数据库连接问题

    • 检查数据库服务是否启动。
    • 检查连接IP、端口、用户名、密码是否正确。
    • 检查数据库驱动版本是否匹配。
    • 检查防火墙设置。
  3. 业务逻辑错误

    • MRP计算不准:检查BOM数据是否正确,库存数据是否及时更新,计算逻辑的循环和累加是否有误。
    • 排程时间不合理:检查工艺路线中的工时单位(是小时还是分钟),检查工作中心日历数据,检查排程算法的日期计算逻辑(是否考虑了非工作日)。
    • 库存数据不同步:检查工单创建、领料、入库等操作是否都在事务内,是否有并发操作导致的数据覆盖。考虑使用数据库悲观锁或乐观锁。
  4. 性能问题

    • 列表查询慢:检查是否缺少索引,特别是whereorder by涉及的字段。使用MyBatis-Plus的@TableField注解优化查询字段。
    • 排程计算慢:当工单和工序数量很大时,后向排程的循环计算可能变慢。考虑对算法进行优化,或引入缓存,将已排程结果缓存起来,除非基础数据变更。
    • 前端甘特图加载卡顿:一次不要加载太多时间范围的数据,采用分页或滚动加载。
  5. 前端显示问题

    • 控制台乱码:确认后端接口返回的Content-Type头包含charset=UTF-8,前端Axios请求也统一使用UTF-8编码。IDEA中SpringBoot应用运行控制台乱码通常是因为IDE或终端编码设置问题,与项目本身关系不大。
    • 时间显示不对:前后端传递时间时,统一使用时间戳或ISO 8601格式(如yyyy-MM-dd'T'HH:mm:ss),并明确时区。

开发这样一个系统,最大的挑战往往不是技术实现,而是对生产管理业务的理解和抽象。最好的做法是,与未来的使用人员(计划员、生产主管)保持紧密沟通,用最短的周期交付一个可用的最小版本,然后根据他们的实际反馈快速迭代。把系统当作一个不断进化的“活工具”,而不是一个一次性交付的“死项目”。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 7:40:13

MPU9250与MPL库在STM32F1上的移植实战经验

简介&#xff1a;这是一套基于STM32F103C8T6与MPU9250的九轴姿态解算完整工程&#xff0c;面向嵌入式开发者和物联网相关学习者&#xff0c;旨在解决传感器数据采集与多源融合实时姿态输出的问题。工程通过PC11、PC12将I2C接口与MPU9250相连&#xff0c;包含完整的驱动层与MPL库…

作者头像 李华
网站建设 2026/9/1 7:39:06

2004-2023美赛O奖论文拆解:价值、整理与迁移实战

简介&#xff1a;2004-2023年美赛特等奖论文合集汇集了近二十年间美国大学生数学建模竞赛的最高荣誉获奖作品&#xff0c;是备赛者不可多得的范本。资源面向计划参加美赛及其他数学建模竞赛的大学生、研究生和指导教师&#xff0c;旨在解决“不知道获奖论文应具备哪些要素、如何…

作者头像 李华
网站建设 2026/9/1 7:38:56

iOS虚拟摄像头:基于AVFoundation与VideoToolbox的视频管道

简介&#xff1a;vcam-ios-main.zip是一份面向iOS开发者的VCAM虚拟相机模块源码包&#xff0c;定位在帮助开发者快速集成高质量相机功能&#xff0c;适用于越狱插件或相机类App的功能扩展场景。资源共10个文件&#xff0c;包含Objective-C源码&#xff08;.m/.h&#xff09;、T…

作者头像 李华
网站建设 2026/9/1 7:35:29

Qt电力组态软件开发实战:核心架构、图元编辑与数据驱动

简介&#xff1a;一套基于Qt开发的电力组态软件完整工程&#xff0c;面向电力行业软件开发者、Qt进阶学习者及自动化监控项目人员&#xff0c;围绕图形化组态、实时监控与数据交互展开。工程涵盖绘图画布、自定义电力图元、属性编辑面板、数据库对话框、网络通信等模块&#xf…

作者头像 李华
网站建设 2026/9/1 7:34:33

正点原子Mini STM32F103RCT6驱动RC522读卡程序详解

简介&#xff1a;这套RC522读卡程序专为正点原子Mini开发板设计&#xff0c;主控芯片是STM32F103RCT6&#xff0c;代码改写自野火Mini工程。程序通过SPI2接口与MFRC522模块通信&#xff0c;利用串口1把读卡结果和调试信息发送到终端&#xff0c;适合正在学习STM32、SPI总线、串…

作者头像 李华