1. 项目缘起这套订餐系统到底做了什么我最近刚结束一个颇为典型的项目——给某高校做的一套订餐管理系统完整交付内容包括源码、论文文档、调试文档和讲解演示。这套系统的亮点在于同时给甲方做了Java SSM版和Python Django版两套后端前端共用一套交互逻辑。如果你正在准备毕业设计或者想自己动手搭一套完整的互联网应用练手这篇文章应该能帮你少走不少弯路。先说清楚这系统解决什么问题餐厅、食堂、小饭店要处理的日常事务无非是菜品展示、顾客下单、后台接单、订单状态更新、基本的数据统计。订餐管理系统就是把这些线下流程搬到线上让顾客在小程序或网页端浏览菜品、加购物车、提交订单让商家在后台看到订单、管理菜品、查看销量。这个业务场景非常典型它包含了用户体系、商品管理、订单流程、角色权限、数据可视化这些互联网应用的核心模块所以一直是课程设计和毕业设计的热门选题也是最适合拿来练手全栈开发的场景之一。这套系统的实际使用角色划分成两边。一个是前台顾客侧功能包括注册登录、浏览菜品分类、加入购物车、提交订单、查看个人订单列表、取消未接单的订单。另一个是后台管理侧功能包括菜品分类维护、菜品上下架、订单状态处理接单、完成、取消、顾客账号管理、销量和营业额统计。整个系统的业务闭环非常清楚顾客点餐 → 商家接单 → 顾客收货 → 交易完成每个环节都有明确的数据表和状态对应。从我个人的经验来说这种管理系统类项目最大的优点在于“门槛适中但五脏俱全”。它不像纯算法项目那样偏理论也不像简单静态页面那样没深度。它能把前端页面、后端接口、数据库表设计、权限逻辑、部署调试全部串起来做完以后你对整套Web开发流程的理解会上一个台阶。这也是为什么我建议基础一般的同学优先考虑这类题材而不是一上来就做秒杀系统、推荐系统那种高并发、高复杂的题目。2. 技术选型为什么同时保留SSM和Django两套实现标题里同时出现了SSM和Django有些人会疑惑这到底是Java项目还是Python项目其实甲方最初的要求是“能做出来、能演示、文档齐全”对语言没有执念。后来考虑到两个团队成员的背景差异——有人主攻Java方向有人学的是Python——我们索性把后端逻辑做了两版实现前端接口设计保持一致这样无论哪边需要参考都能找到对应的完整代码。2.1 SSM版本的内容构成SSM是Spring Spring MVC MyBatis三个框架的合称。这套组合在JavaWeb课程中几乎是必修内容哪怕现在的企业项目很多已经转向Spring Boot但SSM依然是理解Java后端原理的最佳路径之一。Spring负责对象的创建和管理。我们的Service层、Mapper接口、事务管理都交给Spring容器统一装配。这样代码之间的耦合度会大大降低改一个模块不影响其他模块。Spring MVC负责前端请求的分发。用户浏览器发出请求后DispatcherServlet会把请求转发给对应的Controller方法Controller处理完后再把数据塞进Model最后渲染成页面。MyBatis负责数据库操作。我们把SQL写在Mapper.xml文件里通过接口绑定来执行。比起JPA那种全自动的持久层框架MyBatis的SQL自己控制出问题的时候排查起来更直观面试时也更好解释。SSM版我用了IDEA Maven Tomcat 8.5 MySQL 5.7。JDK用的1.8稳定且兼容所有主流框架。需要说明一点虽然Spring Boot现在大行其道但在答辩场景下SSM其实更吃香因为你能明确说出每一个组件在哪一步干了什么事。Spring Boot把一切自动装配了反而没什么好讲的。2.2 Django版本的内容构成Django版是给Python方向准备的一整套独立实现用的是经典的MTV模式Model操作数据库Template渲染页面View处理业务逻辑。Django自带Admin后台这一点在开发调试阶段非常爽甚至不需要自己写任何代码就能在后台添加菜品数据。认证系统Django原生自带User模型注册登录可以直接基于它做扩展省去了SSM版里手动写Session或Token逻辑的麻烦。ORMDjango的ORM自动生成SQL写查询时不用手写原生的SQL语句。比如筛选“状态为已接单的订单”一行代码搞定对Python新手非常友好。Admin后台程序跑起来后访问/admin就能看到可视化的数据管理页面增删改查完全不用自己写模板。用来做演示时也很加分评委能看到一个成熟后台的样子。两套实现共用了同一套前端页面部分表单交互做了适配意味着你可以拿同一套界面分别用两个后端跑起来业务效果一致但底层逻辑不同。这种对照感在实际学习中的价值很大你会知道同一件事在Java里要写接口、写实现类、配置Mapper映射在Python里可能一个类定义加几个装饰器就搞定了。也正因为如此这套项目既适合Java方向答辩也适合Python方向答辩同一个项目两种用法。2.3 数据库设计在这里是重点不管哪个版本底层数据表都保持一致。我用的MySQL 5.7字符集强制指定UTF-8避免中文乱码。整个工程一共设计了六张核心表用户表、菜品分类表、菜品表、购物车表、订单主表、订单明细表。表结构设计时最需要注意的一点是订单主表和明细表要分开。为什么因为一个订单里可能有多个菜品如果把菜品信息直接塞在订单表里不仅数据冗余严重而且后期想做销量统计时无从下手。订单主表存订单编号、总金额、状态、用户ID、下单时间和收货信息订单明细表存这个订单包含了哪些菜品ID、数量、单价、小计。两张表用订单编号关联这就是经典的“主从表”设计思路。在写创建表的SQL时所有主键都用了自增ID订单编号单独设置唯一索引。菜品表里有一个img_url字段存图片路径——注意这里存的是相对路径而不是直接把图片文件塞进数据库数据库只负责“知道图片在哪”不负责“保存图片”。一个常见的错误是很多新手喜欢用BLOB类型把图片以二进制存进数据库这样做会造成数据库文件膨胀非常快备份和迁移都痛苦最后我演示用的所有菜品图片都放在服务器的静态资源目录下通过路径访问。3. 核心模块拆解与实操实现整个系统的开发流程我按“用户故事”的路径来推进先做注册登录再做菜品展示然后才是购物车和订单。这样的顺序保证了每一步完成之后系统都是可运行的而不是攒一大坨代码到最后才调试那样出了问题根本不知道从哪里查起。3.1 注册登录与权限控制用户登录这块SSM版用的是Session方案。登录成功后把用户ID和用户名放进Session在拦截器里检查Session是否存在当前用户。Spring MVC的拦截器其实就是一个实现HandlerInterceptor接口的类我在preHandle方法里写判断如果Session为空就重定向到登录页。这个逻辑很清晰也很好在答辩时画流程图说明。密码存储有个细节必须提醒——绝对不要明文存密码。项目里我用的是一层加盐哈希简单说就是用户注册时在明文密码后面拼接一串随机生成的盐值然后用MD5做摘要把盐和摘要一起存进数据库。校验登录时取用户记录中的盐值和输入密码拼接后再做MD5比对两个摘要是否一致。这样做的好处是就算数据库泄露对方拿到的也是不可逆的摘要无法直接知道明文密码。Django版这边更省力直接用自带的make_password和check_password方法底层用的PBKDF2算法安全性比MD5还要高一截。但为了论文里好解释我还是在代码注释里写明了PasswordBasedKeyDerivation的推导流程。3.2 菜品展示与购物车的实现菜品展示就是典型的分页查询加模糊搜索。前台要把菜品按分类展示每页显示八个支持按菜品名关键字搜索。SSM里我用的是PageHelper插件一行配置后直接在SQL执行前调用PageHelper.startPage(pageNum, pageSize)非常省事。Django里用自带的Paginator类实现同样效果。购物车这块我最初的方案是Redis缓存但考虑到部署环境和学习成本最终采用了数据库表方案。购物车表里存用户ID、菜品ID、数量这三个核心字段加购物车就是先查这条记录是否存在存在则数量加一不存在则插入新记录。这里有一个必须注意的并发细节如果用户同一时间连点两次加入购物车就会产生两条操作同时检查是否存在的竞态问题。虽然在MySQL默认的隔离级别下通过唯一索引用户ID菜品ID能保证不会插入重复数据但更保险的做法是使用INSERT ... ON DUPLICATE KEY UPDATE这种语法遇到已存在记录就直接更新数量这样可以从根本上避免查一次再插一次的“检查-更新”非原子操作。购物车展示页上前端会循环当前用户的所有购物车记录联表查询菜品表拿到菜品名、价格和图片然后在页面上算出总金额。结算的逻辑是删除购物车记录 → 生成订单主表记录 → 生成订单明细表记录 → 跳转到订单详情或支付页面。整个过程必须放在同一个事务里。我遇到过一些同学自己练习的时候把这三步拆开写导致用户点了一次结算购物车删了但订单没生成钱货两空。3.3 订单状态流转与事务处理订单管理是整个系统的中枢环节。订单状态我设计了五个待支付、待接单、待送达、已完成、已取消。前台用户可以看到订单当前处于哪个状态后台商家可以通过操作按钮把状态往下一个阶段推进。这里状态的变更我用一个整数字段来存储同时写了一个状态常量类不在业务代码里到处塞魔法数字。生成订单时的代码逻辑在SSM版里大概长这样Transactional public Order createOrder(Long userId, ListCartItem cartItems) { // 1. 创建订单主表记录 Order order new Order(); order.setOrderNo(generateOrderNo()); order.setUserId(userId); order.setStatus(OrderStatus.PENDING_PAYMENT); order.setCreateTime(new Date()); orderMapper.insert(order); // 2. 创建订单明细 BigDecimal totalAmount BigDecimal.ZERO; for (CartItem item : cartItems) { OrderItem orderItem new OrderItem(); orderItem.setOrderId(order.getId()); orderItem.setDishId(item.getDishId()); orderItem.setQuantity(item.getQuantity()); orderItem.setPrice(item.getUnitPrice()); orderItem.setSubtotal(item.getUnitPrice().multiply( BigDecimal.valueOf(item.getQuantity()) )); orderItemMapper.insert(orderItem); totalAmount totalAmount.add(orderItem.getSubtotal()); } // 3. 更新订单总金额 order.setTotalAmount(totalAmount); orderMapper.update(order); // 4. 清空购物车 cartItemMapper.deleteByUserId(userId); return order; }注意Transactional注解是必须的它的作用就是当第2步或第4步中任意一步抛异常时整个方法里执行的数据库操作全部回滚不会出现“明细表写了一半”这种脏数据。下单成功后的页面需要显示订单详情的所有信息订单编号、下单时间、菜品清单、每种菜品数量、单价、总金额。订单编号我用了年月日时分秒加三位随机数的组合比如20250611163015782这样保证同一秒内提交多次订单也不会撞号。面试官问我为什么不用数据库自增ID当订单编号我说自增ID是业务无关字段会暴露系统订单总量客户输入的时候也容易输错所以外部展示的编号必须用独立的业务编号体系。3.4 后台管理的要点后台功能的第一优先级是“能看、能改、能删”。菜品管理的操作包括新增菜品、编辑菜品价格/描述、上下架逻辑删除不是物理删除和按分类查看。这里我用了一个逻辑删除的字段deleted_flag默认0删除时把值改成1而不是真的执行DELETE FROM语句。这个设计是为了保留历史订单中引用的菜品信息因为如果订单明细表关联的菜品被物理删除了展示历史订单的时候就找不到菜品名只能显示一个孤零零的ID。订单管理后台页面就是一张大表格按订单状态筛选。商家点击“接单”时系统自动记录接单时间点击“完成”时记录完成时间。销量统计页我写了几个简单的SQL聚合查询按菜品维度统计总销量、按天统计营业额、按分类统计占比。数据可视化用的是Chart.js库画柱状图和饼图前端拿到后端返回的JSON数据后直接渲染不需要额外引入重型图表库。Django版的Admin后台自然集成了上述所有模型的管理但在演示时我一般会用自己的定制页面因为Admin的界面审美和交互风格偏后台化和前台UI风格不协调。真正常用的Admin能力是快速造数据——拍照上传前先跑几十条模拟数据方便演示分页和统计效果。4. 环境准备、部署配置与调试文档实战整套系统的运行环境我用Windows做开发机用一台CentOS云服务器做部署演示。以下部署流程同样适用于你是拿自己电脑还是云服务器只是个别命令和路径略有差异。4.1 SSM版环境准备清单SSM版需要的环境JDK 1.8、Maven 3.6、MySQL 5.7、Tomcat 8.5、IDEA或Eclipse。配置MySQL时最常踩坑的是时区问题。连接字符串里我明确加了参数jdbc:mysql://localhost:3306/ordering?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai。如果不加serverTimezone新版驱动会报时区错误程序直接起不来。字符编码参数如果不配插入中文时十有八九会变问号。Maven项目的pom.xml中核心依赖是spring-webmvc、mybatis、mybatis-spring、mysql-connector-java、jackson-databind用于JSON序列化。如果你用的是IDEA自带的Tomcat集成启动要注意设置部署工件把war包部署到Tomcat的webapps目录。如果启动时端口被占用可以在catalina.bat里改端口配置或者在IDEA的Server选项卡直接更换HTTP端口。4.2 Django版环境准备清单Django版需要Python 3.8、Django 3.2、MySQLdb或PyMySQL驱动、django-cors-headers如果前后端分离。安装命令直接是pip install django pymysql mysqlclient djangorestframework django-cors-headersDjango的数据库配置写在settings.py里MySQL连接信息放在DATABASES字典中。注意用PyMySQL时要在项目初始化文件里加一行import pymysql pymysql.install_as_MySQLdb()否则Django会因为你机器上没装MySQLdb而报错。迁移数据库时先python manage.py makemigrations生成迁移文件再python manage.py migrate真正创建表。这两个命令的区别是前者只是生成一个描述表结构的Python文件后者才真正去数据库执行DDL。4.3 调试文档的内容组织调试文档是交付物里的重要一环很多同学写技术文档就变成“复制粘贴操作步骤”其实调试文档的重点是“记录踩过的坑”。我在调试文档里按如下结构组织环境安装步骤及版本要求数据库初始化和表说明项目导入IDEA的详细步骤重点写怎么设置JDK、怎么配置Maven仓库、怎么修改数据库连接参数项目启动步骤SSM部署到Tomcat并启动 → Djangorunserver常见异常对照表比如Access denied for user→ 数据库用户名或密码错误检查application.yml配置Connections could not be acquired from the underlying database→ 数据库服务没启动或连接串错误Whitelabel Error Page→ 后端接口路径写错或Controller没有正确扫描TemplateDoesNotExist→ Django的模板目录配置错误检查TEMPLATES的DIRS路径这套文档的价值在于用户拿到项目后即使完全没接触过这个框架也能按照文档一步步搭起来。我见过不少人写调试文档是“环境JDK8MySQL5.7Tomcat8”一句话带过这种文档对于已经会的人来说没啥用对于不会的人来说根本不够精细化。4.4 部署时的典型问题记录我实际部署过程中遇到过三次典型事故在这里完整记录下来希望能帮大家避坑。第一次是Tomcat能启动但页面一直404。排查发现是部署工件没选对IDEA默认生成的war包没有自动解压到webapps目录需要在Deployment配置里把Application context设成/而不是默认的路径。第二次是MySQL中文乱码启动后所有菜品名显示问号原因是我的建表语句用了DEFAULT CHARSETlatin1需要重建表并明确指定utf8mb4。第三次是Django图片图片全部无法加载排查了半天发现是静态文件URL配置问题STATIC_URL配置正确但STATICFILES_DIRS没有指向图片所在目录导致所有静态资源路由都404。这些排错过程在我的调试文档里都做了记录一方面对答辩有实际帮助另一方面也方便后续接手维护的人。真实的项目经验不是代码写得有多花哨而是你踩过什么坑、怎么找到问题、怎么解决这本身就是非常有说服力的交付物。5. 演示与讲解的实战技巧一套毕业设计交付物里代码和文档是基础真正拉开差距的其实是最后的演示讲解环节。项目做得再好如果讲的时候逻辑混乱、演示操作卡壳分数也会大打折扣。这一节重点讲讲怎么准备项目讲解和演示。5.1 项目讲解词怎么准备讲解的时长一般控制在8到15分钟。我的建议是把讲解词按以下节奏分配项目背景和意义约占15%技术选型原因约占15%系统设计思路包括数据库设计、模块划分约占30%核心功能演示约占30%总结与展望约占10%。核心原则就是少讲历史多讲方案和结果。讲解的重心始终围绕“我做了什么、我为什么这么做、效果怎么样”。比如讲数据库表设计时不要只是念字段名而是要说明订单主表和订单明细表拆分的理由“如果合并在一张表那一个订单里的三个菜就要存三条不完全相同的记录冗余太多而且统计每个菜品的销量时查询会很麻烦。我拆成两张表后订单主表只存一次性的下单信息明细表存菜品级别的数据统计时直接对明细表做聚合查询就行。”这种讲法比单纯念表结构有价值得多。5.2 演示流程的标准化步骤演示时的操作顺序不能随心所欲每一步前最好都想好“我下一步要展示什么功能点”。留给常见的演示流程参考第一步打开前台首页展示菜品分类和菜品列表说明前台页面的信息架构。第二步操作注册一个新用户如果答辩时网络不佳可以提前注册好几个备用的测试账号然后登录。第三步搜索一个菜品加入购物车再搜索另一个加入购物车进入购物车页面展示数量和总金额的计算逻辑。第四步结算并生成订单展示订单成功页面。第五步切换后台界面打开订单管理展示刚刚生成的订单执行接单操作。第六步回到前台用户订单页展示订单状态从“待接单”变成“待送达”的过程。第七步展示后台销量统计页面按不同维度切换图表。这套流程走下来评委对整个业务流程的印象会非常完整。演示前把所有浏览器页签清干净数据库提前用脚本插入一些模拟数据演示时尽量不要现场注册账号这类准备细节很重要。5.3 答辩中被问到的高频问题答辩环节评委最常问的几个问题和应答思路我整理如下“你用的加密方式是什么” 答密码存储用的是加盐哈希核心是避免彩虹表破解。如果评委继续深问可以补充盐值是服务端生成的随机字符串每次注册都会生成新的。“如果同一个菜品有多个规格大份小份你的表结构怎么设计” 答当前是一个菜品对应一个价格如果有规格需求就要拆出“菜品SKU表”存菜品ID、规格名、价格字段订单明细表改成关联SKU表。然后说明自己在系统设计时考虑过扩展性但需求分析阶段客户未提规格要求所以设计时放在了扩展方案里。“你的订单状态为什么用数字而不用字符串” 答数字存储空间小、查询快且能通过常量类统一管理避免代码里字符串拼写不一致导致判断失效。“你做过哪些性能优化” 答查询的地方加了索引如订单表按用户ID建索引、分页查询而不是一次全部加载、图片走静态资源服务而非数据库IO另外对返回给前端的JSON做了字段筛选不把不必要的数据库字段暴露出去。6. 论文文档的写作要点LW即论文文档是毕业设计交付中最看重文本分量的部分。我个人把整篇论文的结构控制在六章左右。第一章绪论写研究背景和意义注意背景不要写得太大太空不要一开口就是“随着信息技术的飞速发展”那是凑字数。直接写餐饮行业的日常运营痛点再点到“通过订餐系统能解决传统手工记单的哪些具体问题”。第二章是系统相关技术介绍这章不需要长篇大论每个技术讲清楚是什么、解决了什么问题即可。Spring控制对象生命周期Spring MVC做路由转发MyBatis封装数据库操作这几个框架之间怎么通过配置文件衔接起来这三段话就是一个技术小节。第三章是系统需求分析分功能需求和非功能需求。功能需求列用例图角色分为顾客和商家每个角色有什么操作按钮都写清楚。非功能需求写系统的响应时间、并发量预估、安全性要求。第四章是系统设计数据库设计是重点。每张表画表格列出字段名、类型、约束和说明同时写清楚表与表之间的外键关联。这一步做扎实之后整个项目的骨架就非常清晰了。第五章是系统实现按照模块一个一个写。展示核心代码截图配上这些代码做什么、为什么要这么写。注意不要贴大整块的代码节选重要核心逻辑即可以及要文字说明执行结果的页面图。第六章是系统测试功能测试用黑盒测试的用例表格式列出测试用例、输入数据、期望结果、实际结果最后结论是全部通过。性能测试如果有条件就写并发下的响应时间数据没条件就写明测试环境和测试工具的局限性。论文最容易出现的问题是文档内容和代码逻辑不一致。比如代码里订单状态有五个值论文里却写了四个代码里角色有两种数据库设计图里却漏掉了商家表。答辩前一定至少要花几个小时逐条核对一遍代码和文档的对应关系。我见过一个同学代码里明明用MySQL论文里却写成了SQLite这种低级错误会严重影响评阅分数。7. 真实踩坑记录从开发到交付的教训复盘最后用一段比较长的内容复盘我个人在这次项目中遇到的几个典型问题这些问题在网上很难找到系统的梳理但对于正在做同类项目的人来说应该会有很大帮助。7.1 购物车与订单的数据一致性这是整个项目里碰到的最隐蔽的Bug。用户把某个菜品加入购物车后修改了数量然后点了结算这时后端拿到的是修改后的数量。如果用户同时在另一个页面用原数量提交就会形成两个并发请求。数据库层面就会出现“购物车里本来有3份最后生成了235份订单”这种问题。解决方式我是从数据库锁的角度去思考的。最简单的方案是把库存扣减放在订单生成事务内部做原子操作比如执行UPDATE dish SET stock stock - #{quantity} WHERE id #{id} AND stock #{quantity}受影响的记录行数如果为0就说明库存不足或菜品不存在直接抛异常让事务回滚。不要先查询库存数量再在Java代码里做减法那个过程是非原子的中间插入任何并发请求都会出错。7.2 图片存储与加载路径的坑菜品的图片用本地文件存储后需要在Tomcat的配置或Django的静态文件配置中做一个映射。我的做法是在Spring MVC中定义资源映射Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceHandler(file: uploadPath); }这样浏览器访问http://localhost:8080/upload/dish1.jpg就能直接加载到图片。Django版本则在settings.py加STATIC_URL /static/ STATICFILES_DIRS [ BASE_DIR / static, ] MEDIA_URL /media/ MEDIA_ROOT BASE_DIR / media印象最深的一次事故是部署到服务器后所有菜品图片都裂了。排查了路由器、防火墙之后才发现是服务器上upload目录不存在Tomcat启动后没有自动创建文件目录。后来我在初始化脚本里加了一条mkdir -p指令问题解决。这里的关键经验是代码可以帮助你定位绝大多数问题是前端还是后端还是数据库但文件系统问题只能靠看目录结构来排查。7.3 版本依赖的兼容性问题SSM版本中依赖的版本组合如果搭配不当会产生各种莫名其妙的问题。比如我最初用的mybatis-spring是2.0的老版本和Spring 5.x一起用的时候直接报NoSuchBeanDefinitionException。后来查资料才明白是因为两个框架的兼容版本区间变动较大最新版本要求Spring的版本必须对齐。最终的版本组合是Spring 5.2.8 MyBatis 3.5.6 MyBatis-Spring 2.0.6这个组合运行平稳。这种版本锁定的方式我也写进了调试文档确保后续使用者直接照搬就能跑通。另外Django版的Django版本和Python版本的对应关系也必须注意——Django 3.2官方支持Python 3.6到3.9但如果用了Python 3.10某些第三方库可能会出现编译错误。最稳妥的方式是统一用Python 3.8搭配Django 3.2.15这个组合兼容性好网上资料也多遇到问题容易搜到答案。7.4 答辩前一份可运行的部署脚本答辩当天现场环境不一定和自己开发机一致我最常用的做法是在项目里附一个init.sh脚本能一键完成建库建表、导入数据、启动服务。脚本内容大致是#!/bin/bash # 初始化数据库 mysql -uroot -p123456 sql/init.sql # 启动Django服务 cd django python manage.py migrate python manage.py runserver 0.0.0.0:8000 # 启动TomcatSSM版本 cd tomcat/bin ./startup.sh脚本本身不是多有技术含量的事情但它代表了项目的工程化完整度。当评委问“你的项目怎么部署”的时候你可以直接现场跑一遍脚本几分钟就能把系统运行起来。这种从交付文档到实际运行画面的完整流程学术内容的评价也会上一个台阶。7.5 关于文档心态的调整最后聊聊对LW和调试文档的心态问题。很多同学把写文档当成负担觉得技术做好了就够了文档随便对付一下。我早年也这么想后来做了几个真实交付项目才意识到文档不是给别人看的是给你自己留的底牌。当你半年后回头维护代码时一份调试文档能让你在三分钟内想起来当时的项目是“怎么跑起来的、依赖了哪些配置、遇到什么问题怎么解决”。答辩时几乎所有项目细节都会被追问文档里写过的东西你能记得更牢固回答问题时也有据可依不会东拼西凑。清单化地整理一下我在开发这套订餐系统过程中的核心注意事项数据库字符集一律UTF-8外部订单号和内部自增主键分离所有金额参数用BigDecimal而不是double下单和扣库存放在同一事务里购物车操作要防重复插入图片走资源映射不走数据库二进制代码和文档的字段名必须完全一致演示前跑一遍全流程确认没有断点。这些经验是我在不同项目里反复试错得来的希望能对正在做或准备做管理系统类项目的朋友有一些实际的帮助。如果后面有时间我打算把Django版本升级一版加上前后端分离的接口设计用Vue做出一个更现代的前台界面顺便接入真实的在线支付沙箱环境让整个业务流程更接近生产环境。管理系统这类项目的上限其实很高前提是你愿意在基础功上多花时间打磨而不是只停留在“能跑就行”的程度。