首页 / 资讯中心 / 文章详情

SpringBoot饮品DIY定制系统设计与实现——毕业设计完整项目复盘

SpringBoot饮品DIY定制系统设计与实现——毕业设计完整项目复盘 ★ FEATURED ARTICLE
每年毕业设计选题季我看到太多同学在SpringBoot和“管理系统”之间反复纠结最后交出一个连自己都不想打开的学生管理系统。今天我把之前完整做过的一个项目复盘出来——基于SpringBoot的饮品DIY制作系统也就是个性化奶茶定制与订单管理平台。这个题目的好处非常直接它既有SpringBoot后端开发的技术深度又能覆盖订单、支付、库存、会员这些电商系统的核心场景而且“饮品DIY”这个交互点特别适合展示前端联动和业务规则设计答辩的时候天然就有亮点。如果你正在为计算机毕业设计选题发愁或者已经选了类似题目但不知道从哪下手这篇文章会给你一份可以直接抄作业的完整思路从为什么选这个题、数据库怎么设计到核心模块怎么写、上线前要处理哪些坑最后连论文结构怎么组织、答辩怎么演示都会一起聊到。1. 为什么我选了饮品DIY这个选题1.1 选题逻辑一个题目覆盖三大考察点毕业设计最怕什么就怕题目看起来热闹但做完发现技术栈薄得可怜。饮品DIY制作系统这个题目表面上是“用户选料、下单、商家出杯”的一件小事拆开之后几乎覆盖了JavaWeb阶段所有核心考点。先说SpringBoot框架本身。小程序端或Vue页面请求进来Controller层接收参数、Service层处理业务、Mapper层操作数据库这三层结构是SpringBoot Web应用的基本盘。再加上Spring Data JPA或MyBatis的集成、事务管理、参数校验、自定义异常处理这些都是面试官和答辩老师最关注的点。再说业务复杂度。一杯奶茶的DIY看起来轻量但它要处理的业务规则其实很不简单基础款饮品搭配什么小料、甜度冰量怎么选、不同小料有没有互斥关系、库存不足时下单怎么提示、订单状态从“已提交”到“制作中”再到“已完成”怎么流转。这些规则写成代码就是业务逻辑设计能力。最后是应用场景。这个系统天然包含用户端、商家端、管理端三类角色。用户端有会员注册、个性化定制购物车、订单支付商家端有订单接单、制作状态更新、库存管理管理端有商品上架、分类维护、数据统计。一个系统把三种角色的权限控制和业务流都做了论文的“系统功能结构图”画出来非常饱满。1.2 这个系统能解决什么问题、适合谁参考站在“门店运营”的角度看这个系统解决的核心问题是连锁奶茶店的标准化订单流程和个性化定制需求之间的矛盾。传统门店靠收银员手记备注高峰期漏单错单是常事如果用户在手机端自己选好小料和口味订单直接进后厨屏幕出杯效率和准确率都会大幅提升。站在“计算机毕业设计”的角度看它解决的问题是如何用一套完整SpringBoot项目展示对Web开发全流程的理解。从需求分析、数据库设计、接口设计到前端联调、部署上线、压力问题排查每个环节都有真实场景可写、可演示、可追问。适合参考这个项目的人有两种一种是JavaWeb基础学完但没做过完整项目的在校生正好用这个题把SpringBoot、MyBatis、Redis、Vue等串起来另一种是选题已经定了“XX管理系统”但内容太泛、不知道往里填什么的同学可以把这套“用户DIY 订单流转 门店库存”的模式迁移过去比如咖啡定制、甜点定制、轻食订单系统思路完全通用。2. 项目整体架构与数据库设计2.1 技术栈选型别追新追稳做毕业设计的技术选型原则就一句话让自己睡得着觉。我见过有人为了显得高级硬上微服务结果Spring Cloud一启动就报错天天在群里问“nacos连不上怎么办”。一个毕业设计的体量单体SpringBoot应用完全够用而且逻辑清晰、易于答辩。我最终选的组合是SpringBoot 2.7 MyBatis-Plus MySQL 8.0 Redis Vue 3 Element Plus。SpringBoot 2.7是目前教材、网课、博客覆盖最全的版本遇到问题一搜就有答案MyBatis-Plus相比原生MyBatis减少了一大堆重复的CRUD代码而且提供了分页插件做订单列表和商品列表都很方便Redis用来做验证码存储和热点数据缓存比如首页的推荐饮品列表我用Redis缓存了压力测试时接口响应时间明显下降。前端用Vue 3配Element Plus组件开箱即用适合一个人同时写前后端的情况。权限框架用了Spring Security加JWT没有引入太重的Sa-Token或Shiro因为Spring Security是SpringBoot官方推荐方案答辩提到“安全框架选型”时有话题可以聊。文件上传用了MinIO存饮品的宣传图和用户DIY作品图比存本地路径更规范。这套组合的性能和稳定性对毕设来说绰绰有余而且每个组件都能单独拿出来写一段选型对比。真不建议在这个阶段用SpringBoot 3.x加JDK 21那些在热词里看起来很新但很多老教程不兼容踩坑成本极高。2.2 核心数据表设计思路数据表的设计直接决定了后面代码好不好写。我花了一天时间画ER图最终拆出了七张核心表外加三张关联辅助表。用户表sys_user用户ID、昵称、手机号、密码BCrypt加密存储、头像、会员等级、积分、注册时间。这里要注意手机号要加唯一索引登录和注册都靠它。饮品表drink饮品ID、名称、分类ID、描述、基础价格、图片URL、状态上架/下架、月销量。这里有一个关键设计我保留了“基础价格”因为DIY选的每一样小料都要在小料表中记录加价最终价格等于基础价格加小料价格之和。小料表ingredient小料ID、名称、类型珍珠/椰果/奶盖/糖浆等、单价、库存、状态。库存字段在这个表里非常重要它直接支撑下单时的库存扣减校验。定制配置表custom_config配置ID、用户ID、饮品ID、甜度、冰量、杯型中杯/大杯、所选小料集合、总价、配置名称。这张表是DIY功能的核心。因为同一个用户可能会保存多个偏好配方我允许用户给配置命名比如“我的快乐水”下次下单可以直接引用。订单表orders订单号、用户ID、订单金额、配送方式自取/外卖、门店ID、订单状态、备注、创建时间/支付时间/完成时间。订单号我用了“时间戳随机数”方式生成没有用数据库自增主键直接透出给用户避免被爬取订单量。订单明细表order_item订单ID、饮品名、最终规格描述比如“大杯/少冰/七分甜/加珍珠椰果”、当时单价、数量、小项合计。注意这里必须要把“最终规格描述”冗余存储。因为小料可能下架改价过几个月再查历史订单时不能依赖关联查询去还原当时的规格。门店表store门店ID、名称、地址、营业状态、库存JSON快照。门店表与库存的关联我用了相对简洁的方案不单独建门店库存明细表而是在门店表存一个JSON字段记录该门店小料库存的实时快照。这样查询快但并发扣减时依赖数据库行锁来保证一致性毕业设计场景已经完全够用。2.3 为什么要在订单里冗余规格快照这个点我觉得值得单独说。刚开始设计表结构时我走的是一套“纯关联查询”方案订单明细表只存饮品ID和小料ID列表前端展示时再去查当前饮品表和小料表拼出名称。听起来很正规但上线试验后发现一个问题我手动把小料“黄金珍珠”的价格从2元调到3元之后历史订单里所有包含“黄金珍珠”的订单明细全都显示出最新价格和名字。这在真实门店运营中是不可接受的。顾客半年前买的那杯奶茶记录就该保持半年前的样子。因此在order_item表里我用一个字段存“规格快照”字符串比如“大杯/少冰/7分甜/加珍珠2元/加椰果3元”下单那一刻就生成好写死。查询历史订单时直接展示字符串不做任何实时计算。这个设计我在论文的需求分析章节也重点描述过答辩时老师问“你如何保证订单历史数据的一致性”我直接把这个快照机制讲清楚就是很好的加分项。数据库设计的总体思路是能冗余的就冗余能提前计算的就别留到查询时再算。毕业设计不是企业级高并发项目表设计的核心目标是逻辑清晰加查询方便。3. 核心功能模块的落地实现3.1 饮品DIY模块业务规则怎么建模饮品DIY是整个系统最有“项目感”的模块也是演示时最有视觉冲击力的一块。用户选一款基础饮品然后进入定制页选杯型、甜度、冰量、加料右侧实时显示价格变化。这个交互在后端对应一个定制接口接收一批参数计算总价返回可下单的配置对象。定制接口的Controller层接收参数时我用了Validated注解加自定义校验规则。前端传上来一个“甜度”字段我约束只能是“不另外加糖/三分甜/五分甜/七分甜/全糖”五种传冰量只能是“热/常温/少冰/正常冰/多冰”传小料List每个元素必须是数据库小料表中存在且状态为可售的ID。价格计算逻辑放在Service层核心代码如下只贴核心片段public BigDecimal calculatePrice(CustomConfigRequest req) { Drink drink drinkMapper.selectById(req.getDrinkId()); if (drink null || drink.getStatus() ! 1) { throw new BizException(饮品不存在或已下架); } BigDecimal totalPrice drink.getBasePrice(); if (大杯.equals(req.getCupSize())) { totalPrice totalPrice.add(new BigDecimal(2)); } if (req.getIngredientIds() ! null !req.getIngredientIds().isEmpty()) { ListIngredient ingredients ingredientMapper.selectBatchIds(req.getIngredientIds()); for (Ingredient item : ingredients) { if (item.getStatus() ! 1) { throw new BizException(小料【 item.getName() 】已售罄或下架); } totalPrice totalPrice.add(item.getPrice()); } } return totalPrice.setScale(2, RoundingMode.HALF_UP); }这段代码有两个容易被忽视的点。第一抛业务异常而不是返回null或false。我自定义了BizException配合全局异常处理器RestControllerAdvice统一返回“{code: 50001, message: 小料已售罄”这样的结构化错误前端拿到code判断提示而不是傻傻地显示“Internal Server Error”。第二所有金额运算使用BigDecimal绝不用double。批判性思考一下double在加减运算时的精度误差在金融或交易场景就是大事故答辩时主动提“金额计算我用BigDecimal避免精度损失”同样是一个亮点。保存用户定制配方时custom_config表记录配置快照和总价。下次用户复制配方前端直接把上次的配置参数带回接口重新校验库存和价格。要注意的是库存校验必须在下单发生时做而不是在保存配置时做因为两次操作之间库存可能已经变化。3.2 订单模块状态机与超时未支付处理订单模块是整个系统的骨架。用户从DIY页面加入购物车提交订单在线支付我在演示环境用的是模拟支付商家接单制作完成用户取餐。这里最关键的是一张订单状态流转图我用文字描述就是已提交待支付 - 已支付待接单 - 制作中 - 已完成 已提交待支付 - 已取消 已支付 - 商家可标记异常 - 已退款实现状态流转时我不建议在Service里散落一堆if判断而是用枚举加状态机校验。核心做一个OrderStatusEnum里面定义状态码和允许到达的下一状态集合。每次修改状态都调用一个统一方法public void changeOrderStatus(Long orderId, OrderStatusEnum targetStatus) { Orders order orderMapper.selectById(orderId); if (order null) throw new BizException(订单不存在); // 核心校验当前状态是否允许变更到目标状态 if (!order.getStatus().canTransitTo(targetStatus)) { throw new BizException(订单状态不允许从 order.getStatus().getDesc() 变更为 targetStatus.getDesc()); } order.setStatus(targetStatus); orderMapper.updateById(order); }这套状态机的好处显而易见所有状态流转都有一处统一校验不会出现“已完成”订单被再改成“制作中”的bug。我最初写代码时是每个业务方法里各自判断状态结果出现了两个坑一个是在“已取消”订单上执行商家接单操作后状态被错误更新另一个是用户重复点击支付导致扣两次款。改用状态机统一校验后这两个问题直接在入口处被拦截了。超时未支付订单的处理我用了两种方案结合。第一种是最简单可靠的定时任务轮询SpringBoot自带Scheduled注解每30秒扫描一次订单表把创建时间超过30分钟且状态仍是“待支付”的订单自动置为“已取消”同时释放预占的小料库存。第二种是Redis过期监听下单时给订单号设置一个30分钟的Redis KeyKey过期时触发回调去取消订单。但在实际测试中我发现Redis的Key过期事件并不保证精确实时而且配置起来稍显繁琐最终线上运行还是以定时轮询为主Redis的过期监听只作为补充。关于库存扣减最关键的一点是要区分两阶段。用户下单提交时不是立即扣减库存而是先校验并预占库存把预占数量记录在Redis中真正支付成功后再扣减数据库库存并释放预占。如果用户下单后一直不支付超时取消时释放预占即可而数据库中的小料库存从未变动过。这个设计与“先锁库存再支付”的电商经典思路一致既避免了超卖也不会出现下单选好料、支付时被告知没货的尴尬。3.3 门店运营管理模块数据可视化的实现门店运营模块主要服务两类角色店长和管理员。店长看到的是本门店的实时订单列表和待处理任务管理员看到的是整体经营数据。实现数据统计时我用了分组查询加定时统计的方式。日销售报表接口按天聚合订单金额、订单数量、热门饮品Top10。这个统计如果用SQL实时计算数据量小的时候没问题但演示时如果订单数据一大聚合查询会明显变慢。我采取的方案是每天早上2点用Scheduled跑批把前一天的统计数据写入store_daily_report表查询报表时直接查这张中间表毫秒级返回。这个方案在论文里可以描述为“离线统计与实时查询结合”。热门饮品排行逻辑值得单独说。排行的核心指标不是“销量”而是“销量乘以基础价”也就是销售额贡献度。按销量排序会把9.9元的柠檬水排到第一但从门店利润角度看它可能只占很小比例。我最终用SQL按“SUM(item_price * quantity)”做分组排序同时保留“销量维度”作为子排行两个维度通过前端Tab切换展示。门店的接单页面使用了WebSocket实时推送。订单支付成功之后后端通过WebSocket向前端推送一条新订单消息门店大屏页面自动弹出提醒并播放提示音。演示时这个交互特别抓眼球答辩老师看到订单从用户端支付到门店端实时出现会认为你对实时通信有理解。我用的方案是SpringBoot集成原生WebSocket没有引入Netty或STOMP协议因为一对多的门店推送场景原生WebSocket已经够简单可靠。除了这些功能外还有一个容易被忽略但很重要的点是操作日志。我在所有敏感操作上加了AOP切面注解OpLog比如“上架饮品”“调整价格”“取消订单”等操作都会记录操作人、操作时间、请求参数和操作结果。这套日志系统虽然不在核心业务链路上但整理成论文的功能模块时显得系统非常完整实际开发中也帮我排查过几次误操作问题。4. 上线前必知的技术细节与踩坑实录4.1 常见问题速查表做这个项目过程中我在不同阶段踩过不少坑有些问题几乎每个做SpringBoot项目的人都会遇到。整理成表格方便你直接对照。问题现象根本原因解决方案POST请求中文乱码SpringBoot默认字符集未设置或前端未指定UTF-8后端在配置类统一注册CharacterEncodingFilter前端设置Content-Type为application/json;charsetUTF-8LocalDateTime返回到前端变成数组Jackson序列化LocalDateTime默认格式不对application.yml中配置spring.jackson.date-format为yyyy-MM-dd HH:mm:ss并配合JsonFormat注解上传图片后访问404本地路径与映射路径不匹配使用配置类实现WebMvcConfigurer的addResourceHandlers将/upload/**映射到实际磁盘路径JWT拦截器放行配置失效拦截器注册顺序或路径匹配规则错误用excludePathPatterns精确配置白名单并确认静态资源全部访问带/static前缀多表分页查询时total不准MyBatis-Plus分页插件未配置或SQL包含嵌套子查询确认PaginationInnerInterceptor已加入MybatisPlusInterceptor复杂SQL用单独写法绕过自动解析高并发下订单号重复时间戳随机数在高并发时随机冲突订单号改用“时间戳用户ID后四位UUID前四位”并加数据库唯一索引兜底表单提交的数据前端校验通过但后端报错前端只做了展示层校验后端参数校验规则缺失Service层加全局参数校验启用Validated并配合自定义校验注解4.2 并发下单场景的库存扣减与超卖处理店铺运营系统一旦上线就会面临一个毕业设计最容易忽略的问题并发超卖。用户A和用户B同时下单都看到“珍珠还有最后一杯”同时支付系统如果处理不当就会扣成负库存最后做不出两杯。我在订单模块里对库存扣减做了两种保护。第一层是数据库乐观锁。在小料表中加了一个version字段扣减库存时用UPDATE语句带版本条件UPDATE ingredient SET stock stock - 1, version version 1 WHERE id #{id} AND version #{version} AND stock 1这个UPDATE的返回值是影响行数如果返回0说明版本不匹配或库存不足Service层重新查询库存并提示用户“该小料刚刚被抢光请重新选择”。这个方案实现简单带来的并发控制效果对于毕设场景完全够用。第二层是Redis预占。如果不是直接扣数据库而是先把用户要选的小料在Redis中对ID加计数超过库存值就直接提示不可选。数据库扣减和Redis预占结合保证下单请求的快速响应同时又不丢失最终一致性。这里想特别说一下我其实也考虑过更复杂的分布式锁方案例如Redisson的可重入锁。但分析下来对于单机单库的毕业设计场景锁太重了反而容易出现死锁或长事务问题。作一个技术选型的判断毕业设计的核心目标是展示你懂并发控制的原理和取舍而不是真的扛住十万并发。用乐观锁的思路足以说明理解深度同时能把风险控制在个人可控范围内。4.3 安全性与配置文件处理技巧做毕设时安全性的比重不需要像企业系统那样高但基础项不能漏。第一项是密码不能明文存储。我用BCryptPasswordEncoder对用户密码做了哈希处理“123456”在数据库里存的是一长串雪花盐值就算数据库泄露攻击者也拿不到明文。我之前见过同学直接把密码明文存在表里答辩时老师看到这一条提问环节直接卡住。第二项是JWT鉴权。用户登录成功后签发一个有效期两小时的Token后续请求在Authorization头携带。拦截器校验Token合法性并通过ThreadLocal工具类保存当前登录用户ID业务代码中直接调用。这块比较容易被忽视的是Token过期后的前端处理。我实现了一个全局响应拦截器当后端返回401时自动跳转登录页并清除本地Token避免用户看着一个无效页面发呆。第三项是敏感配置外置。数据库密码、MinIO的AccessKey、Redis密码都不能硬编码在application.yml里直接提交到GitHub。我使用SpringBoot的多环境配置application-dev.yml放开发环境的宽松配置application-prod.yml放生产环境的加密配置并在.gitignore中排除后者。写论文时这可以作为一个“系统安全设计”的小节说明环境隔离思路既能提升文档完整度又减少真出事的概率。4.4 部署上云与演示环境的准备毕业设计通常有两类演示场景毕设答辩现场和在线演示。我建议至少准备一套可以远程访问的演示环境。部署方案用阿里云轻量应用服务器2核4G的配置足够跑这套SpringBoot加MySQL加Redis加MinIO。服务器上直接装Docker用docker-compose编排MySQL、Redis、MinIO和SpringBoot后端一个命令全部启动。第一次部署时我踩了一个坑服务器安全组默认只开了22和80端口前端访问后端接口时一直超时。解决办法是在安全组把后端服务端口我用的8080和MinIO端口9000都放通同时把MySQL端口不要暴露给公网保证安全。部署前还有一件很重要的事修改SpringBoot的配置文件把数据库地址从localhost改成服务器的内网IP或容器服务名。如果后端也在容器里配置里的other服务名要与docker-compose中定义的MySQL服务名完全一致否则连接失败。本地调试时用dev环境演示时用prod环境一键切换的核心在于启动命令加参数--spring.profiles.activeprod。这个操作很容易被忽略却在答辩时能帮你避免“刚才还能打开现在怎么挂了”的尴尬。5. 毕设论文写作与答辩演示经验5.1 论文结构从需求分析到系统测试的组织逻辑很多同学做完项目之后卡在论文上因为系统能跑但不知道论文怎么写。我的建议是论文的结构不要照抄教材模板而要跟着项目真正的开发流程走。标题里的关键词也要提前想好比如本文依托的项目可以用“基于SpringBoot的个性化奶茶定制与订单管理系统设计与实现”作为主标题摘要里先点明“为解决传统饮品门店在手工点单、订单管理、库存盘点方面的效率问题设计并实现了一套基于SpringBoot框架的饮品DIY系统采用Vue构建前端交互结合Redis缓存和WebSocket实时通知”等关键信息。论文一般分六章。第一章绪论写背景和国内外研究现状研究现状可以引用一些生鲜电商、餐饮SaaS系统的相关文献注意不要大段复制用自己的话重新组织。第二章关键技术介绍把SpringBoot、MyBatis-Plus、MySQL、Redis、Vue、MinIO、JWT这些每个用一节来介绍说明选型理由即可。第三章系统需求分析画用例图、功能结构图和流程图。第四章系统设计放架构图、技术架构分层图、数据库ER图、核心表结构这一章要足够细特别是表字段说明表格要完整。第五章系统实现配合截图和关键代码解说配合截图和关键代码段。第六章测试用黑盒测试用例覆盖注册登录、饮品定制、下单支付、库存扣减等核心流程。写论文最忌讳的就是把系统实现章节写成了代码粘贴。代码块的作用是说明一段复杂逻辑的设计思路而不是把整个类贴上去。比如订单状态机那段代码我贴了三分之一的精简代码重点解释为什么用枚举加状态校验而不是逐行翻译。答辩老师主要看的是你“为什么这样设计”而不是“会不会敲代码”。5.2 答辩演示的流程设计与追问预案答辩演示一般只有10到15分钟别想着把系统所有页面全点一遍。我建议按“主链路法”设计演示路径注册登录 → 浏览饮品列表 → 选择一款饮品进入DIY定制页 → 选甜度、冰量、加小料 → 保存配方 → 加入购物车 → 下单支付模拟支付 → 门店端WebSocket收到新订单 → 商家接单 → 制作中 → 完成订单 → 查看个人订单和历史配方。这一条链路走完系统最重要的功能都展示了逻辑顺畅不混乱。演示之前一定要提前准备一份带造数据的环境。不要拿空数据库演示可以提前用脚本生成一批饮品、小料、用户和50条左右的历史订单数据这样展示列表页、报表页时页面是饱满的。我见过好几次答辩翻车就是因为现场数据库里啥也没有页面白茫茫一片评委老师问“这就是你的系统吗”场面非常尴尬。追问预案方面提前把几个高频问题想清楚。最常见的包括用户定制时价格是怎么计算出来的库存扣减是怎么防止超卖的订单状态是怎么流转的你的系统安全性体现在哪里还有可能是“如果小料在订单支付前下架了怎么办”。这些问题的答案我在前面几个小节里都覆盖了关键是要能脱离代码用口述的方式把逻辑讲清楚。答辩老师考察的是你有没有真正理解自己写的东西遇到不懂的问题就根据分页条件、状态机、乐观锁真实思路来答不许编。5.3 从项目到简历项目经验的表达如果这个项目不只是为了毕业还会写进简历那么项目描述也要提前打磨。不要写“负责了整个系统的开发”就完了会显得空洞。参考这样的写法“基于SpringBoot的个性化奶茶定制与订单管理系统独立完成需求分析、数据库设计与前后端开发。核心功能包括饮品DIY定制、购物车、订单状态机管理、门店接单大屏与经营统计。技术选型采用SpringBoot MyBatis-Plus Redis Vue3利用Redis预占方案解决并发库存扣减问题通过WebSocket实现订单实时推送通过JWT实现无状态鉴权。门店日报表使用离线批处理统计查询性能较实时聚合提升明显。”这样的描述里每一项都是可追问的真实经历面试官感兴趣自然会往细节问这时候你在实践过程中积累的每一个坑和心得都能变成加分项。反而如果简历上写“熟悉分布式高并发”一面试就露馅。项目做完之后我还自己扩充了两个小功能一个是基于MinIO的配方分享图生成用户定制完饮品后生成一张带二维码的分享卡片朋友扫码可以查看配方另一个是会员积分体系下单成功按订单金额累积积分积分可以兑换小料抵用券。这两个功能本质上是给系统增加用户粘性但在毕设论文里可以作为“系统扩展性设计”的一部分虽然工作量不大却突出了系统的商业可行性。如果要我给建议那就是在核心链路完整跑通之后挑一个这样的小点做深整个项目的完成度会立刻提升一个档次。我个人做这个项目最大的体会是毕业设计的价值不在于系统多庞大而在于你真正经历了一遍“从想法到设计到编码到测试到部署”的完整闭环。中间过程踩的那些坑比如中文乱码、订单状态被错误更新、并发扣减造成负库存每一个解决过程都比课程作业里写的那些“HelloWorld”有价值得多。希望这份SpringBoot饮品DIY系统的复盘能帮你少走几步弯路顺利把毕设做完答辩的时候能有底气地讲出自己的设计和判断。
阅读完成 · 觉得有帮助?
咨询建站