ARTICLE DETAIL

资讯详情

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

Spring Boot餐饮财务系统实战:从业务流程到部署避坑全解析

Spring Boot餐饮财务系统实战:从业务流程到部署避坑全解析 我最早接手这类项目是在做毕业设计辅导的时候一个学弟拿着“餐饮财务管理系统”的题目来找我说学校要求用Spring Boot做一套带前端页面的系统但他连项目结构都还没理清。后来这几年陆陆续续又帮人看过不少类似的项目包括本科毕设、课程设计甚至一些小餐馆老板找人做的内部记账工具。说实话这类“基于Spring Boot的餐饮财务管理系统”在表面上看起来是个很常规的CRUD项目但真正动手做起来里面的门道比想象中多得多。这套系统解决的核心问题很明确餐饮行业每天的流水笔数多、来源杂——有前台点餐的有外卖平台的有会员储值的还有供应商采购的支出。如果只靠Excel或者手工账本月底对账能把人逼疯。而一套称职的餐饮财务管理系统至少要把“收入、支出、菜品、库存、报表”这几条线串起来让老板打开系统就能看清今天赚了多少、哪些菜卖得好、这个月食材成本有没有超标。这篇文章我就以这个项目为引子把我实际做这类系统时的完整思路写下来。内容包括业务流程怎么拆解、数据库怎么设计、Spring Boot后端怎么搭、权限和财务数据安全怎么处理以及那些文档里不会写、但你在答辩或实际上线时一定会遇到的坑。无论你是准备拿这个题目做毕设还是真的想给自家餐馆搞一套内部管理系统这篇都能给你一个可以直接照着做的参考。我会尽量说人话不堆术语但该讲清楚的技术细节一处都不会省。1. 别急着写代码餐饮财务系统的业务流程拆解很多新手拿到这个题目第一反应就是建表、写接口。但餐饮财务系统和普通的后台管理系统有个本质区别它的数据是流动的从点餐到结账到入账再到采购和成本核算整条链路是闭环的。你如果不先把业务流程理顺写出来的代码大概率是“能跑但没法用”。1.1 两条核心数据链路钱怎么进来钱怎么出去餐饮财务说到底管的就是现金流。我习惯把整个系统的数据流拆成两条主链收入链钱怎么进来顾客到店 - 服务员开台/点餐 - 后厨出菜 - 顾客结账现金/扫码/会员卡 - 订单状态变为已支付 - 流水进入当日营收。支出链钱怎么出去食材采购 - 供应商送货 - 验收入库 - 库存更新 - 后厨领料出库 - 月末盘点 - 成本核算。这两条链交汇的地方是菜品。菜品既是收入端卖出去了产生营业额又是支出端做一道菜要消耗食材食材是成本。所以菜品的毛利计算本质上是把收入链和支出链的数据在菜品位上做了一次对齐。我在设计系统的时候会先画一张这样的逻辑图而不是直接开写。哪怕你不画图脑子里也必须有这个概念所有财务模块的数据最终要能回溯到一张原始单据——卖出去的每一笔钱要能查到对应的订单花出去的每一笔钱要能查到对应的采购单或费用单。这是财务系统的底线和用什么技术框架无关。1.2 角色权限设计老板、收银员、后厨看到的是不同的东西餐饮系统里至少有三类角色他们的诉求完全不同角色核心诉求系统应该给他们什么老板/财务看总账、看毛利、看趋势关心钱去哪了报表、图表、日结汇总、成本分析收银员/服务员开台、点菜、结账、打印小票要够快简洁的点餐界面、快速结账、桌台状态后厨/库管看今天要备什么菜、领了什么料、库存还够不够菜品估清、备货清单、领料出库、库存预警如果你用的是Spring Boot Vue这种前后端分离的结构权限这块建议直接用Spring Security JWT来做但别再自己手写拦截器判断角色了。我见过太多项目在Controller里写if(user.getRole().equals(admin))这种散装权限后期加一个角色就要改几十个接口维护成本极高。正确做法是用Spring Security的注解比如PreAuthorize(hasAuthority(finance:report:view))把权限粒度细化到操作级别前端用Vue Router的守卫控制页面跳转后端用注解兜底校验。记住一个原则前端控制的是用户体验后端控制的是数据安全。1.3 功能模块的取舍第一版别贪多很多参考论文里的餐饮系统恨不得把会员营销、进销存、人力排班、供应链全塞进去。但你如果是做毕设或者给小店做系统第一版我强烈建议只做四个核心模块桌台与点餐管理桌台状态空闲/占用/结账中、开台、点菜、换桌、并桌。这是收入流水的源头。菜品管理菜品分类、菜品CRUD、上下架状态、菜品估清卖完了就标记。采购与库存管理供应商信息、采购单录入支出流水的源头、食材入库、库存预警。财务与报表日结汇总当日收入/支出/毛利、按时间段的营业报表、菜品销售排行、库存成本核算。这是整个系统的出口也是老板唯一真正关心的地方。把这三个模块做扎实比堆砌十个半成品模块要值钱得多。我辅导过的学生里凡是主动砍掉“会员积分”“拼团秒杀”“员工排班”这些花架子的最后答辩时都能把核心逻辑讲透老师反而会高看一眼。2. 数据库设计是财务系统的命根子代码写得烂还能靠重构救数据库设计错了直接推翻重来。餐饮财务系统涉及钱数据的一致性和可追溯性比啥都重要。我设计数据库时有几条铁律你可以直接抄。2.1 核心表结构一张图理清十来张表的关系一个标准的餐饮财务系统数据库表通常在12到16张左右。我把核心表列出来你建表的时候照这个框架去扩展就行基础数据表sys_user用户表id, username, password, real_name, role_id, statussys_role角色表id, role_name, role_code, description建议用role_code做权限判断别用中文名category菜品分类表id, name, sort, statusdish菜品表id, category_id, name, price, cost, image, statusstatus字段控制上下架和估清dining_table桌台表id, table_no, capacity, status空闲/占用/结账中业务流水表orders订单主表id, order_no, table_id, user_id操作员, total_amount, pay_type, status, create_time——status建议用数字枚举0未支付、1已支付、2已退款、3已作废order_detail订单明细表id, order_id, dish_id, dish_name冗余字段防止菜品改名后历史订单查不到, price, quantity, amountsupplier供应商表id, name, contact, phone, address, statuspurchase_order采购单主表id, purchase_no, supplier_id, total_amount, operator_id, status, create_timepurchase_detail采购明细表id, purchase_id, ingredient_id, quantity, price, amount——注意这里关联的是**食材ingredient**而不是菜品ingredient食材表id, name, unit, stock, warn_stock, pricefinance_record财务流水表id, record_no, biz_type收入/支出, biz_no关联订单号或采购单号, amount, pay_type, create_time, remark最后这张finance_record表是点睛之笔。它把订单和采购单里涉及钱的数据全部冗余了一份做日结报表的时候直接查这张表性能又快又不容易漏。这也是为什么很多初版系统对不上账的原因报表直接从订单表里聚合结果退款单、作废单没有过滤数字就脏了。2.2 冗余字段和逻辑删除财务系统的两个隐藏要求在做业务表的时候有两件事新手最容易忽略第一是冗余业务字段。比如订单明细表里存了dish_name采购明细表里存了ingredient_name而不是只用外键关联。为什么因为菜品和食材是会被改的——厨师长觉得“宫保鸡丁”太难听改成了“宫保鸡丁微辣版”如果不冗余三个月前的订单明细里这道菜就变成了“未知菜品”月底对账的时候你根本没法跟店长解释。这就是典型的“业务数据要保留历史快照”思想。第二是逻辑删除大于物理删除。财务系统的任何记录千万不要用DELETE FROM直接物理删除。订单录错了要作废采购单填错了要冲红这些都是业务操作要留下痕迹。我一般会加一个is_deleted字段默认0删除时置为1。查询时全局过滤掉已删除数据但底层数据永远在。这不是矫情是财务审计的基本要求——你删掉的每一笔账将来都可能要回来查。2.3 索引和字段类型细节决定查询有多快还有一个实际测试中才会暴露的问题。orders表数据量到十万条之后不带索引的create_time范围查询会慢到你想骂人。我在orders、order_detail、purchase_order、finance_record这几张表上都建了这些索引create_time单独建索引按日期查报表必用order_id在order_detail上建普通索引查订单详情必用status和create_time建联合索引查“某时间段内已支付的订单”时效率翻倍字段类型方面所有金额字段一律用DECIMAL(10,2)禁止用FLOAT或DOUBLE。这不是老顽固而是浮点数在二进制里存在精度误差0.1 0.2 计算出来是 0.30000000000000004。财务数据出现这种误差月底平账的时候你会疯掉。Java端对应的是BigDecimal这个没得商量。3. Spring Boot 后端落地项目结构、核心接口与事务控制技术选型上这个项目我用的是 Spring Boot 2.7.x MyBatis-Plus MySQL 8.0 Redis可选 Spring Security。为什么是Spring Boot 2.7而不是3.x因为3.x是基于Jakarta EE的很多老教程和插件还停留在javax命名空间毕设或小团队项目没必要冒这个兼容性的险。Spring Boot 2.7还在社区主流维护期内资料多、坑少稳妥优先。3.1 项目目录结构约定优于配置我见过太多Spring Boot项目Controller里塞了三百行业务逻辑Service层形同虚设。一个清晰的项目结构长这样com.example.restaurant ├── controller/ # 接口层只做参数接收和结果封装 ├── service/ # 业务层核心逻辑都在这 │ └── impl/ ├── mapper/ # MyBatis-Plus的Mapper接口 ├── entity/ # 数据库表对应的实体类 ├── dto/ # 接收前端参数的传输对象 ├── vo/ # 返回给前端的视图对象 ├── config/ # 配置类Security配置、MyBatisPlus配置、跨域配置等 ├── common/ # 通用类统一返回结果、异常处理、常量类 ├── utils/ # 工具类 └── RestaurantApplication.java这个结构用一句话总结就是Controller不写业务、Service不写SQL、Mapper只写数据库操作。分层清晰了后面所有的问题都好排查。3.2 核心接口示例点餐、结账、日结的代码写法我挑三个关键接口的实际写法给你看都是我验证过能直接用的。点餐接口这里的关键是事务。一次点餐要同时更新orders表、插入order_detail明细、更新桌台状态为“占用”任何一个环节失败都不能留下半截数据。所以必须加Transactional注解Transactional public boolean createOrder(CreateOrderDTO dto) { // 1. 校验桌台状态占用中不能重复开台 DiningTable table diningTableMapper.selectById(dto.getTableId()); if (table.getStatus() ! 0) { throw new BusinessException(该桌台当前不可用); } // 2. 生成订单号和明细 Orders order new Orders(); order.setOrderNo(generateOrderNo()); // 例如20240615 6位随机数 order.setTableId(dto.getTableId()); order.setStatus(0); // 未支付 order.setTotalAmount(calculateTotal(dto.getItems())); ordersMapper.insert(order); // 3. 插入订单明细 for (OrderItemDTO item : dto.getItems()) { OrderDetail detail new OrderDetail(); detail.setOrderId(order.getId()); detail.setDishId(item.getDishId()); detail.setDishName(dishMapper.selectById(item.getDishId()).getName()); detail.setPrice(item.getPrice()); detail.setQuantity(item.getQuantity()); orderDetailMapper.insert(detail); } // 4. 桌台状态置为占用 table.setStatus(1); diningTableMapper.updateById(table); return true; }注意那个generateOrderNo()千万不要用数据库自增ID当订单号给顾客看不然竞对一看你的订单号就知道你一天做了多少单。我的做法是yyyyMMddHHmmss 4位随机数订单号看起来像202406151430251234长度稳定又不泄露业务量。结账接口这涉及钱的变更逻辑上要更谨慎。除了改订单状态还要把流水写入finance_record。所以我把这两个动作放在同一个事务里Transactional public boolean settleOrder(SettleDTO dto) { // 1. 校验订单存在且未支付 Orders order ordersMapper.selectById(dto.getOrderId()); if (order null || order.getStatus() ! 0) { throw new BusinessException(订单状态异常无法结账); } // 2. 更新订单为已支付 order.setStatus(1); order.setPayType(dto.getPayType()); // 1现金 2微信 3支付宝 4会员卡 ordersMapper.updateById(order); // 3. 写入财务流水收入 FinanceRecord record new FinanceRecord(); record.setRecordNo(generateRecordNo()); record.setBizType(1); // 1收入 2支出 record.setBizNo(order.getOrderNo()); record.setAmount(order.getTotalAmount()); record.setPayType(dto.getPayType()); financeRecordMapper.insert(record); // 4. 释放桌台状态改回空闲 DiningTable table diningTableMapper.selectById(order.getTableId()); table.setStatus(0); diningTableMapper.updateById(table); return true; }日结报表接口这个接口的核心是聚合查询。我直接在Mapper里写了自定义SQL按天分组统计收入和支出// Mapper中自带的查询用LambdaQueryWrapper配合日期函数实现 public DailyReportVO getDailyReport(String date) { // 查当天的总收入已支付订单 QueryWrapperOrders incomeWrapper new QueryWrapper(); incomeWrapper.select(IFNULL(SUM(total_amount),0) AS totalIncome) .between(create_time, date 00:00:00, date 23:59:59) .eq(status, 1); // 查当天的总支出采购单杂项支出 QueryWrapperFinanceRecord expenseWrapper new QueryWrapper(); expenseWrapper.select(IFNULL(SUM(amount),0) AS totalExpense) .eq(biz_type, 2) .between(create_time, date 00:00:00, date 23:59:59); // 剩余的就是毛利 总收入 - 总支出 }日结的数字要能对上当天的现金流水这是财务系统的第一道红线。测试的时候我习惯把“下单不结账”“结账后申请退款”“采购单录入错误被作废”这三种异常数据全部造一遍看报表数据是否会被污染。3.3 事务的坑自调用失效与回滚策略事务这块我觉得有必要单独拎出来讲一个我踩过的坑。Spring的Transactional默认是通过AOP代理实现的同类内部的互相调用不会走代理注解会失效。什么意思呢比如Service public class OrderServiceImpl { public void doSomething() { this.createOrder(dto); // 这里的事务注解根本没生效 } Transactional public boolean createOrder(CreateOrderDTO dto) { // ... } }this调用绕过了Spring的代理对象Transactional就废了。解决方法是把事务方法放在另一个Service里或者注入自己的代理对象调用。我个人的习惯是每个Service只管自己领域的原子操作跨领域的事务比如结账涉及订单财务流水单独再建一个外层Service来编排这样既避免了自调用问题职责也更清楚。还有一个细节默认情况下Spring事务只在RuntimeException和Error时回滚受检异常Exception的子类不会触法回滚。如果你在代码里吞了异常或者抛的是受检异常事务也会失效。我一般会在事务方法里统一抛出业务运行时异常配合一个全局异常处理器返回友好的报错信息。4. 权限与安全财务系统必须做对的三层防护财务数据是敏感的就算只是个课设答辩老师也会追着问安全问题。这个模块我给你梳理一条从登录到数据访问的完整链路。4.1 登录认证与密码存储别用明文别用MD5说实话我看到很多毕设项目用MD5加盐这种做法已经不多了但确实还有人在用简单的MD5。MD5加盐虽然能挡一下但它的运算速度太快了GPU并行运算可以快速撞库。正规做法是使用BCrypt算法Spring Security自带的BCryptPasswordEncoder就是干这个的每次加密会随机生成盐同一个密码两次加密结果不一样安全性完全不是一个级别。// 注册用户时加密保存 String encodedPassword passwordEncoder.encode(rawPassword); // 登录时校验 boolean matched passwordEncoder.matches(rawPassword, storedPassword);配置也很简单在Security配置类里声明一个BCryptPasswordEncoder的Bean就行。4.2 JWT生效期与Token刷新别让用户天天重新登录餐饮店的收银员早上开店就要登录系统如果Token有效期设成2小时中午高峰期收银台突然弹个“登录已过期”后厨和收银直接乱套。我在实际项目中把JWT有效期设为12小时后台管理端老板看报表的设为8小时然后加一个Token续期的逻辑当用户操作时如果Token剩余有效期不足2小时自动签发一个新Token放在响应头里返回前端收到后替换。这样用户在无感的情况下就完成了续期。具体实现是在JWT过滤器里验证完Token后判断剩余时间如果低于阈值就重新生成签名long remainTime expDate.getTime() - System.currentTimeMillis(); if (remainTime 2 * 60 * 60 * 1000) { String newToken jwtUtils.generateToken(user); response.setHeader(New-Token, newToken); }前端在axios响应拦截器里检测到New-Token就替换本地存储。这个细节做好了系统的使用体验会明显提升。4.3 越权访问与数据隔离按角色过滤返回数据权限安全里最容易被忽略的是垂直越权和水平越权。垂直越权就是普通收银员调了老板的报表接口水平越权是收银员A查了收银员B的某个数据。解决垂直越权用Spring Security的PreAuthorize注解解决水平越权要养成一个习惯在Service层查询时强制加上当前登录用户的ID作为过滤条件。我一般会在项目中加一个SecurityUtils.getCurrentUserId()工具方法从SecurityContext里拿到当前用户然后在所有涉及个人或角色范围数据的查询里带上这个条件。这是防御性的写法哪怕哪天前端页面写漏了后端也会把越权请求挡下来。5. 库存与成本的联动容易被忽视但老板最关心的功能前面说的收入、支出都是面上的账。餐饮老板真正的痛点其实是“钱收了但月底一算没赚多少”——问题大多出在库存损耗和成本核算上。所以财务系统里库存模块不能只是简单的增删改查它必须和“菜品销售”挂钩。5.1 菜品与食材的BOM关系算成本的基础一道菜用了哪些食材、各用多少克这个对应关系在餐饮行业里叫BOM物料清单。比如“鱼香肉丝”的BOM是猪肉丝150g、木耳30g、胡萝卜30g、青椒20g、调味料若干。有了BOM系统才能在卖出这道菜的时候自动扣减对应食材的库存Transactional public void deductStock(Long dishId, Integer quantity) { // 根据菜品的BOM清单循环扣减食材库存 ListDishBom bomList dishBomMapper.selectByDishId(dishId); for (DishBom bom : bomList) { Ingredient ingredient ingredientMapper.selectById(bom.getIngredientId()); BigDecimal deduction bom.getUsage().multiply(new BigDecimal(quantity)); if (ingredient.getStock().compareTo(deduction) 0) { throw new BusinessException(食材库存不足: ingredient.getName()); } ingredient.setStock(ingredient.getStock().subtract(deduction)); ingredientMapper.updateById(ingredient); } }BOM的建立是推进这类系统时最麻烦的环节——厨师长得配合着录入配方。我的建议是第一版可以先把BOM做得粗糙一点只维护主要食材的比例调味料之类的可按固定比例估算。等系统跑起来了老板看到成本数据有价值自然会愿意花时间完善BOM的精度。5.2 库存预警与采购建议让系统从“记账”升级为“帮手”库存表里的warn_stock字段就是库存预警线。当库存低于这个值系统要能主动提醒列表标红、首页看板提示甚至可以生成一份采购建议单SELECT ingredient_id, ingredient_name, (warn_stock - stock) AS suggest_purchase_qty FROM ingredient WHERE stock warn_stock;这一小段逻辑写起来不难但对系统的使用价值提升是质变的。餐饮店的老板每天最头疼的问题就是“今天要进多少货”系统能根据库存余量和菜品销量趋势给出参考值就能真正减轻店里的决策负担。5.3 库存盘点账面数和实际数对不上的处理现实中库存账永远不可能跟实物完全一致——损耗、员工餐、赠菜、过期报废都会造成差异。所以我设计了盘点单功能每月月底库管把实物盘点的数量录进系统系统自动算出盘盈盘亏的差额并生成一条记录Transactional public void checkStock(CheckStockDTO dto) { BigDecimal systemStock ingredientMapper.selectById(dto.getIngredientId()).getStock(); BigDecimal actualStock dto.getActualStock(); BigDecimal diff actualStock.subtract(systemStock); if (diff.compareTo(BigDecimal.ZERO) ! 0) { // 记录盘亏盘盈单 StockCheckRecord record new StockCheckRecord(); record.setIngredientId(dto.getIngredientId()); record.setSystemStock(systemStock); record.setActualStock(actualStock); record.setDiff(diff); stockCheckRecordMapper.insert(record); // 更新库存为实物数 ingredientMapper.updateStock(dto.getIngredientId(), actualStock); } }盘亏的金额会作为一项“成本损耗”进入财务支出这也解释了为什么月底利润比预期低——不是菜卖得不好而是成本跑冒滴漏了。先有盘盈亏数据老板才能有依据去查是哪个环节出了问题。6. 报表模块实战从SQL聚合到ECharts可视化报表是财务系统的门面老板打开系统第一眼看的肯定是首页看板。这一节我讲一下数据怎么查出来、怎么呈现以及哪些坑会让查出来的数字是错的。6.1 首页看板的四个核心指标首页看板不需要花哨但四个数字必须实时、准确今日营收当天已支付订单的总金额今日订单数当天已支付订单的总数本月采购支出当月所有采购单的总金额当前库存预警数库存低于预警线的食材种类数这四个指标分别查四张表用SQL的SUM和COUNT就能搞定。关键是查询的性能和后端缓存。由于首页看板大概率是查当天或当月的最新数据我一般会做一个简单的Redis缓存缓存5到10分钟避免每次刷新都全表聚合一次。等系统访问量大了再考虑用Canal同步MySQL到统计库或者上ClickHouse——但一个小餐馆的系统真用不上这玩意Redis缓存就够用了。6.2 菜品销售排行毛利比营收更重要菜品销售排行榜不要只按“销售额”排那样得出的结论可能是“贵菜卖得好”但对老板没有指导意义。我做的排行榜多了一个维度——毛利SELECT d.dish_id, d.dish_name, SUM(od.quantity) AS sale_count, SUM(od.amount) AS sale_amount, SUM(od.amount) - SUM(od.quantity * d.cost) AS gross_profit FROM order_detail od LEFT JOIN dish d ON od.dish_id d.dish_id WHERE od.create_time BETWEEN #{start} AND #{end} GROUP BY d.dish_id, d.dish_name ORDER BY gross_profit DESC LIMIT 10;有了毛利排行老板才能真正看懂“卖得好的菜不一定赚钱赚得多的是那些成本低毛利高的菜”。这个逻辑写起来只要多加一个字段但对系统的业务价值提升很大。6.3 前端可视化ECharts的接入和坑报表页面我一般用EChartsVue2用vue-echartsVue3用echarts的npm包直接引入。折线图展示一周或一月的营收趋势饼图展示支付方式占比柱状图展示各分类菜品销量。后端返回的数据结构建议直接组好给前端不要让前端去做复杂的计算。一个比较容易踩的坑时间字段在前端显示时差问题。如果后端返回的是2024-06-15 00:00:00这种带时区的字符串前端new Date()解析后按浏览器本地时区显示如果服务器和浏览器时区不一致可能会显示成前一天或后一天。我的解决办法是在Spring Boot的application.yml里明确指定时区spring: jackson: time-zone: GMT8 date-format: yyyy-MM-dd HH:mm:ss另外所有涉及日期范围的查询统一用字符串传参比如startDate2024-06-01、endDate2024-06-30后端用LocalDate解析并在SQL层做BETWEEN。这样既避免了时区混乱又让SQL索引能正常命中。7. 打包部署与常见坑从本地跑通到真正上线很多人开发时一切正常一到部署就翻车。这一节我把Spring Boot项目部署到服务器上的完整流程和最容易出问题的地方都捋一遍。7.1 打包配置与前端静态资源合并如果前后端分离后端打成JAR包前端npm run build之后把生成的dist目录里的文件复制到后端项目的src/main/resources/static下然后一起打包。这样部署时只需要跑一个JAR就行不用单独配Nginx虽然实际生产我还是建议用Nginx但课设和小项目一个JAR最省事。pom.xml里记得加Spring Boot的Maven插件否则打包出来的JAR可能不是可执行的build plugins plugin groupIdorg.springframework.boot/groupId artifactIdspring-boot-maven-plugin/artifactId /plugin /plugins /build然后执行打包命令mvn clean package -DskipTeststarget目录下会生成一个xxx.jar直接传到服务器上运行。7.2 Linux服务器上后台运行把JAR包放到服务器上用nohup后台启动nohup java -jar restaurant-system.jar --spring.profiles.activeprod app.log 21 application-prod.yml里我一般会把生产环境的数据库连接、Redis连接单独配置。请务必不要把数据库账号密码写在代码里提交到Gitee或GitHub上至少用application.yml里的${DB_PASSWORD}占位符配合环境变量注入。7.3 部署时最容易遇到的三个问题端口被占用8080是Spring Boot默认端口服务器上如果跑了其他Java应用端口就会冲突。可以在启动时指定端口nohup java -jar restaurant-system.jar --server.port8081 app.log 21 MySQL时区报错连接字符串里一定要带时区参数不然会报Server timezone value CST is unrecognizedjdbc:mysql://localhost:3306/restaurant?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiJAR包外部配置文件如果你改了配置就要重新打包一次很麻烦。我的习惯是把application-prod.yml直接放在JAR包同级目录下启动时会自动覆盖JAR内部的配置。这样以后只改配置就重启JAR不用重新打包。8. 答辩与验收视角评审老师最爱问的问题和应对思路最后写点应景的。如果你是用这个题目做毕业设计答辩时老师大概率会问下面几个问题提前准备好答案通过率会高不少。问题一为什么选择Spring Boot而不是SSM回答思路Spring Boot简化了SSM中大量的XML配置内嵌了Tomcat让项目能以独立的JAR包形式运行。自动装配机制减少了样板代码开发效率更高。生态成熟和MyBatis-Plus、Spring Security等组件的整合成本低。问题二财务数据的安全性怎么保证回答思路用户密码采用BCrypt加盐哈希存储接口访问采用JWT无状态认证配合Spring Security做注解级权限控制涉及金额的数据修改一律走事务所有业务记录采用逻辑删除保留完整的操作痕迹。如果老师追问可以把上面的代码细节拿出来展开讲。问题三当前系统有哪些不足如果继续扩展会怎么做回答思路这是一道送分题不要回答“没有不足”。可以说目前报表维度还比较简单后续可以考虑接入消息队列实现菜品销售数据的异步统计没有对接真正的支付网关现在是模拟支付流程库存模块的BOM配方依赖人工维护后续可以增加智能估算功能。这种回答既展示了你对自己项目的清醒认识又体现了一定的架构视野。最后的个人体会做这类系统的过程中我最大的感受是大部分项目不是死在技术上而是死在业务流程的认知上。很多人在开发之前根本没搞清楚“日结”和“月结”的差异没弄明白“采购支出”和“库存成本”的区别就直接开始写代码。等你把业务流程理清了用Spring Boot写CRUD反而是最简单的一步。如果你正在做类似的毕设我的建议是先别急着打开IDE花两天时间把业务的流程图和数据字典画出来把每个字段的来龙去脉想明白。后面写代码的时候你会发现之前看似枯燥的设计工作其实帮你省掉了一百次返工。这个项目的每个模块往下挖都有不少值得扩展的地方先把地基打牢才是正事。
返回列表