☰
校园二手交易系统毕设全攻略:Spring Boot+安卓+智能推荐
2026/10/9 3:32:01 网站建设 项目流程

每年毕业季总能遇到一类提问:“学长,我想做校园二手交易平台,用什么技术最合适?”“Java写这个会不会太老?”说实话,校园二手交易这题目确实被写烂了,但绝大多数人交上来的东西还停留在“商品发布+浏览+联系买家”的演示层面,既没有完整的交易闭环,也谈不上“智能”。如果你打算拿它当毕设,又刚好想把分数往上抬一抬,那这篇东西就是冲着你来的。我会从需求分析、技术选型、数据库设计、核心接口、智能推荐、安卓端实现一路讲到测试答辩,里面的图和代码都是我自己在类似项目里验证过、能直接抄的近路。

1. 这个经典选题背后的真实需求与常见误区

1.1 校园二手市场为什么绕不开“管理”而不是“交易”

很多学生一上来就把这个题目理解为“淘宝校园版”,这恰恰是最容易跑偏的地方。校园二手交易的痛点从来不是“没有平台”,而是人与人之间的信任成本和信息匹配效率。你的项目叫“校园二手智能交易管理系统”,核心词不只是“交易”,还有“管理”——管理用户身份、管理商品生命周期、管理订单状态、管理双方评价与纠纷。如果只做商品发布和留言,那连课设都勉强。

我建议你把这个系统拆成四条业务线:

  • 用户管理:学生认证、校级范围限定、信用档案、举报与封禁记录。
  • 商品管理:发布、修改、上下架、审核(如果有后台)、类别与标签、图片。
  • 订单交易管理:发起订单、双方确认、交付状态流转、完成/取消。
  • 智能辅助:推荐匹配、价格参考、信用评分、热门/闲置时间提醒。

答辩时最亮眼的部分是第四条。哪怕算法简单到只是“基于同学院+同分类+关键词相似度”,名字叫“智能推荐”也比做成普通列表更有竞争力。后面第4章我会直接给出一种不需要机器学习框架也能跑的落地方案。

1.2 不要一上来写“智能推荐”,先把事务边界画清楚

不少同学喜欢先研究协同过滤算法,再把算法往半成品系统里硬塞,最后代码和业务互不搭界。正确的做法是:先把商品和订单的完整生命周期跑通,再给某个环节加入算法或规则。整个项目分三层去思考:

  1. 数据层:哪些表会频繁读写、哪些数据需要事务保护(库存、订单状态、余额)。
  2. 业务层:下单时同时扣减商品状态和创建订单,必须在一个事务里完成。
  3. 智能层:只读数据、计算结果、返回推荐列表或参考价,不能反向修改核心业务数据。

这样做的好处是即使推荐逻辑拍脑袋写的,也不会把交易搞崩。我在强调架构的同时,也在教身边学弟们怎么避免那种“代码很多但别人看不懂”的自嗨型毕设。

2. 技术选型:安卓端与后端的一整套取舍思路

2.1 后端为什么选Spring Boot,而不是直接写Servlet/JSP

题目里带“Java”,最稳妥、也最容易答辩通过的组合是后端用Spring Boot + MyBatis Plus + MySQL,客户端用原生Android(Java实现)。除非你面试方向明确要做Vue,否则别给自己加戏。

选Spring Boot的理由不是“现在流行”这种空洞的话,而是它帮你解决三个毕设级别的痛点:

  • 嵌入式Tomcat:一个jar包直接跑,部署到服务器上不用额外配Tomcat,演示环境迁移成本极低。
  • starter依赖体系:Web、AOP、Validator、Redis、测试这些模块通过坐标引入,不用自己拼一大份XML。
  • 与MyBatis Plus配合:单表CRUD几乎不用写SQL,写复杂查询时再自己补注解SQL。

下面是一份可以直接用的核心依赖,版本按你的环境自行调整:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>

2.2 数据库选型与连接配置的注意点

