☰
SpringBoot+Vue车间管理系统:业务设计、数据库与部署全解析
2026/10/1 21:28:18 网站建设 项目流程

这么多年接手的工厂信息化项目里,车间生产管理这块是最容易"看着简单、做起来绕"的。业务方通常会先丢过来一句"就是管一下工单、设备、物料嘛",等真正开始梳理流程才发现:一个工单从下达到完工要经过排产、领料、报工、质检好几道手,中间任何一环状态对不上,后面统计报表全是错的。这篇文章我就以一套基于SpringBoot+Vue的工厂车间管理系统为例,把整个项目的业务模块设计、技术选型理由、数据库核心表结构、后端接口实现要点、前端页面落地方式,以及最后打包部署上线遇到的坑完整拆开讲一遍。无论是拿去做毕业设计、课程设计,还是想给中小型工厂做一套实用的管理工具,这套思路和源码结构都可以直接参考复用。

1. 车间管理系统到底在管什么:业务模块与数据流转

很多初学者拿到这类项目第一反应是"不就是几个增删改查页面嘛"。如果你真这么想,做出来的东西大概率只是看起来能跑,但完全没法在真实车间里用。因为车间管理系统本质上不是CRUD堆砌,而是一条完整的数据流转链路:计划驱动工单,工单驱动领料和生产,生产产生报工记录,报工结果触发质检,质检合格才允许成品入库,整个过程里设备和人员都在产生跟生产相关的关联数据。

1.1 核心业务模块拆解

一套比较完整的工厂车间管理系统,通常至少要覆盖下面这些模块:

  • 工单管理:这是绝对的核心。业务人员创建生产工单,指定产品、数量、计划开始和结束时间,工单下面还可以拆成多道工序,每道工序对应不同的车间、设备和操作人员。工单状态一般要经历:待下发→已下发→生产中→已完工→已关闭。
  • 生产计划与排程:在工单创建之前,需要有一个简单的计划层面逻辑:根据销售订单或者库存预警生成生产计划,再由计划拆解为具体工单。小型系统里这步可以弱化为在工单上直接关联计划单号。
  • 物料与库存管理:车间生产要消耗原材料,完工后要产出成品。所以系统里必须有物料档案、物料出入库记录,并且要和工单联动:工单下发后可以生成领料单,完工后可以生成产品入库单。
  • 设备管理:设备台账、设备状态(运行/停机/维修)、设备点检和维修记录。设备状态直接关联到工单工序的执行——设备停机时不应该允许该工序报工,这一点是车间系统的特色逻辑。
  • 质量检验:报工完成后生成待检记录,质检员录入检验结果(合格/不合格/返工),不合格的工单不能进入入库环节,或者进入返工流程。
  • 人员管理:工人信息、班组划分、工序报工时记录操作人,方便后续做工时统计。
  • 生产看板与统计报表:用图表展示今日工单数量、设备状态分布、完工率、良品率等。这块通常是领导最关心的页面,也是项目答辩时最容易出彩的地方。

1.2 数据是怎么流转起来的

画不出数据流图,就不要急着建表。我一般会先理清楚一条主链:生产计划(或直接下发)→ 生成工单 → 工单下发生成领料需求 → 仓库发料生成出库记录 → 各工序报工 → 完工生成质检任务 → 质检合格生成成品入库记录 → 工单关闭。

这条链路串起来之后,模块之间的关系就很清晰了。比如"工单详情"页面不只是显示工单表那一行数据,它要同时把这道工单关联的领料记录、工序进度、报工记录、质检结果都聚合展示出来。这也是为什么后端接口不能只是单表查询,需要有多表关联聚合的能力。

1.3 系统的功能边界:什么该做,什么不该做

做这类管理系统最容易犯的毛病是"贪大求全"。一个小型工厂可能就几十个人,你非要上复杂的APS高级排程、MES对接设备PLC采集,那是给自己挖坑。作为一套可以落地并且能讲清楚的设计,我更建议控制好边界:

  • 生产计划可以做得简单些,能手工创建和维护计划、由计划一键生成工单,这个程度就够用。
  • 工序报工可以用最直接的方式:操作工在电脑或平板上选择工单和工序,录入完成数量,系统记录时间和人员。
  • 不建议在初版就做复杂的条码/RFID对接,先把核心数据流转做通,后续扩展并不难。

