
去年做毕业设计那阵子我在选题列表里翻来覆去挑了很久最后定的是微信小程序版本的药店管理系统后端主体用SSMSpringSpringMVCMyBatis来实现Java负责全部业务接口另外用Python写了一批辅助脚本比如批量造测试数据、生成销售统计图。现在回头看这个组合确实很适合当毕业设计难度不吓人能完整演示答辩时又有内容可以深挖。这篇就按我当时真实的开发顺序写下来从为什么选这个题、数据库怎么建到小程序端和后端怎么写再到部署踩坑和答辩应对一次讲透。写给自己正在纠结选题的同学看也写给拿到源码不知道怎么入手的同学看。1. 为什么药店管理系统能成为毕业设计的稳选题1.1 难易程度恰好落在可完成区间毕业设计最大的翻车点不是不会做而是想太多做不完。很多同学一上来就选智能推荐购药系统AI辅助问诊平台听着很唬人但实际上算法、模型、数据样本一个都搞不定做到十二月还在改需求最后交上去一个半成品答辩老师随便问两句就露馅。药店管理系统不一样。它的业务边界非常清楚药品、分类、库存、订单、用户翻来覆去就这么几件事。但你别小看它完整的增删改查、角色权限、订单状态流转、事务控制它全都有。也就是说你在课堂上学的那套东西在这个系统里都能用上而且它有真实场景不是那种纯练习的学生管理系统能比的。我后来帮几个学弟看项目的时候发现凡是认认真真把一个药店系统做完的对SSM框架和数据库设计的理解都会比做其他花架子项目的人扎实一大截。原因很简单这个系统的数据关系是实打实的药品挂在分类下订单连着用户和明细库存和销售互相制约表一多、关联一多框架能力自然就练出来了。1.2 微信小程序做前端天然容易被记住同样的后端功能如果你只做一个纯网页的管理后台答辩演示的时候就是打开浏览器点几个链接老师在底下看PPT效果很平。但换成微信小程序就不一样了演示环节直接在手机上操作扫码打开、滑动商品列表、加入购物车、下单支付流程哪怕是模拟的这个视觉冲击力和完整度是纯网页项目给不了的。而且从技术角度说微信小程序虽然是前端但它有自己的一套生命周期、组件化机制、路由和本地存储写起来和传统网页前端差别不小。这个工作量是能摆在台面上讲的。很多答辩老师看到你有独立的小程序端本身就默认你的项目是前后端分离的完整应用印象分会上去不少。还有个实际好处微信开发者工具调试很方便控制台、network面板、真机预览都有对还没进过公司的学生来说这个工具链比配置一个完整的前端工程要友好得多拿来当毕业设计载体非常合适。1.3 说说Python在项目里的真实定位标题里写了后台python但主后端其实是SSM这里必须提前把逻辑理顺不然答辩老师一句话就能把你问懵为什么你一个项目里有Java又有Python到底哪个是主后端我的做法是这样Python不当业务后端只当辅助工程。它干三件事——用Faker批量造测试数据、用Pandas和Matplotlib生成销售统计图、偶尔写个小脚本处理Excel导入导出的数据。真正的业务接口比如登录、药品查询、下单、库存扣减全部走Java的SSM。这样一来技术栈并不混乱反而显得你会用多种工具解决实际问题答辩时话术都是现成的主后端用SSM保证业务稳定Python用于数据分析和测试数据生成两者职责分离。如果你实在想让Python也参与后端那也只能做某一个非核心的统计接口比如首页的销售趋势图表数据用Flask写一个小服务单独部署。千万不要让一条业务链路既走Java又走Python那是给自己挖坑。2. 系统整体设计与数据库拆解2.1 用户角色与功能边界系统我分成两个端角色也分两套。小程序端面向的是普通购药用户功能包括注册/登录、浏览药品、按分类筛选和关键词搜索、查看药品详情、加入购物车、提交订单、查看订单列表和订单状态、维护个人信息。这套功能走的是C端用户的完整购买链路。管理端面向药店运营人员功能包括药品的增删改查、药品分类管理、库存调整、订单处理发货/完成、用户管理、销售统计。管理端我建议单独做一个极简的Web页面和SSM后端共用一套接口不要试图把所有管理功能都塞进小程序里那样小程序页面会膨胀得没法维护答辩也讲不清楚。权限这块不要搞太复杂就在用户表里放一个role字段0代表普通用户1代表管理员。小程序端只要在登录时判断角色如果role为1就多显示一个管理入口的按钮跳转到管理页面后端接口统一做一个简单的拦截器只有role为1的token允许访问管理类接口。这个设计在答辩时非常好解释用角色字段区分访问边界拦截器统一鉴权。2.2 核心表结构与建表SQL数据库设计是答辩考察的重头戏我把核心表列在这里你根据自己项目删减。用户表a_userid、openid微信登录用、username、password、phone、role、create_time。药品表a_drugid、name、category_id、spec规格、unit单位、price、stock库存、manufacturer生产厂家、expire_date有效期、prescription_flag处方药标识、status上架状态。分类表a_categoryid、name、sort。订单表a_orderid、order_no订单号、user_id、total_amount、status、create_time。订单明细表a_order_itemid、order_id、drug_id、quantity、price。如果想做亮点可以加一张a_stock_log库存变动日志表记录每次入库、出库、手动调整的操作答辩时说库存可追溯是很加分的点。建表SQL给个核心示例CREATE TABLE a_user ( id int NOT NULL AUTO_INCREMENT, openid varchar(64) DEFAULT NULL, username varchar(50) DEFAULT NULL, password varchar(100) DEFAULT NULL, role tinyint DEFAULT 0, phone varchar(20) DEFAULT NULL, create_time datetime DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE a_drug ( id int NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL, category_id int DEFAULT NULL, spec varchar(50) DEFAULT NULL, unit varchar(20) DEFAULT NULL, price decimal(10,2) DEFAULT NULL, stock int DEFAULT 0, manufacturer varchar(100) DEFAULT NULL, expire_date date DEFAULT NULL, prescription_flag tinyint DEFAULT 0, status tinyint DEFAULT 1, PRIMARY KEY (id), KEY idx_category (category_id), KEY idx_name (name) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;特别注意order是MySQL的保留字订单表名千万别直接叫order否则建表就报语法错误我见好多同学卡在这。统一用a_或者t_前缀比如a_order、a_order_item又规范又规避关键字问题。2.3 容易被忽略的三个设计细节第一金额字段必须用decimal(10,2)不要用float或double。浮点数在二进制里表达不精确算钱会出现0.10.2不等于0.3的诡异问题答辩老师要是问一句为什么金额用decimal你答上来直接就是加分项。第二库存字段和扣减逻辑一定要考虑并发。最简单的做法是扣库存时用条件更新UPDATE a_drug SET stock stock - #{num} WHERE id #{drugId} AND stock #{num}然后判断影响行数如果返回0说明库存不足。这个写法比先查库存再减库存安全太多也是面试和答辩常考的超卖解决方案。第三订单号不要用数据库自增。自增主键泄露业务量不说并发下生成订单号也容易乱。可以用时间戳加随机数或者简单的雪花算法保证唯一且不连续。3. 小程序端实现要点3.1 页面结构怎么规划小程序端我建议按这个结构来组织页面pages/index首页、pages/category分类、pages/drug/detail药品详情、pages/cart购物车、pages/order/confirm确认订单、pages/order/list订单列表、pages/user个人中心、pages/login登录。页面职责要单一能抽出来的公共组件一定要抽。比如药品卡片组件drug-card首页、分类页、搜索结果页都要用写成组件后传一个drug对象进去就行改样式也只改一处。还有数量加减组件stepper购物车和确认订单页面都用。组件化做得好代码量直接少一半后期改需求也不至于改到崩溃。首页建议放一个大致的布局顶部搜索框、分类轮播区或九宫格入口、推荐药品列表。不要把所有内容堆在一屏小程序页面讲究信息流的感觉用户是往下滑的。底部tabBar我建议设三个首页、购物车、我的分类页可以放在首页的轮播图跳转或者单独加一个tab看你自己取舍。3.2 登录与Token的完整链路微信小程序的登录和传统网页登录不一样它不是用户名密码直接登录而是走wx.login拿到一个临时code然后把code发给后端由后端调微信接口换取openid。整个链路是小程序调用wx.login()获取code。小程序把code通过request发给后端。后端拿着code调用微信的code2Session接口换取openid和session_key。后端根据openid查a_user表查不到就自动注册一个新用户。后端生成一个token返回给前端前端存入storage后续所有请求带上token。这个链路答辩必问你一定要能画出来。我给出一个wx.request的封装示例统一处理token和401跳转const request (url, method GET, data {}) { return new Promise((resolve, reject) { const token wx.getStorageSync(token); wx.request({ url: BASE_URL url, method, data, header: { Content-Type: application/json, Authorization: token }, success(res) { if (res.data.code 401) { wx.reLaunch({ url: /pages/login/login }); return; } resolve(res.data); }, fail: reject }); }); };这里有两个坑必须提。第一个code有效期只有五分钟且只能用一次所以code一定要立刻传给后端不能存在本地过一会儿再用。第二个token过期后后端返回401前端要统一拦截并跳回登录页不然用户会出现页面还能看但是所有操作都没反应的诡异状态。3.3 购物车、下单与订单状态流转购物车数据我建议存后端不要只存在小程序本地storage。存后端的好处是用户换了设备购物车还在而且管理端能统计加购数据。本地storage可以作为未登录状态下的临时购物车登录后合并这个逻辑写清楚后挺加分的但也别做太复杂毕业设计做到登录后购物车数据不丢就够了。下单流程要特别注意顺序。正确做法是前端提交商品列表和数量到后端后端在一个事务里完成——校验商品是否上架、计算总价、扣减库存、生成订单和明细、返回订单号。前端不能自己算总价传给后端不然用户改一下请求参数就能以1分钱下单这是安全常识答辩时主动讲出来是亮点。订单状态我用四个数字表示0待付款、1待发货或待取货、2已完成、3已取消。前端页面用switch或者对象映射显示对应文案不要在每个页面硬编码判断数字后期加一个状态你会改到怀疑人生。3.4 列表分页加载的通用写法小程序列表页最常见的需求就是加载更多首页药品列表、订单列表、搜索结果都用得到。我总结一个通用写法核心就是三个变量page当前页码、hasMore是否还有更多、loading请求锁。Page({ data: { list: [], page: 1, pageSize: 10, hasMore: true, loading: false }, onReachBottom() { if (!this.data.hasMore || this.data.loading) return; this.loadList(); }, async loadList() { this.setData({ loading: true }); const res await request(/drug/list?page this.data.page size this.data.pageSize); if (res.code 0) { const list [...this.data.list, ...res.data.rows]; this.setData({ list, page: this.data.page 1, hasMore: list.length res.data.total }); } this.setData({ loading: false }); } });这里重点说三个细节。第一onReachBottom触发后一定要判断loading不然用户快速滑动会同时发出多次请求导致数据重复。第二hasMore的判断是当前已加载总数小于后台返回total才继续加载不要用这次返回的rows.length等于pageSize来判断否则最后一页数据正好满一页时会多发一次空请求。第三加载完成后要setData整个数组而不是用push小程序setData是同步视图的性能上比一个个push好。4. SSM后端核心逻辑落地4.1 统一返回体与接口风格写后端接口第一件事是定一个统一返回体我采用的是最常见的Result 结构code、msg、data三项。code为0代表成功非0代表各种错误比如401未登录、500服务器异常。这个小东西能让你前后端联调省非常多事而不是每个接口返回的JSON结构都不一样。public class ResultT { private Integer code; private String msg; private T data; public static T ResultT success(T data) { ResultT r new Result(); r.code 0; r.msg success; r.data data; return r; } public static T ResultT error(Integer code, String msg) { ResultT r new Result(); r.code code; r.msg msg; return r; } }Controller层面我用的都是SpringMVC的RestController配合GetMapping、PostMapping。路径规划要一致统一以/api开头比如/api/drug/list、/api/order/create这样小程序端BASE_URL固定以后接口路径一目了然。参数上能用RequestParam就用简单写法POST提交用RequestBody接收JSON。4.2 MyBatis动态SQL与库存扣减写法SSM这套框架真正的技术含量在Mapper层特别是MyBatis的动态SQL。药品列表要支持按关键字搜索、按分类筛选如果每个场景写一个SQL太蠢了动态SQL正好解决。select idpageQuery resultTypecom.example.entity.Drug SELECT * FROM a_drug where if testkeyword ! null and keyword ! AND name LIKE CONCAT(%, #{keyword}, %) /if if testcategoryId ! null AND category_id #{categoryId} /if AND status 1 /where ORDER BY id DESC LIMIT #{offset}, #{size} /select注意几个小点。like拼接不要直接在Java里写%keyword%再传进去尽量在SQL里用CONCAT避免SQL注入风险。分页的offset要自己算offset(page-1)*size别把page直接传进去。排序用id DESC做默认新录入的药品会在前面演示效果更好。库存扣减的SQL我刚才提过再强调一次正确写法update idreduceStock UPDATE a_drug SET stock stock - #{num} WHERE id #{drugId} AND stock #{num} /update这个update返回的影响行数就是关键返回1表示扣减成功返回0表示库存不够或者药品状态不对。很多同学写成先select stock再在Java里判断然后update这在并发情况下一定会超卖。虽然毕业设计并发量不大但写法正确是答辩加分项。4.3 事务管理的正确姿势下单这个操作必须加事务创建订单主表、插入订单明细、扣减库存任何一步失败都要回滚不能出现订单建了但库存没扣的情况。Spring的Transactional用起来很简单但坑不少。Service public class OrderService { Transactional(rollbackFor Exception.class) public Long createOrder(Long userId, ListCartItem items) { // 1. 校验商品是否上架、是否处方药 // 2. 根据最新价格计算总价 // 3. 循环扣减库存任一失败则抛出异常触发回滚 // 4. 插入订单主表 // 5. 插入订单明细表 // 6. 返回订单号 } }三个坑你必须知道。第一Transactional默认只回滚RuntimeException如果你在方法里抛的是普通Exception它不会回滚所以一定要写明rollbackFor Exception.class。第二同类内部方法调用不生效比如A方法没加事务调用同类里加了事务的B方法B的事务不会启动这是Spring代理机制导致的解决方案是分开类或者自己注入代理对象。第三不要在事务方法里try-catch住异常还不往外抛一旦你catch住了事务管理器感知不到异常就不会回滚。4.4 管理后台怎么做管理后台我建议走极简路线不要在这个上面花太多时间。两个选择一是用前端模板Layui、AdminLTE这种做几个静态页面通过Ajax调后端接口二是不做页面直接用Postman或者Apifox演示管理接口。我推荐第一种至少看起来像一个完整系统。Layui这种模板的优点是自带表格、表单、分页组件你不用写复杂的前端逻辑套一个布局往里面填数据就行。药品管理页面就是一张表加上新增/编辑弹窗、删除按钮订单管理页面就是订单列表点一下详情看明细再点一下发货。管理端功能不用花哨能用、能演示、能截图放论文就够了。5. Python在这套系统里能干什么5.1 用Faker批量造一批像样的测试数据做联调的时候最头疼的就是没数据数据库空空如也小程序里翻两页就到底演示毫无说服力。手工录50条数据能录到你崩溃这时候Python就该上场了。用Faker库可以快速生成中文用户名、手机号、时间再配合random随机生成价格和库存一次批量插入几百上千条数据。脚本很简单我用pymysql直连数据库执行插入import pymysql from faker import Faker import random fake Faker(zh_CN) conn pymysql.connect( hostlocalhost, userroot, password123456, databasepharmacy_db, charsetutf8mb4 ) cur conn.cursor() for i in range(500): cur.execute( INSERT INTO a_user (username, password, role, phone, create_time) VALUES (%s, %s, %s, %s, %s), (fake.name(), 123456, 0, fake.phone_number(), fake.date_time()) ) for i in range(200): cur.execute( INSERT INTO a_drug (name, category_id, spec, unit, price, stock, manufacturer, status) VALUES (%s, %s, %s, %s, %s, %s, %s, 1), (fake.word() 片, random.randint(1, 5), 0.25g*24片, 盒, round(random.uniform(5, 80), 2), random.randint(10, 500), fake.company()) ) conn.commit() print(done)这里提个醒造数据不是作弊是开发效率工具。论文里的截图需要数据支撑答辩演示时列表页有数据才能展示分页、搜索、筛选这些功能。你完全可以跟答辩老师说我写了一个Python脚本批量生成测试数据用于系统联调与性能验证这反而是加分项。5.2 用Pandas快速出统计图表论文里一般都会有一章放系统测试和结果分析如果你能放上一张月度销售趋势图、药品分类占比饼图比纯文字表格强太多。用Python处理这种统计任务比Java写一堆循环再拼JSON省事得多。import pandas as pd import pymysql import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] # 防止中文乱码 conn pymysql.connect(hostlocalhost, userroot, password123456, databasepharmacy_db, charsetutf8mb4) df pd.read_sql( SELECT DATE_FORMAT(create_time, %Y-%m) AS month, SUM(total_amount) AS total FROM a_order GROUP BY month ORDER BY month, conn ) df.plot(xmonth, ytotal, kindbar) plt.title(月度销售金额统计) plt.xlabel(月份) plt.ylabel(销售额) plt.savefig(monthly_sales.png)这段代码会生成一张柱状图直接保存成PNG放进论文。注意matplotlib默认字体不支持中文一定要设置中文字体否则图上全是方框在答辩现场非常尴尬。除了销售趋势你还可以做药品分类销售占比、会员消费排行等图表这些都是Python脚本几十行就能出结果的。5.3 如果要让Python参与后端怎么交代如果你已经写了一个Flask或FastAPI的统计接口那也不是不行但你必须想清楚怎么解释。我建议这样定位Python服务只承担销售数据分析这一个模块供小程序端首页的数据看板调用而商品、订单、用户这些核心业务全部走SSM。两者之间不互相调用、不共享数据库连接池只共享同一个MySQL数据库。答辩被问为什么不用Java写统计接口时你可以回答Java写统计逻辑需要循环遍历组装对象Python用Pandas一行SQL就能完成聚合分析而且我只是把统计结果以JSON格式返回并不涉及业务核心所以用Python做数据分析模块更高效。这个回答有理有据老师反而会觉得你思路清晰。最怕的是你模糊地说我就是用Python写了后端那等于承认自己技术选型没想清楚。6. 环境搭建与联调避坑清单6.1 本地环境安装顺序很多同学拿到项目代码后第一步就卡住不是因为代码有问题而是环境顺序装乱了。我总结一下我自己验证过的安装顺序照着来基本不会出大问题安装JDK 8或11配好JAVA_HOME命令行输入java -version能打印版本。安装Maven 3.6以上配好MAVEN_HOME命令行mvn -v能打印版本。安装MySQL 5.7或8.0建好数据库字符集选utf8mb4。安装Tomcat 8.5如果你用IDEA开发可以直接在IDEA里配置Tomcat。用IDEA导入后端工程等Maven把依赖下载完这里要耐心第一次下载Spring全家桶可能要十几分钟甚至更久。修改数据库连接配置重点是url里的serverTimezoneAsia/ShanghaiMySQL 8的驱动也要换。启动后端先用浏览器或Postman访问一个最简单的接口确认服务起来了。打开微信开发者工具导入小程序工程在详情-本地设置里勾选不校验合法域名。前后端联调。这个顺序看着简单但每一步都可能出岔子。最常见的就是JDK和Maven版本不匹配、Maven下载依赖超时、MySQL密码和连接配置不一致这些在答辩前一周解决最头疼所以提前整套跑通非常重要。6.2 小程序请求域名与调试小程序和普通网页不一样它默认只能请求HTTPS的合法域名而且域名必须在小程序后台配置。本地开发阶段你不可能有这个条件所以微信开发者工具提供了一个开关详情-本地设置-不校验合法域名、web-view业务域名、TLS版本以及HTTPS证书勾选之后就能请求http://localhost:8080或者http://192.168.x.x:8080了。这里有一个细节真机预览时后端地址一定不能写localhost要写电脑在局域网里的IP。因为真机上的localhost指的是手机自己不是你的电脑。你在电脑上ipconfig看一下局域网IP把小程序接口的BASE_URL改成http://192.168.x.x:8080手机和电脑连同一个WiFi就能联调。如果真机请求不到多半是电脑防火墙拦了8080端口临时关掉防火墙或者添加入站规则就行。演示当天如果现场没有网络提前把小程序的基础数据都准备好在本地用开发者工具演示比真机预览更稳因为开发者工具不依赖外网验证。别问我怎么知道的我答辩那天就是现场网络抽风靠开发者工具撑下来的。6.3 常见报错速查表把一年多来帮人排错的经历浓缩成一张表每一条都是我自己或身边人真实踩过的坑现象可能原因处理方法请求全部404后端没启动、Tomcat端口不对、路径前缀不匹配确认控制台启动日志检查context-path和RequestMAPPING路径接口报500SQL异常、空指针、前端参数没传对看后端异常堆栈接口入口先打印入参定位到Mapper数据库连接失败密码错、驱动版本不对、时区问题检查url、user、passwordurl加上serverTimezoneMyBatis绑定异常XML的namespace和Mapper接口全限定名不一致逐个检查Mapper接口包名和namespace以及方法id小程序一直转圈域名校验没关、IP写错、后端没响勾选不校验合法域名真机用局域网IP先测后端接口通不通中文乱码连接字符集不是utf8mb4、前端没设置编码url加useUnicodetruecharacterEncodingutf8后端加过滤器库存没有扣减事务没生效、条件更新失败检查Transactional配置确认update影响行数为1手机预览白屏基础库版本太高或太低、微信开发者工具版本旧切换基础库版本更新开发者工具到最新稳定版遇到问题一定要学会看控制台和日志这是一项比写代码更重要的能力。后端异常先看Eclipse/IDEA的Console输出找到第一行Exception信息前端问题先看微信开发者工具的Console和Network面板Network面板能看到请求是否发出、返回了什么。大多数问题都能靠这两步定位出来。7. 答辩演示与提问应对7.1 演示前准备的三个版本答辩现场时间非常有限通常只有5到10分钟演示你不可能把全部功能都点一遍。我强烈建议准备三个演示方案完整演示版从微信登录、浏览首页、搜索药品、查看详情、加入购物车、确认订单、模拟支付、查看订单列表一条主链路走完大概需要3到4分钟。这是最常见的情况。精简演示版如果前面老师提问占用了大量时间演示时间只够2分钟那就只演示核心链路登录、搜索、下单。注意下单是重点一定要走完因为它是系统的核心闭环。异常容错版提前造好一条库存不足的药品数据演示时故意下单让它提示库存不足再准备一个待付款的订单展示订单状态流转。这个小细节会让老师觉得你的系统考虑到了异常情况而很多同学只会演示完美路径一遇到报错就手忙脚乱。7.2 答辩老师爱问的六类问题我把答辩老师最常问的问题整理成一个清单你提前把回答准备好心里就有底了为什么选这个题目回答方向药店管理系统业务闭环清晰有实际应用场景能覆盖课程所学核心知识。为什么用SSM框架回答方向SSM是Java Web经典的轻量级组合分层清晰、社区资料多适合这个规模的项目。数据库为什么这么设计回答方向主外键保持数据一致性状态字段区分业务状态常用查询字段加索引。库存超卖怎么处理回答方向条件更新加事务UPDATE语句里带stock#{num}条件用影响行数判断。用户密码怎么存储回答方向不能明文存储用BCrypt加盐哈希登录时比对哈希值。数据量大了怎么办回答方向分页查询、索引优化、SQL慢查询分析必要时引入缓存。还有一个小概率但很致命的问题这个项目是你自己写的吗如果你是从网上下的源码这个问题直接决定你的生死。提前把所有代码逐行读过、改过、加过注释至少你要能讲清楚任何一个模块的作用这个问题就难不倒你。7.3 回答问题的通用话术答辩问答环节有一个万能结构结论加实现细节加效果。比如问库存超卖你先说我用的是数据库条件更新加事务控制然后说具体是UPDATE语句带库存充足条件扣减成功影响行数为1否则抛异常回滚最后补一句这个方案能保证并发下不超卖。三段式回答大概30秒既清楚又显得有逻辑比想到哪说到哪强得多。遇到完全不会的问题千万不要愣住。你可以说这个知识点我还没深入实践过按照我的理解解决方案可能是……然后我会在后续去查资料验证。承认不足但给出思考方向比硬编一个答案或者沉默要好得多。PPT里一定要放一张架构图把微信小程序、SpringMVC、Service、MyBatis、MySQL之间的调用关系画出来再放一张核心业务流程图。老师问你整体架构的时候指着图讲比空口说一百句都清楚。画架构图用简单的框和箭头就行不用花里胡哨。8. 过来人的几点建议先说一个很多人不愿面对的事实网上下的开源代码如果不经过自己重新理解、修改和调试答辩环节大概率要露馅。源码可以当学习资料但不能直接当交付物。我的习惯是拿到代码第一周什么都别做先把工程在本地跑通然后一个模块一个模块地加注释、改命名、调整结构把别人的代码变成我讲得清楚的代码。这个过程会花时间但它是从会抄到会做的唯一路径。时间规划上我给常问我的学弟学妹一个六周方案第一周搞定环境第二周理清表结构和接口文档第三周完成管理端第四周完成小程序端主流程第五周补亮点和异常处理第六周写论文和准备答辩。这个节奏不紧不慢能稳住心态。论文里一定要有真实的截图包括数据库表结构截图、接口调试截图、小程序界面截图、异常处理截图。答辩老师翻论文的速度很快图文并茂比大片大片的文字有效得多。Python生成的那些统计图也放进去正好对应系统测试与结果分析那一章。最后再分享一个小技巧答辩前两三天找两三个同学当模拟老师让他们按上面的问题清单轮番轰炸你一遍你练着讲。第一次肯定会卡壳讲完你自然知道哪些地方不熟补就完了。等真正站到答辩台上你会发现大多数问题你都提前练过了那种心里有底的感觉比临时抱佛脚强一百倍。我自己做这个项目最大的体会是宁可把五个功能做得干净利落也别堆十个功能然后演示翻车。毕业设计真正考察的不是功能数量是你对自己系统的理解程度。把表结构、接口、事务、权限这些基础细节吃透答辩的时候你会比大多数同学都从容。