MySQL 8.0以上在数据库连接串里必须显式指定时区,否则部署到非中国区的云服务器后时间会差8小时。这是我给一个学弟查了两天的坑,先列在这里:

datasource: url: jdbc:mysql://localhost:3306/campus_secondhand?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: your_password

MyBatis Plus的驼峰映射默认开着,所以你的Java实体类里写createTime,数据库字段写create_time,它能自动对映,不用每个字段都加@TableField。要注意的是逻辑删除:建议在商品表和订单表加一个deleted字段并用@TableLogic,这样所有默认查询都会自动带上deleted = 0条件。这个设计在答辩时很好讲:“所有删除都是软删除,为了保留完整的交易追溯链。”

2.3 安卓端是原生还是跨端,我的建议

说句实在话,如果只是为了毕设演示,原生Android + Java代码就够了。理由如下:

  • 题目里明晃晃写着“APP”,答辩时你需要真机或模拟器现场操作,原生应用启动快、少一层框架转译,少一个崩溃理由。
  • RecyclerView + Glide + OkHttp这套组合足够完成列表、图片加载、网络请求。
  • 抗辩时你可以说“客户端使用了Material Design组件规范”,比说“我用了一个封装好的低代码平台”要硬气。

如果切换成Flutter或React Native,除非你已经很熟,否则不建议在毕设周期内冒险。很多人忽视了一个点:安卓模拟器和后端在同一台电脑上时,测试环境地址要写10.0.2.2而不是localhost,Real机器用局域网IP时还需要在AndroidManifest里允许usesCleartextTraffic,否则走不了HTTP明文请求。这个坑我在后面专门列了一条。

3. 数据库模型与核心接口:从一张订单到一套流程

3.1 核心表结构:别贪多,五张表支撑闭环

建议不要设计二三十张表来显示工作量,那只会让答辩提问漏出马脚。下面五张表加一个中间表就足够撑起全套业务:

表名核心字段说明
userid, student_no, nickname, avatar, credit_score, campus学生认证与信用分
categoryid, name, parent_id分类树,一般两级
productid, user_id, category_id, title, description, price, trade_status, images, view_counttrade_status枚举:0在售、1锁定、2已售、3下架
trade_orderid, product_id, seller_id, buyer_id, status, type(闲置/求购), create_timestatus:0待双方确认、1进行中、2已完成、3已取消、4纠纷
commentid, order_id, user_id, score, content交易完成后双向评价
favoriteid, user_id, product_id, create_time收藏,也是推荐算法的输入

为什么订单表里要保留buyer_id和seller_id各一份?因为“买”和“卖”是两个角色,一条订单必须能关联两本账。交易状态机必须在后端控制,不能由客户端自由跳转。我用枚举常量管理状态,不再用乱糟糟的魔法数字:

public enum TradeStatus { ON_SALE(0, "在售"), LOCKED(1, "交易锁定"), SOLD(2, "已售出"), OFF_SHELF(3, "已下架"); private final int code; private final String desc; // 构造方法、getter... }

3.2 发布、浏览、下单三个接口要讲清楚“为什么这么设计”

发布商品:客户端上传图片走独立接口,先拿到图片URL,再提交商品信息。好处是就算商品信息填写失败,图片不会反复传。图片服务器可以直接用本地文件存储,也可以接入云OSS,毕设用本地路径加上一个Nginx反向代理就够。

@PostMapping("/product") public Result<Void> createProduct(@RequestBody ProductDTO dto, @RequestAttribute("userId") Long userId) { if (!campusVerified(userId)) { return Result.error(403, "未通过校园认证"); } productService.create(dto, userId); return Result.success(); }

浏览商品列表:不要一次性select *返回全表。分页是基本功,排序规则要显式声明。我常用的是“SORT = HOT / NEW / PRICE_ASC / PRICE_DESC”四选一,每个都对应一个明确SQL条件。

LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Product::getTradeStatus, TradeStatus.ON_SALE.getCode()) .eq(Product::getDeleted, 0) .orderByDesc(Product::getCreateTime); page(product, wrapper);