提示:不管最终做多少模块,工单、物料、设备、质检四个模块必须有,因为它们是车间管理的"骨架"。

2. 技术栈选择与版本搭配:为什么是SpringBoot+Vue+MyBatis+MySQL

这套技术栈现在几乎是Java全栈项目的标准配置,但"标准"不等于"无脑选"。每个组件解决什么问题、替换成别的行不行,心里要有数。

2.1 SpringBoot解决的是"快速构建可靠后端"的问题

SpringBoot的核心价值是自动配置和起步依赖。以前用SSH(Spring+Struts+Hibernate)搭一个能跑的项目,光写各种XML配置就要折腾一两天,SpringBoot把这一切摊平了:引入spring-boot-starter-web,一个内嵌Tomcat就起来了;引入mybatis-spring-boot-starter,数据源和SqlSessionFactory的配置就自动完成了。

这套项目我建议用SpringBoot 2.7.x版本,不要直接用3.x。原因是3.x底层是Spring Framework 6和Jakarta EE命名空间,很多老教程、网上资料里的javax.*包代码直接复制会报错,对新手和做课程设计的人来说折腾成本高。2.7.x配合JDK 8或者JDK 11,生态最稳定,资料也最好查。

2.2 为什么前端选Vue而不是别的

Vue的上手曲线比React平滑,中文文档和社区资源丰富,而且Vue的双向数据绑定让"表单收集、表格展示"这类后台管理页面的开发效率特别高。

版本上,Vue 2.7是Vue 2的最后一个大版本,Element UI配套成熟稳定;Vue 3 + Element Plus则是当前的主流方向。如果你是从零开始做新项目,我更推荐直接上Vue 3 + Element Plus + Vite,原因很简单:Vite的本地启动速度比Webpack快一个量级,而且Vue 3的Composition API写业务代码更清晰。不过要注意,Vue 3生态里有些组件库的坑比Vue 2多,比如部分第三方插件还没完全适配,如果用到的功能比较简单,问题不大。

2.3 MyBatis:SQL可控性比ORM的"自动"更重要

JPA(Hibernate)的优点是开发快,但缺点是你很难精确控制SQL,尤其到了多表关联、动态查询条件多、SQL需要针对索引优化的场景,JPA要么写JPQL,要么写原生SQL,体验很割裂。MyBatis则是"SQL你写,映射它做",既保留了SQL的灵活性,又省掉了传统JDBC里ResultSet手动封装的那堆重复代码。

在这个项目里,工单列表的多条件分页查询、工单详情聚合查询、统计报表的按天/按状态分组统计,都是SQL灵活性的典型场景。用MyBatis写动态SQL,<where>、<if>、<foreach>几个标签配合,查询逻辑一目了然。

2.4 MySQL在中小型工厂场景下完全够用

很多人纠结要不要上PostgreSQL或者Oracle,其实对于车间管理系统这种典型的联OLTP系统,数据量级通常就是几万到几十万条工单记录,MySQL InnoDB引擎的性能、事务支持(ACID)和主从复制能力完全覆盖需求。唯一要注意的是建表时统一使用utf8mb4字符集,否则存不了生僻字和特殊符号。

2.5 版本搭配参考表

组件推荐版本说明
JDK1.8 或 11SpringBoot 2.7.x对JDK8支持最稳
SpringBoot2.7.x避免3.x的javax/jakarta命名空间切换问题
Vue3.x + Vite新项目首选,Vue2.7也可但不再建议新开
UI组件库Element Plus后台管理系统最成熟的组件库
MyBatis3.5.x + mybatis-spring-boot-starter 2.3.x保持SpringBoot版本兼容
MySQL5.7 或 8.08.0默认认证插件要留意驱动版本
JDBC驱动mysql-connector-j 8.0.x对应MySQL 8.0

