做车间管理系统这个选题说实话是毕设里特别经典又特别务实的一条路。工厂场景真实、业务链条完整既有数据流转又有权限控制还能用图表把产量、合格率、设备状态这些指标直观呈现出来非常适合作为SpringBootVue的练手项目。我自己做过一套类似的如果你正打算用“SpringBootVueMySQL”这个技术栈做毕设或课设下面这些梳理、代码和踩坑记录可以直接帮你省下大量摸索时间。这套系统面向的是中小型工厂的车间管理场景核心解决生产工单、报工、质检、设备点检、物料流转这些环节的信息化问题。角色上我建议至少拆成管理员、车间主管、操作工、质检员四类再配合JWT做登录鉴权算是技术上比较完整、又不至于过度设计的一个方案。1. 项目概述与整体设计思路1.1 车间管理系统的核心业务需求先说业务侧。中小工厂的车间管理痛点其实非常集中工单靠Excel或者纸质流转更新不及时版本容易乱报工数据靠口头或纸质记录产量统计费时费力产品质量出了问题很难回溯到具体批次、工序和操作人设备点检靠自觉漏检错检很难发现管理层想看产量和合格率需要人工汇总滞后严重所以这个系统我建议围绕“工单驱动生产”这条主线来设计。整体链路是管理员或主管创建生产工单 - 工单下达给车间 - 操作工按工单报工并标记工序进度 - 质检员录入检验结果 - 系统自动汇总产量、合格率、工时等数据 - 看板图表展示。这套逻辑做下来业务流程是闭合的数据也有追溯关系答辩时也容易讲清楚。用户角色方面建议分成四类系统管理员负责用户管理、基础数据维护、角色权限分配车间主管创建工单、调整生产计划、查看统计报表操作工接单、报工、录入工序完成数量、查看个人任务质检员录入检验记录、判定合格/不合格、查看质量统计如果你做的周期比较短也可以把质检员的权限合并到主管角色里但做毕设的话我还是建议拆开这样权限控制的层次感更强代码里多一个角色也就多几行配置而已。1.2 为什么选择SpringBoot Vue这个组合选技术栈的时候很多人纠结过SpringCloud、前后端不分离、或者用模板引擎渲染页面这些方案我个人的判断是这样SpringBoot的好处是开箱即用。起步依赖帮你把Spring MVC、Jackson、Tomcat这些基础组件全部整合好了你只需要关心业务代码。而且SpringBoot 2.x版本在社区里非常成熟网上能查到的资料也最多就算遇到问题也容易搜到解决方案对毕设阶段来说这是很大的隐形优势。Vue的好处是组件化开发足够清晰。页面拆成组件之后工单列表、报工表单、质检记录这些模块之间不会互相干扰而且数据双向绑定让表单交互写起来很顺手。配合Element UI或Element Plus表格、弹窗、表单校验这些后台管理常用的UI组件可以直接拿来用不需要从零写样式。MySQL就不用多说了关系型数据库里最普及的选择。配合Navicat或DataGrip可视化建表效率很高。建议MySQL版本选5.7或8.0表结构设计用utf8mb4字符集避免中文乱码问题。1.3 系统模块划分与功能清单我建议把整个系统拆成六个功能模块模块核心功能关键数据流向登录认证JWT签发、登录鉴权、密码加密用户输入账号密码 - 后端校验 - 返回token用户权限用户管理、角色管理、菜单权限管理员配置 - 用户登录加载对应权限工单管理工单创建、下达、进度跟踪主管创建 - 操作工报工 - 系统更新状态生产报工工序报工、工时登记、产量统计操作工提交 - 写报工表 - 关联工单进度质量检验质检记录、合格率统计检验员录入 - 生成质检报表综合看板产量趋势、设备状态、合格率图表查询统计表 - ECharts渲染这样划分下来每个模块都有独立的前端页面和后端接口两个人协作开发的话也可以按模块分任务互不干扰。如果是单人完成也能按这个顺序逐步递进先跑通登录和工单主链路再补质检和看板。2. 数据库设计与后端核心模块实现2.1 数据库表结构设计要点数据库表设计是这个项目的根基表设计不合理后面写代码会非常痛苦。我建表的原则是“核心业务表独立关联表尽量简单”。建议核心表清单如下-- 用户表 CREATE TABLE sys_user ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, real_name VARCHAR(50), phone VARCHAR(20), role_id BIGINT, status TINYINT DEFAULT 1, create_time DATETIME ); -- 角色表 CREATE TABLE sys_role ( id BIGINT PRIMARY KEY AUTO_INCREMENT, role_name VARCHAR(50), role_key VARCHAR(50) ); -- 工单表 CREATE TABLE work_order ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(50) NOT NULL UNIQUE, product_name VARCHAR(100), product_model VARCHAR(50), plan_quantity INT, completed_quantity INT DEFAULT 0, status TINYINT DEFAULT 0, priority TINYINT DEFAULT 1, create_by BIGINT, assign_to BIGINT, start_time DATETIME, end_time DATETIME, remark VARCHAR(255), create_time DATETIME );工单表要注意几个细节order_no建议设计成业务编号比如WO 日期 流水号这样在列表里一眼就能看出工单的时间和顺序status用整数类型0未下达、1已下达、2生产中、3已完成、4已关闭配合前端做状态标签显示completed_quantity这个字段是冗余设计按理说可以从报工表sum出来但保留这个字段可以简化统计查询代价是更新工单状态时要同步维护这个值报工表是整个系统的核心业务表设计时要保证能够追溯CREATE TABLE production_report ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_id BIGINT NOT NULL, process_name VARCHAR(50), report_quantity INT, report_person BIGINT, report_time DATETIME, work_hours DECIMAL(5,2), quality_status TINYINT DEFAULT 0 );这个表记录的是每一次报工行为包括哪个工单、哪个工序、报了多少钱、谁报的、花了多少工时。有了这张表后续做产量趋势图、工时统计、个人绩效分析就都有了数据基础。质检表建议单独建不要和报工混在一起CREATE TABLE quality_check ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_id BIGINT, report_id BIGINT, check_person BIGINT, check_quantity INT, qualified_quantity INT, defect_reason VARCHAR(255), check_time DATETIME, check_status TINYINT DEFAULT 1 );这里把合格数量和不良原因单独列出来是为了后面统计合格率和分析质量问题原因提供数据支撑。2.2 后端项目结构与分层设计后端项目结构我建议严格遵循经典三层架构Controller、Service、Mapper各司其职。这样代码清晰答辩时也容易解释架构设计思想。src/main/java/com/example/workshop ├── config // 跨域配置、拦截器配置、MyBatisPlus配置 ├── controller // 接口层只做参数接收和结果返回 ├── service // 业务层写核心业务逻辑 │ └── impl ├── mapper // 数据访问层 ├── entity // 实体类 ├── dto // 数据传输对象 ├── vo // 视图对象给前端返回的数据模型 ├── common // 通用返回结果、异常处理、工具类 └── security // JWT相关工具和拦截器分层的好处是要懂得管住自己Controller里不要写业务逻辑Service里不要写SQL。刚开始写代码经常犯的毛病是把一大堆逻辑堆在Controller里结果接口一多自己都乱了。老老实实分层后面扩展功能会省心很多。通用返回结果类是一定要写的前后端对接全靠它统一格式public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.setCode(200); result.setMessage(操作成功); result.setData(data); return result; } public static T ResultT error(String message) { ResultT result new Result(); result.setCode(500); result.setMessage(message); return result; } }前端拿到这个统一结构之后就只需要判断code是否为200然后取data渲染页面非常清爽。2.3 JWT登录认证与异常统一处理登录认证这块我建议用JWT而不是传统的Session方案。因为前端是独立部署的不管是开发环境还是上线部署前后端分离意味着后端接口是无状态的JWT天然适合这种场景。实现逻辑不复杂public class JwtUtils { public static final String SECRET your-secret-key; public static final long EXPIRE_TIME 24 * 60 * 60 * 1000; public static String generateToken(Long userId, String username) { Date expireDate new Date(System.currentTimeMillis() EXPIRE_TIME); return Jwts.builder() .setSubject(username) .claim(userId, userId) .setExpiration(expireDate) .signWith(SignatureAlgorithm.HS256, SECRET) .compact(); } }生成token的SECRET在生产环境一定要用够长的随机字符串不要用简单的sercet这种。至于解析token、判断过期这些逻辑写一个JwtInterceptor统一处理public class JwtInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 放行登录接口 if (request.getRequestURI().contains(/login)) { return true; } String token request.getHeader(Authorization); // 校验token不合法则返回401 return true; } }异常处理这块推荐用RestControllerAdvice做全局异常拦截。这样可以保证即使代码里有未捕获的异常接口返回的也是统一的JSON错误格式而不是一堆堆栈信息。我之前没有做全局异常处理的时候前端一报错就是红色报错框调试起来很头大加了统一异常处理后清爽多了。2.4 工单管理与生产报工的服务端实现工单创建和报工是整个系统的核心业务实现时要注意一些边界情况。工单创建只需要校验参数和权限插入数据即可。关键是工单状态流转逻辑我给你说一下流转规则public void updateOrderStatus(Long orderId, Integer targetStatus) { WorkOrder order workOrderMapper.selectById(orderId); if (order null) { throw new BusinessException(工单不存在); } // 状态只能按顺序流转不允许乱跳 if (targetStatus order.getStatus()) { throw new BusinessException(工单状态不能回退); } order.setStatus(targetStatus); workOrderMapper.updateById(order); }报工逻辑稍微复杂一点。操作工提交报工数量时要同时做三件事插入报工记录、统计工单已完成数量、判断工单是否完成并更新状态。这三步必须放在一个事务里否则容易出现数据不一致。我用Transactional注解解决Transactional(rollbackFor Exception.class) public void reportProduction(ProductionReportDTO dto) { // 1. 校验工单存在且已下达 WorkOrder order workOrderMapper.selectById(dto.getOrderId()); if (order null || order.getStatus() ! 1) { throw new BusinessException(工单不存在或未下达); } // 2. 防重复报工同一订单同一工序同一人短时间内只允许报一次 // 3. 插入报工记录 // 4. 累计完成数量若达到计划数量则状态置为已完成 int newCompleted order.getCompletedQuantity() dto.getReportQuantity(); order.setCompletedQuantity(newCompleted); order.setStatus(newCompleted order.getPlanQuantity() ? 3 : 2); workOrderMapper.updateById(order); }事务回滚这里要注意一个细节事务内rollbackFor Exception.class一定要写。因为Spring默认只在遇到RuntimeException时才回滚如果业务抛的是普通Exception事务是不会回滚的这个坑我在早期踩过数据多了一条冗余记录还是手动删的。3. 前端Vue页面开发与接口联调3.1 Vue项目搭建与路由/状态管理设计前端我建议用Vue脚手架直接创建工程。如果你是Vue 3就使用Vite作为构建工具如果你是Vue 2就用Webpack。毕设场景下我推荐Vue 3 Element Plus的新技术栈因为现在企业用Vue 3越来越多学了更贴合市场需求而且Vue 3的组合式API写起来代码更紧凑。安装命令如下npm create vitelatest workshop-web -- --template vue cd workshop-web npm install npm install vue-router4 axios element-plus echarts如果npm install的时候网络特别慢可以换用cnpm或pnpm或者配置镜像源国内用户一般都会遇到这个体验问题正常处理就好。路由设计上建议用路由懒加载把每个页面按模块拆开import { createRouter, createWebHistory } from vue-router const routes [ { path: /login, component: () import(/views/Login.vue) }, { path: /, component: () import(/layout/Index.vue), children: [ { path: , redirect: /dashboard }, { path: dashboard, component: () import(/views/Dashboard.vue) }, { path: work-order, component: () import(/views/WorkOrder.vue) }, { path: quality, component: () import(/views/Quality.vue) }, { path: device, component: () import(/views/Device.vue) }, ] } ]懒加载的好处是打包之后不会把所有页面塞进一个文件里首屏加载会快不少答辩演示的时候也不用干等着白屏。状态管理方面用Pinia比Vuex更轻量代码更简洁。在车间管理系统里你可以把用户信息和菜单权限放在store中管理登录成功之后拉取一次全局使用import { defineStore } from pinia export const useUserStore defineStore(user, { state: () ({ token: localStorage.getItem(token) || , userInfo: {} }), actions: { setToken(token) { this.token token localStorage.setItem(token, token) } } })3.2 Axios请求封装与拦截器处理Axios一定要封装这是前后端联调的交通枢纽。你需要在请求拦截器里自动带上token在响应拦截器里统一处理业务错误和登录过期import axios from axios import { ElMessage } from element-plus import { useUserStore } from /store/user 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 token } return config }) // 响应拦截器统一处理业务结果 request.interceptors.response.use( response { const res response.data if (res.code 200) { return res.data } if (res.code 401) { localStorage.removeItem(token) router.push(/login) ElMessage.error(登录已过期请重新登录) return Promise.reject(new Error(未授权)) } ElMessage.error(res.message || 请求失败) return Promise.reject(new Error(res.message || Error)) }, error { ElMessage.error(网络异常请稍后重试) return Promise.reject(error) } ) export default request这里有个经验之谈token没过期直接跳登录页其实不太友好好的做法是弹提示然后过一两秒再跳转。但这种细节对毕设来说不是关键功能做个跳转就行。3.3 工单列表与报工表单的核心页面实现工单管理页面是前端最核心的页面包含搜索条件、表格展示、新增弹窗、报工弹窗这些元素。用Element Plus的el-table加el-dialog组合做代码清晰度很高。工单表格列建议展示工单编号、产品名称、计划数量、已完成数量、状态、优先级、创建时间、操作按钮。状态列用标签渲染颜色区分一眼就能看出哪些工单在进行中。报工表单代码可以这样写el-dialog v-modelreportVisible title生产报工 width500px el-form :modelreportForm :rulesreportRules refreportFormRef el-form-item label工序名称 propprocessName el-input v-modelreportForm.processName placeholder请输入工序名称 / /el-form-item el-form-item label报工数量 propreportQuantity el-input-number v-modelreportForm.reportQuantity :min1 :max9999 / /el-form-item el-form-item label工时 propworkHours el-input-number v-modelreportForm.workHours :min0 :max24 :precision1 :step0.5 / /el-form-item /el-form template #footer el-button clickreportVisible false取 消/el-button el-button typeprimary clicksubmitReport确 定/el-button /template /el-dialog提交报工时要注意前端做好二次确认防止误触提交。因为报工数据一旦写入就影响工单状态和统计数字这个操作在工厂里是有严肃业务含义的前端交互上要给用户明确的反馈。3.4 ECharts生产看板的实现方式看板页面是展示系统价值感最强的部分我用ECharts实现近7日产量趋势图、工单状态分布饼图、合格率柱状图这三个核心图表。ECharts在Vue中的使用方式很简单npm install echarts后在组件中引入并初始化script setup import * as echarts from echarts import { onMounted, ref } from vue const chartRef ref(null) onMounted(() { const chart echarts.init(chartRef.value) chart.setOption({ xAxis: { type: category, data: [周一, 周二, 周三, 周四, 周五, 周六, 周日] }, yAxis: { type: value }, series: [{ type: line, data: [120, 200, 150, 280, 190, 230, 260], smooth: true }] }) // 记得监听窗口变化让图表自适应 window.addEventListener(resize, () chart.resize()) }) /script template div refchartRef stylewidth: 100%; height: 350px;/div /template这个页面做出来视觉冲击力很强而且是直接用自己系统的数据展示的答辩时很有说服力。4. 环境准备、部署运行与常见问题排查4.1 本地开发环境搭建与系统启动流程环境准备这块我踩过不少坑列一下我推荐的标准配置组件推荐版本说明JDK1.8/11JDK8最稳JDK11也行Maven3.6后端依赖管理MySQL5.7/8.0数据库Node.js14/16前端构建环境npm6/7/8随Node自带数据库初始化不分两步先用CREATE DATABASE workshop_demo DEFAULT CHARACTER SET utf8mb4;建库然后把建表SQL脚本导进去直接source或者用Navicat执行都行后端启动方式最简单的是直接运行SpringBoot主类application.yml里配置好数据源server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/workshop_demo?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImplserverTimezoneAsia/Shanghai这个配置一定要带上否则MySQL 8.0会报时区错误。map-underscore-to-camel-case开启后数据库字段create_time就能自动映射到Java属性createTime省得你自己写一堆TableField注解。前端启动npm install npm run dev默认端口是5173如果和后端接口交互需要配置开发环境代理。在vite.config.js里export default defineConfig({ server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } })这样前端请求/api/user/list就会被代理到后端http://localhost:8080/api/user/list避免了开发环境跨域问题。生产部署时前端构建出来的静态资源可以直接放到Nginx里再由Nginx把/api代理到后端jar包这是最经典的部署架构。4.2 开发中常见的异常与解决方案速查表我把实际开发中比较高频的问题整理成一张表照着排查会快很多异常/现象排查方向解决方案接口返回404控制器路径写错或前端代理未生效检查RequestMapping路径和控制台请求URL数据库连接失败驱动版本、时区、账号密码加上serverTimezoneAsia/Shanghai检查驱动中文乱码数据库字符集或连接编码不对建库用utf8mb4连接串加characterEncodingutf8前端请求跨域前后端端口不一致开发用代理生产用Nginx转发MyBatis-Plus分页失效缺少分页插件配置配置PaginationInnerInterceptor返回时间格式不对没指定格式化字段上写JsonFormat(pattern...)删除数据提示外键冲突有关联表数据先删子表或改用逻辑删除分页插件配置真是个容易被忽略的细节PaginationInnerInterceptor要注册为Spring Bean否则分页查询直接返回全量数据Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }4.3 代码细节处理心得几个常见的代码细节我在实际开发中花了不少时间才搞明白这里直接分享给你主键策略尽量用TableId(type IdType.AUTO)自增主键。虽然雪花算法听起来高大上但自增主键在MySQL里查询和索引维护效率更好实现也更简单毕设场景够用了。逻辑删除工厂的业务数据不建议物理删除尤其是用户和工单。用TableLogic注解配置逻辑删除字段好处是误删可以恢复而且代码无侵入TableLogic private Integer deleted;密码存储一定不要明文存密码用Spring Security自带的BCryptPasswordEncoder加密。这个类自带盐值同一密码加密出来的结果都不同安全性明显更好代码也就一行String encodedPassword new BCryptPasswordEncoder().encode(rawPassword);全局异常处理如上文所说用RestControllerAdvice统一拦截。像空指针、下标越界这类异常前端能看到统一的JSON错误提示而不是Tomcat默认的错误页。5. 项目亮点整理与答辩/课设演示技巧5.1 这个系统可以讲出来的技术亮点做毕设答辩时光说“我实现了增删改查”是不够的得把技术细节转化成亮点。我总结几个你可以重点讲的点亮点一前后端完全分离RESTful API设计规范接口用RESTful风格设计GET查询、POST新增、PUT更新、DELETE删除URL资源化设计比如GET /api/orders表示获取工单列表POST /api/orders表示创建工单。配合统一返回结果ResultT和全局异常处理整个接口层的设计是规范的、统一的。亮点二JWT无状态认证拦截器统一鉴权这个可以展开讲讲为什么不用Session而用JWT。Session在分布式环境下要解决Session共享问题而JWT把用户信息编码在token里服务端无状态天然适合前后端分离和横向扩展。亮点三事务保证数据一致性报工功能设计为单事务操作任何一步失败都会整体回滚确保报工记录和工单数量更新不会出现“报了数量但工单没更新”的不一致情况。亮点四数据可视化看板用ECharts对接真实业务数据将产量、合格率、工单状态直观展示。开发过程中不造数据全部用真实报工记录渲染这样更有说服力。5.2 演示场景设计建议答辩演示不要上来就点菜单先登录系统然后按照一个完整业务流程走一遍。我建议设计成这样的演示路径登录 - 创建并下达一个工单 - 切到操作工视角报工两次 - 切到质检员视角录入质检结果 - 回到看板页面展示刚才的数据如何反馈到图表上。这样演示下来业务闭环感非常强评委能清楚看到“报工后图表变了”这个比空谈什么技术架构都更有说服力。5.3 可以继续扩展的方向这个项目收尾后如果你想进一步提升至少还有几个方向值得扩展引入Redis做缓存缓存热点菜品或商品列表降低数据库压力引入WebSocket推送生产看板实时刷新不用刷新页面就能看到最新数据引入Spring Security替换手写JWT拦截器获得更完整的权限模型RBAC增加报表导出用EasyPOI把产量报表导出为Excel把部署迁移到Docker用docker-compose一键启动MySQL后端前端扩展方向挑一个深入下去就是加分项比如Redis缓存了用户信息、ECharts对接了实时数据这些都可以补充进文档里。我自己做这套系统最大的体会是真正耗时间的不是写代码而是规划和联调。表结构设计花了我整个前期一半的时间但想清楚之后写代码就顺畅了前后端联调时遇到的大部分问题都集中在跨域、字段名不匹配、时间格式不一致上提前约定好规范和格式能省下大量沟通成本。如果你是课程设计时间不够的话可以砍掉设备管理和物料模块保留登录、工单、报工、质检、看板就足够完整了。本科毕业设计想要拿高分强烈建议把质量统计和可视化看板做扎实再加上一两个扩展点完全可以达到很好的水平。最后提醒一句代码能跑通不等于项目做完了花点时间把数据库设计说明、核心接口文档、部署文档、演示脚本整理好这部分投入对你的答辩帮助很大甚至比你多写几个接口都重要。