SpringBoot 3 + Vue.js 3 构建高校资产管理系统的全栈实践
2026/9/5 16:10:33 网站建设 项目流程

简介:本资源是一套面向计算机专业本科生的2025届毕业设计/课程设计实战项目,聚焦高校资产管理业务场景,解决资产登记、动态监控、预约使用与报废处置等核心管理痛点,适用于Java全栈开发入门到进阶学习者。压缩包共6个文件(123.09MB),含前后端完整源码(Vue.js3管理后台+用户前台、SpringBoot3后端)、MySQL8数据库脚本(含建表与初始数据)、需求文档(.docx格式)、系统操作录屏(mp4)及返修说明材料,覆盖从需求分析、技术实现到部署验证的全流程交付物。已有74人学习下载,配套B站双视频——录屏教程完整呈现开发全过程,启动教程手把手指导环境配置与运行,显著降低上手门槛;源码结构规范,模块划分清晰(资产/用户/审批/统计等),数据库设计贴合高校实际业务逻辑,具备直接复用与二次开发价值。

1. 项目概述与核心价值

最近几年,但凡涉及到计算机、软件工程、信息管理这类专业的毕业设计,选择做一个“XX管理系统”几乎是主流。而“高校资产管理信息系统”更是其中的常青树,几乎每年都能看到。但同样是这个题目,从早期的JSP+Servlet,到后来的SSM,再到现在的SpringBoot+Vue,技术栈的迭代背后,反映的是企业对全栈开发能力要求的提升。今天,我想以一个过来人,也是项目评审者的角度,和你聊聊如何用SpringBoot 3Vue.js 3这套当前企业级开发的热门组合,把这个“老题目”做出新意,做出深度,让它不仅仅是一份能应付答辩的作业,更能成为你简历上亮眼的一笔。

这个系统的核心目标很明确:解决高校内部固定资产(如实验设备、办公家具、电脑等)从采购入库、日常领用、维修保养到最终报废的全生命周期管理难题。传统的手工台账或简单的Excel表格,在资产数量庞大、部门分散、流转频繁的高校场景下,极易导致账实不符、查找困难、责任不清。我们做的,就是用一个Web应用将这些流程数字化、可视化,实现资产信息的精准追踪和高效盘点。对于你而言,这个项目的价值在于:它完整覆盖了后端API开发(SpringBoot 3)前端交互构建(Vue 3 + Element Plus)、**数据库设计(MySQL)**以及前后端分离架构的工程化实践,是检验你Java全栈能力的绝佳试金石。

2. 技术选型背后的逻辑与考量

为什么是SpringBoot 3 + Vue.js 3?这绝不是随大流,而是基于技术趋势、开发效率和项目需求综合判断的结果。

2.1 后端:为什么坚定选择SpringBoot 3?

首先,SpringBoot 3是一个必须的选项,但选择其3.x版本而非更常见的2.x,这里有讲究。SpringBoot 3基于Spring Framework 6和Java 17+,这是一个重要的分水岭。

  1. 拥抱Java LTS版本:SpringBoot 3最低要求Java 17。对于毕业设计,使用最新的长期支持(LTS)版本,能直接向答辩老师或未来面试官展示你跟进主流技术的能力。虽然你可能在本地配置环境时会被“JAVA_HOME”和“Path”折腾一下(记得用java -version检查),但这步是值得的。我遇到过有同学项目用了Java 8,被问及对新特性了解时哑口无言的尴尬。

  2. 原生镜像与性能前瞻:SpringBoot 3为GraalVM原生镜像提供了更好的支持。虽然毕业设计大概率不会用到,但在项目文档或答辩中提及这一点,可以体现你对技术前沿的关注。你可以简单描述:“我们的后端服务未来可以借助GraalVM编译为原生可执行文件,启动速度更快,内存占用更低,适合云原生部署。” 这绝对是一个加分项。

  3. ** Jakarta EE 9+**:这是SpringBoot 3一个重大的、不兼容的变更,包命名空间从javax.*迁移到了jakarta.*。这意味着如果你引入一些旧的、未更新的依赖(比如某些版本的javax.servlet相关JAR),就会直接报错。踩坑提示:在引入如spring-boot-starter-web,spring-boot-starter-data-jpa等依赖时,SpringBoot 3已经帮你处理好了。但要特别注意你额外引入的第三方库,务必检查其是否兼容Jakarta EE 9+。一个常见的错误是连接池配置,确保使用较新版本的依赖。