3. 数据库设计决定项目上限:核心表结构与字段规划

我可以直接说一句可能得罪人的话:这个项目能不能拿高分、能不能真正跑通业务,七成看数据库表设计,三成看代码。很多代码写得很漂亮的项目,因为表设计里状态字段没规划好、关联关系没理清,最后做出来的功能怎么改都别扭。

3.1 核心表清单

按上面的业务模块,一套完整的库表大致需要这些:

功能域表名核心字段
用户权限sys_user / sys_role / sys_menu账号、角色、菜单权限
基础资料product(产品) / customer(客户)产品编码、规格、单位
生产计划production_plan计划单号、产品ID、计划数量、交期
工单管理work_order工单号、计划ID、产品ID、数量、状态、时间
工单工序work_order_process工单ID、工序名称、排序、计划工时
物料库存material / material_stock物料编码、库存量、安全库存
领料与入库material_record类型(领料/退料/入库)、关联工单ID、数量
设备管理device / device_maintenance设备编号、状态、维修记录
生产报工work_report工单ID、工序ID、报工数量、报工人、时间
质量检验quality_check工单ID、报工ID、检验结果、检验员、不良数
生产看板(用视图或接口聚合)无需单独建表

3.2 关键表设计解析:以work_order为例

工单表是整个系统的心脏,字段设计直接影响上下游所有模块的联查效率:

CREATE TABLE `work_order` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `order_no` varchar(32) NOT NULL COMMENT '工单编号,业务唯一', `plan_id` bigint(20) DEFAULT NULL COMMENT '来源生产计划ID', `product_id` bigint(20) NOT NULL COMMENT '产品ID', `order_quantity` int(11) NOT NULL COMMENT '计划生产数量', `completed_quantity` int(11) DEFAULT '0' COMMENT '累计完工数量', `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态:0待下发 1生产中 2已完工 3已关闭', `priority` tinyint(4) DEFAULT '1' COMMENT '优先级:1普通 2紧急', `plan_start_time` datetime DEFAULT NULL, `plan_end_time` datetime DEFAULT NULL, `actual_start_time` datetime DEFAULT NULL, `actual_end_time` datetime DEFAULT NULL, `create_by` varchar(32) DEFAULT NULL, `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_order_no` (`order_no`), KEY `idx_status` (`status`), KEY `idx_product_id` (`product_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='生产工单表';

几个容易踩坑的细节:

状态字段用tinyint,不要用varchar。用数字做状态的好处是排序、过滤、统计都方便,而且前后端用统一的枚举类映射含义,比到处写死字符串"已下发"强得多。我见过有人用"已下发""生产中""已完成"这种中文直接存库,后来报表统计都靠LIKE匹配,改一次状态描述全表都要UPDATE,那酸爽谁经历谁知道。

完工数量单独冗余一个字段。completed_quantity可以从work_report表实时SUM出来,但工单列表页每次都要聚合查询,数据量大了很吃力。冗余这个字段,每次报工时累加更新,性能和逻辑都简单很多。这就是典型的"用空间换时间"。

唯一键用业务编号而不是自增主键。order_no设置UNIQUE KEY,因为多系统对接、Excel导入工单时,业务编号才是唯一身份。

3.3 工序与报工记录怎么挂

work_order_process表记录工单拆出的工序步骤,work_report表记录每一道工序的实际报工。这组关联是整个生产进度追踪的基础。

设计时有个关键点:报工记录上除了关联work_order_id,一定要把process_id也带上。否则一个多工序工单完工后,你想统计"哪个环节产能消耗最大"根本查不出来。另外,报工表要独立记录report_user和report_time,这不仅是操作留痕,也是后续算计件工资的数据来源。

3.4 物料的领用与入库:一个字段区分方向

物料流水表(material_record)一般就两个方向:出库(领料/退料出)和入库(采购入库/成品入库/退料入)。我用一个record_type字段区分,再通过关联ID指向不同的上游单据。这样一个表通吃所有库存变动,月底对账时一张SQL就能拉出所有流水。

