SpringBoot+Vue+MySQL构建企业资产管理系统:从设计到部署全解析
2026/9/19 0:55:33 网站建设 项目流程

毕业设计的选题从来都是个技术活,资产管理系统这五个字每年都能在题目清单里看到,但它真是个好方向——需求明确、前后端技术都能覆盖、业务逻辑完整、答辩时也容易讲出东西。尤其用 SpringBoot + Vue + MySQL 这套组合来做,几乎是一条已经被踩平的路,网上模板虽然多,但大多数源码质量参差不齐,要么直接能跑,要么跑起来全是坑。这篇文章我会把这套系统的完整设计思路、数据库模型、前后端实现要点、部署细节和写论文的章节思路全部拆开讲清楚。

1. 为什么企业资产管理系统用这套技术栈最稳

资产管理系统不管怎么包装,本质就是一个带状态流转的 CRUD 系统,核心是"资产"这个对象贯穿始终。选 SpringBoot + Vue + MySQL 的原因很简单:它恰好覆盖了、前后端分离、关系型数据存储三个关键点,而且每一层都有大量成熟的轮子和踩坑案例,对毕设来说容错率极高。

SpringBoot 解决的是后端开发效率问题。不需要像传统 SSM 项目那样写一堆 XML 配置,依赖自动装配、内嵌 Tomcat、一键启动,这些特性让项目可以快速跑起来,把时间节省到真正核心的业务逻辑上。而且 SpringBoot 的生态里 Spring Security、MyBatis-Plus、Redis 这些组件跟它配合非常顺滑,权限控制、数据持久化、缓存需求都能找到现成方案。

Vue 解决的是前端交互和维护性的问题。资产管理涉及表格、表单、弹窗、状态标签、部门树、审批流程展示,Vue 的组件化开发模式让这些 UI 拆得很干净。配合 Element UI 或 Element Plus,几乎不用自己写 CSS 就能搭出一个像模像样的后台管理界面,这在毕设时间有限的情况下,是非常重要的加分项。

MySQL 更不用多说,开源、免费、资料多、各种版本的问题在网上一搜就有答案。资产数据本身带有鲜明的结构化特征——资产编号要唯一、分类要层级、状态要枚举、领用记录要关联用户和部门,这些用关系型数据库表达非常自然。

关键在于,这套组合在答辩审核时非常好讲。评审老师大概率问的就是"你的系统怎么实现前后端交互""表和表之间是什么关系""遇到过什么问题怎么解决的",而这两个问题在这套技术栈下有非常标准的回答路径,不容易被深挖到死角。不过不要以为选型稳就万事大吉,真正的工程量在于:功能设计是否完整、数据表设计是否合理、代码结构是否清晰、部署文档是否能让别人照着跑起来。下面我会按实际做项目时的顺序,把每个环节的关键点都过一遍。

2. 开工前必须先理清的功能边界:资产系统的核心业务闭环

很多同学拿到这个题目,第一反应是打开 IDEA 写代码,这是最致命的错误。资产管理系统听起来简单,但如果你没想清楚业务流程,写到一半很容易发现表结构设计漏了、状态流转对不上、前后端接口传参对不齐,改起来非常痛苦。我先说说一般企业资产管理系统的标准功能边界,你可以根据自己的需求做增删。

2.1 资产台账管理是绝对的地基

整个系统最核心的数据就是资产本身。每一条资产记录至少要包含:资产编号、资产名称、资产分类、规格型号、购置日期、购置价格、使用部门、当前状态、存放位置、责任人、备注信息。资产编号是企业实际运作中用来追踪实物的唯一标识,所以它必须有唯一索引,很多系统还会用条码或二维码来对应。

资产分类通常做成两级或三级,比如"电子设备-电脑-笔记本电脑",这在数据库里就是一个分类表,用父子 ID 来维护层级关系。分类带来的好处是统计报表的时候可以按不同粒度汇总资产数量和价值。资产状态的枚举值一般有:在库、领用中、维修中、已报废、已处置,这个状态字段几乎贯穿所有功能。

2.2 资产的全生命周期是串联功能的线索