2.2 前端:Vue.js 3的组合式API优势

相较于Vue 2的Options API,Vue 3的组合式API(Composition API)是本次项目的亮点。

  1. 更好的逻辑复用与组织:资产管理中有很多重复逻辑,比如一个“资产选择器”组件,可能在入库、领用、转移多个页面用到。在Vue 2中,你可能要用mixins,但mixins会有命名冲突和来源不清的问题。在Vue 3中,你可以用一个useAssetSelector.js的组合式函数来封装这块逻辑,然后在任何组件中import { useAssetSelector } from ‘@/composables/useAssetSelector’并调用,代码就像堆积木一样清晰、可复用。

  2. 对TypeScript的友好支持:虽然毕业设计不强制用TS,但我强烈建议你尝试。在定义资产、用户等接口时,使用TypeScript能极大减少因属性名拼写错误导致的bug。例如,定义一个Asset接口,那么在任何使用资产对象的地方,IDE都会给你智能提示和类型检查,这对大型项目维护至关重要。

  3. 配套生态成熟:UI库我们选用Element Plus,它是基于Vue 3的,对TS支持好,组件丰富,足够满足管理后台的需求。路由用Vue Router 4,状态管理对于这个规模的项目,如果组件间通信不复杂,其实可以不用Pinia/Vuex,直接用组合式API配合provide/inject或者事件总线也能搞定,这能让你的项目结构更简洁。但如果资产状态(如当前盘点中的资产列表)需要在很多不相关的组件间共享,那上一个Pinia会是更规范的选择。

2.3 数据库与中间件:务实的选择

  • MySQL 8.x:没什么悬念,关系型数据库是管理这类结构化、关联性强数据的最佳选择。资产表、分类表、部门表、用户表、流水记录表,它们之间的外键关联能很好地保证数据一致性。记得在设计表时,为高频查询字段(如资产编号、资产名称、所属部门)加上索引。
  • Redis(可选但推荐):如果你的系统设计了登录功能(肯定有),那么用Redis来存储用户会话(Session)或JWT令牌的黑名单,能有效提升认证性能和安全。另外,一些不常变化但频繁访问的基础数据,如“资产分类下拉框”的选项,可以缓存到Redis里,减轻数据库压力。在答辩时,你能说出引入Redis解决了什么问题,比单纯罗列技术栈更有说服力。
  • Maven/Gradle:SpringBoot项目标配。用Maven的话,pom.xml里依赖管理要清晰,分模块管理(如果项目大)。用Gradle则构建脚本更灵活。选一个你熟悉的就行。

3. 系统核心模块设计与实现拆解

一个完整的高校资产管理系统,绝不是简单的增删改查(CRUD)。我们需要从业务视角拆解模块,每个模块对应一个相对独立的功能包。

3.1 数据库设计:一切的基础

这是最先要做,也是最容易出问题的地方。不要一上来就建表,先画实体关系图。核心实体通常包括:

  • sys_user(系统用户):关联教职工或管理员。
  • sys_dept(部门/院系):树形结构,资产归属的基本单位。
  • asset_category(资产分类):多级分类,如“仪器设备->电子设备->计算机”。
  • asset_info(资产信息表):核心表。字段包括资产ID、编号(唯一规则生成,如GZ-2025-001)、名称、分类ID、型号、规格、单价、购置日期、供应商、状态(在库、领用、维修、报废)、所属部门ID、存放地点、责任人ID等。
  • asset_lifecycle_record(资产生命周期记录):这是体现系统深度的关键。记录资产每一次状态变更,如“入库”、“领用”、“转移”、“维修”、“报废”。每条记录包含资产ID、操作类型、操作前状态、操作后状态、操作人、操作时间、备注。这相当于资产的“流水账”,便于追溯。

设计心得

  1. 状态字段设计asset_info.status不要用简单的0/1。建议使用枚举字符串,如‘IN_STOCK’‘IN_USE’‘UNDER_MAINTENANCE’‘SCRAPPED’。这样代码可读性极高,也方便后续扩展。
  2. 唯一编号生成:不要用数据库自增ID作为对外暴露的资产编号。应该有一套规则,例如“单位代码-年份-序列号”(GZ-2025-00001)。这需要在后端服务中实现一个编号生成器,可以考虑用Redis的原子操作INCR来生成序列号部分,确保在高并发下也不会重复。
  3. 数据字典:像“资产状态”、“操作类型”这种固定枚举值,可以单独建一张sys_dict表,实现动态配置,这样前端下拉框的数据就从接口获取,而不是写死在代码里。

