
上周帮一个学弟看他的毕业设计他选了一个超市管理系统用 SpringBoot 和 Vue 前后端分离。他花了两周前端页面画得挺漂亮后端接口也写了不少但一运行就卡在登录上要么是跨域问题要么是数据库连不上要么是前端传的数据后端收不到。他有点沮丧说“感觉每个技术点都学了但一组合起来就不知道从哪下手了。”这其实不是他一个人的问题。很多同学在做第一个完整的、能跑起来的 Java 全栈项目时都会遇到类似的困境技术栈看起来都会但如何把它们像拼图一样严丝合缝地组装成一个可运行、可演示、可交付的系统中间隔着一条巨大的“工程化鸿沟”。这个鸿沟里填满了环境配置、依赖管理、接口联调、数据交互和部署运行这些“脏活累活”。今天我们就以“鲜享超市管理系统”这个典型的毕设选题为例不聊高深理论只解决一个核心问题如何从零开始把一个 SpringBoot Vue 的项目从本地开发环境一步步搭建、调试、集成最终变成一个能完美运行、功能完整的可交付系统。我的核心判断是对于毕设而言比炫技更重要的是工程的完整性与可复现性。一个能稳定运行、逻辑清晰、代码规范的项目远比堆砌了各种高级特性但bug频出的项目更有价值。所以这篇文章不会教你如何设计最精妙的算法而是会像一个经验丰富的项目搭桥工带你走过从环境准备、项目初始化、前后端开发、联调测试到最终打包部署的每一块“桥板”并重点指出那些最容易踩空掉下去的地方。我们的目标是让你手里有一个“活”的项目而不仅仅是一堆散落的代码文件。1. 环境准备与项目初始化别在起跑线摔倒在开始写第一行业务代码之前确保你的“施工场地”平整且工具齐全是避免后续无数诡异报错的关键。很多同学的问题80%都出在环境上。1.1 开发环境清单锁定版本避免“玄学”问题Java 全栈开发环境依赖环环相扣。版本不匹配是“玄学”错误的万恶之源。对于毕业设计这个场景我强烈建议你使用下面这套经过大量实践验证的、兼容性好的稳定版本组合而不是盲目追求最新版。组件推荐版本说明关键检查点JDK8 或 11 (LTS版本)SpringBoot 2.x 对 JDK 8 支持最成熟。JDK 17 可能需要调整。java -version确认版本。Maven3.6.3项目管理工具负责依赖下载和打包。mvn -v确认安装检查本地仓库路径。Node.js14.x 或 16.x (LTS)Vue 2 生态对 Node 版本有要求太高或太低都可能出问题。node -v,npm -v确认。IDEIntelliJ IDEA (社区版即可)后端开发主力智能提示和 Spring 支持好。确保安装了 Lombok 插件。代码编辑器VS Code前端开发主力轻量且 Vue 插件生态丰富。安装 Vetur 或 Vue 3 对应插件。数据库MySQL 5.7 或 8.0最常用的关系型数据库注意 8.0 的密码加密方式。确保服务启动记住 root 密码。浏览器Chrome用于前端调试和测试。安装 Vue.js devtools 扩展。为什么强调版本因为 SpringBoot 2.7.18、Vue 2、MyBatis-Plus 等组件之间有着隐性的版本依赖网。用官方脚手架创建项目时它会帮你处理好这些依赖。你自己手动组装修改时版本冲突就会导致ClassNotFoundException、NoSuchMethodError等令人头疼的问题。所以第一步请严格按照推荐版本设置你的环境。1.2 后端项目骨架搭建使用 Spring Initializr别从零手搓不要手动创建一个 Maven 项目然后自己去pom.xml里添加依赖那会引入无数配置错误。使用Spring Initializr这是官方的一键项目生成器能确保项目结构、依赖版本和基础配置的正确性。操作路径打开 IDEA选择File - New - Project...。左侧选择Spring Initializr。关键配置Project SDK:选择你安装的 JDK 8 或 11。Type:Maven Project (默认)。Language:Java (默认)。Packaging:Jar (默认)。Java Version:选择与你 JDK 对应的版本 (如 8 或 11)。Group:你的组织域名倒写例如com.freshmart。Artifact:项目名例如freshmart-backend。Name/Description:按需填写。选择依赖 (Dependencies):这是核心步骤勾选你需要的起步依赖。Spring Web:用于构建 RESTful API。Spring Boot DevTools:热部署修改代码后自动重启提升开发效率。Lombok:通过注解自动生成 Getter/Setter/构造函数等极大减少样板代码。MyBatis Framework:数据库持久层框架。注意这里我们通常不直接用它而是用功能更强的MyBatis-Plus但 Initializr 没有。我们可以先选MyBatis Framework确保基础配置稍后在pom.xml中替换依赖。MySQL Driver:MySQL 数据库驱动。点击Next选择项目存储位置然后Finish。项目创建完成后打开pom.xml找到 MyBatis 的依赖将其替换为 MyBatis-Plus 的 starter 依赖版本号与 SpringBoot 2.7.18 兼容!-- 移除或注释掉 spring-boot-starter-data-mybatis -- !-- dependency -- !-- groupIdorg.mybatis.spring.boot/groupId -- !-- artifactIdmybatis-spring-boot-starter/artifactId -- !-- version2.3.0/version -- !-- /dependency -- !-- 添加 MyBatis-Plus -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version !-- 使用与SpringBoot 2.7.x兼容的版本 -- /dependency为什么这么做Spring Initializr 生成的是一个“标准答案”式的项目结构它帮你配置好了 Maven 包装器、正确的资源目录 (src/main/resources)、测试目录以及最重要的application.properties文件。这能避免你在一开始就陷入目录结构错误、配置文件位置不对等低级问题。1.3 前端项目骨架搭建使用 Vue CLI避免配置地狱同样不要手动创建 HTML、JS 文件然后引入 Vue.js。使用Vue CLI来创建标准化的 Vue 项目。操作路径打开终端CMD、PowerShell 或 VS Code 集成终端。确保你的 npm 源速度可以可以使用淘宝镜像npm config set registry https://registry.npmmirror.com。安装 Vue CLI如果尚未安装npm install -g vue/cli创建项目vue create freshmart-frontend进入交互式配置Please pick a preset:选择Manually select features(手动选择特性)。Check the features needed:用空格键选中Babel,Router,Vuex,CSS Pre-processors,Linter / Formatter。Router 和 Vuex 对于管理后台项目几乎是必选。Choose a version of Vue.js:选择2.x。Vue 3 虽然新但生态和部分第三方库的稳定性对于毕设时间紧张的同学可能是个挑战Vue 2 的资源和解决方案更海量。后续关于路由模式选History模式、CSS 预处理器选Sass/SCSS、代码规范选ESLint Standard等按默认或自己喜好选择即可。等待创建完成然后进入项目目录cd freshmart-frontend现在你的前后端项目骨架都已经就位。后端是一个标准的 SpringBoot 工程前端是一个标准的 Vue 2 工程。它们都遵循了各自社区的最佳实践目录结构这是项目能健康生长的第一步。2. 数据库设计与后端核心逻辑先让数据流动起来有了骨架接下来是填充血肉。后端是系统的引擎而数据库是燃料库。设计一个清晰、合理的数据库结构是实现所有业务功能的基础。2.1 数据库设计围绕核心实体展开“鲜享超市管理系统”通常包含商品、分类、订单、用户、员工等核心模块。我们设计一个简化的 E-R 模型来支撑基本功能用户表 (sys_user):系统使用者管理员、员工。字段id (主键), username (用户名), password (密码, 加密存储), name (真实姓名), phone (电话), role (角色, 如admin, employee), status (状态), create_time。商品分类表 (goods_category):商品的一级分类。字段id, name (分类名), sort (排序), create_time。商品表 (goods):核心数据。字段id, category_id (外键), name (商品名), image (图片链接), price (单价), stock (库存), description (描述), status (上架/下架), create_time。订单表 (orders):记录交易。字段id, order_no (订单号), user_id (下单用户), total_price (总金额), status (订单状态待付款、待发货、已完成等), create_time。订单明细表 (order_item):记录订单中的具体商品。字段id, order_id (外键), goods_id (外键), count (购买数量), price (下单时单价)。注意这是一个高度简化的设计用于快速实现核心流程。真实的超市系统还会涉及供应商、库存流水、会员、促销等复杂模块。但对于毕设“完整跑通一个核心业务流程”比“大而全的表结构”更重要。你可以先基于这个模型实现后续再按需扩展。在 MySQL 中创建数据库freshmart_db并执行建表 SQL。这里以goods表为例CREATE TABLE goods ( id int(11) NOT NULL AUTO_INCREMENT COMMENT 主键, category_id int(11) DEFAULT NULL COMMENT 分类id, name varchar(100) NOT NULL COMMENT 商品名称, image varchar(500) DEFAULT COMMENT 商品图片, price decimal(10,2) NOT NULL COMMENT 商品价格, stock int(11) NOT NULL DEFAULT 0 COMMENT 库存, description text COMMENT 商品描述, status tinyint(1) DEFAULT 1 COMMENT 状态 1:上架 0:下架, create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), KEY idx_category (category_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品表;2.2 后端三层架构与 MyBatis-Plus 高效开发SpringBoot 项目通常采用 Controller-Service-Mapper 的三层架构。MyBatis-Plus (MP) 能极大简化 Mapper 层的开发。第一步配置数据库连接在src/main/resources/application.properties中配置# 服务器端口 server.port8080 # 数据库连接 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver spring.datasource.urljdbc:mysql://localhost:3306/freshmart_db?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai spring.datasource.usernameroot spring.datasource.passwordyour_password # MyBatis-Plus 配置 mybatis-plus.configuration.log-implorg.apache.ibatis.logging.stdout.StdOutImpl # 控制台打印SQL调试用 mybatis-plus.global-config.db-config.id-typeauto # 主键自增 mybatis-plus.global-config.db-config.logic-delete-fielddeleted # 逻辑删除字段名如果表里有 mybatis-plus.global-config.db-config.logic-delete-value1 mybatis-plus.global-config.db-config.logic-not-delete-value0第二步创建实体类 (Entity)使用 Lombok 注解简化代码。在entity包下创建Goods.javapackage com.freshmart.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.math.BigDecimal; import java.util.Date; Data TableName(goods) // 指定对应表名 public class Goods { TableId(type IdType.AUTO) // 主键自增 private Integer id; private Integer categoryId; private String name; private String image; private BigDecimal price; private Integer stock; private String description; private Integer status; private Date createTime; }Data注解自动生成了 getter, setter, toString 等方法。第三步创建 Mapper 接口在mapper包下创建GoodsMapper.javapackage com.freshmart.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.freshmart.entity.Goods; import org.apache.ibatis.annotations.Mapper; Mapper // 声明为MyBatis的Mapper让Spring能扫描到 public interface GoodsMapper extends BaseMapperGoods { // 无需编写任何CRUD方法BaseMapper已提供了 insert, deleteById, updateById, selectById, selectList 等 }继承BaseMapperGoods后你就拥有了对goods表进行单表 CRUD 的所有方法。这是 MP 最强大的能力之一。第四步创建 Service 层在service包下创建接口GoodsService.java和实现类GoodsServiceImpl.java。Service 层处理业务逻辑。// GoodsService.java package com.freshmart.service; import com.freshmart.entity.Goods; import com.baomidou.mybatisplus.extension.service.IService; public interface GoodsService extends IServiceGoods { // 可以在此定义特殊的业务方法 boolean reduceStock(Integer goodsId, Integer count); } // GoodsServiceImpl.java package com.freshmart.service.impl; import com.freshmart.entity.Goods; import com.freshmart.mapper.GoodsMapper; import com.freshmart.service.GoodsService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; Service public class GoodsServiceImpl extends ServiceImplGoodsMapper, Goods implements GoodsService { Override Transactional // 事务注解保证减库存操作的原子性 public boolean reduceStock(Integer goodsId, Integer count) { Goods goods this.getById(goodsId); if (goods null || goods.getStock() count) { return false; // 商品不存在或库存不足 } goods.setStock(goods.getStock() - count); return this.updateById(goods); } }ServiceImpl已经实现了IService的基础方法。Transactional确保了在减库存时如果后续操作失败库存会被回滚防止超卖。第五步创建 Controller 层在controller包下创建GoodsController.java提供 RESTful API。package com.freshmart.controller; import com.freshmart.entity.Goods; import com.freshmart.service.GoodsService; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; RestController RequestMapping(/goods) public class GoodsController { Autowired private GoodsService goodsService; // 分页查询商品列表 GetMapping(/list) public MapString, Object list(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(required false) String name) { PageGoods page new Page(pageNum, pageSize); QueryWrapperGoods wrapper new QueryWrapper(); if (name ! null !name.trim().isEmpty()) { wrapper.like(name, name); } wrapper.orderByDesc(create_time); PageGoods goodsPage goodsService.page(page, wrapper); MapString, Object result new HashMap(); result.put(total, goodsPage.getTotal()); result.put(records, goodsPage.getRecords()); return result; } // 根据ID获取商品详情 GetMapping(/{id}) public Goods getById(PathVariable Integer id) { return goodsService.getById(id); } // 新增商品 PostMapping public boolean save(RequestBody Goods goods) { return goodsService.save(goods); } // 更新商品 PutMapping public boolean update(RequestBody Goods goods) { return goodsService.updateById(goods); } // 删除商品 DeleteMapping(/{id}) public boolean delete(PathVariable Integer id) { return goodsService.removeById(id); } }至此一个具备完整 CRUD 和分页查询功能的商品管理后端 API 就完成了。你可以启动 SpringBoot 应用 (FreshmartBackendApplication)使用 Postman 或浏览器测试http://localhost:8080/goods/list等接口。为什么这套流程高效且不易出错标准化每层职责清晰代码结构统一。工具化Lombok 和 MyBatis-Plus 消除了大量重复代码。契约化RESTful 接口设计让前后端交互有明确的约定。可调试每层都可以独立测试和调试。3. 前端开发与前后端联调打通任督二脉后端 API 准备好了现在需要前端界面来调用和展示。前后端分离项目最大的挑战之一就是“联调”。3.1 前端工程化安装依赖与配置代理进入前端项目目录 (freshmart-frontend)安装必要的 UI 组件库和 HTTP 请求库。对于管理后台Element UI是一个成熟且丰富的选择。# 安装 Element UI (Vue 2 版本) npm i element-ui -S # 安装 axios 用于发送 HTTP 请求 npm i axios -S # 安装 vue-axios 方便集成 npm i vue-axios -S在src/main.js中引入并注册这些库import Vue from vue import App from ./App.vue import router from ./router import store from ./store import ElementUI from element-ui import element-ui/lib/theme-chalk/index.css import axios from axios import VueAxios from vue-axios Vue.use(ElementUI) Vue.use(VueAxios, axios) // 这样可以在组件内用 this.$http 调用 axios Vue.config.productionTip false new Vue({ router, store, render: h h(App) }).$mount(#app)关键一步配置开发环境代理。前端运行在localhost:8081后端在localhost:8080直接请求会触发浏览器的跨域限制。我们可以在 Vue CLI 的配置中设置代理让前端开发服务器将特定请求转发到后端。在项目根目录创建或修改vue.config.js文件module.exports { devServer: { port: 8081, // 前端开发服务器端口 proxy: { /api: { // 拦截以 /api 开头的请求 target: http://localhost:8080, // 后端地址 changeOrigin: true, // 改变请求头中的 Origin pathRewrite: { ^/api: // 将请求路径中的 /api 前缀重写为空 } } } } }这样前端代码中请求/api/goods/list就会被代理到http://localhost:8080/goods/list完美解决跨域问题。这是开发阶段最重要的配置之一。3.2 构建商品管理页面组件、路由与状态管理我们以商品列表页为例展示如何构建一个典型的管理页面。第一步创建商品管理路由在src/router/index.js中添加路由import Vue from vue import Router from vue-router import GoodsList from /views/goods/GoodsList.vue // 待创建的组件 Vue.use(Router) export default new Router({ routes: [ // ... 其他路由 { path: /goods, name: Goods, component: () import(/views/layout/Layout.vue), // 假设有个布局组件 children: [ { path: list, name: GoodsList, component: GoodsList } ] } ] })第二步创建 GoodsList 组件在src/views/goods/GoodsList.vue中template div classgoods-container el-card !-- 搜索栏 -- div stylemargin-bottom: 20px; el-input v-modelsearchForm.name placeholder商品名称 stylewidth: 200px; keyup.enter.nativehandleSearch/el-input el-button typeprimary iconel-icon-search clickhandleSearch搜索/el-button el-button typesuccess iconel-icon-plus clickhandleAdd新增商品/el-button /div !-- 商品表格 -- el-table :datatableData border stripe stylewidth: 100% el-table-column propid labelID width80/el-table-column el-table-column propname label商品名称/el-table-column el-table-column propprice label价格 width120 template slot-scopescope¥{{ scope.row.price }}/template /el-table-column el-table-column propstock label库存 width100/el-table-column el-table-column propstatus label状态 width100 template slot-scopescope el-tag :typescope.row.status 1 ? success : info {{ scope.row.status 1 ? 上架 : 下架 }} /el-tag /template /el-table-column el-table-column propcreateTime label创建时间 width180/el-table-column el-table-column label操作 width200 template slot-scopescope el-button sizemini clickhandleEdit(scope.row)编辑/el-button el-button sizemini typedanger clickhandleDelete(scope.row.id)删除/el-button /template /el-table-column /el-table !-- 分页 -- el-pagination size-changehandleSizeChange current-changehandleCurrentChange :current-pagepagination.current :page-sizes[10, 20, 50, 100] :page-sizepagination.size layouttotal, sizes, prev, pager, next, jumper :totalpagination.total stylemargin-top: 20px; text-align: center; /el-pagination /el-card !-- 新增/编辑对话框 -- goods-dialog :visible.syncdialogVisible :form-datacurrentForm refreshfetchData /goods-dialog /div /template script import GoodsDialog from ./components/GoodsDialog.vue // 子组件用于新增/编辑 export default { name: GoodsList, components: { GoodsDialog }, data() { return { tableData: [], searchForm: { name: }, pagination: { current: 1, size: 10, total: 0 }, dialogVisible: false, currentForm: {} } }, created() { this.fetchData() }, methods: { async fetchData() { try { const params { pageNum: this.pagination.current, pageSize: this.pagination.size, ...this.searchForm } // 注意请求路径是 /api/goods/list会被代理到后端 const response await this.$http.get(/api/goods/list, { params }) this.tableData response.data.records this.pagination.total response.data.total } catch (error) { this.$message.error(获取商品列表失败 error.message) } }, handleSearch() { this.pagination.current 1 this.fetchData() }, handleAdd() { this.currentForm {} this.dialogVisible true }, handleEdit(row) { this.currentForm { ...row } // 浅拷贝避免直接修改表格数据 this.dialogVisible true }, async handleDelete(id) { try { await this.$confirm(确定删除该商品吗, 提示, { type: warning }) await this.$http.delete(/api/goods/${id}) this.$message.success(删除成功) this.fetchData() } catch (error) { if (error ! cancel) { this.$message.error(删除失败 error.message) } } }, handleSizeChange(size) { this.pagination.size size this.fetchData() }, handleCurrentChange(current) { this.pagination.current current this.fetchData() } } } /script第三步创建 GoodsDialog 子组件在src/views/goods/components/GoodsDialog.vue中处理表单的提交和验证代码略主要包含一个el-form和提交逻辑调用后端的save或update接口。3.3 联调核心解决跨域与数据格式问题即使配置了代理联调时仍可能遇到问题主要集中在以下几点后端 Controller 需要添加CrossOrigin注解吗在开发阶段因为配置了前端代理请求是从localhost:8081发出被代理到8080对于后端来说请求来源是localhost:8081属于跨域。建议在后端 Controller 类上添加CrossOrigin注解或者配置全局的 CORS 过滤器以允许前端开发服务器的请求。生产环境部署到同一域名下后则不需要。前端请求成功但后端收不到数据检查请求头Content-Type使用axios默认发送的是application/json。后端使用RequestBody接收时需要这个请求头。检查数据格式确保前端POST/PUT请求发送的是一个 JSON 对象而不是FormData。使用浏览器开发者工具的 Network 面板这是你最好的朋友。查看请求的 URL、Method、Headers、Payload 是否都符合预期以及后端的响应是什么。后端返回了数据但前端显示不出来检查响应结构后端返回的 Map 或统一封装的结果对象其字段名是否与前端response.data.xxx的路径匹配。处理异步确保在created或mounted钩子中调用数据获取方法并使用async/await或.then()正确处理 Promise。联调的本质是通信协议的对接。把 Network 面板用熟能解决 90% 的联调问题。4. 项目集成、部署与答辩准备从“能跑”到“好用”一个能在自己电脑上运行的项目距离“可交付”还有最后几步。你需要考虑如何将它打包、部署并整理成一份清晰的文档方便答辩老师查看和运行。4.1 后端打包与部署SpringBoot 项目打包非常简单因为它内置了 Tomcat 服务器。打包在项目根目录下执行mvn clean package。成功后会在target目录下生成一个freshmart-backend-0.0.1-SNAPSHOT.jar文件。运行将生成的jar包和application.properties如果需要外部化配置放到服务器或另一台电脑上确保安装了对应版本的 JDK然后执行java -jar freshmart-backend-0.0.1-SNAPSHOT.jar应用就会启动。你可以通过java -jar xxx.jar --server.port8088来指定端口。生产环境建议将数据库密码等敏感信息从application.properties移到环境变量或专门的配置中心。使用nohup或 systemd 等服务管理工具来保持应用在后台运行。考虑使用 Nginx 作为反向代理处理静态资源、负载均衡和 SSL 加密。4.2 前端打包与部署Vue CLI 项目通过npm run build进行打包。打包在前端项目根目录执行npm run build。完成后会在dist目录生成静态文件HTML, CSS, JS。部署方式一前后端分离部署将dist文件夹里的所有文件上传到你的 Nginx 或 Apache 服务器的网站根目录。然后需要配置 Nginx将所有前端路由请求重定向到index.html并设置 API 请求的反向代理到后端服务。方式二简化部署对于毕设演示可以将dist文件夹直接拷贝到 SpringBoot 项目的src/main/resources/static目录下。然后修改后端application.properties关闭默认的静态资源处理或者调整路由优先级。这样访问http://localhost:8080就能直接看到前端页面。这种方式简单但混合了前后端不利于维护仅适用于演示。4.3 毕设文档与源码整理你的项目“使用说明书”一份清晰的文档和干净的源码是毕设答辩的加分项。必须包含的内容README.md (项目根目录)项目名称和简介。技术栈SpringBoot, Vue, MyBatis-Plus, MySQL, Element UI 等。快速开始环境要求 (JDK 8, Maven, Node.js, MySQL 版本)。数据库初始化提供sql/freshmart_db.sql文件。后端启动步骤导入 IDEA修改application.properties中的数据库配置运行主类。前端启动步骤进入目录npm install,npm run serve。项目结构说明。主要功能截图。数据库设计文档可以在docs目录下放一个数据库设计.md或ER图.png描述核心表结构。API 接口文档可以使用 Swagger 集成后端添加springfox-boot-starter依赖并配置生成在线的交互式文档访问http://localhost:8080/swagger-ui.html即可查看所有接口。这是非常专业的表现。干净的源码删除所有target,node_modules,dist,.idea,*.iml等编译生成文件和 IDE 配置文件。可以使用.gitignore文件来管理。确保源码导入后按照 README 的步骤就能顺利运行。4.4 答辩准备讲清楚“为什么”和“怎么做”答辩时老师关心的不仅仅是功能更是你思考的过程和解决问题的能力。不要只演示功能边演示边讲解。例如“这里是商品管理模块我采用了 MyBatis-Plus 来简化数据库操作它的Page对象和QueryWrapper让分页和条件查询变得非常简洁。”准备回答技术选型问题“为什么用 Vue 不用 React”、“为什么用 MyBatis-Plus 不用 JPA” 你的回答应该是“Vue 学习曲线平缓生态丰富适合快速开发管理后台。MyBatis-Plus 在 MyBatis 基础上提供了大量单表 CRUD 的封装能极大提高开发效率同时保留了原生 SQL 的灵活性适合对 SQL 有一定掌控需求的场景。”展示你遇到的坑和解决方案“在联调时遇到了跨域问题我通过配置 Vue 开发服务器的代理来解决开发环境的跨域并在后端配置了全局 CORS 过滤器以备不时之需。” 这体现了你的调试和解决问题的能力。谈谈不足和展望“目前系统实现了核心的进销存管理但由于时间关系权限控制只做了简单的角色区分未来可以引入 RBAC 模型进行细化。此外商品图片上传功能目前是本地存储可以考虑集成对象存储服务如 OSS。”记住一个能稳定运行、代码规范、文档齐全、逻辑清晰的项目即使功能不复杂也足以让你获得一个不错的评价。这篇文章带你走完了从环境搭建到部署上线的完整路径重点不是复制代码而是理解每一步背后的意图和可能遇到的陷阱。现在你可以基于这个坚实的“骨架”去填充属于你自己的“鲜享超市”的血肉了。祝你毕设顺利。