☰
Spring Boot+微信小程序:二手商品拍卖平台设计与实现
2026/10/15 6:25:14 网站建设 项目流程

1. 项目选题与整体设计思路

1.1 这个题目为什么值得做

但凡经历过计算机毕业设计选题的人都知道,最头疼的不是写代码,而是挑一个"看起来不难、做起来有料、答辩能讲清楚"的题目。二手商品拍卖平台这个方向,其实踩中了好几个关键点。

先说需求侧。闲鱼、转转这些平台把二手交易这个概念已经普及得很透了,每个评委老师都听得懂你在做什么,不需要你费半天口舌解释业务背景。这说明选题的"沟通成本"很低,答辩的时候你只需要讲清楚技术实现,而不需要花时间给老师科普业务逻辑。

再从供给侧看。微信小程序现在是毕业生做毕设的一个"安全牌",因为它用户端不需要安装App,扫码即用,演示的时候非常方便。而Spring Boot作为后端框架,生态成熟、资料多、上手快,属于那种"你哪怕没精通,也能把项目跑起来"的稳妥选择。

但我要说的是,这个题目真正有价值的地方在于"拍卖"这两个字。普通的二手交易平台,核心就是增删改查加一个支付,太单薄了。而拍卖引入了一个"竞拍出价"的业务规则,这意味着你需要处理出价递增、拍卖倒计时、最高价记录、拍卖状态流转这些事情。有业务规则,就意味着有逻辑可讲,有细节可挖,这种项目在答辩时最容易出彩。

1.2 整体方案选型背后的取舍

我见过很多学生拿到这个题目后的第一反应是:用Spring Boot + MyBatis Plus + 微信小程序 + 微信支付,一顿操作猛如虎。但这个组合其实有几个坑需要提前想清楚。

首先是"拍卖"的核心逻辑放在哪里实现。有一种偷懒的做法是把出价逻辑用简单的时间判断来搞定:谁出价高、谁出价早,谁就赢。但这个方案在真实业务中是有问题的,因为拍卖通常有一个"截拍时间",在截拍时间之前出价有效,之后出价无效甚至要自动延时。

我个人的建议是,不要一开始就奔着"完美还原闲鱼拍卖"去,而是把拍卖规则简化成一套清晰的状态机。商品有几种状态:待开始、竞拍中、已截拍、已成交、已流拍。用户的每一次出价动作,都触发服务端去校验当前商品状态、出价金额是否高于当前最高价、是否在有效竞拍时间内。这一整套逻辑,其实就是一个状态机的流转,想明白这一层,你的代码结构就清晰了。

然后是"实时性"怎么处理。很多同学一看到"拍卖"就觉得要用WebSocket做实时推送,每秒钟把最新价格推给所有在线用户。这个想法没有错,但你要考虑自己的工作量和答辩的可解释性。微信小程序的WebSocket支持其实还行,但服务端如果引入WebSocket,你还得处理连接管理、心跳维持、消息广播这些事情,复杂度一下就上来了。

我做了好几个类似的毕设项目之后,一个更务实的技术方案是:小程序端定时轮询。也就是用户进入商品详情页之后,小程序每隔5秒或10秒调一次接口,拉取当前最高出价和剩余时间。这个方案在毕设这个量级下完全够用,代码简单、逻辑容易讲清楚,而且不容易出bug。

注意:如果答辩老师追问"为什么不用WebSocket",你可以回答:考虑到毕设项目在校园网环境下的并发量有限,且微信小程序对WebSocket的连接数有限制,采用短轮询在不影响用户体验的前提下,大幅降低了服务端资源消耗和实现复杂度。这个回答其实是非常标准的。

1.3 功能模块的边界划定

做毕设最忌讳的是功能堆砌。你列了十几个模块,每个都做得稀烂,不如扎扎实实做透五六个核心模块。