3.2 后端SpringBoot 3关键实现

采用经典的分层架构:Controller -> Service -> Mapper/Repository。

3.2.1 统一响应结构与全局异常处理

这是项目规范性的体现。不要在每个Controller方法里都写return new Result(200, “success”, data)

// 1. 定义统一响应体 @Data public class R<T> { private Integer code; private String msg; private T data; // 成功/失败的静态工厂方法 public static <T> R<T> ok(T data) { ... } public static <T> R<T> fail(String msg) { ... } } // 2. 全局异常处理器 (@RestControllerAdvice) @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(BusinessException.class) // 自定义业务异常 public R<?> handleBusinessException(BusinessException e) { return R.fail(e.getMessage()); } @ExceptionHandler(Exception.class) public R<?> handleException(Exception e) { log.error(“系统异常:”, e); return R.fail(“系统繁忙,请稍后再试”); } }

这样,Service层抛出throw new BusinessException(“资产编号已存在”),前端就能收到格式统一、信息明确的错误响应。

3.2.2 资产入库接口的深度实现

以核心的“资产入库”为例,它远不止是向asset_info表插入一条数据。

@Transactional(rollbackFor = Exception.class) // 关键!开启事务 public void addAsset(AssetAddDTO dto) { // 1. 数据校验 (使用Spring Validation @Valid) // 2. 生成唯一资产编号 (调用编号生成服务) String assetNumber = assetNoGenerator.generate(dto.getCategoryCode()); // 3. 构建资产实体,状态设为 ‘IN_STOCK’ AssetInfo newAsset = AssetMapper.INSTANCE.dtoToEntity(dto); newAsset.setStatus(AssetStatusEnum.IN_STOCK.getCode()); newAsset.setAssetNumber(assetNumber); // 4. 插入资产主表 assetMapper.insert(newAsset); // 5. 创建一条“入库”生命周期记录 LifecycleRecord record = new LifecycleRecord(); record.setAssetId(newAsset.getId()); record.setOpType(OpTypeEnum.STOCK_IN.getCode()); record.setFromStatus(null); // 入库前无状态 record.setToStatus(AssetStatusEnum.IN_STOCK.getCode()); record.setOperatorId(SecurityUtils.getCurrentUserId()); // 获取当前登录用户 lifecycleRecordMapper.insert(record); // 6. (可选) 记录入库流水,用于财务对账 // 7. (可选) 清理资产列表缓存 (如果用了Redis缓存) }

注意事项:整个方法必须放在一个数据库事务中(@Transactional)。万一插入流水记录失败,资产主记录也应该回滚,避免产生“半吊子”数据。这是保证业务原子性的关键。

3.2.3 复杂查询:资产盘点与分页筛选

资产列表查询必然伴随多条件筛选和分页。这里推荐使用MyBatis-Plus,它能极大简化单表CRUD。

// Service层 public PageResult<AssetVO> queryAssetPage(AssetQueryDTO queryDTO) { // 构建查询条件 LambdaQueryWrapper<AssetInfo> wrapper = new LambdaQueryWrapper<>(); wrapper.like(StringUtils.isNotBlank(queryDTO.getName()), AssetInfo::getName, queryDTO.getName()) .eq(queryDTO.getCategoryId() != null, AssetInfo::getCategoryId, queryDTO.getCategoryId()) .eq(queryDTO.getStatus() != null, AssetInfo::getStatus, queryDTO.getStatus()) .eq(queryDTO.getDeptId() != null, AssetInfo::getDeptId, queryDTO.getDeptId()) .orderByDesc(AssetInfo::getCreateTime); // 按购置时间倒序 // 分页查询 Page<AssetInfo> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize()); Page<AssetInfo> assetPage = assetMapper.selectPage(page, wrapper); // 转换为VO (Value Object),可能需要关联查询部门名、分类名等 List<AssetVO> voList = convertToVOList(assetPage.getRecords()); return new PageResult<>(assetPage.getTotal(), voList); }

性能提示:如果AssetInfo表数据量极大(超过百万),并且AssetQueryDTO中的deptId条件经常出现,一定要确保dept_id字段上有索引。否则,eq操作会引发全表扫描,页面会卡死。用EXPLAIN命令分析你的SQL语句,是后端开发的基本功。

3.3 前端Vue.js 3关键实现

前端采用典型的单页应用结构,路由按模块划分。

3.3.1 基于Element Plus构建资产列表页

