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

微信小程序+SSM快递管理平台:从源码拆解到联调部署全指南

微信小程序+SSM快递管理平台:从源码拆解到联调部署全指南 ★ FEATURED ARTICLE
简介这是一套基于微信小程序的快递管理平台设计与实现项目包后端采用Java与Spring Boot/SSM框架前端基于微信小程序适合计算机相关专业学生用于毕业设计参考也适合希望快速上手SSM小程序全栈开发的开发者。项目包含完整源码、数据库脚本、功能介绍文档并经过严格调试可本地运行。压缩包共15.86MB含1263个文件类型覆盖Java后端逻辑、Vue管理端页面、JavaScript脚本、小程序WXML/WXSS页面、SQL脚本等结构清晰便于按模块学习。目前已有2665人学习下载足见其实用性与参考价值。通过源码阅读和运行调试可系统掌握前后端分离开发、微信小程序端与SSM后端交互、数据库设计等关键技能为课程设计或毕业设计提供现成模板与落地实现。1. 微信小程序 SSM 的快递管理平台课设源码包值不值得跑通在课设选题里基于微信小程序的快递管理平台配一套 SSM 后端是出现频率非常高的组合。拿到带编号的 zip 之后多数人第一步是解压、导入 IDEA、等 Maven 下依赖然后在 Tomcat 启动报错或者小程序请求不通里卡一整晚。我要先说结论这个方案的价值不在“快递”这个业务而在于它正好覆盖小程序前端 Java 后端 关系型数据库的完整闭环适合用来理解前后端分离、登录态和订单状态机是怎么串起来的。这篇文章不猜源码包内部长什么样只按这类项目最常见的实现方式把目录、表结构、接口和小程序页面一条线讲清楚告诉你每一步怎么做、参数怎么设、坑在哪。适合两类人准备答辩的在校生和想在轻量级履约系统里找参照的初级工程师。2. 拆解 zip 项目骨架目录结构、数据模型和订单状态流转拿到源码包先别急着跑。快递管理平台这种题目业务的角色一般就三类普通用户寄件人/收件人、快递员/配送员、管理员。对应的功能是用户端下单、查件、取件码核销快递员端接单、派送、更新状态管理端做运单列表、统计和用户管理。搞清楚角色和功能再看代码目录就不会迷路。前端选型上原生微信小程序和 uniapp 是两条主流路线。原生小程序打包体积小、调试路径短微信开发者工具里改完马上能预览接手源码包的人不需要额外安装一套跨平台工具链。uniapp 能一套代码同时出小程序、App 和 H5但多一层编译遇到问题排查链路更长。快递管理平台这种以表单、列表、状态切换为主的轻交互项目原生小程序是最稳妥的选择这也是多数课设源码包默认的写法。对比项原生小程序uniapp调试链路开发者工具直接跑改完即预览先编译再预览报错定位多一层跨端能力只有微信一套代码出 App/H5上手成本熟悉 Vue 之外要学小程序语法会 Vue 基本能写课设源码包常见度最常见较少依赖复杂度无框架层依赖需要 HBuilderX 或 CLI 工程2.1 从压缩包到可运行工程读懂 SSM 项目的三层目录SSM 项目常见的目录结构是 src/main/java 下按 controller、service、mapper、pojo/entity 分包src/main/resources 放 Spring、SpringMVC、MyBatis 配置文件src/main/webapp 放 WEB-INF 和前端静态资源。小程序代码通常在独立目录里叫 miniprogram 或者和 backend 并列的 wechat 目录。如果压缩包里没有小程序目录只有后端 src那多半是把小程序代码放在另一个项目里没打进来需要自己新建小程序工程再把页面拷贝过去。project-root/ ├── src/main/java │ ├── com/xxx/express │ │ ├── controller # Controller 层接收请求、返回 JSON │ │ ├── service # Service 层业务逻辑、事务边界 │ │ ├── mapper # MyBatis Mapper 接口 │ │ └── pojo # 实体类User、ExpressOrder、PickupCode │ ├── resources │ │ ├── mybatis/mybatis-config.xml │ │ ├── spring/applicationContext.xml │ │ └── spring-mvc.xml │ └── webapp/WEB-INF/web.xml └── miniprogram/ # 微信小程序前端 ├── pages/index ├── pages/order ├── pages/mine ├── utils/request.js └── app.js目录结构看明白之后第一步是把 SQL 脚本导入 MySQL。绝大多数课设源码包里都有 db.sql 或 init.sql直接用 Navicat 或命令行执行即可。如果源码包里没有 SQL 文件说明作者把建表语句放在了 resources 目录或 README 里实在找不到就按下面的业务模型自己建也一样能跑。这里有个隐藏问题Maven 工程导入 IDEA 后如果 resources 目录没有被标记为资源根applicationContext.xml 等配置文件不会被拷贝到 target/classes启动时就会报 ClassNotFoundException 或 FileNotFoundException。检查方法是打开 Project Structure 看 Resources 文件夹是否高亮没高亮就手动 Mark as Resources Root这个操作能解决一大批“代码没问题但启动就挂”的故障。2.2 快递业务的表设计用户、运单、取件码与状态机快递管理平台的核心表通常是这几张t_user用户、t_express_order运单、t_pickup_code取件码/核销记录有的还有 t_address地址簿。运单表是整条业务的主线字段一般包含 order_no、user_id、courier_id、sender/recipient 信息、status、create_time、finish_time。状态机是这类项目的答辩重点也是最容易做乱的地方。我一般把订单状态设计成数字枚举0 待接单、1 已接单/待揽收、2 运输中、3 待取件、4 已签收、5 已取消。用户下单后状态为 0快递员接单后变 1驿站入库变 3 并生成取件码用户凭码核销后变 4。这样每个状态变更都能对应一个后端接口前端按状态展示不同的按钮。表结构这样建CREATE TABLE t_express_order ( id BIGINT AUTO_INCREMENT PRIMARY KEY, order_no VARCHAR(32) NOT NULL COMMENT 订单号业务查询用, user_id BIGINT NOT NULL COMMENT 下单用户, courier_id BIGINT DEFAULT NULL COMMENT 接单快递员, status TINYINT DEFAULT 0 COMMENT 0待接单 1已接单 2运输中 3待取件 4已签收 5已取消, sender_name VARCHAR(50) NOT NULL, sender_phone VARCHAR(20) NOT NULL, recipient_name VARCHAR(50) NOT NULL, recipient_phone VARCHAR(20) NOT NULL, pickup_code VARCHAR(10) DEFAULT NULL COMMENT 取件码, create_time DATETIME NOT NULL, finish_time DATETIME DEFAULT NULL, KEY idx_status (status), KEY idx_user_id (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;订单号和取件码注意区分order_no 是业务号用户用来查物流pickup_code 是到驿站取件时输入的核验码通常 6 位数字。两者都用随机数生成不要用数据库自增 id 直接暴露给前端否则别人遍历 id 就能看到所有订单。取件码生成后需要独立存储我一般建一张 t_pickup_code 表包含 code、order_id、expire_time、use_time 四个字段比单纯放在订单字段里更好排查核销记录。2.3 初始化数据与分页查询MyBatis 动态 SQL 的用武之地快递列表页几乎必然要分页用户端按 user_id 查自己下的单管理端查全部快递员端按 courier_id 查已接单。如果每个页面写一套查询三套 SQL 重复代码会很多。MyBatis 里用动态 SQL 拼条件是这类项目最理所当然的写法select idselectOrderPage resultTypecom.xxx.express.pojo.ExpressOrder SELECT * FROM t_express_order where if testuserId ! null AND user_id #{userId} /if if testcourierId ! null AND courier_id #{courierId} /if if teststatus ! null AND status #{status} /if if testorderNo ! null and orderNo ! AND order_no LIKE CONCAT(%, #{orderNo}, %) /if /where ORDER BY create_time DESC /select注意 where 标签会自动去掉第一个多余的 AND这是 MyBatis 动态 SQL 最常用的技巧。模糊查询不要直接写LIKE %#{orderNo}%那样会把#{}当字符串拼进去必须用 CONCAT 拼接。分页我常用 PageHelper引入依赖后在 Service 层调用 PageHelper.startPage(pageNum, pageSize)紧跟的下一条查询会被自动加上 LIMIT。这里有一个隐藏坑startPage 只对紧接着的第一条查询生效如果中间插了其他查询分页会作用到错误的 SQL 上血泪经验是把 startPage 和查询放到同一个方法里且保持紧邻。分页参数也需要约定pageNum 从 1 开始pageSize 普通用户列表给 10管理端列表可以给 20 或 30超过 50 的 pageSize 直接拒绝。前端滚动到底部时 pageNum 加 1 再请求下一页同时把新数据追加到数组末尾而不是整体替换。这个追加逻辑用展开运算符[...oldList, ...newList]就能实现但要注意去重因为分页边界上可能会出现同一条记录。3. 小程序端从登录到订单闭环请求封装、导航适配和表单组件微信小程序端是这个项目的门面。用户从首页下单到订单列表查看状态再到个人中心确认签收整个闭环里最值得讲的不是页面 UI而是请求层和登录态。很多课设项目把 wx.request 直接写死在页面里十几处请求代码各写各的一旦后端接口地址变化就要全局搜索替换这是最典型的翻车点。3.1 请求封装把 wx.request 包成带 token 的 Promise所有请求统一走一个 request.js会把三件事一次性解决自动附带 token、统一处理 HTTP 错误、统一处理业务码。这是小程序端复用性最高的一段代码也是答辩时最容易被追问“你封装了什么”的部分。// utils/request.js const BASE_URL https://your.domain.com/api // 生产环境地址 function request(path, method, data {}) { return new Promise((resolve, reject) { wx.request({ url: ${BASE_URL}${path}, method: method, data: data, header: { Content-Type: application/json, Authorization: wx.getStorageSync(token) || }, success(res) { if (res.statusCode 200) { const body res.data if (body.code 0) { resolve(body.data) } else { wx.showToast({ title: body.msg, icon: none }) reject(body) } } else { reject({ statusCode: res.statusCode }) } }, fail(err) { wx.showToast({ title: 网络请求失败, icon: none }) reject(err) } }) }) } module.exports { request, BASE_URL }这里 BASE_URL 要区分开发环境和正式环境。开发工具里可以用 http://127.0.0.1:8080真机预览必须换成局域网 IP 或已备案的 HTTPS 域名。token 用 wx.setStorageSync 存入本地缓存读取时用 wx.getStorageSync这比把 token 放在全局变量里更扛重启小程序冷启动后不会丢。响应体约定 code 0 表示成功这个约定要求后端 Controller 返回统一格式否则前端每个接口都要再套一层判断。登录态是小程序项目的核心环节。常见做法是前端调 wx.login 拿到临时 code传到后端后端拿 code 加上 appid 和 secret 去微信接口换取 openid再生成业务 token 返回前端。注意 openid 不能直接返回给前端存储这是安全上的原则后端要把 openid 和用户表绑定前端只拿 token。Session 过期时间一般设置 7 天过期后前端请求会收到 401此时应该引导用户重新静默登录而不是直接报错。3.2 自定义顶部导航栏高度适配与胶囊按钮快递管理平台的底部 Tab 一般有三个首页、订单、我的。如果用了自定义导航顶部标题栏的高度在小屏和老机型上是不一样的直接写死 64px 会出现在 iPhone 上偏上、在 Android 上偏下的现象。标准做法是在 onLoad 里读系统信息onLoad() { const systemInfo wx.getWindowInfo() const menu wx.getMenuButtonBoundingClientRect() this.setData({ navBarHeight: systemInfo.statusBarHeight menu.height (menu.top - systemInfo.statusBarHeight) * 2 }) }菜单按钮的 boundingClientRect 拿的是右上角胶囊按钮的位置导航栏高度一般是状态栏高度加胶囊按钮高度再加两倍胶囊顶部与状态栏的间距。这个值在 iPhone 和老 Android 上能差出近 20px所以必须动态计算。尺寸单位不要用 rpx导航高度是像素值用 px 直接设到行内样式更省事。除了高度还要注意自定义导航胶囊的右侧占位。微信胶囊按钮宽约 87px页面的右上角操作按钮要避开这个区域否则会被胶囊盖住。做法是在导航栏右侧留出至少 100px 的安全边距列表页的扫码入口、消息图标这类元素都放在这个边距之外。3.3 订单提交页表单组件、单选框和缓存时间设置下单页涉及寄件人、收件人、物品类型、是否保价等字段。物品类型用单选组件比输入框更省事配送方式同样用 radio 组件切换“普通快递”和“加急”。微信小程序的 radio-group 需要自己管理选中值change 事件里 e.detail.value 拿到的就是 value 属性的字符串用它去设置提交数据里一个字段即可。radio-group bindchangeonDeliveryTypeChange label classradio-item radio valuenormal checked{{deliveryType normal}} / text普通快递3-5天/text /label label classradio-item radio valueurgent checked{{deliveryType urgent}} / text加急快件次日达/text /label /radio-group注意checked{{deliveryType normal}}这种写法在 data 里要先定义 deliveryType: normal组件绑定表达式时小程序不支持箭头函数和复杂调用只支持简单的比较运算。onDeliveryTypeChange 里把 e.detail.value 赋给 this.setData 即可提交时读取同一个字段。缓存时间设置也是快递平台里常见的小需求比如把用户上次填写的寄件人信息缓存 24 小时避免重复输入。用 wx.setStorageSync 时自己拼一个过期时间戳而不是依赖微信的某个开关const cacheKey sender_info const expiredAt Date.now() 24 * 60 * 60 * 1000 wx.setStorageSync(cacheKey, { data: formData, expiredAt })读取时先判断 Date.now() 是否超过 expiredAt超过就清除缓存并返回空对象。这套手动过期逻辑比直接 setStorageSync 整个对象更可控所有业务缓存都能复用。小程序没有真正意义上的后台定时器过期判断必须在读取时做这一点和网页端 localStorage 的处理思路一致。4. SSM 后端的接口设计与业务落库 Controller 到 Mapper 的一条线SSM 这个组合在小程序后端项目里还能占一席之地是因为它足够轻Spring 管理对象生命周期SpringMVC 处理路由和参数绑定MyBatis 负责 SQL 和结果映射。对于一个快递管理平台这种 CRUD 为主、加少量状态流转的业务SSM 的复杂度刚好合适。用 Spring Boot 当然也可以但课设场景里 SSM 更容易讲清楚“请求进来之后每一层做了什么”。4.1 SSM 整合的关键配置Spring 管 Bean、MVC 管路由、MyBatis 管 SQL项目能跑起来的前提是三份配置不打架。applicationContext.xml 里扫描 service 和 mapperspring-mvc.xml 里只扫描 controller这个边界非常关键。如果 spring-mvc.xml 把 service 也扫了会出现事务注解不生效或者 Bean 重复创建的诡异问题。!-- spring-mvc.xml -- context:component-scan base-packagecom.xxx.express.controller/ mvc:annotation-driven/ mvc:default-servlet-handler/controller 包扫描一定要精确到 controller不要写 com.xxx.express否则把 service 也交给 MVC 容器管理事务边界会乱。mvc:annotation-driven 开启 JSON 转换、参数解析等能力default-servlet-handler 让静态资源不被 DispatcherServlet 拦截。MyBatis 配置里重点是 SqlSessionFactoryBean 要指定 mapper 文件路径和实体类别名包否则 Mapper 接口和 .xml 对不上启动时只报一堆找不到 statement 的错误。applicationContext.xml 里还有一个容易漏的配置事务管理器。快递单创建、取件码核销这类涉及多表更新的操作必须加事务。常见写法是 DataSourceTransactionManager 配tx:annotation-driven/然后在 Service 实现类或方法上加 Transactional。漏掉事务管理器时Transactional 不报错但也不生效数据写到一半出异常也不会回滚属于很难察觉的坑。4.2 Controller 到 Service快递单创建与状态流转的接口设计后端接口设计要和小程序页面对齐常用接口就六个左右登录、下单、查订单列表、接单、更新状态签收/取消、查取件码。Controller 只做参数接收和结果包装业务逻辑全在 Service。下单接口是这样一条线RestController RequestMapping(/api/order) public class OrderController { Autowired private OrderService orderService; PostMapping(/create) public Result? create(RequestBody OrderCreateDTO dto) { String orderNo orderService.createOrder(dto); return Result.success(orderNo); } GetMapping(/list) public Result? list( RequestParam Long userId, RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize) { return Result.success(orderService.pageByUserId(userId, pageNum, pageSize)); } PostMapping(/pickup) public Result? pickup(RequestBody PickupDTO dto) { orderService.pickupByCode(dto.getPickupCode()); return Result.success(null); } }create 接口用 RequestBody 接收 JSON对应前端 request.js 里 data 对象list 接口用 RequestParam 接收查询参数对应 URL 上的 query string。pageNum 和 pageSize 要设默认值否则前端漏传时 MyBatis 拼出没有 LIMIT 的 SQL数据量大一点直接把服务器拖慢。pickup 接口是核销动作Service 里必须加事务校验取件码、更新状态、写核销记录三个操作要么全成功要么全失败典型的需要 Transactional 的地方。Service 层创建订单时order_no 的生成不要用时间戳拼接并发下容易重复。我一般用 UUID 去掉横线取前 16 位转大写或者用 Redis 自增序列加日期前缀。取件码则用 6 位数字但要注意避开 000000 和 123456 这类弱码生成后查一次库确认不重复重复就重新生成最多重试三次。4.3 Mapper 层动态 SQL分页、条件查询与模糊搜索Service 层把业务状态算清楚后落到 Mapper 的 SQL 要能处理多种查询条件。除了前面给的 selectOrderPage更新状态的 SQL 也要注意只更新允许变更的状态。直接 UPDATE 订单表会把校验逻辑放在应用程序里MyBatis 的写法倒是很简单update idupdateStatus UPDATE t_express_order SET status #{newStatus}, finish_time CASE WHEN #{newStatus} 4 THEN NOW() ELSE finish_time END WHERE id #{id} /update这里用 CASE WHEN 处理签收时写完成时间比业务代码里先查再更新少了两次数据库交互。如果想让状态流转更严谨可以在 WHERE 里加旧状态条件比如WHERE id #{id} AND status #{oldStatus}更新影响行数为 0 说明状态已经被别人改过再抛出异常避免脏覆盖。这是快递员并发接单场景下最常见的并发问题做了这个校验答辩时能讲出东西。取件码核销的 SQL 同样要注意原子性。核销接口同时被用户和快递员调用如果两个人同时输入同一个码不加条件限制的 UPDATE 会被执行两次。正确写法是核销 UPDATE 里加上AND use_time IS NULL影响行数为 0 说明码已经被用过直接返回“取件码已使用”。这个思路和上面订单状态的乐观锁是同一套理解了能举一反三。5. 联调与部署避坑域名白名单、时区、Tomcat 版本的 5 个真实翻车点这一章是血泪经验集合。快递管理平台这类全栈项目代码写得再顺部署联调阶段也逃不过几类固定故障。碰到的时候不要怀疑是自己写的代码有问题先按下面几条逐一排查。5.1 联调阶段的三个翻车现场域名、跨域和真机地址第一个坑是小程序请求直接报 fail页面空白。现象开发工具里一切正常点击真机预览后所有请求全部失败。原因是微信小程序对网络请求有校验真机上必须使用已配置到后台的 HTTPS 域名。解决开发调试期间在开发工具里勾选“不校验合法域名”真机预览时把 request 合法域名临时加到小程序后台或者使用局域网 IP 加自定义端口连本地后端。开发阶段的临时方案是在详情-本地设置里打开不校验上线前一定要换成正式的 HTTPS 域名并配置到小程序后台。第二个坑是后端接口通了但前端拿不到数据。现象用浏览器打开后端接口正常小程序里请求返回 statusCode 405 或者响应被拦截。原因多半是 SpringMVC 返回的 JSON 里中文乱码或跨域头缺失。解决SpringMVC 配置里加 StringHttpMessageConverter 的 UTF-8 编码同时在 WebMvcConfigurer 里配置 addCorsMappings 允许跨域访问。小程序请求本身不强制走 CORS但开发工具模拟和 H5 调试时常受影响配一下不会吃亏。注意“不校验合法域名”只对 request 生效上传图片等场景同样有域名校验需一并配置。第三个坑是后端在本地跑得好好的小程序扫一扫预览就连不上。现象真机上请求 127.0.0.1 超时。原因显而易见手机访问不到电脑的 localhost。解决把 BASE_URL 里的 127.0.0.1 改成电脑的局域网 IP同时保证手机和电脑在同一 Wi-Fi 下并检查电脑防火墙是否拦截了 8080 端口。最常见的组合是后端跑在 8080、前端连 192.168.x.x:8080。Windows 防火墙记得放行对应端口这个坑能卡一晚上。5.2 数据与环境的坑时区、JDK 版本和中文乱码数据库时区问题排在第四。现象插入订单后前端看到的时间比本地时间整整快了 8 小时或者少了 8 小时。原因MySQL 驱动连接串里没有指定 serverTimezone驱动按 JVM 默认时区解析 DATETIME导致时间错位。解决JDBC URL 里明确加上serverTimezoneAsia/ShanghaiuseSSLfalsecharacterEncodingutf8。另外建表时 DATETIME 和 TIMESTAMP 的选择也有讲究快递平台的创建时间用 DATETIME 就够不需要 TIMESTAMP 的自动更新特性避免索引和范围方面的额外麻烦。第五个坑是 JDK 版本和 Tomcat 版本不匹配。现象Tomcat 启动后页面能打开但接口一调就 500控制台报 UnsupportedClassVersionError。原因这个报错就是编译用的 JDK 版本比运行用的高编译出的 class 文件 Tomcat 所在的 JVM 不认。解决Maven 编译版本设成 1.8Tomcat 用 8.5 或 9.x两者匹配。顺便一提Spring 4.x 和 JDK 11 以上会有兼容问题这一整套 SSM 方案最省心的搭配是 JDK 8 Tomcat 8.5/9 MySQL 5.7。如果你的源码包是 Spring 5 写的JDK 8 同样适用不要为了追新上 JDK 17课设项目不值得在这个环境搭配上折腾。中文乱码单独说一句。页面显示快递公司名称变成问号多数是三个位置不一致数据库连接串没带 characterEncodingutf8、表字符集不是 utf8mb4、SpringMVC 返回 JSON 的编码不是 UTF-8。三个位置只要有一个不对就会出现“数据库里是对的页面是错的”这种像玄学一样的问题。用 Navicat 查看表和字段的 collation全部改成 utf8mb4_general_ci再清理浏览器和小程序缓存通常能一次解决。5.3 上线前的合规检查虚拟支付、年审和缓存时效小程序端的虚拟支付是容易被忽略的红线。快递管理平台如果把“运费支付”做成在线支付需要申请微信支付商户号用 wx.requestPayment 拉起支付但如果是“充值余额再下单”这类虚拟支付个人主体小程序根本无法开通审核也不会通过。课设项目一般做到货到付款加状态流转即可避开虚拟支付这个雷区。上线前还要检查小程序年审个人主体小程序每年要续费审核忘了年审会被暂停服务这个问题虽然不是代码问题但每年都能看到有人因为这个翻车。缓存时效也要单独说一句。快递管理平台里如果有用户地址簿、快递员位置等数据后端接口可能需要加缓存。常见做法是在 Service 层用本地 Map 或者 Redis 存热数据但要注意设置过期时间。如果后端没有 Redis也可以用 Caffeine 这种轻量级缓存TTL 按业务设比如取件码有效期为 24 小时、订单列表缓存 30 秒。缓存不是越久越好快递状态是实时性很强的数据缓存时间设长了用户会投诉“快递到了还显示运输中”。宁可让请求多打一次数据库也不要让用户看到过期状态。6. 给快递管理平台做渐进增强从课设到可运维的四个动作到这里基础版本已经能跑通了但距离“敢拿到答辩现场演示”还差两步。我想再讲一个具体技巧把散装的 JSON 响应统一成规范体这个改动最小、收益最大。6.1 统一响应体与错误码从散装 JSON 到可排查的接口规范我用 Result 类包所有接口返回值成功时 code0失败时返回业务码。前端 request.js 已经假设了这套结构所以后端必须和前端约定好否则成功提示和失败提示都会错位。public class ResultT { private int code; 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 error(int code, String msg) { ResultT r new Result(); r.code code; r.msg msg; return r; } }统一之后前端只需要判断 body.code业务异常可以在全局异常处理器里转成 error 返回Controller 里不再出现 try-catch 堆业务逻辑的脏代码。错误码也要有约定0 成功400 参数错误401 未登录403 无权限500 服务器异常。前端对 401 做统一跳转登录其他 code 直接 toast msg排障时看日志里的 code 就能定位是哪一类问题。这一步做完再配合 logback 打请求日志一个请求从进来到返回的完整链路就能看清楚了。6.2 三道快速验证接口自检、小程序体验版和日志定位提交答辩或者交付之前我用三件事做最终验证。第一把后端启动后逐个接口用 curl 打一遍确认 CRUD 和状态流转都正常重点验证带 token 的请求能通。第二在小程序开发工具里跑一遍从下单到签收的完整流程特别注意中间状态切换时的按钮文案。第三打开后端控制台或者日志文件观察有没有异常堆栈和慢 SQL慢 SQL 可以通过 MyBatis 的日志输出看到执行时间超过 500ms 的查询要考虑加索引。最后说一个多写了几年代码才明白的道理这种课设项目面试官和评委最在意的不是你用了多少新技术而是你能不能把一条业务链路从头到尾说清楚。快递管理平台恰好是能讲清楚的题因为它的状态机足够具体。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站