基于"二手商品拍卖"这个核心定位,我把功能边界划定为:

  • 用户模块:微信登录、个人信息维护、收货地址管理
  • 商品模块:商品发布(带图片)、商品分类、商品列表、商品详情
  • 拍卖模块:出价竞拍、最高价展示、拍卖状态流转、截拍处理
  • 订单模块:拍卖成交后生成订单、订单状态管理
  • 管理后台:用户管理、商品审核、拍卖记录查看

你看,这个边界划分有几个好处。第一,每个模块都有明确的存在理由,没有任何一个是凑数的。第二,模块之间耦合度适中,比如拍卖结束后生成订单,这就是一个很自然的业务串联。第三,所有功能加起来正好是一个完整的闭环,从商品上架到拍卖成交再到订单确认,用户在一个流程里就能走完。

我特别想说的是,不要一上来就做积分系统、收藏系统、分享裂变、优惠券…… 这些功能单独看都不难,但堆在一起会无限拉长你的开发周期。毕设的核心评价标准,永远是"你把你承诺的东西做出来了",而不是"你画了一个多大的饼"。

2. 数据库设计与会话状态管理

2.1 核心数据表的设计思路

数据表是整个项目的基石,表结构设计得合理,后面写代码就是水到渠成;表结构设计得有坑,后面每一行SQL都是在为自己当初的偷懒还债。

我先说说最核心的几张表。

用户表(user)是基础表,字段主要是微信用户的openid、昵称、头像、手机号、注册时间。这里有一个关键点:微信小程序登录拿到的openid,是用户在某个小程序下的唯一标识。也就是说,同一个微信用户在你这个小程序里和在别人家的小程序里,openid是不同的。所以在表设计时,openid一定要加唯一索引,这是后续登录逻辑能正确运行的前提。

商品表(product)字段比较多,商品标题、描述、图片、分类、起拍价、加价幅度、拍卖开始时间、拍卖结束时间、当前最高价、当前最高出价用户ID、状态、卖家ID。这里我想强调一个容易被忽略的字段:加价幅度。有了这个字段,后端才能校验用户每次出价是不是符合规则,而不是用户随便报个价就能往上加。

拍卖记录表(auction_record)是拍卖模块的灵魂。它记录了每一次出价的完整信息:商品ID、出价用户ID、出价金额、出价时间。为什么一定要单独建一张表?因为你可以通过这张表做几件重要的事情:查看竞拍历史、校验出价是否合法、处理竞价纠纷。比如用户说"我明明出过价",你直接把这张表的数据拉出来,一目了然。

订单表(order)则是在拍卖成交之后生成的,字段包括商品ID、买家ID、卖家ID、成交价格、订单状态、创建时间、支付时间。订单状态可以简单划分为待支付、已支付、已发货、已签收、已完成、已取消。

2.2 字段类型与索引的个人建议

很多同学在字段类型上很随意,比如价格用DOUBLE,时间用VARCHAR存字符串。这些习惯在初学阶段不算致命,但在一个正经项目里会让你吃尽苦头。

价格字段我建议一律用DECIMAL(10,2),比如DECIMAL(10,2)刚好可以存最大九位数的金额,保留两位小数。为什么要这么较真?因为DOUBLE是浮点数,存在精度误差。你在本地测试的时候感觉不到,但一旦涉及支付退款、对账这些操作,一分钱的误差都够你排查半天的。与之配套的一个小技巧是,所有价格相关的运算都放在服务端用BigDecimal做,前端只负责展示。

时间字段用DATETIME就好,不要用VARCHAR。DATETIME的好处是你可以在SQL里直接做时间比较,比如"查询所有拍卖结束时间小于当前时间的商品",一句WHERE end_time < NOW()就搞定了。如果你用VARCHAR存时间,这种查询就退化成字符串比较,一旦格式不统一就容易出错。

索引方面,我建议在拍卖记录表的product_id上加普通索引,因为每次查询某个商品的出价记录,都是按照商品来过滤的。在订单表的buyer_id和seller_id上也各加一个普通索引,方便用户查看自己买到的和卖出的商品。需要注意,索引不是越多越好,毕设这个量级,每张表两三个索引就顶天了,加太多反而会拖慢写入速度。