下单:这是整个系统里最需要事务保护的地方。要点是用SELECT ... FOR UPDATE锁住商品行,再检查状态是否为在售,是则置为锁定并创建订单。如果没锁行,两个用户同一秒同时下单,就会出现超卖。

@Transactional public boolean createOrder(Long productId, Long buyerId) { Product product = productMapper.selectByIdForUpdate(productId); if (product == null || product.getTradeStatus() != TradeStatus.ON_SALE.getCode()) { throw new BizException("商品不存在或已被下单"); } int updated = productMapper.updateTradeStatus(productId, TradeStatus.ON_SALE.getCode(), TradeStatus.LOCKED.getCode()); if (updated == 0) { throw new BizException("手慢了,商品已被锁定"); } orderMapper.insert(buildOrder(product, buyerId)); return true; }

3.3 为什么引入Redis,而不只靠MySQL

Redis在这里至少干三件事:

  • 首页商品缓存:热门列表一次性放入Redis,过期时间5分钟,扛住并发浏览。
  • 简单分布式会话:登录后用UUID生成token,以userId为key存入Redis,客户端每次请求带token。比传统HttpSession更适合多端。
  • 防重复提交:下单时用“商品ID + 用户ID”作为Redis key,加上setIfAbsent做幂等,重复点击同一商品时直接拦截。

毕设答辩时这一层非常加分,因为能说明你考虑了性能和并发控制。缓存与数据库一致性问题不用展开太深,只要保证商品状态变更时主动删除对应缓存,就能规避绝大部分脏读。

4. “智能交易”到底怎么落地:推荐、搜索与信用评分

4.1 不带机器学习框架的推荐方案:标签向量 + 最近邻

这是整个项目最容易吹嘘也最容易翻车的地方。我的经验是别用Spark、别用PyTorch,就把服务端Java写个轻量计算器:

  1. 为每个商品打N个标签,例如“二手”“教材”“考研”“电子”“九成新”。
  2. 用户的历史行为(收藏、发布、成交)也能收集成标签向量。
  3. 计算当前用户向量与待推荐商品向量的余弦相似度,取Top10。

向量存在MySQL里用临时计算,数据量几千条毫无压力。核心代码很短:

double cosineScore(List<Double> userVec, List<Double> itemVec) { double dot = 0, uNorm = 0, iNorm = 0; for (int i = 0; i < userVec.size(); i++) { dot += userVec.get(i) * itemVec.get(i); uNorm += userVec.get(i) * userVec.get(i); iNorm += itemVec.get(i) * itemVec.get(i); } return dot / (Math.sqrt(uNorm) * Math.sqrt(iNorm) + 1e-6); }

如果时间充裕,可以再加一条改进:从favorite表里找“和你收藏同一件商品的人,还收藏了哪些商品”,做一个基于物品的协同过滤。这条逻辑编程不难,但是答辩时的“智能含量”直接提升一个档次。

4.2 信用评分:把“勤劳用户”从“放鸽子用户”里区分出来

校园二手的关键问题是交易双方不一定认识,需要在系统层面建立信任。信用分建议按加权公式计算:

  • 初始分100。
  • 完成一单并收到好评,加2分,上限150。
  • 超时未履约被投诉,扣10分。
  • 累计3次未按时交付,禁止发布商品14天。
public void afterTradeCompleted(TradeOrder order) { int delta = 2; if (order.getCommentScore() != null && order.getCommentScore() < 3) { delta = -10; } userService.changeCredit(order.getSellerId(), delta); }

分数、徽章和权限三者联动,才是评分系统的意义。答辩时很多老师会问“凭什么扣分”,你只要回答“每次扣分都有对应的评价或举报记录支撑”即可。建议为每个订单维护一条trade_log流水表,写清是“卖家延迟发货”还是“买家未按约定取件”,申诉界面也能给证据。