这是最常用的页面,包含表格、筛选表单、分页和操作按钮。

<template> <div class="asset-container"> <!-- 筛选表单 --> <el-form :model="queryParams" inline> <el-form-item label="资产名称"> <el-input v-model="queryParams.name" placeholder="请输入" clearable /> </el-form-item> <el-form-item label="资产状态"> <el-select v-model="queryParams.status" placeholder="请选择" clearable> <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> <el-form-item> <el-button type="primary" @click="handleQuery">搜索</el-button> <el-button @click="resetQuery">重置</el-button> </el-form-item> </el-form> <!-- 操作按钮行 --> <div style="margin-bottom: 20px;"> <el-button type="primary" @click="handleAdd">新增资产</el-button> <el-button @click="handleExport">导出Excel</el-button> </div> <!-- 资产表格 --> <el-table :data="assetList" v-loading="loading"> <el-table-column prop="assetNumber" label="资产编号" width="180" /> <el-table-column prop="name" label="资产名称" /> <el-table-column prop="categoryName" label="分类" /> <el-table-column prop="status" label="状态"> <template #default="{ row }"> <el-tag :type="getStatusTagType(row.status)">{{ getStatusText(row.status) }}</el-tag> </template> </el-table-column> <el-table-column prop="deptName" label="所属部门" /> <el-table-column label="操作" width="220"> <template #default="{ row }"> <el-button link type="primary" @click="handleView(row)">详情</el-button> <el-button link type="primary" @click="handleEdit(row)">编辑</el-button> <el-button link type="danger" @click="handleDelete(row)">删除</el-button> </template> </el-table-column> </el-table> <!-- 分页组件 --> <el-pagination v-model:current-page="queryParams.pageNum" v-model:page-size="queryParams.pageSize" :total="total" @current-change="handleCurrentChange" layout="total, sizes, prev, pager, next, jumper" /> </div> </template> <script setup> import { ref, onMounted } from 'vue' import { getAssetPage, deleteAsset } from '@/api/asset' import { ElMessage, ElMessageBox } from 'element-plus' // 响应式数据 const loading = ref(false) const assetList = ref([]) const total = ref(0) const queryParams = ref({ pageNum: 1, pageSize: 10, name: '', status: '' }) const statusOptions = ref([ { label: '在库', value: 'IN_STOCK' }, { label: '领用', value: 'IN_USE' }, // ... ]) // 方法 const loadData = async () => { loading.value = true try { const res = await getAssetPage(queryParams.value) assetList.value = res.data.list total.value = res.data.total } catch (error) { ElMessage.error('获取数据失败') } finally { loading.value = false } } const handleDelete = (row) => { ElMessageBox.confirm(`确认删除资产“${row.name}”吗?`, '提示', { type: 'warning' }).then(async () => { await deleteAsset(row.id) ElMessage.success('删除成功') loadData() // 刷新列表 }).catch(() => {}) } // 生命周期 onMounted(() => { loadData() }) </script>

组件化思维:这个页面中的“筛选表单”和“操作按钮行”其实可以抽离成独立的组件,比如AssetSearch.vueAssetActionBar.vue,这样在“资产领用”、“资产转移”等其他页面也能复用,保持UI和交互的一致性。

3.3.2 资产入库表单与前端校验

表单是数据入口,校验必须严谨。除了Element Plus表单组件自带的rules校验,对于复杂逻辑(如资产编号唯一性)需要配合后端。

<template> <el-dialog title="资产入库" v-model="dialogVisible"> <el-form :model="formData" :rules="rules" ref="formRef" label-width="100px"> <el-form-item label="资产分类" prop="categoryId"> <el-cascader v-model="formData.categoryId" :options="categoryTree" :props="{ value: 'id', label: 'name', children: 'children' }" clearable /> </el-form-item> <el-form-item label="资产名称" prop="name"> <el-input v-model="formData.name" /> </el-form-item> <el-form-item label="规格型号" prop="model"> <el-input v-model="formData.model" /> </el-form-item> <el-form-item label="单价" prop="price"> <el-input-number v-model="formData.price" :min="0" :precision="2" controls-position="right" /> </el-form-item> <!-- 更多字段... --> </el-form> <template #footer> <el-button @click="dialogVisible = false">取消</el-button> <el-button type="primary" @click="submitForm">确定</el-button> </template> </el-dialog> </template> <script setup> import { ref, reactive } from 'vue' import { addAsset } from '@/api/asset' import { ElMessage } from 'element-plus' const formRef = ref() const formData = reactive({ categoryId: '', name: '', model: '', price: 0, // ... }) const rules = reactive({ name: [{ required: true, message: '请输入资产名称', trigger: 'blur' }], categoryId: [{ required: true, message: '请选择资产分类', trigger: 'change' }], price: [{ required: true, message: '请输入单价', trigger: 'blur' }], }) const submitForm = async () => { // 1. 前端表单校验 if (!formRef.value) return const valid = await formRef.value.validate() if (!valid) return // 2. 提交数据 try { await addAsset(formData) ElMessage.success('入库成功') dialogVisible.value = false emit('success') // 通知父组件刷新列表 } catch (error) { // 这里会捕获到后端抛出的BusinessException,如“资产编号重复” ElMessage.error(error.message || '操作失败') } } </script>