CREATE TABLE `material_record` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `material_id` bigint(20) NOT NULL COMMENT '物料ID', `work_order_id` bigint(20) DEFAULT NULL COMMENT '关联工单ID', `record_type` tinyint(4) NOT NULL COMMENT '1领料出库 2退料入库 3采购入库 4成品入库', `quantity` decimal(12,2) NOT NULL COMMENT '变动数量,出库为负数,入库为正数', `record_time` datetime NOT NULL COMMENT '变动时间', `create_by` varchar(32) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_material_id` (`material_id`), KEY `idx_work_order_id` (`work_order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='物料出入库流水表';

关于数量字段,有个建议:库存类字段能用decimal(12,2)就不要用int,因为很多原材料按重量、长度计量,会有小数。省这一步,后面做单据的时候哭着改字段类型的滋味不好受。

3.5 扩展:如果想加多租户/多工厂

如果系统要卖给多个工厂用,或者集团下有多个厂区,建议在核心业务表(工单、物料流水、报工)上预留一个factory_id字段,所有查询默认带上这个租户条件。加这一个字段的成本很低,但这是你从"单机项目"走向"商用产品"的关键一步。

4. 后端实现:SpringBoot项目结构、鉴权、动态SQL与事务

后端部分我按"项目怎么分层、接口怎么设计、核心功能怎么落地"三个角度来讲。这套项目的后端代码结构长这样:

src/main/java/com/example/mes ├── controller # 接口层,只做参数接收和结果返回 ├── service # 业务逻辑层,事务控制在这层 ├── mapper # MyBatis数据访问层,接口+XML ├── entity # 数据库实体类 ├── dto # 前端交互对象(VO/Query对象) ├── common # 统一返回体、异常处理、枚举 ├── config # 配置类(WebMvc、CORS、拦截器) └── utils # JWT工具、日期工具等

4.1 统一返回体与全局异常处理

所有接口统一返回Result<T>结构,前端拿到数据后不需要各种判断,省掉大量重复代码:

{ "code": 200, "message": "操作成功", "data": { } }

配套地,用@RestControllerAdvice做全局异常处理。业务异常直接抛BizException,校验异常自动转为400返回,数据库异常统一转为500并记录日志。这块是很多课程设计项目做得最差的地方——异常处理散落在每个Controller里,try-catch满天飞,改一个逻辑要动三个地方。

4.2 JWT登录鉴权:token怎么发、怎么验

不推荐用Session,因为前后端分离后前端可能部署在独立端口,Session跨域处理麻烦,而且Vue打包后的静态资源一般走Nginx,后端接口在另一个域名或端口,Cookie跨域是坑。用JWT最简单:

用户登录成功后,后端生成一个有效期为24小时的token,里面带上用户ID和角色编码,返回给前端。前端每次请求在HTTP头里带Authorization: Bearer <token>。后端用一个拦截器统一校验token,解析出用户身份后放行。

具体实现上,我会用一个JwtUtil类负责生成和解析token,然后在WebMvcConfigurer里注册一个HandlerInterceptor处理校验。要注意:拦截器要放行登录接口、静态资源(如果前后端混合部署)、swagger文档路径,其他接口全部走校验。

提示:JWT有个常见误区是"把用户密码写进payload"。token里只需要用户ID和角色,不要放敏感信息,因为payload只是Base64编码,不是加密。

4.3 工单分页查询:MyBatis动态SQL实战

工单列表是系统最核心的查询接口,查询条件可能有:工单号模糊匹配、产品ID、状态、计划开始时间范围。用MyBatis的动态SQL写这个分页查询,是体现"为什么选MyBatis"的最佳例子:

