
如果你正打算做一个SpringBoot相关的全栈项目又不想落俗套地做个图书管理、商品秒杀那农机租赁服务平台是个挺不错的选择。这个项目本质上是把共享经济那一套逻辑搬到农业场景里农户家里有闲置的拖拉机、收割机、旋耕机与其放在院子里吃灰不如挂到平台上按天出租给周边需要作业的农户另一边种粮大户或者农机手有作业需求也不用非得自己花几十万买设备直接按需租就行。这个平台做出来之后既覆盖了信息发布、检索、下单、支付、订单履约这些电商核心链路又额外带上了农机认证、作业计价、押金结算、定位检索这些农机特有的业务逻辑非常适合拿来练手SpringBoot、MyBatis-Plus、Vue这一整套前后端分离技术也能让毕设或者简历项目有足够的业务复杂度。这篇文章我打算从项目定位、技术选型、数据库设计、关键业务实现、部署避坑这五个方面展开不整虚的全部按真实项目开发时会遇到的问题来写。你可以把它当作一份完整的项目复盘来读也可以直接照着里面的表结构和业务方案去动手实现。1. 项目定位与技术选型1.1 农机租赁到底在解决什么场景问题先搞清楚平台解决的核心问题是什么。农业机械化率越来越高但农机价格一直居高不下一台大型联合收割机动辄二三十万普通农户根本不会为了每年那十几天的收获季去买一台。与此同时很多农机手和农机合作社的设备在非作业季长期闲置闲着就是亏钱因为农机折旧是按年算的不是按作业小时算的。农机租赁平台要做的就是两端撮合一端是有农机资源的供给方把农机信息、可作业区域、计费方式发布上来另一端是有作业需求的需求方按区域、按农机类型、按作业季节去搜索并线上下单。这个业务模型和传统的房屋短租很像但农机本身是移动的作业设备订单不只是“租你一台机器”还涉及作业地点、作业亩数、到达费用、机手作业费这些农业特有的规则。站在技术实现的角度这个项目不只是一个后管系统加一个H5商城那么简单它至少要覆盖四个端农户/农机手使用的C端小程序或H5、管理员使用的后台管理端、农机主使用的设备发布端以及后端管理服务。如果你作为毕设去做一般会把前两个端合并成一个Vue管理端再加一个面向用户的H5端节省工作量。1.2 为什么后端选了SpringBoot而不是其他方案网上关于SpringBoot的介绍铺天盖地但真正到自己做项目选型时还是要说清楚理由。SpringBoot最大的价值是解决了Spring时代配置地狱的问题——以前搞一个SSM项目要写一堆XML配置数据源、事务管理器、Mapper扫描、拦截器全部要靠手配配错一个Bean启动就报错。SpringBoot把这些统一变成了自动配置内置Tomcat打成一个Jar包就能跑这对独立开发和中小型系统来说体验好得不是一星半点。拿这个农机租赁平台来说它需要的核心能力SpringBoot全都覆盖得比较完善Web层用SpringMVC天然支持RESTful接口设计C端和后台可以共用一套API持久层整合MyBatis-PlusCRUD不需要手写SQL业务复杂时再上自定义SQL和分页插件安全认证可以用Spring Security或者更轻量的Sa-TokenJWT无状态登录对前后端分离非常友好定时任务用Spring自带的Scheduled或者集成Quartz正好用来处理超时未支付订单、作业完成后的自动结算缓存整合Redis会话、热点农机数据、验证码这些都能放进去。相比之下PHP的LNMP方案更适合快速搭CMS系统Python的Django在ORM和Admin后台方面虽然省事但招人、部署、后续维护和SpringBoot技术栈的成熟度、社区解决方案丰富度比还是有差距。所以做这个项目SpringBoot几乎是标准答案简历上写它也能更好地面试。1.3 前端、数据库和中间件怎么搭配整个系统的常用户口和业务承载我是这样搭配的前端框架选Vue3加Element-Plus原因很简单——后台管理界面的主流方案组件成熟文档齐全。用户端如果不想单独做小程序可以直接用Vue3写一个移动端适配的H5页面。维表数据和后台图表类的展示用ECharts看农机分布和订单趋势比较直观。数据库用MySQL 8.x字符集一定要设置成utf8mb4农机描述里经常有表情符号或者生僻字常规utf8会直接报错或者乱码。Redis负责缓存、分布式锁和临时验证码另外就是做农机热力榜单这类实时性要求高的缓存数据。文件存储这块初期不用想得太复杂本地磁盘加FastDFS或者直接上MinIO就行农机合格证、行驶证照片、农机实拍图、作业凭证这些图片资源必须要有一个统一的对象存储入口不要散落在业务代码里。后端项目用Maven管理依赖SpringBoot版本这里要重点说一句——不要一上来就用3.x和4.x的早期或者过新版本JDK版本、依赖兼容性都会出问题。我用的是SpringBoot 2.7.18配JDK8这是我目前做这类项目比较稳妥的组合网上资料多遇到问题也容易搜到答案。如果你是非要用JDK17的SpringBoot选3.x系列但注意旧版MyBatis-Plus相关插件要升级到对应版本。1.4 项目工程结构怎么规划很多新手拿到项目就开写代码全堆在一个Application类或者一个Controller包里后面扩展一个功能要翻半天代码。这个项目我建议后端代码按这样的结构划分com.farm.lease ├── common // 公共模块统一返回结果、异常处理、常量、工具类 │ ├── result │ ├── exception │ └── utils ├── config // 配置类RedisConfig、WebMvcConfig、MybatisPlusConfig、Knife4jConfig ├── controller // 接口层按业务模块划分只做参数接收和返回 ├── service // 业务层事务控制、核心业务逻辑 │ ├── impl │ └── task // 定时任务 ├── mapper // 数据访问层MyBatis-Plus的Mapper接口 ├── entity // 数据库实体映射 ├── dto // 前端交互参数对象 ├── vo // 视图返回对象 └── security // 登录认证、权限控制相关这个结构最大的好处是各层职责清晰controller只负责接收参数和调serviceservice里写业务规则mapper只管数据读写不会出现Controller里直接写SQL这种后续没法维护的情况。前端项目单独建一个目录和Vue工程分开开发时通过代理转发接口避免跨域问题部署时再统一打包放到Nginx下。2. 系统核心模块拆解与数据库设计2.1 用户与农机认证怎么设计农机租赁不能像闲鱼卖二手手机那样随便注册就能发布农机作业涉及人身安全和作业质量所以平台一定要设计资质审核链路。用户体系上我建议设计三类角色普通用户需求方、农机主供给方、平台管理员。普通用户注册后可以直接浏览农机、下单租赁农机主需要额外提交身份证、驾驶证、农机行驶证、农机照片这些材料后台审核通过后才有权发布农机。管理员负责农机审核、用户管理、订单仲裁、投诉处理。这个设计在数据库上会体现为user表加一个user_type字段农机主资质单独放一张farmer_auth表审核状态用audit_status字段0待审核、1通过、2驳回。农机主提审后后台管理员审核的操作要记录日志如果被驳回还要填驳回原因方便农机主修改后重新提交。2.2 租赁订单的核心流程整个平台最核心的链路是搜索农机 → 查看农机详情和计价规则 → 发起租赁下单 → 支付押金或租金 → 农机主接单确认 → 线下作业/取还机 → 确认完成 → 资金结算。农机不是快递无法通过物流发货履约过程是在线下完成的。所以我在订单状态里专门设置了待接单、待作业、作业中、待确认完成、已取消、已完成、已退款这些状态。农机主接单之后双方可以电话沟通实际作业时间作业完成后由需求方确认平台再把冻结的租金打给农机主。这种模式其实和美团到店消费很像平台做的是信息撮合和资金担保而不是物流履约。支付这块建议直接对接微信支付Native支付或者H5支付。如果你是做毕设不需要真开商户号可以做一个模拟支付的开关——本地环境走模拟支付演示时输入验证码就算支付成功这样功能链路是完整的又不会卡在商户资质上。这块在论文里也可以如实写设计了对接微信支付的接口同时支持沙箱模拟支付用于测试。2.3 数据库核心表设计我建表时始终遵循一个原则核心业务表必须有create_time、update_time、deleted逻辑删除标记金额字段用decimal(10,2)状态字段用tinyint并注释清楚含义。下面是六张跑不掉的核心表用户表t_userid 主键、open_id微信OpenID可空、phone、password、user_type1普通用户 2农机主 3管理员、nick_name、avatar、real_name、id_card、status农机信息表t_machineid 主键、user_id所属农机主、machine_name、category拖拉机/收割机/旋耕机/播种机/植保无人机等、brand、model、manufacture_date、hours_used已使用小时、attachment_urls图片JSON数组、province/city/district、address_detail、longitude、latitude、rent_type1按天 2按亩 3按小时、rent_price、deposit押金、description、audit_status、status1上架 2下架租赁订单表t_lease_orderid 主键、order_no唯一订单号、machine_id、lessee_id需求方、lessor_id农机主、total_amount、deposit_amount、pay_amount、status0待支付 1待接单 2待作业 3作业中 4待确认 5已完成 6已取消 7退款中、start_time、end_time、work_province/work_city/work_district、work_address、acreage作业亩数、contact_name、contact_phone、cancel_reason、finish_time支付流水表t_payment_recordid 主键、order_id、order_no、pay_type1微信 2模拟支付、pay_amount、transaction_id第三方流水号、status、notify_time、notify_data回调原始报文这个字段很重要评价表t_evaluationid、order_id、machine_id、user_id、rated_user_id、score、content、images意见反馈与投诉表t_feedbackid、user_id、type、content、images、status、handle_result农机作业日历可以暂时不做成表直接在订单表上通过时间条件查询判断某台农机在指定时间段内是否已被租赁。如果农机主可能有多台机器每台机器的档期独立这样查询不会串。2.4 订单状态机与流转约束我见过很多订单系统写着写着就乱了的根本原因是状态更新没有单一入口业务代码里到处直接order.setStatus()最后都不知道这个状态是什么时候变的。做这个项目时我建议把状态的流转控制收敛到OrderService里的一个统一方法并且明确好合法的流转方向状态流转图可以这样理解待支付0只能走向待接单1或已取消6取消条件是有时限的一般15分钟或30分钟不支付就自动取消待接单1只能走向待作业2或已取消6农机主接单后不能随意取消如果确需取消要让农机主输入原因并经过平台审核防止恶意拒单待作业2在作业开始后走向作业中3这个操作可以由农机主或者任意一方确认作业中3结束后走向待确认4需求方确认后走向已完成5已完成5之后只能走评价流程和售后投诉流程不能再改金额。这里面有一个点常常被忽略无论哪一步数据库里的订单记录都不能只更新status字段而要考虑把操作人和操作时间一并更新也就是记录status_history。我会规划一张订单状态履历表每个状态流转都插一条数据后面出纠纷时拿着时间线直接就能对账。这个设计在答辩时也是一个加分项。3. 关键业务实现与踩坑记录3.1 农机检索中的位置距离与条件筛选农机租赁平台有一个很有业务特色的查询场景——按位置找附近的农机。农户要找收割机他关心的是这台收割机到他的田里有多远太远了光拖运费就不划算。在数据量不大几千台的情况下不需要引入Elasticsearch或者专门的GIS数据库直接在MySQL里用经纬度计算距离即可。农机表里有longitude和latitude字段查询时用Haversine公式计算距离SQL这样写SELECT id, machine_name, rent_price, ROUND(6371 * 2 * ASIN(SQRT( POWER(SIN((#{lat} - latitude) * PI() / 180 / 2), 2) COS(#{lat} * PI() / 180) * COS(latitude * PI() / 180) * POWER(SIN((#{lng} - longitude) * PI() / 180 / 2), 2) )), 2) AS distance_km FROM t_machine WHERE audit_status 1 AND status 1 HAVING distance_km #{distance} ORDER BY distance_km如果你的表数据量超过几十万这条路效率就不够了需要上Elasticsearch的geo_distance查询或者用MongoDB的GeoJSON。但对毕设或者中小型平台上面的SQL配合联合索引完全够用。注意不要在where里直接用距离去算因为那会让索引失效应该先按经纬度范围粗筛比如纬度加减0.5度、经度加减系数再在HAVING里精确过滤性能会更稳。筛选条件上除了距离还要支持农机类型下拉菜单、租金价格区间、租用方式按天/按亩/按小时、农机主信用分。这些条件在Mapper里用MyBatis-Plus的LambdaQueryWrapper动态拼装就够用不需要写一堆XML。3.2 支付回调与订单状态的一致性保证支付是这类平台最容易出事故的环节。微信支付的工作方式是用户在小程序里发起支付微信那边收到钱之后异步通知你的后端接口你的后端收到回调后要校验签名、校验金额然后更新订单状态、给农机主发通知。这个异步通知的时机是不可控的可能支付成功了但通知一直没到或者延迟很久也可能通知重复到达好几次。我在做这个模块时吃过两个亏在这里直接告诉你第一个是回调用“参数校验”。回调接口收到微信的通知后不能只验签名就完事还要拿通知里的amount.total和本地订单的pay_amount做比对不一致的必须拒绝防止中间环节报文被篡改或回调地址被恶意刷。验签失败的回调不返回成功应答微信那边会重试这没问题。第二个是重复回调导致的状态覆盖。微信同一个支付结果会通知多次后端的处理逻辑必须是幂等的。我当时的做法是先用order_no加redis分布式锁锁内再查一次订单状态如果已经是“待接单”或者“已支付”直接返回成功不再处理。为了稳妥还加了一张payment_record表每次回调先尝试插入唯一transaction_id如果插入冲突说明这单处理过直接跳过。这套方案下就算通知来了十次也只有第一次真正改状态。3.3 超时订单自动取消的定时任务逻辑用户下单后如果一直不支付订单要自动取消农机这段时间才能重新被其他用户看到。我一开始用一个SpringBoot的Scheduled定时任务每30秒扫描一次订单表把超过15分钟还没支付的订单批量取消。逻辑很简单生产上也确实能跑但数据量大了之后会有两个问题第一个是扫描范围太宽每次都全表扫数据库压力大。优化方案是扫的时候只关注最近30分钟内创建且status0的订单配合create_time索引每次只扫小范围。第二个问题是批量更新的时候要小心并发不能把用户正在支付的订单给取消了。用户在最后几秒完成支付此时后台扫到了这笔订单超时两边同时操作就会出问题。我的做法是更新语句里带着状态条件UPDATE t_lease_order SET status 6, cancel_reason 超时未支付自动取消, update_time NOW() WHERE id #{orderId} AND status 0如果影响行数是0说明订单已经被人改了状态就不能再取消。这个“状态条件更新”的思路在并发场景下非常重要它其实就是一个轻量的乐观锁。类似的做法在农机主接单、需求方确认完成时也都应该用上。3.4 农机档期冲突与防重复下单还有一块新手很容易翻车用户给同一台农机下单A客户选了8月20日到8月25日B客户在A还没支付的时候也选了同样的日期并发起下单。如果没有防护两个订单都创建成功了等于超卖。结合前面说的状态机最稳妥的方案是在订单创建时做一次档期冲突校验查询条件就是同一台机器、状态是待支付/待接单/待作业/作业中/待确认也就是说订单还在生效流程中已取消和已完成的除外并且时间区间有交集SELECT COUNT(*) FROM t_lease_order WHERE machine_id #{machineId} AND status IN (0,1,2,3,4) AND start_time #{requestEndTime} AND end_time #{requestStartTime}如果这个count大于0直接返回“该农机在所选时间段已被租赁”下单不成立。这个同样要用唯一索引保障防止查询后插入时并发穿透——如果数据库用的是MySQL可以在订单表上建一个(machine_id, start_time, end_time)的业务索引来做最后底线。更硬核的方案是引入Redis分布式锁但做这个平台时上面的两段式校验加数据库兜底已经很够用了。3.5 计费规则与押金结算的设计细节农机租赁的计费五花八门按天租、按亩作业、按时租还有的要算拖运费。我建议不要把这些规则写死在代码里而是做成计价规则表t_price_rule关联到农机的category和单台农机上。比如一台收割机可以同时配置“按亩作业8元/亩最低起步20亩”和“按天出租1500元/天含机手食宿自理”两种方案用户在详情页看到的是组合后的报价下单时选择一种方案。押金处理也需要独立设计。押金不等于租金它在订单完成后应该自动退回到用户余额或者原路退回。我设计的是用户下单时支付租金押金订单进入待作业状态后押金冻结作业完成且双方无异议后平台把租金部分结算给农机主押金原路退回给用户。要是作业过程中农机损坏或者没有按时到位需求方可以发起平台介入仲裁仲裁结果出来前押金一直冻结。这套逻辑在做的时候会踩到很多边界情况比如部分退款、退款到余额而不是原路支付处理好这些细节项目的完成度会比普通毕设高出来一大截。4. 工程化落地与部署调试4.1 SpringBoot中MyBatis-Plus的实用配置MyBatis-Plus是这个项目在数据访问层的主力我在实际项目里一般这样配置mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml type-aliases-package: com.farm.lease.entity configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true global-config: db-config: logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0 id-type: assign_id这里要重点说两个配置第一个是map-underscore-to-camel-case数据库字段是create_timeJava实体类字段是createTime如果没开这个配置查询结果会全部为null很隐蔽。第二个是logic-delete-field全表逻辑删除查询时会自动加上deleted0的过滤条件应用层不用每次手动写。分页查询直接用MyBatis-Plus的分页插件核心是配置一个拦截器Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; }没有这个插件的话你调Page也会查出全表数据这个坑很经典。另外注意如果你把Mapper XML和注解SQL混用接口方法上的注解SQL优先级更高XML里同名方法的SQL会被忽略调试的时候不要在这上面浪费时间。4.2 认证与接口权限设计农机租赁平台至少有三类角色的权限区分普通用户能看到农机详情并下单农机主能管理自己的农机和订单管理员能审核农机和处理投诉。我用Sa-Token做登录认证比Spring Security上手快得多自带的注解权限校验也很方便。登录流程是用户微信授权登录或手机号验证码登录后端生成token返回前端前端每次请求在header里带token后端通过拦截器统一解析并存入当前用户上下文。每个核心接口都要做两层校验第一层校验是否登录第二层校验是否有操作权限。比如订单详情接口需求方和农机主都能看但普通用户不能看别人的订单更不能取消别人的订单。具体实现上Controller里的当前用户可以通过Sa-Token的StpUtil.getLoginId()获取然后和请求参数里的userId比对不一致就抛出业务异常。千万不要直接把前端传的userId拿来当操作用户那是很经典的水平越权漏洞。网上那些“越权攻击”渗透测试打得最多的就是这种接口。面试如果问到这块你能把这个讲清楚加分是实实在在的。4.3 打包部署与Vue前端整合开发阶段前后端分离但部署时可以有两种选择。第一种是前后端分开部署后端打Jar包跑在服务器上前端构建成静态文件放到Nginx里Nginx再做/api反向代理。第二种是直接把前端构建出来的dist目录复制到SpringBoot的resources/static下打成一个大Jar包一键启动。毕设演示和写论文时第二种方式方便很多不需要额外安Nginx。如果说要把前端打包进SpringBoot注意清理旧的静态资源Maven clean package时不要缓存了旧的dist目录。另外后端接口的上下文路径建议统一加/api前缀比如/api/machine/page这样不管是开发环境的Vite代理还是生产环境的Nginx转发只配一个前缀规则就完事。Vite开发环境联调在vite.config.js里这样配代理server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }后端接口明确返回统一结果格式我用的是Result对象字段包含code、message、data。code为200表示成功其他为失败。前端axios响应拦截器里统一处理错误提示不要在每一个页面都写一遍弹窗逻辑。4.4 数据库连接池和插件版本选择数据库连接池我就用HikariCPSpringBoot 2.x默认内置的就是它配置很小的几个参数就够了spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/farm_lease?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 30000这里有个小细节连接串里的serverTimezone一定不能省否则在高版本MySQL驱动下会报时区错误。allowPublicKeyRetrievaltrue是MySQL 8.x驱动在连接时需要的否则可能出现Public Key Retrieval is not allowed。插件和版本选择上我再提醒一遍SpringBoot 2.7.x对应MyBatis-Plus 3.5.xknife4j接口文档对应4.x版本Redis客户端用commons-pool2这些版本在Maven中央仓库里都有明确的兼容声明先到官方GitHub的README看一眼再引入能省去至少一天的依赖冲突排错。5. 常见问题排查与避坑实录5.1 SpringBoot版本太高引发的连锁问题这个问题在热搜里能排得上号太真实了。很多新手打开Spring Initializr默认下载的就是SpringBoot 3.4.x甚至更高版本然后引入旧版MyBatis-Plus Starter启动直接报错Invalid value type for attribute factoryBeanObjectType。原因很简单SpringBoot 3.x基于JDK17和Jakarta EE规范旧的MyBatis-Plus还没有适配。我的建议是如果你是做部署演示和写论文不要追求版本最新。SpringBoot 2.7.18加MyBatis-Plus 3.5.7加JDK8是目前兼容性最稳的组合。如果你确实需要JDK17那就整个技术栈一起升级SpringBoot换到3.2.x对应升级MyBatis-Plus 3.5.9以上还要注意javax.servlet替换成jakarta.servlet。这个决策在项目一开始就要定好不然后面每引入一个依赖都在踩版本坑。5.2 接口联调遇到跨域和参数接收问题前后端分离开发时跨域问题经常遇到。如果前端和后端都在本地最简单的方案是在后端加一个全局跨域配置Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true) .maxAge(3600); } }但注意如果用了allowCredentials(true)allowedOriginPatterns不能用*必须写具体域名这是浏览器规范限制。如果后端还配置了拦截器拦截器里要放行OPTIONS请求否则前端预检请求直接就被拦截了表现就是明明接口能通但浏览器一直报跨域。参数接收这块RequestBody接收JSON对象和RequestParam接收表单参数要分清楚。前端axios默认POST的是JSON后端接口要用RequestBody如果你是页面表单提交要用RequestParam或者直接让方法参数名匹配表单字段。最常见的问题是后端用RequestBody接收前端用form-data方式提交后端一直拿到null。5.3 部署上线时的端口、日志和静态资源问题本地开发一切正常部署到服务器就出问题这类问题多半集中在三个地方。第一个是端口问题Linux服务器上防火墙没有放行8080端口外网访问不到。检查的时候用curl localhost:8080看本机是否通如果本机通但外网不通优先查安全组和防火墙。第二个是日志里看不到有效的错误信息。提前把logback配置好至少要做到生产环境输出到文件、并按天滚动保留30天。排错第一件事就是看日志没有日志寸步难行。第三个是静态资源404。前端打包后的dist目录放进resources/static后如果接口返回的图片地址是写死的localhost:8080在服务器上就全部裂图。我建议所有图片上传后保存相对路径返回给前端时通过配置项拼完整路径这样切换环境时只需要改一个配置。5.4 典型问题速查表我把这个项目开发中最常见的问题整理成一张速查表建议你收藏一份遇到问题先对号入座问题现象可能原因解决思路启动失败提示数据库连接失败数据库服务没启动或URL、账号密码不对先用Navicat或命令行测试连接确认无误后再启动应用查询结果全是nullMyBatis-Plus没开启驼峰映射检查配置map-underscore-to-camel-case是否为true分页查询无效返回全表数据缺少分页插件拦截器注入MybatisPlusInterceptor并添加分页内置处理器前端请求报跨域错误后端CORS未配置或预检请求被拦截器拦截配置全局CORS并放行OPTIONS请求商品图片不显示图片返回的是绝对地址localhost统一用配置项拼图片访问前缀定时任务没有执行漏加EnableScheduling注解启动类上加上EnableScheduling接口报401但token明明有header名称前后端不一致前后端约定统一header名称如Authorization删除数据后查询还能看到逻辑删除字段类型或配置不对确认logic-delete-field值实体类上写TableLogic支付回调重复处理回调接口不是幂等增加唯一订单号事务状态校验或建唯一索引依赖冲突启动报错SpringBoot版本与Starter不兼容对齐版本号尽量用Starter自带管理版本这部分内容看起来琐碎但每一个都是我在实际开发中真实踩过的。你可以把它们写进开发文档或者项目README里论文的“系统测试”章节也可以作为测试用例的一部分。做这类SpringBoot全栈项目其实最忌讳的就是把代码写出来能跑之后就撒手不管。你把它当成一个真正的产品来做认真设计订单状态机、处理并发、对接回调、考虑部署运维这些思考过程和实际调通的细节远比代码本身有价值。我个人的体会是农机租赁这个业务场景特别适合练SpringBoot技术栈它既有电商项目的交易属性又有“线上交易线下履约”的与众不同的业务复杂性好好做完并复盘一遍之后你对SpringBoot生态的理解会明显不一样。答辩或者面试时不用讲太多虚的直接把你对支付幂等、定时任务、状态机约束这几个点的设计思路讲清楚已经可以证明你是一个有工程意识的人了。