ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SpringBoot+Vue点餐系统毕设:从数据库设计到部署上线全指南

SpringBoot+Vue点餐系统毕设:从数据库设计到部署上线全指南 又到了毕业设计的高峰期每年这个时候都会有大量同学在“做点什么系统”这个问题上反复纠结。点餐管理系统算是JavaWeb方向常年热门的一个选题原因很简单业务场景贴近生活、功能边界清晰、技术栈主流而且演示效果好——你能让评委老师直观看到用户从选菜、下单到后台处理的完整闭环。这篇文章我把当初带学生做这个项目的全过程拆开揉碎讲一遍从功能规划、技术选型、数据库设计到前后端核心代码、部署上线再到论文和答辩的准备思路一次讲透。无论你现在是刚把SpringBoot和Vue跑通的入门选手还是已经有点基础但不知道怎么把整个项目串起来这篇文章都适合你参考。1. 项目定位这个“点餐系统”到底要做什么聊技术之前先把需求说清楚。很多同学做毕业设计最大的问题不是不会写代码而是不知道自己的系统“要解决什么问题”。点餐管理系统如果只做一个“展示菜品加购物车下单”那和培训机构里的练习项目没有任何区别答辩时老师随便问两句业务逻辑你就露馅了。我给学生定的定位是一套面向小型餐厅比如校园食堂、街边快餐店的数字化点餐管理解决方案。它的用户分两类顾客端和商家端管理员。顾客扫码或打开网页浏览菜单、加购、下单、结算商家在后台维护菜品、处理订单、统计营收。如果时间和精力允许再加上一个“桌台管理”或者“排队叫号”的功能整个系统的业务完整度会明显上一个档次。为什么选“餐厅点餐”这个场景而不是通用的“进销存”或者“商城系统”三个原因第一演示叙事完整。从顾客打开菜单那一刻起到后厨看到订单、出餐、结账整个流程是连贯且有故事性的。答辩时你可以按“用户视角”和“商家视角”两条线完整演示逻辑非常顺畅。第二业务复杂度恰到好处。一个点餐系统涉及的实体关系不复杂但足够典型用户、菜品、分类、购物车、订单、订单明细。这些关系能体现你对数据库设计的基本功又不会因为过度复杂导致做不完。第三可扩展性强。后面想加分加个微信小程序端口、加个Redis缓存热点菜品、加个RabbitMQ处理订单通知都是顺理成章的演进路径。这些“展望”写在论文里也显得自然不是生拼硬凑。2. 技术选型为什么是SpringBootVueMySQL这三件套关于技术栈不少同学会问我“老师现在Spring Cloud微服务这么火我能不能直接上微服务架构”我的回答通常是做毕业设计最忌技术炫技脱离业务。一个面向单一餐厅的点餐系统强行拆成多个微服务只会暴露你对技术边界理解的欠缺。先说说为什么SpringBoot是合理选择。SpringBoot解决了传统Spring项目配置繁琐的问题内置Tomcat支持自动配置让开发者能专注于业务代码本身。对毕业设计而言这意味着你可以用最少的时间搭出一个干净、规范的Java后端工程。而且SpringBoot是当前Java后端开发的事实标准论文里写“基于SpringBoot的快速开发”是完全站得住脚的表述。Vue这边选择Vue 2还是Vue 3一开始就要想清楚。我的建议是直接上Vue 3 Element Plus。Vue 3的组合式API让业务逻辑的组织更灵活Element Plus的组件库能让你的管理后台界面在短时间内达到一个不错的颜值水平。如果是基础比较薄弱的同学用Vue 2 Element UI也未尝不可毕竟网上现成的教程和组件示例更多但既然是从零开始没必要学一套即将过时的东西。MySQL则不用多说关系型数据库里的常青树。这里要多说一句版本选择——网上很多教程还在推MySQL 5.7但我更建议新项目直接上MySQL 8.x。8.0默认字符集是utf8mb4对中文和emoji的支持更友好窗口函数这类实用特性也给后续扩展留了余地。之前有个学生照着5.7的老教程安装结果密码加密规则和驱动兼容性问题折磨了他整整两天这个坑后面细说。技术选型的核心逻辑选择这套组合意味着你用的每一样技术都有庞大的社区支持和海量踩坑案例遇到问题搜得到答案这在毕业设计的时间表里比什么都重要。记住毕业设计的核心目标是用一套主流、稳妥、能自圆其说的技术把业务需求完整落地而不是证明你掌握了多少新技术。3. 环境准备把开发基础打牢正式写代码之前环境配置是第一道坎。这一步看起来简单但我在指导过程中发现不少同学在环境问题上浪费的时间比写代码还多。这里给出一套经过验证的安装配置流程和版本搭配方案。3.1 完整工具清单与版本搭配工具推荐版本说明JDKJDK 8 或 JDK 11如果SpringBoot用2.xJDK 8/11最稳妥用3.x建议JDK 17Maven3.6.3 或 3.8.x构建工具配置阿里云镜像加速依赖下载MySQL8.0.x建议直接8.0避免老版本踩坑Node.js16.x 或 18.x LTSVue 3 Vite建议Node 16以上IDEIDEA后端 VSCode前端也可以用IDEA全家桶装Vue插件这个组合的兼容性我已经验证过多次。特别注意SpringBoot版本和JDK版本要匹配SpringBoot 2.7用JDK 8没问题升到SpringBoot 3.x就强制要求JDK 17了。很多同学在pom.xml里直接配了个3.0以上的版本结果本机装的是JDK 8启动直接报错慌了半天不知道怎么回事。3.2 MySQL安装避坑指南Windows下安装MySQL建议直接下载ZIP压缩包版本手动配置比用MSI安装包更可控。具体步骤第一步去MySQL官网下载mysql-8.0.x-winx64.zip包解压到指定目录比如D:\tool\mysql-8.0.46-winx64。第二步在解压根目录创建my.ini配置文件关键内容如下[mysqld] basedirD:/tool/mysql-8.0.46-winx64 datadirD:/tool/mysql-8.0.46-winx64/data port3306 character-set-serverutf8mb4 [client] default-character-setutf8mb4第三步用管理员身份打开CMD进入bin目录执行mysqld --initialize-insecure这里注意如果用--initialize会自动生成随机root密码并且日志里才有用--initialize-insecure则root初始密码为空对本地开发来说更方便。第四步注册Windows服务并启动mysqld -install net start mysql之前我遇到过学生执行net start mysql报“服务名无效”的情况原因多半是上一步mysqld -install没有用管理员权限运行。还有的报“发生系统错误 2”基本就是路径配置问题检查my.ini里的basedir和datadir配没配对。3.3 后端工程初始化要点创建SpringBoot项目官方的Spring Initializrstart.spring.io是最快的途径。选好Maven工程、JDK版本勾选Web、MyBatis或MyBatis-Plus、MySQL Driver、Lombok这几个依赖生成后导入IDEA即可。一个非常关键的建议项目创建后立刻在pom.xml里配置阿里云公共仓库镜像。国内网络环境直接拉Maven中央仓库的依赖经常会卡死或极慢配置镜像能节约大量时间repositories repository idaliyun/id urlhttps://maven.aliyun.com/repository/public/url /repository /repositories3.4 前端工程初始化要点前端我用Vite创建Vue 3项目命令是npm create vitelatest 点餐系统前端 -- --template vue这里说明一下很多人习惯用vue create那是在Vue CLI时代。新项目用Vite是趋势启动速度比Webpack快一个量级Vue官方也明确推荐。进入项目后安装Element Plus和Vue Router和Pinianpm install element-plus vue-router4 pinia axios npm installNode版本如果太低会报错Vite 4以上要求Node至少14.18建议直接用最新LTS版本。4. 数据库设计这个系统的“骨架”长什么样数据库设计是毕业设计里最见功底的部分也是论文里的核心章节。点餐系统的表结构我建议控制在6张核心表左右不要多也不要少正好能把关系讲清楚。4.1 核心表结构设计用户表sys_user用户ID、用户名、密码BCrypt加密存储、手机号、角色类型0-顾客1-管理员、创建时间。角色用一个字段区分即可不必单独建角色表避免过度设计。菜品分类表category分类ID、分类名称、排序号、是否上架。分类和菜品是一对多关系。菜品表dish菜品ID、分类ID外键、菜名、图片URL、价格、描述、月销量、上架状态。价格用DECIMAL类型不要用FLOAT精度是钱的基本底线。购物车表shopping_cart记录ID、用户ID、菜品ID、数量、加入时间。购物车更像会话维度的临时数据也可以用Redis实现但对毕业设计来说MySQL表最直观易懂。订单表orders订单ID、订单编号唯一字符串、用户ID、订单总金额、订单状态待支付/已支付/制作中/已完成/已取消、下单时间、支付时间、备注。订单明细表order_detail明细ID、订单ID、菜品ID、菜品名称冗余字段、菜品单价冗余字段、数量、小计金额。为什么要冗余菜品名称和单价到明细表因为菜品信息是可变的如果厨师改了菜名或价格历史订单里的记录会被连带改变这在业务上是不允许的。保存下单时刻的快照这就是数据冗余的经典意义。4.2 表关系梳理各表之间的关系可以这样描述一个用户对应多个订单一个订单对应多个订单明细一个分类下包含多个菜品一个用户拥有一个购物车含多行数据。这个关系结构在论文里画一张标准的ER图整体逻辑就非常清晰了。4.3 数据库创建的实操建议写SQL建库建表时注意几点字符集统一utf8mb4排序规则utf8mb4_general_ci。不要在代码里拼接SQL语句要使用MyBatis或MyBatis-Plus的预编译机制防止SQL注入这个安全习惯从学习阶段就要养好。表名和字段名尽量用有业务含义的英文命名不要用拼音缩写。表名用单数还是复数没有强制的行业标准但一个项目内必须统一。初始化数据要精心准备。把菜品分类业务处理好设计一些像样的菜品数据图片提前准备些高清的美食图价格定得合理这样才能让演示效果最好。这个细节直接影响最后效果值得认真做一遍。5. 后端实现SpringBoot核心业务落地后端是整个系统的心脏所有业务逻辑都在Java代码中实现。下面把最核心的几个模块的编码思路和关键代码拆开讲。5.1 项目目录结构规划一个清晰的项目包结构是专业感的直接体现com.example.restaurant ├── controller # 控制层接收前端请求 ├── service # 业务逻辑层接口 │ └── impl # 业务实现类 ├── mapper # 数据访问层MyBatis接口 ├── entity # 实体类与数据库表字段对应 ├── common # 通用类统一返回结果、异常处理等 ├── config # 配置类WebMvc、跨域等 ├── utils # 工具类 └── RestaurantApplication.java # 启动类我见过有些同学把Controller里的代码写了一大堆SQL逻辑Service层空着没用这是典型的反面案例。记住Controller只做参数接收和结果返回Service层承载业务逻辑Mapper层只做数据库交互这个分层规范在答辩时一定会被问到。5.2 统一返回结果与异常处理前后端分离项目中后端返回给前端的数据格式要统一不然前端同学或者你自己写前端时处理起来会很痛苦。定义一个通用返回类Data public class ResultT { private Integer code; // 1-成功0-失败 private String msg; // 提示信息 private T data; // 返回数据 public static T ResultT success(T data) { ResultT result new Result(); result.setCode(1); result.setMsg(成功); result.setData(data); return result; } public static T ResultT error(String msg) { ResultT result new Result(); result.setCode(0); result.setMsg(msg); return result; } }同时配一个全局异常处理器用RestControllerAdvice捕获项目里的业务异常和未预期异常返回统一的错误信息。这一套配置完了后面所有Controller写起来会非常清爽省去大量重复的异常处理代码。5.3 菜品模块最基础的CRUD范本菜品管理是点餐系统最核心的基础功能。以管理员添加菜品为例Controller层的写法PostMapping(/dish) public ResultString addDish(RequestBody Dish dish) { dishService.saveDish(dish); return Result.success(添加成功); }这里的RequestBody接收前端传来的JSON格式数据SpringBoot会自动将其反序列化为Dish实体对象。Service层保存时要注意检查菜品名称是否重复并将图片URL做一个合法性校验。菜品的分页查询是另外一个大头。用MyBatis-Plus的分页插件可以节省大量代码配置一个分页拦截器并实现分页查询过程十分清晰。前端传入当前页和每页条数后端返回总记录数和数据列表。5.4 购物车逻辑一次需要思考的业务实现购物车不算复杂但有几个业务规则要说清楚同一个用户、同一个菜品只保留一条购物车记录重复添加时累加数量购物车内的库存校验在真正下单时做用户清空购物车时直接按用户ID删除向购物车添加菜品的核心代码Service public class ShoppingCartServiceImpl implements ShoppingCartService { Override public ShoppingCart addToCart(ShoppingCart cart) { // 先查这个用户的购物车里有没有这个菜品 ShoppingCart existing getOne( new LambdaQueryWrapperShoppingCart() .eq(ShoppingCart::getUserId, cart.getUserId()) .eq(ShoppingCart::getDishId, cart.getDishId())); if (existing ! null) { // 已经有数量加1 existing.setNumber(existing.getNumber() 1); updateById(existing); return existing; } // 没有新建一条数量默认1 cart.setNumber(1); save(cart); return cart; } }这段代码用到了MyBatis-Plus的LambdaQueryWrapper避免了硬编码数据库字段名代码可读性和可维护性都好很多。5.5 下单与订单状态流转下单是整个系统的核心环节涉及事务操作。事务在这时必须加上Transactional因为下单涉及多个表的写操作生成订单主记录、写入订单明细、清空购物车、扣减菜品库存任何一个步骤失败都要回滚不允许出现“订单建了但明细没写进去”这种脏数据。订单状态这里用状态机思想来设计定义一组状态常量0 - 待支付 1 - 已支付后厨开始制作 2 - 制作中/已出餐 3 - 已完成 4 - 已取消这个状态流转要定义清楚。用户下单后默认待支付支付成功后状态置为“已支付”后厨端看到新订单后操作“开始制作”制作完成后置为“已完成”。整个流程闭合合理答办时也会问到这种流程设计。另外一个隐藏要点是“超时未支付取消”。简单做法是用户在订单列表里手动取消如果需要演示“自动取消”可以用Spring Task定时任务扫描超过30分钟未支付的订单这个可以作为一个加分项写在论文里。5.6 后端一些关键的配置细节跨域问题在前后端分离项目中几乎100%会碰到。前端跑在localhost:5173后端跑在localhost:8080两者端口不同即产生跨域。在SpringBoot中写一个CorsConfig配置类或者用CrossOrigin注解解决。更规范的方式是配置CorsFilter统一放行。登录认证这里做个提醒不要用Session那套老办法。建议使用JWTJSON Web Token实现无状态认证用户在登录接口换取Token之后的请求在Header中携带Authorization: Bearer token后端通过拦截器解析Token获取用户信息。这个技术点也很成熟写论文时能体现你对前后端分离架构的深层次理解。6. 前端实现Vue 3从页面到交互全流程前端是整个项目里最容易被低估的部分。不少同学觉得后端才是重点前端“随便搞搞就行”结果答辩时界面粗糙、交互生硬给评委的第一印象分大打折扣。其实用Vue 3加Element Plus做出一个整洁美观的页面并没有多难。6.1 前端项目结构划分Vue前端建议按“顾客端”和“管理端”两个模块来规划页面目录结构如下src ├── api # 接口请求封装 ├── assets # 静态资源图片、样式 ├── components # 公共组件 ├── router # 路由配置 ├── store # Pinia状态管理 ├── views # 页面组件 │ ├── customer # 顾客端菜单展示、购物车、订单列表 │ └── admin # 管理端菜品管理、订单处理、数据统计 ├── App.vue └── main.js6.2 顾客端菜单页技术组合的集中体现顾客端的菜单页是核心页面重点在于调用后端API、渲染菜品列表按分类分Tab展示、加入购物车。请求后端需要用到axios先做一个简单的封装import axios from axios import { ElMessage } from element-plus const request axios.create({ baseURL: /api, // 通过Vite代理转发到后端 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 0) { ElMessage.error(res.msg) return Promise.reject(new Error(res.msg)) } return res }, error { ElMessage.error(网络异常请稍后重试) return Promise.reject(error) } ) export default request这里的/api前缀用到了Vite的代理配置在vite.config.js里设置export default defineConfig({ server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true, rewrite: path path.replace(/^\/api/, ) } } } })这样可以避免开发环境下频繁处理跨域问题前端写代码时直接请求相对路径生产部署时只需把/api在Nginx里转发到后端接口即可同一个代码不需要改就能适配不同环境这是我最推荐的实践方式。推荐全程使用这种方式避免跨域错误。6.3 菜品分类Tab与菜品卡片渲染用Element Plus的el-tabs组件做分类切换用el-row和el-col栅格系统做菜品卡片布局。菜品卡片需要展示图片、名称、描述、价格和“加入购物车”按钮价格展示可以用¥前缀加一个强调色。这里的“加入购物车”操作背后需要两个要点如果用户未登录去登录页面跳转可以用Vue Router的router.push方法实现用户已登录调用后端POST /cart接口并附带菜品ID另外还要处理数量加减和实时汇总。可以在状态管理里维护一个购物车数量的状态每次操作后从后端重新拉取购物车数据逻辑更清晰也不容易出现前端本地状态与后端不同步的问题。6.4 管理端页面表格操作与表单校验管理端的菜品管理页核心是一个数据表格加新增、编辑、删除、分页的操作。Element Plus的el-table组件加el-dialog表单弹窗几乎是标准做法。给菜品添加“上架/下架”状态切换用el-switch组件操作后立即调用后端更新接口。这个交互很直观也展示了前端事件处理能力。表单校验做在提交到后端之前避免无效请求打过来。比如菜名不能为空、价格必须是正数、图片URL格式是否合法等。这些校验既在前端Form rules里做一遍后端也要用Valid注解做同样校验。前后端双层校验的原因很实际前端校验是为了用户交互体验好后端校验才是真正的安全防线因为绕过前端直接调API太容易了。6.5 订单列表与轮询“新订单提醒”后厨看板是管理端的一个亮点页面。后厨需要实时看到新订单最简单的实现是前端定时轮询后端接口比如每10秒拉一次最新订单列表状态为“已支付”的优先展示。用setInterval就可以实现这个页面能把项目演示的带入感拉满。路由配置方面记得使用Vue Router的路由守卫功能在进入管理端页面之前判断当前用户的角色是否为管理员不是则重定向到首页保护后台页面。7. 核心功能实现JWT登录、购物车、下单、订单处理的完整闭环前面功能点分散讲了不少这一章把这些功能串成一个完整的业务闭环按一个顾客从登录到完成点餐的真实路径走一遍方便你看清楚后端各个模块之间的调用关系。7.1 注册与登录流程用户在前端填写用户名、手机号和密码密码在后端用BCrypt加密后存储Service public class UserServiceImpl implements UserService { Override public void register(User user) { // 检查用户名是否已存在 long count this.count(new LambdaQueryWrapperUser() .eq(User::getUsername, user.getUsername())); if (count 0) { throw new BusinessException(用户名已存在); } // BCrypt加密密码 String encodedPassword DigestUtils.bcrypt(user.getPassword()); user.setPassword(encodedPassword); save(user); } }登录的核心是“校验用户名密码 颁发JWT令牌”。JWT生成时把用户ID和角色放进去生成代码public String generateToken(User user) { MapString, Object claims new HashMap(); claims.put(userId, user.getId()); claims.put(role, user.getRole()); return Jwts.builder() .setClaims(claims) .setSubject(user.getUsername()) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() 3600 * 1000 * 24)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) .compact(); }在实际使用中可以把登录后的token存储到LocalStorage并添加一个基于Pinia的状态记录用户信息。这是最常见的做法。7.2 下单事务数据一致性是硬要求下单代码是整个系统中最重要的一段逻辑必须保证真正的数据一致性完整代码逻辑如下Transactional(rollbackFor Exception.class) public Order submitOrder(Long userId, String remark) { // 1. 查询购物车中该用户的所有菜品 ListShoppingCart carts cartMapper.selectList( new LambdaQueryWrapperShoppingCart() .eq(ShoppingCart::getUserId, userId)); if (carts null || carts.isEmpty()) { throw new BusinessException(购物车为空无法下单); } // 2. 构建订单主记录计算总金额 Order order new Order(); order.setUserId(userId); order.setOrderNo(UUID.randomUUID().toString().replace(-, )); order.setStatus(0); // 待支付 order.setRemark(remark); BigDecimal totalAmount BigDecimal.ZERO; ListOrderDetail orderDetails new ArrayList(); for (ShoppingCart cart : carts) { Dish dish dishMapper.selectById(cart.getDishId()); // 校验菜品上架状态与库存 if (dish.getStatus() ! 1) { throw new BusinessException(dish.getName() 已下架请重新选择); } OrderDetail detail new OrderDetail(); detail.setDishId(dish.getId()); detail.setDishName(dish.getName()); detail.setDishPrice(dish.getPrice()); detail.setNumber(cart.getNumber()); BigDecimal subtotal dish.getPrice().multiply( BigDecimal.valueOf(cart.getNumber())); detail.setAmount(subtotal); orderDetails.add(detail); totalAmount totalAmount.add(subtotal); } order.setTotalAmount(totalAmount); // 3. 保存订单和明细 orderMapper.insert(order); for (OrderDetail detail : orderDetails) { detail.setOrderId(order.getId()); orderDetailMapper.insert(detail); } // 4. 清空购物车 cartMapper.delete( new LambdaQueryWrapperShoppingCart().eq(ShoppingCart::getUserId, userId)); return order; }这里你注意到几个关键判断菜品下架状态在下单时校验、总金额用BigDecimal运算而非double、事务回滚保障数据一致性。这三个细节放到答辩里都是加分项尤其是“为什么用BigDecimal”这个问题几乎必被问到。7.3 支付模拟不要真的对接三方支付很多同学在“支付”功能上纠结很久担心不接入微信/支付宝支付会不会显得不完整。这里告诉你一个成熟的做法做一个“模拟支付”流程即“点击支付”按钮前端弹出一个支付确认框用户确认后调后端接口把订单状态从待支付改为已支付。这个设计在毕业设计中完全合理且有更好的实施方式因为你避开了申请商户号的繁琐流程又完整演示了订单状态流转。可以把这部分的阅读理解清楚后在论文里有技巧地说明解释为“因毕业设计环境限制采用模拟支付完成流程验证”。7.4 订单流全过程概览一个顾客完成一次完整点餐的流程如下注册/登录进入菜单页预览菜品分类和菜品信息选择菜品加入购物车购物车角标同步更新进入购物车页面确认菜品、数量、合计金额提交订单并“模拟支付”订单状态变为已支付后厨管理端看到新订单点击“开始制作”状态置为制作中出餐后点击“完成”订单状态变更为已完成顾客可以在订单列表中查看订单的实时状态这套流程描述清晰业务闭环完整可以让老师在演示前就建立对一个系统全局的理解。8. 联调、测试与部署让你的系统跑起来并能给人演示项目开发完成后的联调和部署是很多同学容易忽略的最后环节这里重点提醒几个关键操作。8.1 前端与后端联调的常见错误联调时最容易出现的问题一是跨域配置未生效前端报CORS policy错误二是前端请求路径写错——前端发的/api/dish/list后端接口实际却没有这一条路径映射三是JSON字段名对不上后端返回的是createTime前端却用了create_time导致界面上的时间一直是空。自己一个人做全栈时出现这些问题尤其是别慌用浏览器的Network面板看具体请求和响应基本都能很快定位问题。8.2 Linux服务器部署全流程如果时间允许强烈建议把项目部署到远程Linux服务器上做一个公网可访问的演示环境比较有说服力。最稳妥也最基础的方式是手动部署后端部署三步走把项目用mvn clean package打成JAR包后上传到服务器任意目录用nohup java -jar restaurant-system.jar log.log 21 启动服务。前端部署也可以用npm run build打生成静态文件再配置Nginx将静态页面和后端API的代理同时处理好。用宝塔面板可以简化不少操作部署一套下来能直观看到自己写的系统在公网运行的感觉心态也会不一样。9. 常见问题与排查技巧实录那些踩过的坑这部分是这些年来学生在开发过程中反复踩坑的实战经验记录整理成速查表帮你省下大量的排查时间。9.1 SpringBoot启动类报错现象启动时提示Failed to configure a DataSource: url attribute is not specified。原因添加了MyBatis或JPA依赖但还没有配置数据库连接信息。解决在application.yml里配置spring.datasource.url、username、password和driver-class-name或者临时去掉数据库相关依赖。9.2 MyBatis-Plus的Mapper扫描问题现象项目启动报错Invalid bound statement (not found)。原因启动类上没有加MapperScan注解或者Mapper接口上漏了Mapper注解。解决在启动类上加上MapperScan(com.example.restaurant.mapper)保证扫描到Mapper接口。9.3 Vue安装依赖时出现engine / 版本不支持现象npm install时报Unsupported engine或ERESOLVE unable to resolve dependency tree。原因Node和依赖包的版本兼容问题或者在安装Element Plus时与Vue版本不匹配。解决升级Node到18删除node_modules和package-lock.json后重新install必要时用npm install --legacy-peer-deps绕过依赖冲突。9.4 Element Plus图标不显示现象页面上的图标组件空白控制台报警告element-plus/icons-vue未注册。解决需要全局注册图标库import * as ElementPlusIconsVue from element-plus/icons-vue for (const [key, component] of Object.entries(ElementPlusIconsVue)) { app.component(key, component) }9.5 JWT登录后刷新页面丢失用户信息原因Vuex或Pinia里的用户状态存储在内存中刷新即丢失。解决页面刷新时从localStorage中读取token再调用一个/user/info接口重新拉取用户信息然后重新填充状态管理。9.6 时间字段显示不正常原因后端返回的是LocalDateTime对象默认序列化格式为yyyy-MM-ddTHH:mm:ss前端直接显示会带一个T。解决在application.yml中配置spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT89.7 数据库连接失败现象后端日志报Access denied for user rootlocalhost。原因MySQL连接的用户名或密码错误或者MySQL驱动版本不支持。解决检查配置文件里的账号密码和MySQL实际一致同时确认MySQL服务已启动net start mysql。9.8 JWT SecretKey 报错现象Signing key is too short运行时异常。原因HS256算法要求Key的最小长度是256位太短的字符串会报错。解决SecretKey设置一个足够长的随机字符串至少32个字符。10. 源码管理与论文写作毕设不止是写代码每次指导答辩总有一部分学生代码本身很能打、但论文逻辑一塌糊涂或者答辩时打开一个“脏乱差”的代码目录。这里给出一些在项目做完之后用来准备论文和答辩的重要经验。10.1 论文结构的合理组织毕业设计论文大致按以下结构写不容易出错第一章绪论写背景和意义时聚焦餐饮行业管理痛点纸质菜单更新慢、人工下单易出错、后厨与前台信息不同步等。研究现状尽量引用几篇真实文献并用滚雪球的方式搜索。第二章关键技术介绍SpringBoot、Vue、MySQL、MyBatis-Plus、JWT等。这个部分篇幅不易过大每项技术写原理和特性即可。注意不要照搬官网介绍。第三章系统需求分析功能需求、用例图、非功能需求三个维度展开。第四章系统设计架构图、功能模块图、E-R图、数据库表设计这里是图表密集区域。第五章系统实现核心功能模块的实现描述加功能截图。这里记得给页面逐张截好高分辨率图。第六章系统测试功能测试用例表加部分性能测试结果。论文写作最重要的原则是“图表结合”不要让大段文字堆砌页面。能画图说明的就不要只用文字描述。10.2 Git版本管理的最佳实践从项目第一天起就养成使用Git的习惯。推送到Gitee或GitHub私有仓库每天做完一个独立功能就提交一次确保每一次commit的信息符合提交内容。提交的文档尽量简洁比如“feat: 完成用户注册登录模块”“fix: 修复下单事务回滚问题”。这样定时推送的好处有两个一是防止电脑突然坏了导致项目文件丢失二是论文答辩时老师问“这个项目是怎么开发的”可以打开Git提交历史给对方看你的开发进度和迭代过程这个“事实依据”让整个项目变得更可信。最后在README里写清楚项目的启动方式、技术栈、默认账号密码和演示流程交给老师或评委时对方不至于看不懂你的项目。结语毕业设计的价值不在“做完”在于“做出名堂”带过这么多届毕业生我最大的感受是真正拉开差距的不是谁的技术点使用更炫而是谁更完整地把一个需求交付成了一个可用、可演示、可讲解的产品。同样是点餐系统有人做出来是“课程作业”有人做出来就可以直接当成一个成品给小型餐厅用差别体现在每个细节例如设计的完整度、异常情况的考虑是否周全、以及在需要时能否写出有深度的讲解说明。我个人在实际操作中体会最深的一点是写四个月代码不如认认真真写一份完整的设计文档。很多当年在代码里没有想清的问题在画架构图、写设计说明时才会暴露出来。所以建议你在编码之前先画好E-R图先把接口命名和参数约定议清楚再动手打代码。希望站在你前方替你踩过这些坑的这份详细拆解能让你的毕业设计之路平坦很多。如果你在搭建过程中遇到了什么别的问题也建议先自己想一个排查的思路再去搜索能收获的远比“复制粘贴解决方案”要多得多。觉得哪个章节对你有帮助不妨动手把对应代码先敲一遍好记性不如烂键盘。
返回列表