资产从入库开始,到报废结束,中间会经历领用、归还、维修、调拨等操作。我建议先把这条流程在纸上画通:

  • 资产入库:采购来的新资产录入系统,状态为"在库",录入时校验资产编号不重复。
  • 资产领用:员工申请领用某台资产,管理员审核通过后,资产状态改为"领用中",并生成一条领用记录,关联领用人、领用部门、领用时间。
  • 资产归还:员工归还资产,管理员确认后状态回到"在库",同时更新归还记录。
  • 资产维修:使用过程中的资产损坏,登记维修单,状态改为"维修中",维修完成后再回到"在库"或"领用中"。
  • 资产报废:无法继续使用的资产提交报废审批,通过后做逻辑删除,状态标记为"已报废"。

这套流程的好处是每张业务表都有一条自己的时间线,而且和资产主表的状态字段互相照应,审批环节又给了权限管理一个落脚点。

2.3 权限模型:三种角色是最常见且合理的划分

资产管理系统里的角色权限,大部分毕设做到三种就够了:系统管理员、部门管理员、普通员工。系统管理员拥有所有权限,包括用户管理、部门管理、资产管理、审批管理和系统日志;部门管理员只能管理本部门的资产和操作记录;普通员工只能查看资产信息和发起领用、归还申请。

权限实现上建议直接采用 RBAC 模型,也就是"用户-角色-权限"三层结构。菜单路由可以根据角色动态生成,后端接口用注解区分访问级别。毕设阶段不建议过度设计成细粒度的按钮权限,如果你用 Shiro 或 Spring Security,做好接口级别的权限拦截就完全可以支撑答辩时的提问了。

2.4 关键功能选配:报表统计可以大幅提升项目档次

如果你想让项目和普通模板拉开差距,建议加上数据统计功能。比如首页仪表盘展示资产总数、资产总值、部门资产分布、各状态资产数量占比,这些用 ECharts 图表展示,视觉效果好,答辩时也很加分。数据来源其实非常简单,就是数据库里的聚合查询,比如对资产表按部门和状态 group by 统计,再按月份统计购置趋势。

还有一个容易被忽视的功能是操作日志,建议把登录、资产新增、领用审核、数据修改这些关键操作记录到一张日志表里。这个功能不仅是企业真实需求,还是一个很好的答辩谈资,当老师问"你的系统怎么保证数据安全审计"时,这就是你的答案。

3. 数据库设计:资产系统的表结构规划与字段细节

数据库设计是这个项目的灵魂,表结构合理,后端代码写起来会非常顺畅。我把自己整理过多次的表结构方案说一遍,这个方案是从实际项目里提炼出来的,字段没有堆砌冗余,也没有为了省事把外键全部去掉。

3.1 表清单与关系划分

整套系统的表大致分成三类:基础数据表、业务流转表、系统支撑表。

类别表名说明
基础数据sys_user用户表,存登录信息和关联部门
基础数据sys_role角色表,管理员/部门管理员/普通员工
基础数据sys_user_role用户角色关联表,多对多
基础数据sys_department部门表,树形结构
基础数据asset_category资产分类表,父子层级
基础数据asset_info资产信息主表
业务流转asset_use_record资产领用/归还记录表
业务流转asset_repair_record资产维修记录表
业务流转asset_scrap_record资产报废记录表
业务流转asset_approval审批记录表
系统支撑sys_operation_log操作日志表
系统支撑sys_menu菜单权限表

资产主表和业务流转表是一对多关系,资产可以有多条领用记录、维修记录、报废记录;业务流转表通过 user_id 和 department_id 关联到用户和部门,这样查询"某个员工领过哪些资产"时只需要一条 join 就能完成。

3.2 资产信息表的字段设计

这是最核心的一张表,我给出一个可以直接借鉴的字段版本:

