资讯动态

智慧乡村旅游小程序毕业设计:Spring Boot+MySQL+微信小程序全栈实践

发布时间:2026/10/27 6:35:47 来源:尧图企业网站定制
简介一份面向高校毕业设计/课程设计的微信小程序Java智慧乡村旅游服务平台源码完整覆盖后台管理、小程序端与数据库设计。系统内置管理员、用户、商家三个角色管理员可维护景点、路线、类型、订单与系统配置用户在小程序端完成旅游景点浏览、路线查看、收藏、充值、购物车与订单操作商家负责景点信息维护和订单处理。压缩包共1178个文件、仅17.01MB以Java、Vue及JS等前后端源码、wxml/wxss小程序页面、png/svg界面素材以及sql数据库脚本为主体目录按角色与功能模块划分方便快速定位与检索。已吸引86人浏览学习适合作为毕业设计选题、课程设计样例或二次开发蓝本。资源内含完整前后端源码、SQL数据库文件、环境配置说明及一键构建部署脚本可基于JDK1.8、MySQL5.7、Tomcat7等条件快速运行帮助掌握小程序与Java后端联调的项目全流程。1. 智慧乡村旅游小程序毕业设计这套源码到底能做什么值不值得你上手做毕设拿到“智慧乡村旅游服务平台”这套源码时我建议你先别急着解压就跑。用微信小程序做游客端、Java 后端做业务接口、MySQL 存全量数据这是当前校园项目里最常见也最稳妥的组合。它的价值在于完整串起“游客浏览景区和线路—登录授权—在线下单—订单管理”这条闭环链路代码结构清晰适合计算机、软件工程专业做毕业设计哪怕是刚起步的文旅团队拿它当原型也比从零写快得多。但初次运行你多半会卡在三件事小程序连不上本地后端、数据库脚本里有字段对不上、LW 文档里的 E-R 图跟实际表结构不一致。下面按落地顺序把这些讲透。2. 项目架构与数据模型Java 后端和小程序端的骨架先立住2.1 前后端分离的必然性为什么小程序端只能走 JSON 接口微信小程序运行在微信的宿主环境里页面由 WXML、WXSS、JS 组成没有服务端渲染 HTML 的能力。做智慧乡村旅游服务平台这种项目常见做法是后端只输出 JSON 数据小程序端负责渲染和交互。这也是为什么源码里 Java 工程通常是 Spring Boot 项目提供 RESTful 风格接口小程序工程是独立的原生微信小程序目录通过 wx.request 发起请求。后端为什么选 Spring Boot 而不是 SSH 或纯 Servlet简单说Spring Boot 内嵌 Tomcat一键启动不用单独配置服务器答辩演示最怕环境搭不起来它的 starter 机制让 MyBatis、Web、文件上传这些依赖很省事。MyBatis 适合需要手工写 SQL 的场景乡村旅游平台的景区列表、多条件筛选、订单统计都离不开 SQL把 SQL 写在 Mapper 文件里比 JPA 自动生成的直观得多。数据库用 MySQL理由更直接多数机器上已经装了 MySQL 5.7 或 8.0环境成本低Navicat 或命令行都能随手建库。接口设计上我一般会用统一的返回结构code0 表示成功msg 存提示信息data 放业务数据。前端所有请求都按这个约定解析后期调试只要盯 code 字段就能定位是后端业务异常还是参数错误。这个约定在第三章和第四章会反复用到先在这里立住。2.2 乡村游核心数据模型用户表、景区表、订单表怎么建才不返工乡村旅游平台的核心不是“商品 SKU”而是“景区 线路套餐 订单”的组合。用户进来先看景区列表点进详情后能看到推荐线路然后下单。基于这个业务链路表结构至少包含五张t_user 用户表字段要有 id、openid、nickname、avatar、phone、create_time。openid 是微信用户的唯一标识一定要加唯一索引不然后端做自动注册时会出现重复用户。t_scenic 景区表字段包括 id、name、summary、cover、images、address、longitude、latitude、price、status。price 可以理解成基础门票价images 存多个图片地址用逗号分隔。t_route 线路套餐表一个景区对应多条线路字段有 id、scenic_id、title、days、price、include_items、cover、detail。线路有自己的价格不能直接引用景区票价include_items 存“交通住宿餐饮”这类套餐说明供详情页图文展示。t_order 订单表这是全项目最容易踩坑的地方。字段要有 id、order_no、user_id、goods_type、goods_id、title_snapshot、price_snapshot、nums、total_amount、status、create_time、pay_time。title_snapshot 和 price_snapshot 是冗余快照字段意思是下单那一刻把商品名称和价格原样存进来。为什么这么做因为后续景区或线路改价订单不受影响否则用户投诉和答辩演示都会尴尬。t_comment 评论表字段包括 id、user_id、scenic_id、content、rating、create_time用于景点详情页展示真实游客评价。总结设计原则凡是下单时需要展示的商品信息都在订单里冗余一份凡是需要统计的金额都用 DECIMAL 类型不用 FLOAT凡是时间都用 DATETIME。表设计返工大多返工在这三个点上。2.3 一键初始化 MySQL建库建表脚本与测试数据拿到源码后数据库通常要自己执行。第一步是先建库建表下面这段 SQL 可以把地基浇好。-- 建库utf8mb4 才能存 emoji游客头像昵称里很常见 CREATE DATABASE IF NOT EXISTS rural_travel DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE rural_travel; -- 用户表 CREATE TABLE t_user ( id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT 主键, openid VARCHAR(64) NOT NULL COMMENT 微信openid, nickname VARCHAR(50) COMMENT 昵称, avatar VARCHAR(255) COMMENT 头像地址, phone VARCHAR(20) COMMENT 手机号可空, create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 注册时间, UNIQUE KEY uk_openid (openid) ) ENGINEInnoDB COMMENT用户表; -- 景区表 CREATE TABLE t_scenic ( id BIGINT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL COMMENT 景区名称, summary VARCHAR(500) COMMENT 简介, cover VARCHAR(255) COMMENT 封面图, images TEXT COMMENT 多图逗号分隔, address VARCHAR(255) COMMENT 地址, longitude DECIMAL(10,6) COMMENT 经度, latitude DECIMAL(10,6) COMMENT 纬度, price DECIMAL(10,2) DEFAULT 0 COMMENT 门票价, status TINYINT DEFAULT 1 COMMENT 1上架 0下架, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB COMMENT景区表; -- 线路套餐表 CREATE TABLE t_route ( id BIGINT AUTO_INCREMENT PRIMARY KEY, scenic_id BIGINT NOT NULL COMMENT 所属景区, title VARCHAR(100) NOT NULL COMMENT 线路标题, days INT DEFAULT 1 COMMENT 天数, price DECIMAL(10,2) DEFAULT 0 COMMENT 套餐价, include_items TEXT COMMENT 包含项目, cover VARCHAR(255) COMMENT 封面, detail TEXT COMMENT 详细介绍, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_scenic (scenic_id) ) ENGINEInnoDB COMMENT线路套餐表; -- 订单表 CREATE TABLE t_order ( id BIGINT AUTO_INCREMENT PRIMARY KEY, order_no VARCHAR(32) NOT NULL COMMENT 订单号, user_id BIGINT NOT NULL COMMENT 用户id, goods_type TINYINT COMMENT 1景区票 2线路套餐, goods_id BIGINT COMMENT 商品id, title_snapshot VARCHAR(100) COMMENT 商品名称快照, price_snapshot DECIMAL(10,2) COMMENT 下单时单价快照, nums INT DEFAULT 1, total_amount DECIMAL(10,2) COMMENT 订单总金额, status TINYINT DEFAULT 0 COMMENT 0待支付 1已支付 2已使用 3已取消, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, pay_time DATETIME COMMENT 支付时间, UNIQUE KEY uk_order_no (order_no), KEY idx_user (user_id) ) ENGINEInnoDB COMMENT订单表; -- 测试数据至少保证一个景区和一条线路演示才不空 INSERT INTO t_scenic (name, summary, cover, price) VALUES (龙泉山生态园, 集果蔬采摘、田园餐饮、亲子研学于一体的综合园区, /upload/cover1.jpg, 49.00); INSERT INTO t_route (scenic_id, title, days, price, include_items) VALUES (1, 龙泉山一日游含餐, 1, 129.00, 往返交通午餐采摘体验);这段 SQL 有四个地方要注意。第一库名写成 rural_travel后端 jdbc 连接串默认也是这个别自己改成带中横线的名字。第二t_order 的 goods_type 用 TINYINT 而不是字符串方便后端做枚举映射也省空间。第三order_no 加唯一索引生成逻辑在后端用时间戳加随机数避免并发重复。第四测试数据别只插景区不插线路否则首页景点详情页点“立即购买”会直接空数据翻车。数据到位后后端一启动前端拉到列表这步就通了。3. 小程序端页面与接口对接从首页轮播到下单支付的完整链路3.1 小程序登录与手机号获取的坑wx.login 与 openid 换取的顺序不能乱打开小程序的第一个动作就是登录。一个容易踩坑的思路是先调用“获取手机号”再去后端注册这在新版接口已经行不通。正确顺序是先 wx.login() 拿到临时 code把 code 发给自己的 Java 后端后端去微信接口换 openid再返回自定义 token 给小程序端。手机号在用户点击授权按钮时另外获取两者分开。小程序端登录逻辑写成这样// pages/login/login.js const app getApp(); Page({ async onLoad() { const token wx.getStorageSync(token); if (token) { wx.switchTab({ url: /pages/index/index }); return; } }, async handleLogin() { // 1. 先取 wx.login 返回的临时凭证 const { code } await wx.login(); // 2. 把 code 交给后端后端换取 openid 并生成 token const res await wx.request({ url: app.globalData.baseUrl /user/login, method: POST, data: { code } }); if (res.data.code 0 res.data.data.token) { wx.setStorageSync(token, res.data.data.token); wx.switchTab({ url: /pages/index/index }); } else { wx.showToast({ title: res.data.msg || 登录失败, icon: none }); } } });逻辑说明wx.login 的 code 有效期很短约 5 分钟拿到就要立刻发给后端绝不能存起来复用。后端如果换 openid 失败常见原因一是 code 重复使用二是小程序 AppID 和后端配置的 AppID 不一致。源码里后端通常有 wechat.appid 和 wechat.secret 配置注意和微信公众平台申请的小程序保持一致。接着是手机号获取。新版小程序要求获取手机号的按钮必须用 open-typegetPhoneNumber并且需要企业主体小程序的权限个人主体没这个能力。毕设项目用个人主体跑真机手机号授权基本会直接失败常见做法是让用户手动输入手机号或者把 phone 当可选字段。别在答辩现场拿着个人主体的小程序演示手机号授权这是必翻车点。3.2 首页轮播、景点列表、乡村路线把请求层封装好才能少返工小程序里多个页面都要请求后端接口我习惯先把 wx.request 封装成 promise 风格的工具函数这样页面里一行 await 就能发起请求。// utils/request.js const request (url, method GET, data {}) { const token wx.getStorageSync(token); return new Promise((resolve, reject) { wx.request({ url: getApp().globalData.baseUrl url, method, data, header: { Authorization: token ? Bearer ${token} : , Content-Type: application/json }, success: (res) { if (res.statusCode 200 res.data.code 0) { resolve(res.data.data); } else { wx.showToast({ title: res.data.msg || 请求失败, icon: none }); reject(res.data); } }, fail: (err) { wx.showToast({ title: 网络异常, icon: none }); reject(err); } }); }); }; module.exports request;封装之后首页拉取景区列表只需要这样写// pages/index/index.js const request require(../../utils/request); Page({ data: { scenics: [], loading: true }, async onLoad() { try { const scenics await request(/scenic/list, GET, { page: 1, size: 10 }); this.setData({ scenics: scenics.list || [] }); } catch (e) { console.error(首页加载失败, e); } finally { this.setData({ loading: false }); } } });页面里再按项目实际需求渲染横幅位和景区卡片。数据里不要指望直接拿到 images 字符串因为它是逗号分隔的路径渲染前要拆成数组。最容易被疏忽的是图片地址后端返回给小程序的是相对路径比如 /upload/cover1.jpg小程序端直接把image的 src 写成它是加载不出来的必须由后端拼好完整路径或者前端在图片地址前面拼接 baseUrl。如果要做顶部导航栏适配不同机型的 statusBarHeight 和胶囊位置也不一样可以用 wx.getSystemInfoSync 拿到状态栏高度再按需给自定义导航栏设置 paddingTop避免内容顶到刘海屏。3.3 订单流程与支付先走模拟支付再谈真实微信支付参数电商类项目绕不开订单。小程序侧的逻辑是“商品详情页选线路 → 确认订单页填份数 → 提交订单 → 模拟支付或拉起微信支付”。订单提交在小程序里通常长这样// pages/order-confirm/order-confirm.js async submitOrder() { const data { goodsType: 2, // 2 表示线路套餐 goodsId: this.data.route.id, nums: this.data.nums }; const order await request(/order/create, POST, data); // 进入支付环节毕设项目基本走模拟支付 await request(/order/pay, POST, { orderNo: order.orderNo, payType: mock }); wx.navigateTo({ url: /pages/order-list/order-list }); }很多毕设源码没有真实微信支付原因不是技术难而是微信支付需要企业资质和商户号个人项目申请不下来。可靠的做法是后端把支付接口做成两个实现一个 mock 支付直接改订单状态为“已支付”一个预留 wxpay 接入位置。答辩时只要说清楚“生产环境可以替换成微信支付 SDK演示环境用模拟支付保证流程完整”评委一般不会为难你。后端收到创建订单请求后要做三件事校验商品是否存在且上架、计算总价、生成唯一的 order_no最后落库。注意在并发提交时同一用户快速点击按钮会产生两笔订单前端按钮置灰之外后端最好也根据订单状态做幂等判断。这个黑匣子如果不处理答辩现场连点两下出现一堆重复订单观感很差。4. Java 后端接口开发Spring Boot 和 MyBatis 把小程序请求接住4.1 Controller-Service-Mapper 三层结构一个景点列表接口的完整落地方案后端工程拿到手先看目录通常分成 controller、service、mapper、entity 四层。我以“查询景区列表”为例把三层代码串起来讲。先看统一返回结构// common/Result.java Data public class ResultT { private Integer code; // 0 成功1 业务失败 private String msg; private T data; public static T ResultT success(T data) { ResultT r new Result(); r.code 0; r.msg ok; r.data data; return r; } public static T ResultT fail(String msg) { ResultT r new Result(); r.code 1; r.msg msg; return r; } }Controller 层只做参数接收和结果包装不写业务逻辑// controller/ScenicController.java RestController RequestMapping(/scenic) RequiredArgsConstructor public class ScenicController { private final ScenicService scenicService; GetMapping(/list) public ResultPageResultScenicVO list(RequestParam(defaultValue 1) Integer page, RequestParam(defaultValue 10) Integer size) { return Result.success(scenicService.pageList(page, size)); } }Service 层负责业务组装调用 Mapper 拿数据// service/impl/ScenicServiceImpl.java Service RequiredArgsConstructor public class ScenicServiceImpl implements ScenicService { private final ScenicMapper scenicMapper; Override public PageResultScenicVO pageList(Integer page, Integer size) { PageResultScenicVO pr new PageResult(); int offset (page - 1) * size; pr.setList(scenicMapper.selectPage(offset, size)); pr.setTotal(scenicMapper.count()); return pr; } }Mapper 层的 SQL 写在 XML 里避免注解里拼长 SQL 的尴尬!-- mapper/ScenicMapper.xml -- select idselectPage resultTypecom.demo.entity.Scenic SELECT id, name, summary, cover, images, price, address, longitude, latitude FROM t_scenic WHERE status 1 ORDER BY create_time DESC LIMIT #{offset}, #{size} /select select idcount resultTypejava.lang.Integer SELECT COUNT(*) FROM t_scenic WHERE status 1 /select逻辑说明Controller 不碰 SQLService 不写大段 SQLMapper 只做数据访问这是为了让后续换掉 MyBatis 或调整分页时不牵连前端。分页参数里特意用 offset 而不是 page因为 MySQL 的 LIMIT 后面跟的是偏移量新手经常把页码直接传进去导致第二页以后查不到数据。这里要换算offset (page - 1) * size。这个换算漏了是小程序端“翻到第二页为空”的最常见原因。4.2 文件上传与图片访问小程序端 image 标签为什么经常加载不出图乡村旅游小程序里图片特别多景区封面、线路图、用户头像都要上传。后端接收图片的接口常见做法是接收 MultipartFile保存到服务器指定目录再把访问路径返回给前端。// controller/FileController.java RestController RequestMapping(/file) public class FileController { Value(${file.upload-dir}) private String uploadDir; Value(${file.access-prefix}) private String accessPrefix; PostMapping(/upload) public ResultString upload(RequestParam(file) MultipartFile file) { if (file.isEmpty()) { return Result.fail(文件为空); } String originalName file.getOriginalFilename(); String ext originalName.substring(originalName.lastIndexOf(.)); String newName System.currentTimeMillis() _ (int)(Math.random() * 1000) ext; try { file.transferTo(new File(uploadDir, newName)); } catch (IOException e) { return Result.fail(上传失败); } return Result.success(accessPrefix / newName); } }对应的 Spring Boot 配置要这样写否则上传成功也访问不到spring: servlet: multipart: max-file-size: 5MB max-request-size: 20MB file: upload-dir: ./upload access-prefix: /upload再写一个 WebMvcConfigurer 把本地目录映射成 URL// config/WebConfig.java Configuration public class WebConfig implements WebMvcConfigurer { Value(${file.upload-dir}) private String uploadDir; Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceLocations(file: uploadDir /); } }图片加载不出来的坑就在这里数据库存的是 /upload/xxx.jpg小程序端 image 的 src 如果直接写成这个路径它不知道主机在哪。正确做法是后端返回时拼成 http://127.0.0.1:8080/upload/xxx.jpg或者小程序端用 baseUrl 拼接。这个“相对路径 vs 绝对路径”的坑我碰到过不下十次。另外 transferTo 方法的目标目录默认不存在最好在应用启动时创建否则第一次上传会直接报 FileNotFoundException。4.3 JWT 令牌与用户鉴权让每个订单请求都认识你是谁订单、评论这类接口不能裸奔后端需要知道当前请求是哪个用户。毕设项目最常用的方案是 JWT。用户登录时后端根据 openid 签发一个 token小程序端每次请求放在 Authorization 头里后端拦截器解析 token 后把 userId 放进请求上下文。JWT 工具类的一个简化版本// util/JwtUtil.java Component public class JwtUtil { private String secret your-secret-key-change-me; private long expireMs 7 * 24 * 3600 * 1000L; public String createToken(Long userId) { return Jwts.builder() .setSubject(String.valueOf(userId)) .setExpiration(new Date(System.currentTimeMillis() expireMs)) .signWith(SignatureAlgorithm.HS256, secret) .compact(); } public Long parseToken(String token) { Claims claims Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody(); return Long.valueOf(claims.getSubject()); } }再写一个拦截器校验请求头// config/AuthInterceptor.java Component RequiredArgsConstructor public class AuthInterceptor implements HandlerInterceptor { private final JwtUtil jwtUtil; Override public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception { String auth req.getHeader(Authorization); if (auth ! null auth.startsWith(Bearer )) { Long userId jwtUtil.parseToken(auth.substring(7)); UserContext.set(userId); return true; } resp.setStatus(401); return false; } }有两点要注意拦截器要注册进 WebMvc 配置并且放行登录接口和上传接口不然登录接口自己也被拦截形成死循环JWT 的 secret 在毕设里可以写死但生产环境一定要挪到环境变量或配置中心别把私钥写进源码提交。演示环节你还能主动把 UserContext 里的 userId 打出来给评委看证明鉴权链路是通的。5. 部署调试与避坑指南小程序真机预览、后端端口、MySQL 版本这些坑5.1 现象真机预览所有请求都 fail模拟器里明明正常原因微信小程序真机环境强制要求请求地址是 HTTPS 且域名已在小程序后台配置个人开发阶段没有备案域名用 IP 或 localhost 发请求会被拦。解决开发阶段在微信开发者工具里勾选“不校验合法域名、web-view 域名、TLS 版本以及 HTTPS 证书”真机调试时点击右上角菜单打开调试模式微信会暂时放开限制。想长期在真机上看效果要么自己配一台有备案域名的服务器并部署 HTTPS 证书要么把小程序和 Java 后端跑在同一局域网把请求地址改成电脑的局域网 IP比如 http://192.168.1.100:8080。注意改成 IP 后依然要开启真机调试开关否则还是失败。5.2 现象后端明明启动成功小程序端就是连不上提示网络异常原因三种情况最常见——端口被电脑防火墙拦截、端口被其他进程占用、小程序端 baseUrl 写的是 localhost 而真机上 localhost 指向手机自己。解决先用命令确认端口在监听# Windows 查看 8080 端口占用 netstat -ano | findstr :8080 # Linux / macOS lsof -i :8080如果被占用修改 application.yml 里的 server.port 并重启如果没被占用检查防火墙入站规则放行对应端口。baseUrl 的配置我做了一个约定小程序端把 app.globalData.baseUrl 单独放在一个文件里模拟器用 http://127.0.0.1:8080真机用局域网 IP这样排查问题不用全项目搜着改。这个文件是项目里最容易出问题的黑匣子改错一个字符所有请求全挂。5.3 现象Spring Boot 启动时 MySQL 连接失败报 Public Key Retrieval is not allowed 或 Access denied原因MySQL 8.0 默认认证插件是 caching_sha2_passwordJDBC 驱动与它握手时需要额外的公钥获取步骤而有的源码配的是空密码和本地安装时设置的 root 密码不一致。解决检查两处。第一处是 JDBC URL完整写法加上参数再试spring: datasource: url: jdbc:mysql://localhost:3306/rural_travel?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltruecharacterEncodingutf8mb4 username: root password: 你自己的密码 driver-class-name: com.mysql.cj.jdbc.Driver第二处是 MySQL 里的用户权限。本地调试建议直接 localhost 连接把密码写进环境变量别提交到公开源码里。MySQL 5.7 和 8.0 的驱动类名也有差异对比如下MySQL 版本驱动类名常见问题5.7com.mysql.jdbc.Driver时区导致的时间偏差8.0com.mysql.cj.jdbc.Driver公钥检索、认证插件报错旧源码经常在这里翻车遇到问题时先把版本对齐再看连接参数。5.4 现象按 LW 文档里的 E-R 图建表接口查出来全是空字段原因LW 文档是先写的代码是后改的两边的表字段名对不上。比如文档里写 user_id代码里可能是 userId文档里写 createTime数据库里是 create_time。MyBatis 开启驼峰映射能解决一部分但不是所有工程都开了。解决以源码的实体类为基准把数据库字段和实体属性对齐。最稳妥的做法是打开 entity 包挨个对照给不一致的字段加 TableField 注解或者在 MyBatis 配置里打开驼峰映射mybatis: configuration: map-underscore-to-camel-case: true这个配置开完后数据库的 create_time 能映射到实体的 createTime但如果数据库字段叫 create_time实体叫 createAt那还是要手动改。答辩前把 E-R 图和实际表结构完整对一遍别让 LW 文档成为评委挑刺的把柄。6. 毕设演示与答辩验证按这份清单过一遍评委挑不出硬伤6.1 三分钟把闭环流程走完的演示脚本演示最理想的效果是“一镜到底”中间不出错。顺序我建议这样先把 MySQL 服务开起来确认数据库在再启动 Spring Boot 后端看控制台没有异常最后打开微信开发者工具编译小程序。演示动作依次是“首页景区列表 → 点进详情 → 下单购买 → 模拟支付成功 → 跳转订单列表看到状态为已支付”。这五个动作能一口气跑完小程序端和 Java 后端的核心价值就都讲清了。打开数据库表结构给评委看订单数据变化这个动作非常加分。你可以在模拟支付后用 Navicat 刷新 t_order 表让评委亲眼看到 status 变成了 1、pay_time 有值。这能证明“前端页面不是写死的后端接口真的同时写入了 MySQL”。另一个容易忽略的细节是演示时把开发者工具的 Network 面板打开每点一个页面能看到一次真实的 wx.request 请求技术含量立刻就出来了。6.2 答辩前必查的 5 处代码与边界条件答辩前我会过这五处避免现场翻车。第一登录接口有没有空 code 的校验直接传空字符串不能报 500第二订单创建接口有没有判断商品状态下架商品不能下单第三金额计算用 BigDecimal浮点数相加会出现 0.10.2 不等于 0.3 的尴尬第四所有接口的返回都走统一 Result避免有的接口直接返回字符串或 null 给前端判断造成混乱第五小程序端的 app.json 里页面路径要和实际 pages 目录一致删了页面忘记配置会让编译直接报错。另外我有个习惯答辩前把 LW 文档里“运行环境”一节和代码里的 Spring Boot 版本、MySQL 版本做一次比对。评委经常翻这一节如果文档写的是 MySQL 5.7代码里连的是 8.0虽然能跑但会被扣“文档与实现不一致”的分。反之提前统一好这就是一个加分项。希望这些实战细节帮到你至少让你拿到源码后不再对着报错日志发呆。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