ARTICLE DETAIL

资讯详情

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

SpringBoot+微信小程序景区门票售卖系统设计与实现

SpringBoot+微信小程序景区门票售卖系统设计与实现 说实话SpringBoot加微信小程序做旅游景区门票售卖系统这个组合在计算机毕业设计里确实是高频选择身边不少学弟学妹也来问过到底怎么落地。这个项目能火不是没道理技术栈覆盖面广后端、移动端、数据库、缓存、对象存储都能展示业务逻辑贴近真实场景库存、订单、支付、核销都是实际系统里的硬骨头再加上旅游业本身是热门赛道写进简历和答辩都很有说头。我按“项目全景、小程序端、后端、联调部署、论文答辩、踩坑扩展”这条线把完整经验梳理一遍。不管你是零基础想拿一个稳妥毕设还是已经在写代码但被各种细节卡住这篇内容都能直接对着做。后端我用SpringBoot 2.7.x前端用微信小程序原生语法数据库MySQL 8缓存Redis图片存储MinIO整体偏中小型但五脏俱全。1. 项目全景系统定位与技术选型拆解1.1 为什么是SpringBoot加微信小程序选型逻辑先说清楚很多同学纠结选题其实核心就三条好实现、好展示、好答辩。SpringBoot加小程序恰好把这三条都占了。SpringBoot把SSM那套繁琐的配置全部自动化你不需要写一堆XML一个启动类就能跑起来适合时间有限的学生小程序端则是“真移动端”评委看到手机上的实际界面印象分完全不一样比纯网页系统高出不少档次。另外这个组合天然带“前后端分离”的影子能引出不少答辩话题wx.login登录流程、Token鉴权、HTTPS域名配置、支付回调等等每一段都有真实的技术深度可聊。相比之下单纯用PHP做后台管理系统的传统选题这几年明显吃亏因为能讲的技术点太薄了。这里也回应一下选题时的常见顾虑标题里提到可做JAVA、PHP、爬虫、APP、C#、C、python等版本这确实是同一套业务模型在不同语言下的复刻。但就景区门票售卖场景而言Java方案是最稳妥的因为相关参考代码多、社区问题库全、答辩导师也最熟悉。你要是代码基础一般别贪新鲜选小众语言Java生态是最容易“抄作业抄明白”的。1.2 功能模块边界游客端、管理端和数据层各管什么景区门票系统核心参与者就两类游客和景区运营人员。游客关心的是“看景区、选票、买票、入园验票”运营人员关心的是“维护景区、上下架门票、核销订单、看收入数据”。围绕这两个角色我把功能切成三个维度游客端微信小程序首页景区轮播图、热门推荐、公告栏景区列表按地区、评分、价格排序支持关键字搜索门票详情票型展示成人票、学生票、儿童票、库存余量、游玩日期选择下单支付生成订单、微信支付、支付状态实时刷新订单中心待支付、已支付、已使用、已取消多状态管理个人中心微信头像昵称展示、登录态维护、联系客服管理端Web后台景区管理景区基础信息、图片、介绍、开放时间维护门票管理不同票型定义、价格、库存、有效期设置订单管理订单列表检索、退款审核、订单导出核销管理扫码验证游客电子票标记已使用数据统计门票销量、营业收入、热门景区排行用ECharts做可视化大屏专项加分数据层配合MySQL存储业务数据、Redis扛高并发读写、MinIO存图片文件。为什么强调“数据统计”这个模块因为“数据可视化”在标题里专门出现了后面用ECharts做管理端统计面板可以说是答辩时最容易展示的亮点模块工作量不大但视觉冲击强。1.3 数据库与核心表设计思路订单表是重中之重表数量不用太多6到8张足够支撑整个系统太多反而增加开发量和维护成本。我实际落地用了这些表用户表、景区表、门票表、订单表、订单明细表可并入订单表、支付流水表、评价表、管理员表。订单表的设计是核心中的核心字段至少包括订单号业务单号不是自增主键、用户ID、景区ID、票型ID、数量、单价、总金额、状态0待支付/1已支付/2已使用/3已完成/4已取消/5退款中、创建时间、支付时间、使用时间。有几个关键经验订单号别用自增id用时间戳加随机数生成方便后续对账和客服查询状态字段用tinyint而不是varchar性能和存储都更好代码里维护常量或枚举下单时间、支付时间、使用时间分开存后续统计报表全依赖这几个时间字段景区表和门票表是1对多关系一张景区对应成人票、学生票、亲子票等多个票型库存放在票型上而不是景区上索引方面订单表的user_id、status、create_time必须建索引数据量上来之后不建索引的订单查询会慢到你怀疑人生。景区表按状态建普通索引就够了。这套表结构应对并发量不大但逻辑完整的教学型需求完全够用。2. 小程序端开发实录列表、导航栏、选票与下单2.1 门票列表“加载更多”分页交互的标准实现小程序列表页最常见的痛点就是“一次性把数据全查出来”。你会发现接口响应慢、页面卡顿、内存占用高核心原因就是没有做分页。标准做法是后端按“页码每页条数”返回数据前端触底时再加载下一页。小程序端实现分页要抓住三个关键技术点onReachBottom触底事件、pageIndex和pageSize参数、加载状态锁。我的核心代码长这样// pages/tickets/tickets.js Page({ data: { list: [], pageIndex: 1, pageSize: 10, total: 0, loading: false, hasMore: true }, onLoad() { this.fetchTickets(true); }, onReachBottom() { // 触底加载如果正在加载或者没更多数据直接忽略 if (this.data.loading || !this.data.hasMore) return; this.fetchTickets(false); }, fetchTickets(isRefresh) { if (this.data.loading) return; this.setData({ loading: true }); const pageIndex isRefresh ? 1 : this.data.pageIndex 1; wx.request({ url: https://api.example.com/ticket/list, data: { pageIndex, pageSize: this.data.pageSize }, success: (res) { const data res.data.data || {}; const newList isRefresh ? data.records : this.data.list.concat(data.records); const hasMore this.data.pageIndex * this.data.pageSize data.total; this.setData({ list: newList, pageIndex, total: data.total, hasMore, loading: false }); }, fail: () this.setData({ loading: false }) }); } });这里有个细节容易被忽略loading锁必须放在请求开始前而不是请求成功后。不然用户快速滑动时onReachBottom会连续触发多次发出大量重复请求白白浪费流量。列表底部我还加了个“没有更多了”空态提示数据加载完毕时展示否则用户会一直往上滑以为是卡住了。2.2 自定义顶部导航栏适配胶囊按钮与状态栏高度景区门票系统的小程序端我强烈建议用自定义导航栏而不是默认导航栏。因为业务上经常需要把景区名称动态展示在标题位置或者把导航栏背景换成和景区主色调一致的颜色默认导航栏完全做不到这些灵活调整。自定义导航栏的核心难题是适配不同手机的刘海屏和状态栏高度。每个手机的状态栏高度都不一样要做的是通过wx.getWindowInfo获取状态栏高度和胶囊按钮位置动态计算导航栏高度const app getApp(); Page({ data: { statusBarHeight: 0, navBarHeight: 44 }, onLoad() { const windowInfo wx.getWindowInfo(); const menuButton wx.getMenuButtonBoundingClientRect(); // 导航栏高度 (胶囊上边界 - 状态栏高度) * 2 胶囊高度 const navBarHeight (menuButton.top - windowInfo.statusBarHeight) * 2 menuButton.height; this.setData({ statusBarHeight: windowInfo.statusBarHeight, navBarHeight }); } });然后在app.json里关闭默认导航栏页面顶部用自定义view留出状态栏高度和导航栏高度这样布局在任何机型上都不会错位。我在真机测试时发现如果直接用固定的44px高度iPhone X以上机型会出现标题被刘海遮挡的问题这个动态计算公式是官方推荐的方案务必用上。2.3 选票单选框与库存联动交互细节决定体验门票详情页的选票逻辑是这个小程序端交互复杂度最高的部分。游客进入门票详情后要能看到不同票型的价格、选择游玩日期、调整购买数量。票型选择用radio-group实现数量用stepper组件这两个基础控件的联动才是关键。我的联动逻辑是这样的切换票型时立刻请求一次该票型在选定日期的剩余库存把库存余量展示在界面上数量如果超过剩余库存则自动截断为最大可购数。这里不要用本地缓存里的库存数因为后端随时可能因为其他用户下单而扣减库存必须实时请求。选日期的组件用小程序原生日期选择器picker modedate设置start为当天、end为未来30天景区门票一般提前30天预售。日期切换后同样要触发一次库存查询因为不同日期的库存是独立的——这是景区门票跟普通商品最大的区别门票库存是按日期维度拆分的。库存不足时的交互也非常重要剩余0张的日期要置灰不可选票型库存为0时禁用该选项。测试时我发现很多同学忽略了这个禁用态用户选了一个已售罄的日期提交订单时后端报错体验很差。做前端的时候后端返回的库存字段要精细到“某票型某日期”的粒度接口设计在后面章节展开。2.4 用户离开监听与支付幂等方案防掉单的兜底机制用户在小程序里拉起微信支付后会跳转到微信的收银台这时小程序本身进入后台。支付完成后用户回到小程序这个“回来”的过程就是整个系统最容易出bug的环节支付结果可能还没回调到后端或者回调失败导致用户付了钱但订单状态没更新。我的经验是套两层保险。第一层在小程序的onShow事件里主动查询一次订单状态onShow() { const orderId this.data.currentOrderId; if (!orderId) return; wx.request({ url: https://api.example.com/order/status, data: { orderId }, success: (res) { const status res.data.data.status; if (status 1 || status 2) { this.setData({ paymentStatus: success }); // 刷新订单列表、清理待支付状态 } else if (status 0) { this.setData({ paymentStatus: pending }); } } }); }第二层后端收到微信支付回调后更新订单状态并将结果同步推送给小程序。如果用户支付成功但小程序没有收到回调结果比如用户杀掉小程序、网络中断下次打开订单中心时前端仍然可以拿到“已支付”状态完成状态修正。监听用户离开还要考虑另一个场景用户在填写订单信息时突然切走去看别的App再回来时订单可能已经被后端自动取消我的设计是15分钟未支付自动释放库存。所以onShow刷新时还要判断订单是否已被取消如果被取消了要提示用户重新下单而不是让用户对着一个失效的订单继续操作。3. SpringBoot后端接口设计、防超卖防爬与文件存储3.1 Maven项目构建与分层规范代码结构决定开发效率后端我分成四个包controller、service、mapper、entity外加config和common两个支撑包。controller只做参数接收和结果返回不写业务逻辑service是核心业务层mapper管数据库操作common里放统一返回体、异常处理、工具类。分层清晰的好处是答辩时你可以直接指着代码说“我的项目遵循了分层架构设计”这也是评委最买账的规范性加分项。Maven构建时核心依赖如下spring-boot-starter-web、mybatis-plus-boot-starter数据库操作、mysql-connector-java、spring-boot-starter-data-redis、lombok、hutool工具类库、minio文件存储SDK。用MyBatis-Plus而不是原生MyBatis的原因很简单单表CRUD不用写SQL内置的QueryWrapper能省大量重复代码把精力集中在订单和库存这种真正的核心逻辑上。统一返回体也很关键。我定义了Result类所有接口都返回“code message data”的结构前端拿到数据后先判断code是否为200再处理data。配合全局异常处理器业务异常统一抛BizException框架层的异常转化成友好提示前端再也不用面对乱七八糟的堆栈信息。3.2 订单状态机与Redis预扣库存防超卖的核心实现防超卖是整个系统技术含量最高的部分也是答辩必问的点。先明确问题两个用户同时买最后一张票如果代码是先查库存再扣库存两个请求都可能查到库存为1都认为自己能买最终库存变成-1超卖了。我的处理方案是Redis预扣加数据库兜底的双重防护。用户提交订单时先在Redis里用DECR操作扣减对应日期库存同时创建待支付订单设置15分钟过期。用户支付成功后再把Redis的扣减同步到MySQL的库存字段如果15分钟内未支付订单取消并执行INCR把库存加回来。数据库层的兜底用的是条件更新SQL语句里带上库存校验UPDATE ticket_inventory SET stock stock - #{quantity} WHERE ticket_id #{ticketId} AND stock_date #{date} AND stock #{quantity}这条语句执行后判断受影响行数如果为0说明库存不足直接回滚订单。有了Redis预扣在前加上数据库条件更新兜底即使Redis崩溃或者缓存没命中也不会出现超卖。关于JDK版本温和提示SpringBoot 3.x需要JDK17很多学校机房还在JDK8做毕设建议直接用SpringBoot 2.7.x配JDK8省去环境折腾。Redis的key设计也要提前规划好库存key用“ticket:stock:{ticketId}:{date}”订单key用“order:pending:{orderId}”订单人的库存预扣记录用“ticket:locked:{userId}:{ticketId}:{date}”。命名规范了后续排查问题一眼就能定位。锁过期时间用15分钟和未支付取消订单的定时任务保持一致避免用户还在付款流程里库存就被释放了。3.3 接口防爬实操拦截器、签名校验与频控限流说真的景区门票系统的接口一旦上线被爬的概率非常高爬门票价格的、爬库存余量的、甚至用脚本抢低价票的都有。如果你答辩时能讲出“接口防爬体系”绝对是个加分项。我的防护分三层。第一层是登录鉴权小程序端通过wx.login拿到code后端用code向微信接口换取openid再生成自定义Token返回给前端。后续所有请求都在Header里带Token拦截器校验Token是否存在、是否过期。没有Token的请求一律返回401。第二层是签名校验。对下单、支付这类敏感操作前端和约定一个密钥把时间戳、随机数、请求参数拼接后做HMAC-SHA256签名后端校验签名合法性。这样即使有人抓到接口报文伪造请求也会因为不知道密钥而失败。// 拦截器核心逻辑 public class SignInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String timestamp request.getHeader(X-Timestamp); String nonce request.getHeader(X-Nonce); String sign request.getHeader(X-Sign); // 时间戳5分钟内有效防止重放攻击 if (Math.abs(System.currentTimeMillis() - Long.parseLong(timestamp)) 5 * 60 * 1000) { throw new BizException(请求已过期); } // 服务端重新计算签名并比对 String serverSign genSign(timestamp, nonce, getRequestParams(request)); if (!serverSign.equals(sign)) { throw new BizException(签名校验失败); } return true; } }第三层是频控限流。用Redis计数器记录每个IP或每个用户ID在单位时间内的请求次数超过阈值直接拒绝。比如限制“获取余票接口”每个用户每分钟最多请求30次普通游客完全不会触发限制但脚本爬虫就会被挡住。有个简便做法是用Redisson的RRateLimiter几行代码就能接入令牌桶算法不需要自己手写计数器。3.4 MinIO接入门票图片的本地对象存储方案景区图片、轮播图这类文件资源如果直接用本地磁盘存储会有两个麻烦服务器重启或迁移时文件容易丢小程序正式环境要求图片域名必须是HTTPS且配置在合法域名中本地磁盘的访问方式很难满足这个要求。所以我用MinIO搭了一个免费轻量的对象存储服务。MinIO通过Docker一条命令就能启动docker run -p 9000:9000 -p 9001:9001 \ -e MINIO_ROOT_USERadmin \ -e MINIO_ROOT_PASSWORDadmin123456 \ -v /data/minio:/data \ minio/minio server /data --console-address :9001端口9000是API服务9001是管理控制台。服务跑起来后创建bucket并设置下载策略为只读公开把桶名设为“tour-ticket”然后在SpringBoot里配置MinIO客户端上传文件返回可访问的URL给前端。// MinIO配置 Configuration public class MinioConfig { Bean public MinioClient minioClient() { return MinioClient.builder() .endpoint(http://localhost:9000) .credentials(admin, admin123456) .build(); } }上传文件后把URL存到景区表或门票表的image字段里。这里有个提示MinIO的文件访问URL将来对外提供服务时最好经过Nginx做一层反向代理把9000端口隐藏起来避免直接把存储服务暴露到公网安全性和规范性都更好。线上部署时同理生产环境文件服务走独立域名加HTTPS小程序图片才能正常展示。4. 前后端联调与上线部署全记录4.1 用Charles抓包小程序接口快速定位前后端问题我调试小程序时最常用的工具是Charles。它能把小程序发出的每个HTTPS请求都截获下来查看URL、请求头、请求体和返回值前后端数据对不上时一眼就能看出问题出在哪边。常规配置流程不复杂电脑上启动Charles后开启SSL代理把手机或开发者工具的代理地址指向电脑的IP和端口8888然后安装并信任Charles的SSL证书。配置完成后小程序里每次请求都能在Charles的会话列表里看到点进去就能看完整的请求报文和响应报文。我带过的学弟常遇到的问题有两类一类是页面报404打开Charles发现请求路径少了“/api”前缀属于前端路径写错或nginx转发规则有问题另一类是接口返回了数据但页面空白打开Charles看响应体发现data字段是null而前端代码里直接取了data.list导致异常。Charles的价值在于把“感觉哪不对”变成“确凿是哪不对”这是联调效率的分水岭。它本身就是常规网络调试工具抓自己的小程序包排查问题完全够用。4.2 联调期高频异常定位手册我把前后端联调中经常踩到的异常整理成了一张排查表遇到问题直接对着查效率最高现象可能原因解决方式请求一直转圈不返回域名未配置在小程序合法域名中开发者工具勾选“不校验合法域名”正式环境配置request合法域名返回401Token缺失或过期检查请求头Authorizationwx.login重新登录换取Token返回500后端代码异常查看后端日志定位异常堆栈注意空指针和参数类型转换错误列表数据重复分页参数没传到后端检查pageIndex是否正确拼接下拉刷新时pageIndex是否重置为1中文乱码字符编码不统一数据库连接串加characterEncodingutf-8前端请求头声明Content-Type为application/json;charsetUTF-8订单重复创建前端没有防重复提交提交按钮加loading状态后端按用户ID加分布式锁库存一直没恢复Redis和MySQL数据不一致检查预扣释放定时任务是否开启检查订单取消是否执行了INCR恢复联调过程的另一个重要建议是在接口层面统一了时间格式。后端返回的日期时间格式定义为“yyyy-MM-dd HH:mm:ss”字符串前端不需要再处理时区偏移。这个约定看起来小但能避免大量“时间显示差了8小时”的奇怪问题——不要问我为什么强调这个都是血泪教训。4.3 上线部署从SpringBoot Jar包到HTTPS小程序一个能正常上线的小程序服务端必须使用HTTPS域名这是微信平台的硬性要求。完整链路是小程序发出的请求到Nginx的443端口Nginx终结SSL加密然后把请求转发到后端应用的8080端口。Nginx核心配置片段server { listen 443 ssl; server_name api.example.com; ssl_certificate /etc/nginx/ssl/example.pem; ssl_certificate_key /etc/nginx/ssl/example.key; location /api/ { proxy_pass http://127.0.0.1:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }后端应用打包成Jar后放到服务器上用nohup启动nohup java -Xms512m -Xmx1024m -jar tourist-ticket.jar --spring.profiles.activeprod app.log 21 上线前还必须在小程序后台配置request合法域名把接口域名、图片域名都加进去。另外提一个容易被忽略的点安全组规则、防火墙端口、Redis端口都不要暴露到公网只开放80、443和SSH端口服务器安全配置这块基本是毕设项目的盲区但写上绝对加分。5. 毕设文档与答辩的加分细节5.1 论文结构怎么搭从绪论到测试的写作重点毕设论文和开发代码同样重要甚至在某些导师眼里更看重论文。我用的是最稳妥的六章结构绪论、相关技术介绍、需求分析、系统设计、系统实现、系统测试。绪论部分重点写研究背景和意义逻辑是“旅游数字化是大趋势、传统购票方式存在排队耗时、信息不透明、高峰期管理难等痛点因此开发一套基于微信小程序的实名购票系统具有现实意义”。相关技术介绍不需要写太深每个技术写清楚“是什么、为什么选它、在本项目中承担什么角色”即可。需求分析部分要画出用例图游客用例包括注册登录、浏览景区、购买门票、查看订单管理员用例包括景区管理、票务管理、订单管理。系统设计部分重点给E-R图和数据库表设计说明这是答辩时评委最常翻看的部分。系统实现部分按模块写每个功能配上核心代码和截图。系统测试部分要有测试用例表测试编号、测试项、操作步骤、预期结果、实际结果、是否通过添上几列真实执行的数据比空泛写“系统测试通过”有说服力得多。整套文案里还要包含字数不少于3000字的绪论、不少于2000字的需求分析、完整的功能清单和测试报告等这些内容环环相扣不能等到代码写完再临时编我习惯每完成一个模块就顺手截图、记录过程最后汇总时素材都是现成的。5.2 答辩高频问题与示范答法答辩时评委问的往往不是具体代码而是系统设计的决策理由。我把被问到最多的5个问题和对应的思路整理出来。为什么用SpringBoot而不是SSM回答思路SpringBoot简化了大量配置内置Tomcat自动装配能力强便于快速开发和维护和SpringMVC一脉相承适合轻量级微服务的快速搭建。如何防止超卖回答思路先说清问题再给方案。前端限制购买数量后端用Redis DECR预扣库存下单时校验数据库层用条件更新兜底扣减库存时加stock quantity条件受影响行数为0则回滚。微信支付流程怎么实现的回答思路前端wx.requestPayment拉起支付后端统一下单并签名微信服务器异步回调通知支付结果后端更新订单状态前端在onShow里查询最新状态并刷新页面。Redis在项目中除了库存还用来做什么回答思路Token会话缓存、热点数据缓存景区列表、接口频控限流、订单预扣库存的过期自动释放。能答出多个使用场景评委就会认为你真正理解了Redis。项目有什么创新点回答思路一个是有小程序端完整的购票闭环另一个是库存分日期管理支持预售模式再加一个接口防爬体系包括Token鉴权、签名校验、频控限流三层防护。这些都是实打实的功能点不是空话。6. 踩坑记录与后续扩展方向6.1 我踩过的几个比较隐蔽的坑第一个坑是微信支付回调延迟造成的数据不同步。用户付款成功后回调通知偶尔会延迟几秒甚至十几秒期间用户在小程序里看到的订单状态还是“待支付”会非常慌张地来找我。解决方式是前端支付成功后先展示“支付成功正在确认订单状态”的过渡提示同时用onShow主动刷新一次订单状态另外再配合定时器轮询两到三次作为兜底。把“主动查询”和“被动回调”双通道打通后这个问题基本消失。第二个坑是MinIO上传大图时内存飙高。默认的putObject方法会把整个文件流加载到内存景区上传一张5MB的实拍图JVM堆内存就紧张一下。后来改用putObject的InputStream参数配合流式上传限制上传文件大小不超过10MB内存占用大幅下降。通用的做法是用MultipartFile.getInputStream把文件流转成输入流再交给MinIO不要直接用bytes数组。第三个坑是订单取消定时任务没生效。我一直以为用了Scheduled就能自动释放超时未支付的预扣库存但本地测试时发现库存一直不恢复。排查半天发现SpringBoot的定时任务默认是单线程串行执行当任务耗时过长或异常时后续任务会被阻塞。解决方式是Scheduled配置线程池同时给定时任务加try-catch和异常日志。这个坑不遇到一次真的很难想到是线程模型的问题。第四个坑是自定义导航栏在Android上点击区域偏移。iOS和Android对导航栏点击区域的渲染逻辑不同Android上如果只给标题文本设置点击事件而不包裹整个导航栏容器点击空白区域会没有反应。把所有导航栏内的图标和标题都放进同一个view容器点击事件挂在容器上兼容性就正常了。6.2 如果时间充裕这几个方向值得扩展基础的“景区门票售卖”功能完成后如果时间还够可以按这几个方向做扩展每一个都能继续撑起一轮答辩亮点。数据可视化大屏是最推荐的扩展。把订单数据按日期维度汇总后用ECharts画出近7天销售额趋势、热门景区Top5、票型销量占比饼图、实时订单滚动列表。管理端大屏直观展示经营数据比单纯列订单表格高级太多。这个方向贴合“数据可视化”的技术关键词而且实现难度不高就是用SQL做聚合统计加一个图表组件。拼团和秒杀是第二个方向。景区门票很适合做限时特惠和多人拼团技术上无非是引入Redis的分布式锁和消息队列但业务完整度和趣味性都会上一个台阶。要注意的是秒杀场景需要提前把库存预热到缓存中并做好超时释放和异常恢复这部分逻辑写清楚又是一个答辩大亮点。多景区联票和年卡次卡是第三个方向。联票就是几个景区打包出售技术上要在订单明细里增加子项支持价格计算换成套餐模型。年卡属于次卡类型需要设计次数扣减逻辑和使用记录表。这两个扩展都能展示你对业务复杂度的处理能力。我个人的体会是做这种全栈项目不要追求新潮花哨的技术堆叠而是把一个核心业务链条浏览、下单、支付、核销做扎实、把异常边界想清楚答辩时能把自己写的每一行代码背后的为什么说透就已经超过大多数人了。尤其是那些隐蔽的坑和对应的解决方案是你最宝贵的答辩素材也是这篇分享里最想让你带走的东西。
返回列表