CREATE TABLE `asset_info` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `asset_code` varchar(64) NOT NULL COMMENT '资产编号', `asset_name` varchar(128) NOT NULL COMMENT '资产名称', `category_id` bigint(20) DEFAULT NULL COMMENT '分类ID', `specification` varchar(255) DEFAULT NULL COMMENT '规格型号', `purchase_date` date DEFAULT NULL COMMENT '购置日期', `purchase_price` decimal(10,2) DEFAULT NULL COMMENT '购置价格', `supplier` varchar(128) DEFAULT NULL COMMENT '供应商', `department_id` bigint(20) DEFAULT NULL COMMENT '当前使用部门', `user_id` bigint(20) DEFAULT NULL COMMENT '当前使用人', `status` tinyint(4) DEFAULT '0' COMMENT '资产状态:0在库 1领用中 2维修中 3已报废', `location` varchar(255) DEFAULT NULL COMMENT '存放位置', `picture` varchar(255) DEFAULT NULL COMMENT '资产图片路径', `remark` varchar(500) DEFAULT NULL COMMENT '备注', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `deleted` tinyint(4) DEFAULT '0' COMMENT '逻辑删除标记', PRIMARY KEY (`id`), UNIQUE KEY `uk_asset_code` (`asset_code`), KEY `idx_category_id` (`category_id`), KEY `idx_department_id` (`department_id`), KEY `idx_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='资产信息表';

这里有几个细节值得解释。资产编号要加唯一索引,这既是业务要求也是防重复录入的技术保障;状态字段用 tinyint 而不是字符串,是为了查询效率和代码里维护枚举的方便;逻辑删除标记是几乎所有企业系统都用的做法,资产报废后不物理删除,只是标识成已报废,这样历史记录是可追溯的。还有一个容易忽略的点是department_iduser_id这两个字段,资产的状态是"在库"时这两个字段可能为空,但一旦领用就必须填上,这个约束可以在后端业务逻辑里判断。

3.3 领用记录表的设计与状态机实现

领用记录表把资产领用和归还合并到一张表里,好处是可以轻松统计每个资产的"累计使用次数"和"累计使用时长"。关键字段如下:

CREATE TABLE `asset_use_record` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `asset_id` bigint(20) NOT NULL COMMENT '资产ID', `user_id` bigint(20) NOT NULL COMMENT '领用人ID', `department_id` bigint(20) DEFAULT NULL COMMENT '领用部门ID', `type` tinyint(4) DEFAULT '1' COMMENT '记录类型:1领用 2归还', `operation_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间', `remark` varchar(255) DEFAULT NULL COMMENT '备注', PRIMARY KEY (`id`), KEY `idx_asset_id` (`asset_id`), KEY `idx_user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='资产领用归还记录表';

领用和归还统一存到这张表,通过type区分操作方向,整个资产的使用轨迹就是一条完整的流水。状态机逻辑在后端实现:领用时检查资产状态是否为"在库",如果是则改成"领用中",插入一条 type=1 的记录;归还时检查是否"领用中",改成"在库",插入 type=2 的记录。这个逻辑不算复杂,但它是整个系统最容易出 bug 的地方,后面的后端实现部分我会展开讲。

3.4 其他表的字段结构设计参考

维修记录表需要字段:资产ID、报修人、故障描述、维修费用、维修状态(待维修/维修中/已完成)、维修时间、完成时间、备注。报废记录表需要字段:资产ID、申请人、报废原因、审批状态、审批人、审批时间、备注。审批记录表可以不单独建表,直接在维修表和报废表里通过approval_status字段管理,但如果想做得更通用,单独建一张审批表,字段包括业务类型(领用/维修/报废)、业务ID、申请用户ID、审批人ID、审批结果、审批意见、审批时间,会更加灵活。

部门表是树形结构的,字段包括:部门ID、父部门ID、部门名称、负责人、联系电话、排序。用户表在基础字段之外要注意密码的存储方式,不能明文存,用 BCrypt 或 MD5 加盐加密。我强烈推荐用 MyBatis-Plus 的MP插件来自动填充create_timeupdate_time,省去每次手动维护的麻烦。

4. 后端 SpringBoot 实现:分层结构、资产状态流转与接口设计

后端部分的重点不是把代码堆出来,而是要有一个清晰的层次。我见过太多毕设项目把 Controller 里直接写 SQL,虽然能跑,但答辩时老师追问代码结构就露馅了。规范的写法是 Controller -> Service -> Mapper 三层,外加统一的 VO/DTO 类做参数和返回值的隔离。

4.1 工程结构与基础配置

工程结构建议按模块分包:

com.example.asset ├── controller // 接口层 ├── service // 业务逻辑层 │ └── impl // 业务实现 ├── mapper // 数据访问层 ├── entity // 实体类 ├── dto // 数据传输对象 ├── vo // 视图返回对象 ├── config // 配置类 ├── common // 通用工具、统一返回、异常处理 └── security // 权限相关

依赖方面建议用 Spring Boot 2.7.x 而不是最新的 3.x,原因在于 3.x 要求 JDK17,很多同学的机器上装的是 JDK8,而且毕业设计环境里最常见的也是 JDK8 + Spring Boot 2.x 的组合。MyBatis-Plus 选择 3.5.x 版本,它自带分页插件和代码生成器,可以省掉大量重复的 Mapper XML 编写工作。权限控制可以选用 Sa-Token,比 Spring Security 简单太多,学习和调试成本低,适合毕设这种规模的项目。