用户体验细节:对于“资产分类”这种层级数据,使用el-cascader级联选择器比两个下拉框体验更好。分类数据通常来自一个接口,且不常变化,可以在应用初始化时加载并缓存在前端(比如Pinia store里),避免每次打开表单都请求。

4. 项目进阶与亮点功能实现

要让你的毕业设计脱颖而出,除了基本的CRUD,必须有几个体现思考和深度的功能。

4.1 资产二维码/条形码管理

这是将物理资产与数字系统绑定的关键。思路很简单:为每个资产生成一个唯一编号,并以此编号生成一个二维码(例如,使用qrcode库),打印出来贴在资产上。

  1. 生成与打印:在后端提供一个接口GET /api/asset/{id}/qrcode,返回二维码图片流。前端可以打开一个新页面显示并打印。
  2. 移动端盘点:这是亮点!你可以做一个非常简单的H5盘点页面,或者用Uni-app等框架打包成小程序。盘点员用手机扫描资产上的二维码,页面自动解析出资产ID,然后调用接口GET /api/asset/{id}/detail显示资产信息,并提供一个“盘点”按钮,点击后上报当前地理位置、盘点时间和盘点人。后端更新该资产的“最后盘点时间”和“盘点状态”。
  3. 技术点:这里涉及前后端分离下的跨域问题(CORS配置)、文件流响应、H5的Web API(如Canvas生成二维码,Geolocation API获取位置)等。

4.2 数据可视化与仪表盘

领导喜欢看图表。用EChartsAntV在首页做一个仪表盘。

  • 资产价值分布环图:按资产分类统计总价值。
  • 资产状态分布柱状图:直观展示在库、领用、维修、报废资产的数量。
  • 月度资产入库/出库趋势折线图
  • 部门资产数量Top10排行榜

这些数据都需要后端提供聚合查询接口。例如,资产状态分布的数据接口,SQL可能这样写:

SELECT status, COUNT(*) as count FROM asset_info GROUP BY status;

后端将结果封装,前端用ECharts渲染。这个功能技术难度不高,但视觉效果和实用性俱佳。

4.3 权限控制(RBAC模型)

一个完整的系统要有权限管理。采用经典的RBAC(角色-权限)模型。

  • 表设计sys_user(用户),sys_role(角色,如“资产管理员”、“部门领导”、“普通教师”),sys_menu(菜单/权限),sys_user_role(用户-角色关联),sys_role_menu(角色-菜单关联)。
  • 后端控制:使用Spring Security或Sa-Token框架。在Controller方法上添加注解如@PreAuthorize(“hasAuthority(‘asset:add’)”),来校验用户是否拥有“新增资产”的权限。
  • 前端控制:登录后,后端返回该用户可访问的菜单树。前端动态路由(router.addRoute())只添加这些菜单。同时,在页面内的按钮级别也可以进行控制,例如:
    <el-button v-if=“hasPermission(‘asset:export’)” @click=“handleExport”>导出</el-button>
    这个hasPermission函数检查当前用户的权限列表是否包含指定字符串。

5. 开发部署全流程与避坑指南

5.1 环境搭建与项目初始化

  1. Java环境:务必安装JDK 17或21,并正确配置JAVA_HOMEPath。用java -version验证。很多同学在这里出错,导致Maven编译失败。
  2. 初始化SpringBoot项目:直接上 start.spring.io ,选SpringBoot 3.x,依赖勾选Spring Web,Spring Data JPA(或MyBatis-Plus),MySQL Driver,Lombok(简化实体类代码)。生成后导入IDE。
  3. 初始化Vue项目:使用Vite,更快更现代。npm create vue@latest,按提示选择TypeScript、Router、Pinia等。
  4. 连接数据库:先在MySQL中创建好数据库schema,然后在SpringBoot的application.yml中配置数据源。避坑:SpringBoot 3默认的MySQL驱动是mysql-connector-j,URL中的时区建议加上serverTimezone=Asia/Shanghai,避免时间差问题。