2.3 会话保持与登录态管理

微信小程序的登录机制和传统的Web登录有一个很大的区别:小程序端没有一个"浏览器",所以你没法用Session + Cookie那一套传统玩法。

标准的做法是:小程序端调用微信的登录接口拿到一个临时凭证code,把这个code发给你的后端,后端再拿这个code去微信服务器换openid和session_key。换到openid之后,你在本地数据库里查一下有没有这个用户,没有就自动注册一个,然后签发一个自定义的登录凭证返回给小程序端。

这个自定义凭证我建议用JWT(JSON Web Token)。JWT的好处是无状态,后端不需要存session,只需要在签发时设置一个过期时间,之后每次请求只要带上这个token,后端验签通过就认为身份有效。

提示:你在写登录逻辑的时候,要注意把"换openid"这一步做异常处理。微信服务器偶尔会有短暂的网络抖动,如果没做异常处理,用户可能莫名其妙就登录失败了,而且报错信息还不友好。我当时就在这个坑里栽过,后来在换openid的外面包了一层try-catch,失败时提示用户重新授权,问题就解决了。

3. 核心功能模块的实现细节

3.1 发布商品与图片上传

商品发布功能是用户侧的主入口,流程是:用户在小程序端填写商品信息,选择分类,上传图片,点击发布。后端收到请求后,先校验数据合法性,再把商品插入数据库,状态设为"待开始"。

图片上传这里有个点要注意:微信小程序的wx.chooseImage拿到的是一张临时文件路径,你需要用wx.uploadFile接口把这张图片以文件流的形式传到后端,后端再把它保存到服务器的磁盘目录里。保存之后,后端要返回一个可访问的URL给小程序端,小程序端在展示商品图片的时候,直接使用这个URL。

这里有一个很常见的坑:小程序的wx.uploadFile请求头是固定的Content-Type: multipart/form-data,如果你后端用Spring Boot,接口参数用的是MultipartFile,那你请求时name属性必须和后端参数名对齐。比如后端是public Result upload(@RequestParam("file") MultipartFile file),小程序端的name就要传file,否则后端点不到文件,直接报400。