application.yml里的关键配置要注意几个点:数据库连接串要指定serverTimezone=Asia/Shanghai,否则日期写入会差 8 个小时;MyBatis-Plus 的逻辑删除配置要打开;如果使用 Swagger/Knife4j 接口文档,要在配置里放行这些路径。

4.2 实体类与统一返回结构

实体类直接映射数据库表,在 MyBatis-Plus 中通过@TableName注解指定表名,通过@TableId指定主键策略。资产实体的状态字段可以用 Integer 类型存活,或者定义一个AssetStatusEnum枚举保证代码可读性。统一返回结构非常重要,我一般定义一个Result<T>类,包含codemessagedata三个字段,成功返回 200,业务异常返回自定义编码。这样前端 Axios 拦截器可以统一处理错误提示,不用每个请求都写 if-else 判断。

4.3 资产状态流转的并发与事务问题

领用和归还的逻辑虽然看起来简单,但有个隐藏的坑:如果两个人同时领用同一台资产,就可能出现超领的问题。处理方式有几种,最简单的做法是在asset_info表的记录行上加乐观锁,MyBatis-Plus 已经内置了@Version注解的支持,更新时自动带上版本号作为条件,如果版本号对不上就更新失败。另外一个更直接的办法是对状态字段用 update 语句做条件更新,比如:

UPDATE asset_info SET status = 1, user_id = #{userId} WHERE id = #{assetId} AND status = 0

通过判断更新行数是否为 1 来确定是否抢占成功。这个方法不需要额外加版本号字段,简单高效,非常适合这个场景。领用逻辑不仅涉及资产的更新,还涉及领用记录的插入和后端日志的记录,所以必须加@Transactional事务控制,保证这些操作要么全部成功,要么全部回滚。

4.4 关键接口代码示例

资产分页查询接口是系统里最常用的接口,我用代码示例说明:

@ApiOperation("分页查询资产列表") @GetMapping("/page") public Result<IPage<AssetVO>> page(AssetQueryDTO queryDTO) { Page<Asset> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize()); LambdaQueryWrapper<Asset> wrapper = new LambdaQueryWrapper<>(); wrapper.like(StringUtils.isNotBlank(queryDTO.getAssetName()), Asset::getAssetName, queryDTO.getAssetName()) .eq(queryDTO.getCategoryId() != null, Asset::getCategoryId, queryDTO.getCategoryId()) .eq(queryDTO.getStatus() != null, Asset::getStatus, queryDTO.getStatus()) .eq(queryDTO.getDepartmentId() != null, Asset::getDepartmentId, queryDTO.getDepartmentId()) .orderByDesc(Asset::getCreateTime); IPage<Asset> result = assetService.page(page, wrapper); return Result.success(convertToVO(result)); }

这里的查询条件全部用LambdaQueryWrapper动态拼装,前端传入什么条件就拼接什么条件,可读性好也能避免 SQL 注入。分页参数使用 MyBatis-Plus 的分页插件,配置一个PaginationInnerInterceptor就能用,它底层自动生成LIMIT语句。

领用资产的接口示例:

@ApiOperation("领用资产") @PostMapping("/use") public Result<?> useAsset(@RequestBody AssetUseDTO useDTO) { Asset asset = assetService.getById(useDTO.getAssetId()); if (asset == null) { return Result.error("资产不存在"); } if (asset.getStatus() != 0) { return Result.error("资产当前状态不可领用"); } boolean success = assetService.useAsset(useDTO); return success ? Result.success() : Result.error("领用失败,请重试"); }

这里有一个隐性需求:普通员工发起领用应该走审批流程,而管理员可以直接领用。所以useAsset方法里要根据当前登录用户的角色判断是否要调用审批服务,或者把领用请求的状态分成"待审批"和"已生效"。是否需要审批取决于你的功能划分,做成"普通员工申请->管理员审核->资产状态变更"会让系统流程更完整。

4.5 权限控制的实现思路

用 Sa-Token 做权限控制时,用户登录成功后会签发一个 Token,前端每次请求在请求头携带,后端通过拦截器判断是否登录,再通过注解判断接口权限。比如:

@SaCheckPermission("asset:add") @PostMapping("/add") public Result<?> addAsset(@RequestBody AssetDTO assetDTO) { ... }