5.2 前后端联调与跨域问题

开发时,前端运行在localhost:5173,后端运行在localhost:8080,浏览器会因为同源策略阻止请求。

  • 后端解决(推荐):在SpringBoot中配置一个全局的CORS过滤器。
    @Configuration public class CorsConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(“/**“) .allowedOriginPatterns(”*“) // 生产环境要改具体域名 .allowedMethods(”GET”, “POST”, “PUT”, “DELETE”, “OPTIONS”) .allowCredentials(true) .maxAge(3600); } }; } }
  • 前端代理(开发环境):在vite.config.js中配置proxy,将/api开头的请求转发到后端。这样前端代码里写的请求地址可以是相对路径/api/asset,更干净。

5.3 部署上线(毕业设计演示用)

答辩时,你需要一个正在运行的系统。最简单的部署方式:

  1. 后端打包:使用Maven命令mvn clean package -DskipTests,会在target目录生成一个*.jar文件。
  2. 前端构建:运行npm run build,生成静态文件在dist目录。
  3. 部署
    • 方案A(简单):将后端jar包和前端dist文件夹放到服务器同一目录。写一个Dockerfile或简单的启动脚本。运行java -jar your-app.jar启动后端。后端同时托管前端静态资源(将dist内容复制到SpringBoot的src/main/resources/static下,或者配置spring.web.resources.static-locations指向dist目录)。这样访问8080端口就能看到整个应用。
    • 方案B(更规范):用Nginx。Nginx监听80端口,负责托管前端dist静态文件,并将/api/开头的请求反向代理到后端8080端口。这是生产环境更常见的做法。

部署大坑:确保服务器(或你的笔记本电脑)的防火墙开放了应用所使用的端口(如8080、80)。经常有同学一切就绪,但就是无法访问,最后发现是端口被防火墙拦了。

5.4 常见问题排查实录

  1. 前端调用接口报404

    • 检查后端Controller的@RequestMapping路径是否正确。
    • 检查前端请求的URL是否完整(特别是开发环境代理配置是否正确)。
    • 查看浏览器开发者工具的Network面板,确认请求是否真的发到了正确地址。
  2. 后端启动报错:java: 警告: 源发行版 17 需要目标发行版 17

    • 这是IDE(如IDEA)的Java编译版本设置问题。去File -> Project Structure -> ProjectModules里,确保Language levelProject SDK都是17或以上。
    • 同时检查Maven的pom.xml,确保maven-compiler-plugin插件配置的sourcetarget也是17。
  3. 使用Lombok注解(如@Data)不生效,get/set方法找不到

    • 首先确保IDE安装了Lombok插件(IDEA和Eclipse都需要)。
    • 然后在设置中启用注解处理(IDEA:Settings -> Build -> Compiler -> Annotation Processors,勾选Enable)。
    • 最后,检查pom.xml中Lombok依赖的scope是否是provided,并且版本与SpringBoot兼容。
  4. 数据库插入中文变成乱码

    • 检查数据库、表、字段的字符集是否为utf8mb4
    • 检查SpringBoot数据源URL,是否在连接参数中指定了characterEncoding=utf8,例如:jdbc:mysql://localhost:3306/asset_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
  5. Vue页面刷新后,路由跳转白屏或404

    • 这是Vue Router在history模式下部署到非根路径的经典问题。在Nginx配置中,需要添加一个try_files指令,将所有非静态文件请求重定向到index.html
      location / { try_files $uri $uri/ /index.html; }
    • 如果前端应用部署在子路径(如/asset),还需要在Vue Router和Vite的base配置中设置相同的路径。

做这个项目的过程中,你一定会遇到比上面更多、更奇怪的问题。我的建议是:善用搜索引擎,精准描述你的报错信息;仔细阅读官方文档和日志;学会在IDE中调试,打断点跟踪代码执行流程。每一个坑踩过去,都是实实在在的经验积累。这个项目做完,你对一个完整Web应用的生命周期——从需求分析、技术选型、数据库设计、前后端开发、调试到部署——会有一个非常清晰的认识,这份经历和作品,足以让你在求职时从容应对大多数初级全栈开发的面试问题。

本文还有配套的精品资源,点击获取

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

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

立即咨询