4.3 搜索排序不只有SQL的LIKE

如果商品标题像“九成新高数教材+考研英语”,你用LIKE '%考研%'查没问题;但如果用户只搜“数学”,你就得考虑同义词关联。最简单的增强是建一个keyword_alias表,把“数学”“高数”“数学分析”映射到同一组词条。搜索时先查别名,再查标题和描述。排序权重我建议这样算:

排序分 = 关键词命中标题权重3 + 命中描述权重1 + 商品发布时间新鲜度衰减分

时间衰减可以用exp(-hours/72)之类的指数,也可以直接用“发布三天内的商品加固定权值”,简单实用。这块和机器学习区分开,你在论文里写“基于规则的多因子排序模型”,导师不会觉得你在水。

5. 安卓APP端的关键实现细节与踩坑记录

5.1 网络层:用Retrofit还是OkHttp

原生Android比较合理的组合是Retrofit 2 + OkHttp + Gson。不要把业务代码写死在Activity里,建议做成三层:

  • API接口层:一个Service接口定义所有请求。
  • Repository仓库层:管理数据来源(网络/缓存)。
  • ViewModel层:通过LiveData通知UI刷新。

Retrofit定义示例:

public interface SecondHandApi { @POST("api/auth/login") Call<Result<LoginVO>> login(@Body LoginDTO dto); @GET("api/product/recommend") Call<Result<List<ProductVO>>> recommend(@Query("page") int page, @Query("size") int size); }

登录后token要保存到SharedPreferences,同时通过OkHttp的Interceptor在每个请求的Header里追加Authorization。切记token不要放明文日志里,否则打印日志时会被同学看到。

5.2 图片上传与压缩:一个必须处理的体积问题

手机原图动不动5MB,如果直接传给后端,既慢又占存储,联调和面试演示时还会把WiFi跑满。解决方式很常规:

  1. Bitmap按最大边不超过1280像素缩放。
  2. 压缩质量设为85%,转成JPEG。
  3. 直接在后台把byte[]上传到后端,后端再用MultipartFile接收。

安卓端压缩代码:

private File compressImage(File file) { Bitmap bmp = BitmapFactory.decodeFile(file.getAbsolutePath()); int maxWidth = 1280; if (bmp.getWidth() > maxWidth) { float ratio = maxWidth / (float) bmp.getWidth(); bmp = Bitmap.createScaledBitmap(bmp, maxWidth, (int)(bmp.getHeight() * ratio), true); } File outFile = new File(getCacheDir(), "compressed_" + file.getName()); try (FileOutputStream fos = new FileOutputStream(outFile)) { bmp.compress(Bitmap.CompressFormat.JPEG, 85, fos); } bmp.recycle(); return outFile; }

5.3 容易让项目当场翻车的三个坑

  • 明文HTTP被拦截:Android 9开始默认禁止明文流量,真机调试接口如果返回CLEARTEXT communication not permitted,在AndroidManifest.xml的application节点加上android:usesCleartextTraffic="true"。
  • 网络操作放在主线程:跨进程访问后端必须放到子线程,用enqueue回调或RxJava,直接在onCreate里同步请求会抛出NetworkOnMainThreadException。
  • RecyclerView复用导致图片闪烁:Glide加载图片时一定要override固定宽高并提供placeholder,否则列表滚动时会出现旧图闪一下再变新图的现象。

5.4 “管理系统”的另一个形态:后台管理端

标题里的“管理系统”不一定非得做成Web后台,但建议你为管理员做一个Web管理页面或再补一个简易Web管理模块。功能就三块:用户列表、商品审核、举报处理。技术上用Thymeleaf加简单后台模板就够了,服务端共用同一套Service层。

这个后台不是应付差事,而是证明你有“系统级”思维:前端用户、后台管理、服务端API能构成一枚完整的项目架构。答辩演示时,直接在后台把某个违规商品下架,然后切到APP刷新看变化,这套联动演示比单独介绍功能截图要生动得多。