菜单权限和按钮权限可以统一从数据库读取,登录时把用户拥有的权限编码列表放在StpUtil.getSession()里,权限校验时直接比对,这样权限系统是动态的,改数据库就能控制接口访问,不需要改代码。

5. Vue 前端的页面规划与交互细节

前端和后端一样,也存在版本选择的问题。如果你打算用 Vue2 + Element UI 还是有一定量的历史资料可以查;但新项目我建议直接上 Vue3 + Element Plus + Vite,性能更好,而且 Element Plus 的组件和文档都更完善。不过要注意 Vite 要求 Node.js 版本在 16 以上,装环境时别用太老的版本。

5.1 前端工程结构划分

包管理器建议用 npm 或 pnpm。项目目录按照"页面-组件-接口"三个维度拆:

src ├── api // 接口请求封装 │ ├── asset.js │ ├── user.js │ └── dashboard.js ├── assets // 静态资源 ├── components // 通用组件 ├── router // 路由配置 ├── store // 状态管理(Pinia) ├── views // 页面视图 │ ├── login │ ├── dashboard │ ├── asset │ ├── useRecord │ ├── repair │ ├── scrap │ └── system └── utils // 工具函数

路由的设计要考虑到角色的动态菜单。登录成功后,后端根据角色返回菜单列表,前端动态生成路由和侧边栏,这样普通员工不会看到"用户管理"菜单,管理员则能看到所有菜单。Pinia 里存用户信息和权限标记,刷新页面时重新拉取。

5.2 Axios 封装与请求拦截

Axios 不封装的话,每个页面都要重复写 token 注入和错误处理,所以必须有一个统一的请求模块:

import axios from 'axios' import { ElMessage } from 'element-plus' import { useUserStore } from '@/store/user' import router from '@/router' const service = axios.create({ baseURL: '/api', timeout: 10000 }) service.interceptors.request.use(config => { const userStore = useUserStore() if (userStore.token) { config.headers['Authorization'] = userStore.token } return config }) service.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 }, error => { if (error.response && error.response.status === 401) { ElMessage.error('登录已过期,请重新登录') router.push('/login') } else { ElMessage.error('网络异常,请稍后重试') } return Promise.reject(error) } ) export default service

Vite 的 dev server 里配置 proxy 把/api转发到后端的 8080 端口,这样开发时不会遇到跨域问题;生产环境部署时再由 Nginx 做反向代理,后面部署部分会细说。

5.3 资产页面与领用页面的交互设计

资产管理页是最核心的页面。布局上我建议的排列是顶部分四个筛选条件(资产名称、分类、状态、部门),中间一个"新增资产"按钮,下面是表格,表格操作列里根据状态显示不同的操作按钮:在库的可做"领用"和"编辑",领用中的可做"归还"和"维修登记",维修中的只能"维修完成",已报废的只有"详情"。

Element Plus 的el-table结合el-pagination完成分页,搜索条件变化时把页码重置为 1,这是很容易忽略的小细节。资产的"新增/编辑"可以共用一个el-dialog弹窗,通过判断是否传入资产 ID 来区分是新增还是编辑,表单校验用el-form内置的 rules 规则。

领用弹窗里至少要选择领用人,领用部门通过当前登录用户的部门自动填充,如果资产跨部门领用则弹窗里再加一个部门选择器。归还操作可以做成一个"确认归还"的弹出确认框,后端接口成功后用ElMessage.success提示并重新加载当前页数据。

5.4 仪表盘与统计报表的实现

仪表盘页面在 Vue 里的实现,建议用 ECharts。先要在package.json里安装echarts依赖,然后在组件里写一个initChart方法,用ref绑定 DOM 容器,在onMounted生命周期里初始化图表,最后记得在onBeforeUnmount里销毁实例避免内存泄漏。图表数据可以从后端一个聚合接口一次性返回,比如返回各状态数量、各部门资产数量、近半年购置趋势,前端直接塞进 ECharts 的 option 里。

有一个常见的坑是 ECharts 在el-tab或弹窗里初始化时容器宽度为 0,导致图表不显示。解决方法是等容器渲染完成后再调用init,或者在容器显示后调用chart.resize()。如果对 ECharts 不够熟,这个坑很可能会卡住你半天时间。

6. 部署上线、论文写作与交付材料整理的经验

