资讯动态

SpringBoot校园自助商城系统:跳蚤市场与跑腿业务的设计与实现

发布时间:2026/10/13 21:37:14 来源:尧图企业网站定制
这几年陆陆续续帮不少同学看过毕业设计的代码校园商城这个方向几乎每届都有几个人选但大多数都把路子走窄了——只做一个商品发布加购物车下单的普通页面后台套个模板答辩演示完就没了。其实如果换成校园自助商城这种带跳蚤市场和跑腿业务的综合服务交易平台能发挥的空间完全不一样。一方面业务形态更接近真实电商场景另一方面跳蚤市场的闲置流转和跑腿任务的派单接单能够把用户角色、订单状态、支付流程这些核心点全部覆盖无论是应付毕设还是作为求职项目写进简历含金量都会高很多。这篇文章我就把SpringBoot校园自助商城系统的整体思路、表结构、核心实现和踩坑记录完整梳理一遍尽量讲清楚每个设计是为什么而不是光贴代码。正在准备计算机毕业设计、或者想在这个题目上做功能扩展的同学可以直接当参考手册用。1. 需求定位校园自助商城到底在做什么1.1 跳蚤市场与跑腿商城的业务差异校园商城如果只做买卖本质上就是简化版电商。但校园场景里有两个特别接地气的需求一个是毕业生离校、学期末换宿舍时大量闲置物品需要流转另一个是代取快递、代买食堂、代拿外卖这类跑腿服务。这两个业务形态差异很大跳蚤市场是C2C交易买方和卖方都是学生核心是商品信息展示、议价沟通、线下交付确认跑腿业务则是任务众包发布者付报酬、接单者出力核心是任务分配和状态流转。很多同学容易把这两块混在一个商品表里处理结果跑腿任务被当成普通商品销售状态管理一塌糊涂。我的建议很明确跳蚤市场走标准电商流程跑腿业务单独建任务表两个业务共享用户体系但订单和状态机必须分开。这样代码清晰答辩时也能讲出业务理解。1.2 角色模型与权限边界这个系统里的核心角色有三个普通学生用户、跑腿接单员、管理员。普通用户可以浏览商品、发布闲置、加入购物车、下单购买、发布跑腿任务、查看订单进度。跑腿接单员在普通用户功能基础上多一个接单权限能查看任务大厅、抢单、更新任务状态、确认送达。管理员负责用户管理、商品审核、分类管理、订单监管和跑腿任务监管。这里有一个设计细节跑腿接单员不需要单独建角色表用user表里的role字段区分就行。如果做成独立的角色对象反而复杂因为一个学生既可以发布跑腿任务也可以同时去接别人的任务身份是动态切换的。用role字段标记当前用户的身份类型是学生还是接单员再加上一个权限标识控制接口访问权限就可以了。1.3 功能清单梳理在实际动手写代码之前我建议先花半天时间把功能清单列出来因为后面所有表设计和接口设计都要对齐这个清单。用户模块注册登录、基本信息管理、密码修改、余额管理跳蚤市场模块商品发布、商品浏览搜索、商品分类、收藏、商品留言、下架、编辑购物车与订单模块加入购物车、修改数量、结算下单、订单列表、订单状态同步、取消订单、确认收货跑腿模块任务发布、任务大厅列表、抢单、任务进度更新、完成确认、报酬结算管理后台用户管理、商品审核、分类管理、订单查看、跑腿任务查看、统计看板功能清单画出来后你会发现这个项目的信息量其实不小但每个模块单独拆出来又都不复杂这正好适合毕业设计的体量。2. 技术选型和数据库设计2.1 SpringBoot MyBatis-Plus这套组合为什么稳技术选型上SpringBoot是当前Java后端毕业设计的主流选择没有悬念。具体版本需要注意一下如果环境是JDK 1.8就选Spring Boot 2.7.x如果是JDK 17可以直接上Spring Boot 3.x。我见过不少同学在自己电脑上装了新版JDK结果用Spring Boot 2.x启动报错折腾半天最后才发现是版本兼容问题所以这个一定要提前确认。持久层框架我推荐MyBatis-Plus。理由很简单单表CRUD几乎不用写SQL分页插件有现成支持代码量可以少写三分之一。有些同学一开始用的是Spring Data JPA但JPA的复杂关联查询在订单统计这种场景里写起来比较绕MyBatis-Plus配合XML可以灵活控制SQL更契合这个项目的需求。前端方面毕设通常不需要过度追求工程化一个Vue Element UI或者Thymeleaf模板方案就够用。选Vue的时候注意后端要解决跨域问题选Thymeleaf就省了跨域但前后端代码耦合一些。我更推荐前后端分离因为答辩时可以展示接口文档和独立前端项目看起来工作量更饱满。权限这块直接用Spring Security JWT。不要觉得安全框架难其实这个项目里只需要配置好登录接口放行、其余接口拦截、JWT解析校验三件事。JWT的好处是不需要做服务端session存储后端集群部署也不受影响而且移动端可以复用同一套接口。2.2 商品表与订单表的核心字段设计数据库我直接用MySQL。表结构设计是整个项目的地基很多同学上来就写代码写到订单时才发现少字段然后又回去改表非常浪费时间。我把自己觉得合理的核心表结构贴一下。商品表productCREATE TABLE product ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL COMMENT 发布者ID, title VARCHAR(100) NOT NULL COMMENT 商品标题, description TEXT COMMENT 商品描述, price DECIMAL(10,2) NOT NULL COMMENT 价格, original_price DECIMAL(10,2) COMMENT 原价或参考价, category_id BIGINT COMMENT 分类ID, status TINYINT DEFAULT 0 COMMENT 0在售 1已售 2下架, view_count INT DEFAULT 0 COMMENT 浏览数, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;商品图片不要直接存到product表里单独建product_image表一张商品对应多张图片排序用sort字段控制。这样做的好处是不会因为图片地址太长让主表字段变得臃肿也方便后续扩展图片数量。订单表要注意表名不要叫order因为order是MySQL的SQL关键字写SQL时每次都要加反引号很麻烦。我习惯用trade_order或者orders。订单表核心字段CREATE TABLE trade_order ( id BIGINT PRIMARY KEY AUTO_INCREMENT, order_sn VARCHAR(32) UNIQUE NOT NULL COMMENT 订单编号, buyer_id BIGINT NOT NULL COMMENT 买家ID, seller_id BIGINT NOT NULL COMMENT 卖家ID, product_id BIGINT NOT NULL COMMENT 商品ID, amount DECIMAL(10,2) NOT NULL COMMENT 成交金额, status TINYINT DEFAULT 0 COMMENT 0待付款 1已付款待交付 2已交付 3已完成 4已取消, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;跳蚤市场的订单和电商订单最大的区别在于c2c场景下订单里同时有买家ID和卖家ID这两个字段都不能缺。我在某个同学的项目里看到他只存了买家ID结果商品成交后卖家界面查不到状态后来只能加字段补救。2.3 跑腿任务表的状态机设计跑腿任务表errand_task的状态设计是整个模块的关键。先把业务流转想清楚发布者创建任务任务初始待接单接单员抢单后变为进行中任务完成后接单员标记送达等待发布者确认发布者确认后任务完成报酬结算。CREATE TABLE errand_task ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL COMMENT 发布者ID, taker_id BIGINT COMMENT 接单员ID, task_title VARCHAR(100) NOT NULL COMMENT 任务标题, task_type TINYINT COMMENT 1代取快递 2代买 3代送 4其他, reward DECIMAL(10,2) NOT NULL COMMENT 报酬, from_location VARCHAR(255) COMMENT 起点, to_location VARCHAR(255) COMMENT 终点, describe_detail TEXT COMMENT 任务描述, status TINYINT DEFAULT 0 COMMENT 0待接单 1进行中 2已完成 3已取消, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;状态机设计这里有一个要点不要让接口随意修改任务状态每一个状态迁移都要做合法性校验。比如只有状态为0的任务才能被抢单只有状态为1且当前用户是接单员才能标记送达。如果不做校验一个请求就能把任务从待接单直接改成已完成业务逻辑就崩了。2.4 登录鉴权的方案取舍登录方案用JWT生成token后在拦截器里校验。流程是用户登录成功后后端用用户ID和过期时间生成一个token返回前端后续请求在header里带Authorization: Bearer token。后端写一个拦截器解析token解析不到就返回401解析出来就把它放到ThreadLocal里方便后续获取当前用户。这里有一个好习惯写一个LoginUser工具类里面用ThreadLocal存当前登录用户信息提供getUserId()、getUserRole()这类静态方法。这样业务代码里想取当前用户时不用到处从请求头里手动解析token代码会很干净。我在开发时一直坚持这个写法到后面写多个模块时能省很多事。redis在这个项目里主要用来存验证码和做并发控制。手机验证码登录这种功能如果不想对接短信服务商可以用Redis生成六位随机码并设置五分钟过期来模拟演示时把验证码打印到后端日志里。这样Redis的使用也体现了答辩时是一个加分项。3. 核心功能模块的实现细节3.1 商品发布与图片上传的实现逻辑商品发布跳蚤市场这个模块的信息量其实不小。首先这个模块的注入点在于“C2C交易”本身买家和卖家的交互逻辑、商品状态同步、交易安全都是可以展开讲的内容。SpringBoot项目实现时这类业务一般会用Controller Service Mapper的结构商品模块的特别之处在于Service层的事务边界怎么划得想清楚。发布商品目前来看是用户自己的行为不需要审批但商品创建后如果要新增一个“管理员审核”环节业务链会完整一些也能把AOP或消息通知这类技术点引出来。这个看选题要求不是必做项。图片上传我建议先用本地存储加虚拟路径映射的方式。配置一个上传目录然后通过WebMvcConfigurer把上传目录映射成访问URL。上传接口用MultipartFile接收文件判断文件类型和后缀名重命名为时间戳加随机数保存。这里有两个很容易踩的坑一个是上传后访问不到图片几乎都是静态资源配置没加另一个是中文文件名乱码统一用UUID命名可以规避。从实现角度讲这几个点是跳蚤市场必写的商品列表接口支持分页、关键词搜索、分类筛选、排序商品详情接口要同时返回商品信息和图片列表、卖家的信誉信息商品下架接口只允许商品所属用户操作自己的商品商品修改管理员有强制下架权限用户有编辑权限跳蚤市场商品下架后如果这个商品有未完成订单不能直接物理删除只能改状态。这是业务层面的一个硬性约束写代码前先把这个规则定下来后面就不会乱。3.2 购物车与订单提交流程购物车是标准的加购加结算功能但跳蚤市场里的购物车有一个特殊性每一个购物车项对应一个商品而且这个商品是唯一的没有规格。所以购物车表不需要存数量属性只要记录user_id和product_id两个字段。下单接口是整个项目里最容易出并发问题的地方。我推荐的实现方式是前端点击下单后后端先判断商品状态是不是在售然后在事务里把商品状态改成已售再创建订单。这里必须是用事务加行锁而不是先查再改不然两个用户同时下单同一个商品就都判断成功了。下单成功之后如果接入了模拟支付就用一个payment_log表记录支付流水支付成功后把订单状态改成已付款。没有支付功能的话直接把创建出来的订单视为已付款跳蚤市场场景里大多数是线下交付这个简化是合理的。3.3 跑腿任务从发布到结算的完整链路跑腿任务的核心链路是发布、抢单、执行、确认、结算五步。用代码做的时候我把它们拆成五个接口每个接口只做一件事状态合法性判断全部放在Service层。发布接口很简单插入任务记录状态为待接单。抢单接口就要多考虑一些了因为同一个任务可能有多个接单员同时去抢只有一个能抢到。实现时不建议用先查再更新的模式而是直接用带条件的update语句条件里加上status 0SQL写成这样boolean update errandTaskService.update(new LambdaUpdateWrapperErrandTask() .eq(ErrandTask::getId, taskId) .eq(ErrandTask::getStatus, 0) .set(ErrandTask::getTakerId, currentUserId) .set(ErrandTask::getStatus, 1));这条update语句执行后如果影响行数是1说明抢单成功是0说明被别人先一步抢走了。这是很典型的乐观锁思路不用Redis也能保证不重复接单。任务进行中接单员可以多次更新进度比如填写备注或者上传照片。发布者确认完成后任务状态变为已完成同时给接单员结算报酬。如果账户余额功能已经做了就直接从发布者的余额里扣减到接单员余额如果没有余额就只做状态变更在线下完成报酬交付。3.4 后台管理模块怎么快速搭后台管理不用每个业务都从头写。我的做法是做一个通用的用户管理页面和商品管理页面然后加一个简单的统计数据看板。统计看板可以统计每个分类下的商品数、每日注册用户数、跑腿任务完成率这些用SQL聚合就能算出来。商品管理页需要支持分页搜索和上下架操作管理员不是对商品有多大的运营需求而是要能控制非法物品的上架。所以商品列表加一个关键词搜索和一个状态筛选就够用了。很多同学把后台管理做成一个独立的工程为的是看起来工作量饱满但我的建议是后台和前台放在同一个SpringBoot工程里只是用不同的路径前缀区分比如/api/admin。这样部署简单代码也不会太碎片化。当然如果导师要求独立后台那另说。4. 开发中容易踩的坑与排查记录4.1 分页查询SQL执行报错MyBatis-Plus自带分页但是版本不同需要注意。在旧版本里需要自己配置PaginationInnerInterceptor配置完成后分页查询返回的是IPage。我遇到过几次同学把分页插件的配置类漏掉结果前端传了pageNum和pageSize后端返回的全量数据还以为是前端分页没处理。另外分页插件在连表查询时不生效这个也常见。比如查商品列表要连分类名称、连卖家昵称如果直接在Mapper XML里写自定义SQL就要手动使用Page参数或者把分页条件放到wrapper里。MyBatis-Plus的官方文档有说明但不少人没注意到联表分页这个坑排查时报错信息还不明显更多的是数据量多了之后内存占用变大。建议是尽量用MyBatis-Plus的单表查询能力处理简单数据连表场景写独立SQL并显式传入IPage参数这样两边都能稳定工作。4.2 图片上传和回显的路径问题图片上传后回显404这个Bug我见了太多次。本地存储图片时上传保存的路径是真实磁盘路径但前端要通过URL访问必须有静态资源映射。我一般这样写Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/upload/**) .addResourceHandler(file: uploadDir /); } }注意这个映射的路径末尾一定要加斜杠不然会映射失败。另外本地存储方案在项目打包部署到服务器之后会有个问题就是上传目录和jar包所在目录不一致导致资源映射找不到所以上传目录我建议配置成动态的比如从application.yml里读取不要写死。4.3 并发抢单导致的重复接单这个问题如果不用带条件的update语句而是用先查询再更新的方式就会有竞态条件。两个接单员同时查询到任务状态是0都走到更新逻辑就有可能双成功。解决方式上面提到了把状态判断放到update的where条件里。如果要更严谨可以再加一层唯一约束比如taker_id和task_id的唯一索引但这属于兜底方案。在Service层用乐观锁更新已经足够应对绝大多数毕设场景。我建议把这个设计单独在答辩时列出来讲说明你理解了并发问题虽然实现不复杂但体现了思路。4.4 前后端联调时的跨域和日期格式问题前后端分离时跨域几乎必遇到。在SpringBoot里写一个CorsConfig允许指定前端地址跨域然后spring.mvc配置里要把allowedHeaders开放。之前有同学只配了allowedOriginPatterns忘了allowedHeaders结果前端请求带自定义header时预检请求直接失败这个排查了挺久。日期格式的坑也很隐蔽。后端返回的LocalDateTime会序列化成带T的格式比如2024-06-01T12:30:00前端展示很难看。解决方案是给全局配置Jackson的日期格式化在application.yml里设置spring.jackson.date-format。还需要指定时区不然可能差8个小时这个问题不仔细看还真发现不了。4.5 订单号生成的唯一性订单号如果只是用时间戳拼接随机数并发高的时候还是可能出现重复。其实简单做也行但既然都写了建议用时间戳加用户ID加随机数生成一个32位订单号。订单号生成接口加一个唯一索引兜底生成时循环判断已经能防止大多数重复。如果想用分布式ID也可以引入开源组件但对毕设项目来说有点过度设计。把时间戳和随机数组合逻辑简单且不容易出问题这个方案更适合这个项目。5. 个人经验与后续扩展建议整个项目开发下来我最深的感受是毕业设计的核心不是把功能堆得多满而是能不能把每个设计决策解释清楚。比如表结构为什么要拆图片表、跑腿任务为什么独立建模、并发抢单为什么要用带条件的更新这些想清楚了写代码只是时间问题。有一个建议想特别提一下项目做完以后一定要把数据库的ER图、接口文档、核心模块流程图整理出来不光是答辩要用自己后面复盘也有帮助。整理的过程中你会发现一些表结构或者代码逻辑不够合理的地方这些都可以优化。如果后续想在这个项目上继续扩展方向其实不少。可以加入WebSocket实时通知有人在商品下面留言、跑腿任务被抢单时给用户推送一条在线消息也可以接入真正的微信支付或支付宝沙箱支付把支付回调的逻辑补上就更接近生产项目了。还可以做一个简单的推荐算法根据用户浏览和收藏记录推荐闲置商品这个方向做出来的东西会更有亮点。最后讲一个实在的小技巧写代码的时候顺手写单元测试尤其是订单服务和抢单服务这类核心逻辑哪怕只是用JUnit跑几个用例到答辩前调试功能时你会感激自己当时留了这些测试。真心建议不要等到所有功能写完再一起去调那是一种可以避免的折磨。

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

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

免费获取报价 →
↑