6. 项目测试、打包与毕业答辩准备

6.1 后台功能测试不只测“能点通”

不要只写“打开APP,点按钮,能显示列表”就完事。毕业设计测试要体现边界情况和数据一致性。我的建议是把核心流程写成一套测试用例表:

编号场景前置条件操作预期结果
TC01正常登录已注册学生用户输入账号密码登录成功,返回token
TC02密码错误已注册用户输入错误密码返回401,提示重新输入
TC03发布商品缺图登录状态无图片直接提交返回参数校验错误
TC04并发下单同一商品两个不同用户同时点击购买只有一个成功
TC05交易完成订单状态进行中双方确认完成商品变为已售出,双方信用分变动
TC06未认证用户发布游客登录点发布按钮跳转认证页面/拒绝

这六条用例足以覆盖主干链路,论文里写“功能测试模块覆盖率达到XX%”时,至少手里有真材实料。Spring Boot自带spring-boot-starter-test,可以顺手写两个针对Service的@Transactional单元测试,让代码覆盖率报告更好看。

6.2 打包部署的最后一公里

后端建议用Maven打包成一个jar,部署到云服务器时用nohup java -jar xxx.jar --spring.profiles.active=prod &启动。配置文件要区分application-dev.yml和application-prod.yml,数据库密码、Redis密码不要硬编码,放到环境变量或JVM启动参数里。

安卓端打包正式签名APK时,记得保证minifyEnabled不要随便开shrinkResources,毕设项目开启混淆很容易把Retrofit的接口类搞挂。演示前检查一遍签名包能正常安装,别到答辩现场才发现debug包没法覆盖安装。

6.3 答辩演示脚本:两分钟讲清一个核心设计

演示不需要完整走一遍所有功能,但要按业务流程一口气串下来。我的建议顺序是:

  1. 登录 → 首页推荐列表(点这一点要强调“这里的商品是根据谁收藏了什么算的推荐”)。
  2. 发布一个商品并上传图片(强调压缩和图片服务设计)。
  3. 换一个账号模拟买家,搜索、收藏、下单(强调事务锁与防重复提交)。
  4. 双方确认完成,展示信用分变化(强调事务日志)。
  5. 打开后台管理端,下架一个违规商品并回APP验证(强调软删除与状态联动)。

老师后续最可能问的问题是“如果用户量到一万,这个系统哪里是瓶颈?”你不用答得很玄,就说“商品表和订单表需要加索引,图片建议迁到对象存储,推荐计算可以改离线预计算”。这几句话一出口,你已经甩开一堆背书选手。

7. 我从这个项目里总结的几条实操经验

项目做完回头审视,我最想强调的一点是:不要为了“智能”两个字硬上高深算法。校园二手交易的数据量就几千条,真正的复杂性在交易状态和信任机制里。把“商品锁定状态机”“信用分与权益联动”“基于用户行为的相似度推荐”这三件事做扎实,即便技术上很朴素,也远比光是套公式更打动人。

另外,毕设不是软件工程毕业论文,没必要把架构搞得飞起。如果你能在一个月内把“发布-浏览-下单-完成-评价”的闭环跑通,再花两周把推荐和后台管理补上,后面基本就是查漏补缺的事了。写论文时尽量别用“使用了大数据分析技术”这种词,改用“基于用户行为的轻量级推荐策略”这种准确表述,评审老师反而觉得你认知清醒。

最后分享一个让项目更像“作品”的小技巧:给商品图片加水印、给APP启动页加一个学校名字的定制化入口、在用户协议里写明“仅限校园内部师生使用”。这些小细节不会变成论文得分点,但能让你在演示时从“这可能是外包”变成“这是认真做的”。做毕设说到底是在做一件能证明你完整开发能力的作品,请把它当成你未来简历里的第一份项目经验来对待。

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

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

立即咨询