<select id="selectWorkOrderPage" resultType="com.example.mes.dto.WorkOrderDTO"> SELECT wo.id, wo.order_no, wo.order_quantity, wo.completed_quantity, wo.status, wo.priority, wo.plan_start_time, wo.plan_end_time, p.product_name FROM work_order wo LEFT JOIN product p ON wo.product_id = p.id <where> <if test="query.orderNo != null and query.orderNo != ''"> AND wo.order_no LIKE CONCAT('%', #{query.orderNo}, '%') </if> <if test="query.productId != null"> AND wo.product_id = #{query.productId} </if> <if test="query.status != null"> AND wo.status = #{query.status} </if> <if test="query.startTime != null"> AND wo.plan_start_time &gt;= #{query.startTime} </if> <if test="query.endTime != null"> AND wo.plan_end_time &lt;= #{query.endTime} </if> </where> ORDER BY wo.plan_start_time DESC </select>

分页用PageHelper插件,引入依赖后在Service层直接PageHelper.startPage(pageNum, pageSize),紧接着的查询自动拼接LIMIT,返回的PageInfo里自带总条数和总页数,前端表格的分页组件直接对接就好。

这段XML有几个细节:0 1 != ''的判断是防控制返回模板,一定要记得擦除那部分(模板页内无需输出)——直接返回纯净的模板页内容。 `标签自动处理多余AND,首条条件不成立也不会出现SQL语法错误,这是MyBatis动态SQL最方便的地方。

4.4 报工事务:库存扣减和工单进度必须一起成功

车间报工这个动作涉及三个数据变更:新增work_report记录、累加工单的completed_quantity、可能触发物料流水(产成品入库)。这三步要么全成功,要么全失败,必须放在同一个事务里。

@Transactional(rollbackFor = Exception.class) public void reportWork(WorkReportRequest request) { // 1. 校验工单状态是否为生产中 // 2. 校验报工数量不超过剩余待完工数量 // 3. 插入work_report记录 // 4. 累加工单completed_quantity,到达计划数量后置为已完工 // 5. 生成成品的物料入库流水 }

这里有个业务规则值得注意:超量报工必须拦截。一不留神操作工多报了数量,后面成本统计和库存账面就全乱了。校验逻辑写在Service层,基于乐观锁或者直接在UPDATE语句里带条件,保证并发下也不会超量。

4.5 报表统计:一个SQL搞定生产看板数据

生产看板需要展示今日工单数、完工率、良品率,这些数据如果每一个都单独查一次库,代码啰嗦性能也差。我更推荐写几个聚合SQL,比如:

SELECT COUNT(*) AS total_order, SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) AS finished_order, ROUND(SUM(CASE WHEN status = 2 THEN 1 ELSE 0 END) / COUNT(*) * 100, 2) AS finish_rate FROM work_order WHERE create_time >= #{todayStart} AND create_time &lt; #{tomorrowStart}

以及按设备状态分组统计:

SELECT status, COUNT(*) AS cnt FROM device GROUP BY status

这类SQL配合一个DashboardController,一次性返回多个统计指标给前端看板组件,前端ECharts拿到数据直接渲染,效果很好。

5. 前端落地:Vue3工程搭建、Axios封装与核心页面实现

前端这部分,我按从搭建到核心页面开发的顺序来讲。Vue项目的工程化程度直接影响开发效率,很多人卡在"环境装好了但页面怎么写都别扭",多半是基础配置没做踏实。

5.1 工程结构:用Vite搭建Vue3项目

用Vite创建项目只需一条命令:

npm create vite@latest mes-web -- --template vue

生成后在项目里安装核心依赖:

npm install element-plus axios vue-router pinia echarts

工程结构建议保持清爽:

src ├── api # 每个模块的接口请求函数统一放这里 ├── assets # 静态资源 ├── components # 通用组件(分页表格、弹窗表单等) ├── layout # 后台主框架布局(侧边栏+顶栏+内容区) ├── router # 路由配置 ├── store # Pinia状态管理(用户信息、token) ├── utils # axios封装、工具函数 └── views # 页面组件

5.2 Axios封装:拦截器统一处理token和错误

Axios不封装直接用,每个页面里写重复的请求配置,后期要改baseURL能把人改疯。我通常在utils/request.js里做一个统一实例:

import axios from 'axios' import { ElMessage } from 'element-plus' import router from '@/router' const request = axios.create({ baseURL: '/api', timeout: 10000 }) // 请求拦截器:自动带上token request.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) // 响应拦截器:统一处理业务错误和登录过期 request.interceptors.response.use( response => { const res = response.data if (res.code !== 200) { ElMessage.error(res.message || '请求失败') return Promise.reject(new Error(res.message)) } return res.data }, error => { if (error.response && error.response.status === 401) { ElMessage.error('登录已过期,请重新登录') router.push('/login') } else { ElMessage.error('网络异常,请稍后重试') } return Promise.reject(error) } )

关键在baseURL设置/api:开发环境通过Vite的代理把/api转发到后端地址,生产环境通过Nginx把/api反向代理到后端服务。这样前后端分离部署不存在跨域问题,代码里也不用写死IP地址。

5.3 路由守卫:未登录不能进后台

后台系统的路由必须做登录校验:

router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') if (to.path !== '/login' && !token) { next('/login') } else { next() } })

多角色系统还可以在路由meta里加roles字段,做基于角色的菜单过滤。比如管理员看到"用户管理"菜单,普通操作工只能看到"工单报工"和"我的任务"。这一步实现起来不难,但对项目的完整度很加分。

5.4 工单管理页面:列表、筛选、弹窗表单的三件套

后台管理页面写多了会发现套路非常固定:页面顶部是搜索条件区,中间是数据表格,右侧或弹窗里是详情/编辑表单。工单管理页也不例外。

我习惯把"列表页+表单弹窗"拆成三个组件:WorkOrderList.vue(页面容器)、WorkOrderSearch.vue(搜索条件)、WorkOrderFormDialog.vue(新增/编辑弹窗)。这样页面逻辑清晰,后续加字段改动范围小。

表单校验是Element Plus的强项,比如工单创建时产品必选、数量必须大于0、计划时间不能为空,写好rules规则后,表单提交前调用formRef.validate()即可。手写校验逻辑又慢又容易漏,这个便宜一定要占。

5.5 生产看板:ECharts让数据"说话"

看板页面建议至少做四个图表模块:今日工单状态饼图、近7天完工量柱状图、设备状态分布图、车间良品率折线图。ECharts的用法很直接:先init一个DOM容器,再setOption传入配置项,数据部分从后端接口获取后填入series即可。

一个容易忽略的细节:图表容器在页面刚渲染时可能宽度为0,导致图表显示不正常。解决办法是在nextTick里初始化图表,或者给容器设置固定高度。另外,页面切换时记得调用chart.dispose()释放实例,否则内存会持续上涨。

5.6 权限控制的前端配合:按钮级权限

光有菜单级权限还不够,比如"工单关闭"按钮只有车间主管能点。我的做法是在登录时把用户权限标识列表存入Pinia,页面里用自定义指令v-permission控制按钮显隐:

const permission = { mounted(el, binding) { const required = binding.value const userPermissions = useUserStore().permissions if (!userPermissions.includes(required)) { el.parentNode.removeChild(el) } } }

这样在模板里写<el-button v-permission="'workorder:close'">关闭工单</el-button>,没有权限的用户压根看不到这个按钮,配合后端的接口权限校验,双重保障。

6. 打包部署与上线踩坑:从本地跑到服务器稳定运行

项目开发完只是第一步,真正部署到Linux服务器上跑起来,你会发现坑一个接一个。这部分我单独拎出来讲,是因为"能跑"和"上线稳定跑"完全是两码事。

6.1 后端打包:Maven跳过测试

后端项目在服务器上打包时,我习惯先本地执行:

mvn clean package -DskipTests

在application-prod.yml里把数据库地址改成服务器地址,然后上传jar包到服务器:

nohup java -jar mes-server.jar --spring.profiles.active=prod > logs/app.log 2>&1 &

这里有个前车之鉴:日志文件一定要单独指定,并且定期切割。否则时间长了可能要看你系统磁盘,虽然数据量不大,但前期系统还是需要留意一下。生产环境上线前建议在application.yml里显式配置日志级别和输出路径,我用logback按天切割,保留30天,这个配置花十分钟,后面排查问题会感激自己。

6.2 前端打包:路由模式与刷新404问题

前端构建:

npm run build

生成dist目录后上传到Nginx的html/mes-web目录。这里最大的坑是:如果用Vue Router的history模式,直接访问/workOrder这种二级路由刷新会报404,因为Nginx找不到对应的物理文件。

解决方案是在Nginx配置里加一个try_files指令:

location / { root /usr/share/nginx/html/mes-web; index index.html; try_files $uri $uri/ /index.html; }

这样所有前端路由都回退到index.html,由Vue Router接管路由解析。

6.3 Nginx反向代理解决跨域

前端代码里所有请求baseURL是/api,Nginx配置把/api转发到后端服务的实际端口:

location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }

注意proxy_pass结尾的斜杠:有斜杠表示把/api前缀去掉后转发,比如/api/workOrder/list转发到后端变成/workOrder/list,和后端Controller的RequestMapping保持一致就行。没有斜杠则是保留完整路径转发,两种写法对应不同的后端接口设计,千万别混。

6.4 MySQL连接常见坑:时区和SSL

SpringBoot连接MySQL8.0最容易报的两个错:The server time zone value 'Öйú±ê׼ʱ¼ä'(时区问题)和SSL connection error。在JDBC连接串上加上参数一次性解决:

url: jdbc:mysql://127.0.0.1:3306/mes_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true

useSSL=false是测试环境省事,生产环境如果数据库和服务器在同一内网,也可以关掉SSL减少开销。allowPublicKeyRetrieval=true是MySQL8.0配合caching_sha2_password认证方式时的常见参数,不加连不上。

6.5 上线后的系统检查清单

服务器部署成功后,不要急着交付,按这个清单过一遍:

  • 数据库备份策略是否配置?建议每天凌晨自动备份,保留7天。
  • 后端日志有没有接入logback按天切割?
  • 前端页面有没有用nginx -t验证过配置语法?
  • 服务器防火墙端口是否只开放了80/443和SSH?后端8080端口不要暴露公网。
  • 如果有多台服务器或者以后要扩容,Redis要不要引入?当前阶段可以不用,但代码里缓存逻辑最好预留接口。

7. 扩展思路:这套系统还能往哪个方向升级

如果你的项目是用于毕设或者想作为产品原型继续迭代,下面几个方向的扩展性价比很高:

引入Redis缓存:工单列表热点数据、产品基础资料的查询频率很高,用Redis缓存可以显著降低数据库压力。SpringBoot集成Redis相当简单,引入spring-boot-starter-data-redis,把字典数据、产品列表做一次缓存即可。但要注意缓存和数据库的一致性,写入操作要同步更新缓存或设置合理过期时间。

引入EasyExcel做导入导出:真实工厂里Excel操作是逃不掉的。工单批量导入、物料库存导出盘点表,用EasyExcel可以轻松实现。这块功能在答辩展示时效果很好,因为直观解决了"工厂办公日常"的实际问题。

引入WebSocket做实时看板:生产看板目前是打开页面才请求数据,如果要做到"工位报工后看板自动刷新",可以引入WebSocket,后端在报工事务提交后推送一条消息,前端看板收到后重新拉取统计数据。这个功能能显著提升系统的"实时感",而且技术亮点也够。

引入工作流引擎(如Flowable)做审批流:如果车间的领料超量、工单变更需要走审批流程,可以集成Flowable。但我的建议是:除非业务上有硬性需求,否则用状态机加一张审批记录表完全够用,工作流引擎的学习和维护成本对小项目来说偏重了。

我在实际做这类项目时最深的体会是:技术永远是为业务兜底的,真正让这个系统能被车间师傅用起来的关键,是"数据流转逻辑顺不顺"。一个工单从下发到完工,每一步操作的人在系统里走的路径,和他在车间里实际干活的动作越一致,系统就越容易被接受。所以拿到这套源码后,我建议你先别急着改代码,而是把表结构和工单流转状态图理清楚,后面加功能、改需求都会顺手很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询