还有一点,上传目录要放在服务器上可写的位置,并且建议在Spring Boot配置里设置一个静态资源映射,把/upload/**映射到实际的磁盘目录。这样图片才能通过URL直接访问到。

3.2 出价竞拍的核心逻辑

出价竞拍是整个项目的技术核心,也是答辩时最能展示你逻辑能力的一段代码。我来仔细拆解一下这个逻辑。

当用户点下"出价"按钮,小程序端把productId和bidPrice两个参数传给后端。后端要做的事情按顺序排列如下:

第一步,校验商品是否存在、状态是否为"竞拍中"。如果商品是"待开始"或"已截拍",直接拒绝出价,返回友好提示。

第二步,校验出价金额是否达到起拍价。如果商品还没有任何出价记录,那本次出价金额必须大于等于起拍价;如果已经有人出过价,那本次出价金额必须大于当前最高价加上加价幅度的结果。

第三步,校验拍卖时间。如果当前时间已经超过了商品的拍卖结束时间,则拒绝出价。

第四步,更新商品表的当前最高价和最高出价用户ID,同时在拍卖记录表插入一条新的出价记录。

第五步,返回最新的最高价给到小程序端,小程序端刷新页面显示。

这个逻辑看起来不复杂,但有几个细节一定要处理好。比如"校验出价金额"这一步,你要注意当前最高价是在商品表里冗余的字段,它和拍卖记录表里的最高记录是两条独立的数据。为了避免并发出价时数据不一致,建议在更新商品表的SQL里加上一个条件:WHERE current_max_price = 上一个最高价,如果更新影响行数为0,说明在你操作期间有人改了价格,这次出价就作废,让用户重试。

这个方案用到了乐观锁的思想,虽然不完美,但在毕设这个量级下,它既简单又足够可靠。

3.3 拍卖倒计时与截拍处理

拍卖的倒计时是一个典型的"展示逻辑"和"业务逻辑"分离的问题。

在小程序端,你当然可以用JavaScript写一个简单的setInterval,每秒减一秒,展示给用户看。但你要想清楚,前端倒计时只是一个视觉效果,真正的裁判是后端时间。

举个例子:用户A看到倒计时还剩10秒,于是出了个价。但这个出价请求到达后端之后,后端发现商品的实际拍卖结束时间已经过了3秒,那这次出价就是无效的。这就是前后端时间不一致导致的典型问题。

所以,我建议的架构是:前端负责"展示"倒计时,每秒从本地剩余秒数减一;后端负责"裁决"时间,每次出价、查询详情时都以服务器的当前时间为准。前端展示到0之后,再调一次详情接口,看看商品状态是不是已经变为"已截拍"。

至于截拍处理,有两种方式可以实现。第一种是懒处理:当用户查询商品详情时,后端顺带检查一下,如果商品状态还是"竞拍中"但结束时间已经过了,就把状态改为"已截拍",再判断存在最高出价就标记为"待支付",不存在就是"已流拍"。第二种是定时任务:用一个Spring的@Scheduled注解,每分钟扫描一次所有竞拍中的商品,把已经过期的商品批量更新状态。

我个人的建议是懒处理为主、定时任务兜底。因为懒处理可以保证用户在访问到商品时立刻得到最新状态,体验最好;定时任务兜底则是为了防止某些商品永远没被访问,导致状态一直停留在"竞拍中"。两个方案加起来,代码量不多,但逻辑上非常完备。

3.4 拍卖成交后如何生成订单

拍卖结束之后,最高出价用户就自动成了买家。但这个"生成订单"的时机,一定要想清楚。

我见过有同学是这么做的:在截拍处理的逻辑里,检测到有最高出价就直接插入一条订单记录。这样做当然也行,但有一个问题:万一最高出价用户后悔了,不想买了呢?你就需要额外做"取消订单"和"重新拍给第二高者"的逻辑,这复杂度就上来了。

一个更合理的方案是:截拍之后,商品状态进入"待支付",但订单先不生成。买家在商品详情页看到"你已拍得此商品,请在24小时内支付"的提示,点击"去支付"按钮时,后端才创建订单。这种做法的好处是,订单的生成是由买家主动触发的,买家不想要了可以直接不点,后端只需要在超过24小时后把商品状态改回流拍即可。

当然,为了让用户明确感知到这个流程,前端需要在小程序里做一个清晰的待支付入口,比如增加一个"我的拍卖"页面,列表展示用户参与竞拍且胜出的商品,每条都带一个"去支付"按钮。

顺便说一句,如果答辩老师问你"买家不支付怎么办",你可以说毕设里把超时时间设为24小时,超过时间未支付,系统自动取消订单并将商品状态置为流拍,后续可以扩展为"顺延给第二高出价者"。

4. 后端工程结构与关键代码解析

4.1 工程目录结构怎么组织才不乱

Spring Boot项目的工程结构,直接反映了你的代码组织能力。我推荐的做法是:按业务模块分包,而不是按技术分层分包。很多教科书喜欢把项目分成controller、service、mapper、entity四层,但这样做的后果是,一旦业务多了,每个包下面的类会变得越来越不好找。

我更推荐"包内再分层"的结构。具体来说,顶层包名比如com.example.auction,下面按模块建子包:user、product、auction、order、common。每个业务子包里面再按照controller、service、entity、mapper来细分。

这样划分的好处是,当你要改拍卖相关的代码时,你只需要打开auction这个包,所有相关的controller、service、mapper都在一起,不会翻遍整个项目去找类。

4.2 出价接口的代码实现演示

我这里用一段简化代码来演示出价接口的核心逻辑,帮大家把前面说的流程落到代码层面。

@PostMapping("/bid") public Result bid(@RequestBody BidRequestDTO dto) { // 1. 查询商品 Product product = productMapper.selectById(dto.getProductId()); if (product == null) { return Result.error("商品不存在"); } // 2. 校验商品状态 if (!"ON_SALE".equals(product.getStatus())) { return Result.error("该商品当前不可出价"); } // 3. 校验出价金额 BigDecimal currentMaxPrice = product.getCurrentMaxPrice(); BigDecimal stepPrice = product.getStepPrice(); if (dto.getBidPrice().compareTo(currentMaxPrice.add(stepPrice)) < 0) { return Result.error("出价金额不足,至少为当前最高价加价幅度:" + stepPrice); } // 4. 校验时间 if (System.currentTimeMillis() > product.getEndTime().getTime()) { return Result.error("拍卖已结束"); } // 5. 乐观锁更新商品表 int updated = productMapper.updateMaxPrice(product.getId(), dto.getBidPrice(), dto.getUserId(), product.getCurrentMaxPrice()); if (updated == 0) { return Result.error("出价失败,请重试"); } // 6. 插入拍卖记录 AuctionRecord record = new AuctionRecord(); record.setProductId(product.getId()); record.setUserId(dto.getUserId()); record.setBidPrice(dto.getBidPrice()); record.setCreateTime(new Date()); auctionRecordMapper.insert(record); // 7. 返回最新状态 return Result.success(productMapper.selectById(product.getId())); }

你看,这个接口的逻辑是线性的,每一步都很清楚,答辩的时候照着讲就行。要注意的是,第5步使用了乐观锁更新,这是整个接口最关键的细节,也是体现你工程能力的地方。

4.3 时间字段与状态字段的枚举设计

状态字段的设计,我强烈建议不要用魔法值(字符串或数字散落在代码各处),而是用枚举或者常量类统一管理。

比如商品状态,我定义这样的枚举:

public enum ProductStatus { WAIT_START("待开始", 0), ON_SALE("竞拍中", 1), FINISHED("已截拍", 2), SOLD("已成交", 3), FAILED("已流拍", 4); private String desc; private Integer code; }

使用枚举后,你在代码里到处写product.getStatus().equals(ProductStatus.ON_SALE.getCode())这种逻辑,可读性就非常好了。数据库里存的是整型code,展示的时候转成枚举描述,可以省去很多不必要的if-else。

4.4 定时任务的简单实现

前面提到的"定时任务兜底"截拍处理,其实用Spring的@Scheduled注解几行代码就搞定了。

启动类上加上@EnableScheduling注解,然后单独写一个定时任务类:

@Component public class AuctionTask { @Resource private ProductMapper productMapper; @Scheduled(fixedDelay = 60000) public void checkExpired() { // 查询所有竞拍中且结束时间小于当前时间的商品 List<Product> expiredList = productMapper.selectExpiredOnSaleList(); for (Product product : expiredList) { // 有最高价 -> 待支付; 无最高价 -> 流拍 if (product.getCurrentMaxPrice() != null) { productMapper.updateStatus(product.getId(), 2); } else { productMapper.updateStatus(product.getId(), 4); } } } }

这段代码每分钟跑一次,逻辑非常清晰。这里有一个经验教训:定时任务里批量操作数据库时,最好先查出来再逐条更新,不要直接写一条UPDATE ... WHERE end_time < NOW()。原因在于,毕设的数据库表不一定很大,直接写批量update效率很高,但这样你就失去了对每条商品状态的精细控制,比如某些商品可能因为特殊原因需要跳过状态更新。代码写清楚一点,后期扩展也方便。

5. 微信小程序端的页面与接口设计

5.1 小程序端的页面架构

微信小程序端的页面,我建议按Tab栏分成四个主要页面:

  • 首页:展示拍卖商品列表,支持按分类筛选和关键词搜索
  • 发布:发布新商品(核心功能页)
  • 消息:展示与拍卖相关的通知,比如出价被超、商品成交等
  • 我的:个人中心,展示用户发布的商品、参与拍卖的记录、订单列表

首页的商品列表,推荐使用wx:for循环渲染卡片列表。每个卡片展示商品封面图、当前价格、剩余时间、加价幅度等关键信息。剩余时间这个字段,建议在列表接口里就计算好,而不是返回结束时间戳让前端算。因为省去前端时间戳转换的代码,也可以避免用户本地时间不准的问题。

发布页面,需要用到wx.chooseImage选择图片,wx.uploadFile上传图片,wx.request提交商品表单。这三步是递进关系,你先拿到图片URL,再把包含图片URL的商品表单提交给后端。这里有个小技巧:上传图片和提交表单可以异步并行,即先上传图片拿到URL,再提交表单,体验上好很多。

5.2 接口层的参数设计与统一封装

小程序端请求后端接口,我建议做统一封装。小程序端写一个request.js工具文件,封装wx.request:

function request(url, method, data) { return new Promise((resolve, reject) => { wx.request({ url: baseUrl + url, method: method, data: data, header: { 'Content-Type': 'application/json', 'token': wx.getStorageSync('token') }, success: (res) => { if (res.data.code === 200) { resolve(res.data.data); } else { reject(res.data.msg); } }, fail: (err) => { reject('网络错误'); } }); }); }

这段封装看似简单,但解决了几个非常实际的痛点:统一携带token、统一处理业务错误、将返回的Promise化。之后在每个页面里调用,比如查询首页列表,只需要request('/api/product/list', 'GET', {}),代码非常清爽。

5.3 小程序端轮询机制的实现

前面提到用轮询来实现最新价格的更新。在小程序里,轮询可以用setInterval实现,但有一个明显的坑:不要在页面onHide之后还继续轮询。

我早期的写法是把轮询逻辑写在onLoad里,结果用户退出页面后,定时器还在跑,白白浪费流量和电量。后来改正的做法是:

在onShow里启动轮询,在onHide里清掉定时器。同时,在商品详情页里,把轮询间隔设为8秒一次,实测下来在校园网络环境下体验完全OK。

onShow() { this.startPolling(); }, onHide() { this.stopPolling(); }, startPolling() { this.timer = setInterval(() => { this.loadProductDetail(); }, 8000); }, stopPolling() { if (this.timer) { clearInterval(this.timer); this.timer = null; } }

注意,loadProductDetail里要做防抖处理。如果上次请求还没回来,就不要再发新请求了,否则接口会被打爆。可以用一个isLoading标志位控制。

5.4 支付功能的简化实现

微信小程序里的支付,正规流程是调用wx.requestPayment发起支付。但这个接口需要你具备微信商户号资质,而且后端要和微信支付服务器做签名交互,整个过程挺繁琐。

考虑到毕设的性质,我建议做一个"模拟支付"功能:点击"去支付"按钮后,弹出一个确认弹窗,用户点确认,后端直接把订单状态更新为"已支付",模拟支付成功。在代码里,这个模拟支付是闭包的,方便之后替换成真实的微信支付。

注意:答辩时可能会被问到"你这里为什么不做真实支付",标准的回答是:因为微信支付申请商户号需要企业资质,个人主体无法申请,因此本项目使用模拟支付来演示完整的业务流程。如果后续需要上线商用,只需替换支付模块即可。这个回答既诚实又合理。

6. 部署上线与常见问题排查

6.1 本地开发的调试配置

本地开发时,小程序端有一个麻烦的问题:微信开发者工具里,wx.request请求的URL必须是HTTPS的,或者你需要在开发者工具里勾选"不校验合法域名"。如果不勾选,本地请求http://localhost:8080会被拦截。

我建议的做法是,在开发阶段就勾选"不校验合法域名",本地后端起在8080端口,小程序端的baseUrl填http://localhost:8080。等到需要真机预览时,再把后端部署到一台服务器的公网IP上,baseUrl改成http://服务器IP:8080。

这里有一个必须提前说清楚的问题:微信小程序正式发布时,要求所有请求域名必须是HTTPS且完成ICP备案。但毕业设计阶段,用开发者工具的"不校验合法域名"功能就可以完美演示,不需要真去备案。

6.2 服务器部署的若干细节

如果你需要把项目部署到服务器上演示,我给一个稳妥的步骤清单:

  1. 在后端项目的application.yml里,把数据库连接地址改成服务器上的MySQL地址
  2. 上传图片的目录,配置一个绝对路径,比如/home/ubuntu/auction/upload/
  3. 用mvn clean package打包成jar包
  4. 服务器上用nohup java -jar auction-0.0.1.jar &方式后台启动
  5. 在服务器安全组里放行8080端口
  6. 小程序端的baseUrl改成服务器公网IP

这个过程看起来不复杂,但我在实际部署中踩过几个坑。最典型的是上传的图片URL写死为localhost。我一开始在本地测试时,上传图片的URL是http://localhost:8080/upload/xxx.jpg,结果部署到服务器上后,小程序访问这个URL就会指向用户自己的手机,肯定打不开。

解决办法是:后端在上传接口里,返回图片访问URL时,动态拼接request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort(),也就是从当前请求里取域名和端口。这样本地和服务器都能返回正确的访问地址。

6.3 典型问题Top5与排查方法

我把这个项目里最容易遇到的问题整理成一张排查表,各位可以直接对照着查。

问题现象可能原因排查方向
小程序请求后端接口报404接口路径写错或未加/api前缀先看后端控制台日志,确认请求是否到达
图片上传成功但网页打不开静态资源映射未配置检查Spring Boot的addResourceHandlers配置
出价后页面价格没刷新轮询未开启或被onHide清掉检查页面是否进入了onHide状态
用户登录后刷新就失效JWT过期时间设置太短检查token有效期,建议后端设置7天
拍卖结束后商品状态不变懒处理未触发且定时任务未配置检查@Scheduled注解和启动类的@EnableScheduling

有一个问题我要单独拎出来讲:很多同学在小程序端测试时,发现wx.requestPayment根本弹不出来,其实是模拟支付那段代码的返回格式和后端不一致。建议你在后端模拟支付的返回值里,保留code=200和data=null的统一结构,前端拿到code=200就直接跳转订单详情页。

6.4 答辩时的功能演示动线

最后分享一个答辩演示的建议。演示时不要东点一下、西点一下,最好按一条完整的业务主线走:

  1. 进入小程序首页,展示商品拍卖列表
  2. 点进一个正在竞拍的商品,展示当前价格和倒计时
  3. 演示一次出价,刷新展示最新的最高价
  4. 切换账号(可以用两个微信账号或模拟数据)出价,展示竞价过程
  5. 等拍卖结束后,展示成交订单的生成
  6. 进入管理后台,展示商品审核和拍卖记录

这条动线走下来,整个项目的核心功能就全部覆盖了。比你零散地展示"登录功能""发布功能""列表功能"要有说服力得多。

7. 我的几点个人体会

做这个项目最大的体会是:技术难点其实不多,真正的难点反而是"把业务逻辑理清楚然后用代码表达出来"。

一开始我其实走了弯路,上来就想着把WebSocket做了、把真实的微信支付接了、把消息队列加上了。后来发现,这些功能每加一个都要花好几天调试,而且对毕业设计这个场景来说,边际收益并不高。反而是在把出价逻辑、状态流转、订单生成这些核心业务做得滴水不漏之后,整个项目的完成度迅速就上来了。

如果你做的是类似的毕设项目,我真心建议你先把核心闭环打通,再考虑锦上添花。功能做少一点不可怕,可怕的是每个功能都是半成品。

另一个想说的是代码规范。答辩老师也许不会逐行读你的代码,但当你展示项目结构的时候,一个分包清晰、命名规范的项目和一个全是一坨坨test1、test2类名的项目,给人的印象是截然不同的。哪怕功能一模一样,代码规范好的项目在评分上一定占优势。

最后,希望这篇内容能帮到你。如果做项目的过程中有什么具体问题,欢迎留言交流,我看到都会回复。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询