毕设和普通课程作业最大的区别在于,除了"能跑"之外,你还要提交一套完整的材料,包括源码、数据库、论文、部署文档。很多同学项目做完了,结果不会部署,答辩时只能在 IDEA 里点运行,老师心里就会打个问号。所以部署这块一定不能马虎。

6.1 本地打包与服务器部署的完整流程

后端打包用 Maven 的package命令,建议跳过测试:

mvn clean package -DskipTests

打包后在target目录下会生成一个 jar 文件。直接运行:

java -jar asset-system.jar --spring.profiles.active=prod

生产环境的数据库连接配置可以放在application-prod.yml里,数据库地址从localhost:3306改成云数据库或服务器上的 MySQL 地址。前端打包是:

npm run build

生成dist目录,把 dist 目录下的所有文件放到 Nginx 的html目录下。Nginx 配置需要注意两点:一是把/api路径反向代理到后端的 8080 端口,否则前端请求都会 404;二是 Vite 构建默认使用 history 模式路由,刷新非首页时会 404,需要加一个 try_files 配置:

server { listen 80; server_name your-domain.com; location / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

服务器上还要装好 MySQL,并导入你本地导出的 SQL 文件,修改 root 密码或单独创建一个数据库账号。这一步建议写成部署文档,把每一步的命令行、截图都记录进去。

6.2 数据库初始化与测试数据准备

交付的 SQL 文件最好包含建表语句和必要的初始数据。初始数据至少要包含一个管理员账号(密码加密后的字符串)、3~4 个部门、几类资产分类、以及 10~20 条资产测试数据。填测试数据不是为了好看,而是为了让老师打开系统时第一眼就能看到效果,页面不至于空空荡荡。

6.3 论文的章节搭建思路

论文结构一般按绪论、相关技术、需求分析、系统设计、系统实现、系统测试、总结与展望来写。重点章节是系统设计和系统实现,系统设计里要放数据库 E-R 图、表结构说明文档、系统架构图;系统实现里要放核心功能页面的截图和关键代码说明。截图一定要截得干净,不要有乱七八糟的浏览器标签栏或桌面背景,这会显得很不专业。

测试章节建议做一个功能测试用例表,把每个模块、测试步骤、预期结果、测试结果列成一整个表。如果能加一点性能测试的说明会更好,比如用 Jmeter 压一下登录接口或分页查询接口,说明并发情况下系统表现稳定,这个能大幅提升论文的专业度。

6.4 部署文档、答辩 PPT 与演示路径设计

部署文档的作用是让任何一个不熟悉你项目的人,能从头到尾把项目跑起来。我的习惯是文档里只写必须的命令和配置项,不写过程性废话。至少包含:环境要求(JDK8、Maven 3.6+、Node 14+、MySQL 5.7 或 8.0)、数据库初始化步骤、后端启动命令、前端打包命令、Nginx 配置示例、访问地址与默认账号。如果交付对象是在校同学,还可以额外附一个"常见问题排查"部分,把数据库连不上、端口占用、Node 版本不兼容这几个典型问题写进去。

答辩演示时我建议按这条路径走:用管理员登录 -> 展示仪表盘的数据统计 -> 新增一台资产 -> 修改资产信息 -> 领用这台资产 -> 归还资产 -> 登记维修 -> 报废流程 -> 查看操作日志。这条路径把系统的核心功能全部覆盖了一遍,而且有明确的故事线,老师跟着你的操作就能理解系统的完整业务逻辑。

7. 实操过程中最常见的坑:环境、版本与联调排错记录

做这个项目的过程中,我踩过不少坑,有些坑几乎每个用这套技术栈的人都会遇到。我按报错出现的概率排序,把问题和解决方案一并给出。

7.1 SpringBoot 版本引起的连带问题

如果你创建新项目时 Spring Initializr 默认拉取了 3.x 版本,而本机 JDK 是 8,启动时会直接报class file version 61.0UnsupportedClassVersionError。解决思路是降低 SpringBoot 版本到 2.7.x,同时把 Maven 仓库里的依赖重新拉取。还有一种情况是 SpringBoot 2.x 和 MySQL 8.0 的驱动兼容问题,5.1.x 的驱动连 MySQL 8.0 会报认证协议错误,解决方法是升级 mysql-connector-java 到 8.0.x,并在 JDBC URL 里加上useSSL=false&allowPublicKeyRetrieval=true

7.2 Node 环境版本与依赖安装失败

前端最常见的报错是node-sass安装失败,它需要从 GitHub 下载编译好的二进制文件,网络不好几乎必挂。新项目完全没必要用 node-sass,Vite + sass 或纯 CSS 就能搞定,如果项目是别人给的源码里面用了sass-loadernode-sass,建议换成dart-sass(也就是sass包)。

Node 版本太高也可能导致依赖兼容问题。比如 Node 18 搭 Vue CLI 4.x 时经常报Error: error:0308010C:digital envelope routines::unsupported,这是 OpenSSL 版本变化引起的。解决方式有两个:一个是用 Node 16 LTS 版本,另一个是在启动命令前加NODE_OPTIONS=--openssl-legacy-provider。我个人更推荐前者,少折腾。

7.3 前后端联调时的跨域与接口格式不统一

开发环境跨域最常见的报错是Access-Control-Allow-Origin。最简单的方案是前端在 Vite config 里配置 proxy,让/api开头的请求转发到http://localhost:8080,浏览器看到的请求是同源的,就不会有跨域问题。后端也可以配置一个 CORS 过滤器,但前后端分离项目里建议优先考虑 proxy 方案,这样生产环境切 Nginx 也更平滑。

接口格式不统一的问题也很典型。比如获取资产列表接口返回的数据里createTime字段是 "2024-05-20T10:00:00",前端显示时格式不对。建议后端在application.yml里配置统一的 Jackson 日期格式,或者直接在实体类字段上用@JsonFormat注解指定pattern = "yyyy-MM-dd HH:mm:ss",前端拿到字符串后直接展示就行。

7.4 MyBatis-Plus 的常见坑

MyBatis-Plus 虽然好用,但有两个坑要注意。第一个是逻辑删除配置了以后,自定义写 SQL 时如果用了select *并拼接了查询条件,可能把逻辑删除条件覆盖掉,解决办法是自定义 SQL 里也手动加上deleted = 0条件。第二个是 MyBatis-Plus 的updateById默认不会更新值为 null 的字段,如果想把某个字段更新成 null,要使用UpdateWrapperset方法。

7.5 盒装数据库导入导出时的编码问题

从 MySQL 导出 SQL 时如果字符集不对,导入到服务器后中文全部变成乱码。导出导入统一增加--default-character-set=utf8mb4参数,创建数据库时指定字符集为utf8mb4,建表语句里也显式加上DEFAULT CHARSET=utf8mb4,三层都设置好后基本不会再出现乱码。这个坑虽然小,但一旦出现就会让整个系统显得非常不专业,建议提前预防。

8. 从毕设到真实项目的差距:给即将答辩的同学一些实在建议

做完这套系统之后,我最大的感受是:毕设项目的分数不在于用了多高级的框架,而在于你能不能把每一个功能为什么这样设计讲清楚。很多同学能跑通项目,但离开代码就不会说话,老师随便问一句"你这条数据怎么校验的"就愣住了。

建议你自己在答辩前做一次"模拟评审",把你项目的所有功能从上到下过一遍,对每个功能提前写一份回答草稿,核心问题无非是:表结构怎么设计的、为什么这么设计、接口如何校验参数、某个异常情况你处理了没有、项目中你印象最深的坑是什么怎么解决的。前三个问题考察基本功,第四个问题是加分项。如果你能说出"我踩过 MyBatis-Plus 逻辑删除和自定义 SQL 冲突的坑,最后改用手动加条件解决了",这一句话比你在论文里抄三页理论知识都更有说服力。

另外,如果时间来得及,建议在项目中加一个不太起眼但完整的特性,比如资产图片上传、Excel 导入导出或验证码登录。这些功能代码量不大,但能让老师觉得你的系统考虑到了真实使用场景。Excel 导入导出可以用 EasyExcel,验证码登录可以用 Hutool 的 CaptchaUtil 工具类,都是现成轮子。

最后再分享一个小技巧:部署文档和论文里的系统架构图,不要随手画一张丑图。架构图用 draw.io 整理,数据库 E-R 图用 Navicat 或 MySQL Workbench 自动生成再微调,截图统一用 Snipaste 截取并统一命名。这些细节虽然看着不起眼,但在打印论文或答辩展示时,你会在质感上和 "随手交一份" 的项目拉开明显的差距。这套系统做完一遍,你对 SpringBoot、Vue、MySQL 三者的理解会有一个质的变化——从"会写 demo"到"能独立掌控一个小型项目的全流程",这才是毕业设计真正的收获。

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

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

立即咨询