☰
uniapp+Java后端交友软件源码落地:技术选型、环境搭建与避坑指南
2026/9/28 12:14:12 网站建设 项目流程

简介:基于uniapp跨端框架和hbuilderX编辑器打造,采用Java后端支撑的交友社交软件完整项目源码,主要面向毕业设计、课程实践及移动端社交产品开发者。软件同时适配小程序与App端,前端交互与后台服务均已调试完成,核心功能包括用户资料展示、关键词搜索、兴趣匹配、私信聊天、活动组织以及婚礼场景模板,用户能够自定义界面布局与功能模块,灵活满足个性化需求。资源包共四百八十个文件,主体包含二百一十五个前端逻辑脚本、九十二个Java服务端类、四十七个页面结构和三十一个样式表,同时收录多种图片、字体及工程配置文件,压缩包大小约十四点五兆,整体目录组织清晰,便于快速定位前端代码与后端接口。项目采用典型的MVC分层和前后端分离通信方式,通过接口交换数据,对学习跨端开发、接口设计、用户认证与社交业务逻辑很有帮助。目前已有四百一十二人学习下载,作为毕业设计参考资料或二次开发起点,均有较强的参考价值。

1. 这个仿探探/树洞项目到底在解决什么:先看清源码的边界再动手

很多找“基于uniapp+hbuilderX的Java后端交友社交软件设计与实现源码”的人,想解决的并不是“怎么设计一个社交App”,而是“我如何在答辩前把它跑起来,并且能讲明白”。标题里的三个词已经划好了技术栈:前端用 uniapp 一套代码同时做 App、微信小程序和 H5,开发工具是 HBuilderX,后端是 Java 写的接口服务,典型组合是 Spring Boot + MySQL。这类源码的任务通常是把交友软件的主链路打通:注册登录、滑卡片、互相喜欢、好友私聊、个人动态。适合计算机相关专业做毕业设计、前后端分离想补全栈、以及买了源码想自己改造二次开发的人。

但拿到源码并不等于毕业设计通过了。源码里真正藏坑的地方,不在业务代码而在环境:JDK 版本、HBuilderX 的编译配置、数据库连接参数、后端接口地址是不是写死成了别人电脑的 IP。这篇笔记不替某个具体源码包背书,只给你一套最可靠的落地路径:先判断技术选型,再按步骤跑通,最后对照避坑清单排查。照着走,至少能把这个项目从“黑匣子源码”变成“自己讲得清的作品”。

2. 为什么是 uniapp + HBuilderX + Java 后端:技术选型与交互流程拆解

2.1 前端只有一份代码,却要跑 App、小程序和 H5:uniapp 与 HBuilderX 的分工

uniapp 是一个“编写一次,多端运行”的前端框架,底层基于 Vue 语法。HBuilderX 是 DCloud 推出的编辑器,内置了 uniapp 的运行、编译、打包能力。很多新手把 HBuilderX 当成“只能写前端代码的 IDE”,实际上它更像一个集成工具链:你能在同一个窗口里点击“运行到浏览器”“运行到手机 App 基座”“运行到小程序模拟器”,HBuilderX 会把 uniapp 语法转译成对应平台能识别的代码,并完成资源打包。

这个组合在交友社交项目中非常合适,因为交友产品的用户来源很杂:有人从微信小程序进来,有人从安卓应用市场下载,有人直接点开 H5 网页。如果给每个端单独写一套,工作量至少是三倍。用 uniapp 先把前端页面和业务逻辑写一遍,再按平台差异做条件编译,就能覆盖绝大多数场景。比如滑动卡片组件用到的触摸事件,在 App 端和 H5 端行为基本一致;但微信小程序的登录接口与 App 不同,就需要用uni.login配合条件编译区分。

HBuilderX 在运行 uniapp 项目时,实际上会执行两条编译路径:一条是 Web 路径,生成浏览器能直接访问的静态资源;另一条是 App 基座路径,把前端代码打包进一个带原生能力的 APK 调试基座。所以你只要写好一套 Vue 页面,HBuilderX 负责把它翻译成对应平台需要的形态。这也是为什么能靠标题里的“前端 uniapp + HBuilderX”跑遍三个端。

提示:HBuilderX 只是编译器和运行器,真正的前端代码还是 uniapp 工程。因此拿到源码后,第一件事不是看代码,而是确认它是不是一个完整的 uniapp 项目,目录里必须存在pages.json、manifest.json和App.vue。缺少任何一样,HBuilderX 都无法正常编译。

2.2 Java 后端该选 Spring Boot 还是 SSM:交友项目不该为了“学过”而选老框架

标题里只说 Java 后端,没有限定框架,但市面上常见源码几乎都用 Spring Boot。不是 SSM(Spring + SpringMVC + MyBatis)不能写,而是 Spring Boot 帮你省掉了大量 XML 配置,内嵌 Tomcat,直接java -jar就能启动,对需要快速跑通的毕业设计更友好。交友项目的业务并不复杂:用户、匹配、聊天、动态,核心工作量集中在接口设计和数据表关系上,Spring Boot 的自动配置能把这部分成本压到最低。

如果源码是 SSM 架构,也不代表不能跑,只是你会多花半天配 spring-mvc.xml、mybatis-config.xml 和 web.xml。我的建议是:只要拿到了 Spring Boot 源码,优先使用它自带的 Maven 依赖版本,不要手动升级到最新版;如果拿到的是 SSM 源码,优先查看是否有pom.xml,并确认 JDK 是 1.8 还是 11。很多二手源码里带着一堆用不到的依赖,最典型的是把 Spring Boot 从 2.x 升到 3.x,结果 JDK 不匹配,启动直接报错。

从数据访问层来看,Spring Boot + MyBatis Plus 是目前交友项目源码里最常见的组合。MyBatis Plus 提供了单表 CRUD 的封装,不需要为user、like_record这种表写一堆 XML,你只需要定义实体类和BaseMapper接口,就能完成基本增删改查。需要自定义 SQL 时再在 Mapper 里写 XML,比如“查出所有喜欢我而我还没喜欢回的用户”这种双向匹配逻辑。MyBatis Plus 的LambdaQueryWrapper在交友项目里尤其好用,因为社交业务的条件查询非常多,随时要按用户 id、性别、配对状态筛选,用 Lambda 表达式写不会因为字段改名而编译报错。

2.3 前后端数据流:从滑动卡片到私聊消息的接口设计蓝图

把整套交友软件拆成数据流去看,比直接读代码容易理解。用户进入 App 后,先登录,拿到后端返回的 token;然后请求“推荐卡片列表”,后端返回一批用户信息,前端用动画展示卡片;用户对卡片左滑表示不感兴趣,右滑表示喜欢。这里每次滑动都是一次请求,只是很多源码为了省事没有实时上报,而是等滑完再批量提交。无论怎么实现,接口层最终都会落到下面几张表:用户表、喜欢记录表、好友表、消息表、动态表。

场景前端动作后端接口返回结果
注册登录提交手机号+密码POST /api/user/logintoken + 用户信息
获取卡片列表滑动前请求GET /api/user/recommend用户数组
喜欢 / 不喜欢滑动结束时提交POST /api/match/action是否互相喜欢
我的好友进入消息页GET /api/friend/list好友列表
私聊发消息 / 拉历史POST /api/message/send + GET /api/message/history发送状态 / 聊天记录
发布动态上传图片和文字POST /api/dynamic/publish动态 id
动态流刷信息流GET /api/dynamic/feed动态列表

这个表格虽然粗略,但已经覆盖了交友项目 80% 的功能。源码里如果没有这些接口,要么是功能确实没做,要么是用了别的命名,你需要按自己的业务文档重新对齐。一个很常见的现象是:源码作者把匹配功能和好友功能混在一个实体表里,导致“互相喜欢的人”和“已经是好友的人”界限模糊,数据库设计上通常是like_record表记录单向喜欢,friend表记录匹配成功的关系。在做二次开发前,先画清楚这两张表的关系,后面改逻辑才不会翻车。

接口设计上还有一个容易被忽略的点:返回给前端的卡片列表不能包含已经滑过的人。源码里常见做法是前端本地维护一个 id 列表,滑动后存到缓存里,下次请求时带入excludeIds参数。这个方案能做,但换设备就丢了;更稳妥的是后端在like_record表里记录所有互动,推荐接口查询时用NOT IN排除掉。设计交互流程时最好把这一点在文档里写清楚,否则上线后会出现“左右滑没了还是重复刷到同一个人”的体验问题。

3. 从零到本地跑通:搭建环境、导入源码、启动后端与前端

3.1 环境版本匹配:JDK 8、Maven、MySQL 8、HBuilderX 的排列组合

拿到源码第一步不是双击导入,而是检查版本匹配。我碰到过最耽误时间的情况是:代码里用了 Java 11 的var语法,但本机只装了 JDK 8,编译直接失败;或者 MySQL 驱动版本不兼容连接串写法。先确认系统环境再动手,能省掉一半的玄学问题。

推荐的一组版本组合是:JDK 1.8、Maven 3.6.3、MySQL 5.7 或 8.0、HBuilderX 最新稳定版。Spring Boot 版本如果是 2.x,用 JDK 8 最稳;如果是 3.x,必须用 JDK 17。很多网上下载的源码写的是 Spring Boot 2.3.4 或 2.5.x,这些都能在 JDK 8 下运行。检查 JDK 版本:

java -version mvn -version mysql --version

如果mvn命令不存在,可以用 IDEA 自带的 Maven,也可以把 Maven 的bin目录配进系统变量。注意 MySQL 8 的连接驱动是com.mysql.cj.jdbc.Driver,MySQL 5.7 是com.mysql.jdbc.Driver,连接串里的serverTimezone也要显式设置,否则后端日志会报时区错误。这步不用急着改代码,先让本机软件版本和源码项目的 Pom 文件声明对齐。如果源码里没有 Pom 文件,说明它可能是一个非 Maven 项目,需要手动引入依赖,这种情况建议直接换一份源码,血泪经验:不要和高版本 Gson、Jackson 的兼容性硬刚。

3.2 后端启动:改 application.yml、建库、跑起 Spring Boot 服务

后端启动前,先看资源目录下的配置文件。常见位置是src/main/resources/application.yml或application.properties。把数据库地址改成localhost,用户名密码改成你自己的。这里给出一个常见配置模板:

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/dating_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 10MB max-request-size: 100MB mybatis-plus: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

这段配置的作用:server.port把后端端口固定在 8080;datasource.url里的serverTimezone=Asia/Shanghai解决数据库和本地时区差 8 小时的问题;multipart设置上传文件大小上限,交友软件经常传图片,默认 1MB 太小,调到 10MB 更合理;map-underscore-to-camel-case让user_id自动映射成userId,省去大量手工@TableField配置。

改完配置后,创建数据库。推荐用源码自带的sql文件夹里的初始化脚本,没有的话就自己建库:

CREATE DATABASE dating_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE dating_db; -- 后续执行源码提供的 .sql 或手动建表

utf8mb4是为了支持表情符号。交友软件的昵称和聊天消息里经常会输入 emoji,如果库是utf8,插入带表情的字符串会报错。建好库后,在项目根目录执行:

mvn clean package -DskipTests java -jar target/dating-backend-0.0.1-SNAPSHOT.jar

第一次执行 Maven 会下载大量依赖,建议切换镜像源,否则等待时间会让人怀疑人生。在~/.m2/settings.xml里添加镜像地址即可,这里不做具体推荐。启动成功后,控制台会出现Started DatingApplication字样。此时可以先访问后端健康检查接口,确认服务真的活着,再开始前端联调。

3.3 前端运行:在 HBuilderX 里导入 uniapp 并指向本地后端

打开 HBuilderX,点击“文件 -> 导入 -> 从本地目录导入”,选择前端项目所在目录。导入后首先检查manifest.json里的应用名称和 AppID。没有 AppID 也能运行到浏览器和手机基座,但微信小程序需要自己注册。基础配置不必改,重点改接口地址。

在 uniapp 项目里,通常有一个utils/request.js或api/request.js封装请求。找到基准地址,把它从http://192.168.x.x:8080改成你后端实际地址。不要改成localhost,因为真机调试时手机访问的是电脑的局域网 IP。建议这样封装:

// utils/request.js const BASE_URL = 'http://192.168.1.100:8080' // 改成你电脑的局域网IP export function request(options) { return new Promise((resolve, reject) => { uni.request({ url: BASE_URL + options.url, method: options.method || 'GET', data: options.data || {}, header: { 'Content-Type': 'application/json', 'token': uni.getStorageSync('token') || '' }, success: (res) => { if (res.data.code === 200) { resolve(res.data.data) } else { uni.showToast({ title: res.data.msg, icon: 'none' }) reject(res.data) } }, fail: (err) => { uni.showToast({ title: '网络异常,请检查后端服务', icon: 'none' }) reject(err) } }) }) }

这段封装里,BASE_URL是全局唯一的接口入口,后续所有接口都走request方法。token从本地缓存读出,自动加到请求头里,省得每个接口手写。成功判断依赖后端返回结构,常见约定是{code:200, msg:"success", data:{}},如果你的源码不是这个约定,要同步修改判断条件。建议把BASE_URL提成独立配置文件,比如config.js,这样打包测试包时只改一个文件,不用满项目找接口地址。

3.4 联调验证:真机预览与接口返回的“成功”不一定是成功

在 HBuilderX 菜单栏点击“运行 -> 运行到手机或模拟器”,首次运行会提示安装 HBuilderX 真机运行基座,用 USB 连接手机并开启 USB 调试。如果不方便插线,可以用“浏览器运行”,但浏览器里没有小程序特有的接口,也不会有 App 基座的原生能力,所以只适合看页面,不适合验证登录和相机。

后端接口返回 200 不代表业务成功。比如登录接口如果返回code:200,但data里的 token 是空字符串,前端会存一个空 token,后续所有请求都被后端鉴权拦截,只表现为“列表加载不出来”。联调时建议把后端配置里的log-impl打开 SQL 日志,观察后端打印的 SQL 和请求参数,能一眼看出是参数没传对,还是 SQL 条件写错。验证的标准是:注册一个测试账号,登录成功,刷新卡片列表,执行一次右滑,再查看数据库中是否多了一条like_record记录。这步做到位,说明整个链路是通的。

4. 交友软件的核心业务实现:用户、匹配、动态、私聊

4.1 用户登录与 token 鉴权:怎么让 uniapp 记住登录状态

交友项目的用户模块和电商不同,不只是一张 user 表和密码校验,它还要记录性别、生日、头像、个性签名、定位等资料,因为这些字段直接影响推荐算法。后端通常用 JWT 生成 token,把用户 id 放进去,前端每次请求带上,后端通过拦截器解析 token 再查出用户。

常见的登录接口实现:

@RestController @RequestMapping("/api/user") public class UserController { @Resource private UserService userService; @PostMapping("/login") public Result login(@RequestBody LoginDTO dto) { String token = userService.login(dto.getMobile(), dto.getPassword()); return Result.ok(token); } }

这段代码是典型的 Controller 层写法,只负责接收参数并调用 Service。真实的校验逻辑在userService.login()里:先按手机号查用户,比对密码(通常用 BCrypt 加密,不是明文),生成 JWT 返回。参数说明:LoginDTO里至少有两个字段mobile和password,源码里如果有验证码需求,就再加code字段。前端拿到 token 后调用uni.setStorageSync('token', token),下次请求自动带上。

JWT 的过期时间建议设置 7 天。交友软件用户打开频率高,但不需要像银行 App 那样敏感,7 天过期可以在“方便”和“安全”之间平衡。如果过期时间太长,用户在小程序里被杀掉重进,token 还在但后端 Redis 里的会话信息没了,就会出现“看起来登录了但接口全 403”。所以源码里如果用到了 Redis 存储,要确保 Redis 服务也在运行,否则登录会直接失败。很多源码在本地启动时需要 Redis,作者不会在 README 里写清楚,报错只会说“连接超时”,这时候要先看application.yml里有没有spring.redis.host配置。

4.2 滑动匹配的接口设计:左滑右滑终究要落到一次 update

滑动匹配是交友软件最核心的玩法。它的数据模型很简单:一张like_record表,记录谁喜欢了谁,状态用type区分左右滑。当用户 A 右滑用户 B 时,前端调用“提交滑动记录”接口,后端插入一条数据,并反向查一遍 B 是否已经喜欢过 A,如果存在,就说明配对成功,同时建立好友关系。

用 MyBatis Plus 实现,代码大致是:

public boolean swipe(Long userId, Long targetId, Integer type) { LikeRecord record = new LikeRecord(); record.setUserId(userId); record.setTargetId(targetId); record.setType(type); // 1=喜欢 0=不喜欢 record.setCreateTime(new Date()); likeRecordMapper.insert(record); if (type == 1) { // 查反向记录 LambdaQueryWrapper<LikeRecord> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(LikeRecord::getUserId, targetId) .eq(LikeRecord::getTargetId, userId) .eq(LikeRecord::getType, 1); LikeRecord reverse = likeRecordMapper.selectOne(wrapper); if (reverse != null) { // 建立好友关系 friendMapper.insert(new Friend(userId, targetId)); return true; } } return false; }

这段逻辑有几个关键点:LikeRecord的userId是哪一方主动滑动,targetId是被滑动的人;插入前最好查重,否则用户反复右滑同一个人,数据库里会出现多条“喜欢”记录。配对成功时,前端需要弹窗提示“你和他互相喜欢了”,所以接口不能只返回true,最好把对方的头像和昵称也带回来。失败时则正常刷新下一张卡片。

真正上线时,swipe接口还需要考虑并发:用户 A 和用户 B 同时右滑对方,两边都执行“插入喜欢记录”和“查反向记录”,都查不到,导致配对窗口错过。这种问题在小项目里不会出现,但如果你要写进论文,最好在like_record表上建立唯一索引(user_id, target_id),这样重复滑动会被数据库拦截;再给后端加入一个简单的幂等处理,比如用 Redis 锁,避免同一条记录插入两次。作为毕业设计能讲到这个深度,答辩会很加分。

4.3 动态发布与图片上传:前端压缩、后端校验、对象存储延迟落实

动态功能在交友项目里承担的是“展示生活”的作用。它的实现难点不在表结构,而在图片上传。前端用 uniapp 的uni.chooseImage拿到图片,再通过uni.uploadFile上传到后端。拍照出来的图片动不动 3MB 以上,直接上传很慢,还会被服务器拒绝,所以前端要先压缩。

// 选择图片并压缩到 800px 宽 uni.chooseImage({ count: 9, success: (res) => { const tempFiles = res.tempFilePaths; tempFiles.forEach((path) => { uni.compressImage({ src: path, quality: 80, success: (r) => { uploadDynamicImage(r.tempFilePath) } }) }) } })

uni.compressImage是 HBuilderX 提供的原生压缩能力,quality: 80表示 80% 质量,肉眼几乎看不出区别,但体积能小一半。这里调用uploadDynamicImage需要把文件路径传到一个uni.uploadFile方法里,后端接收 MultipartFile。压缩后的图片建议限制在 2MB 以内,服务端再做一次校验,防止上传垃圾文件。count: 9表示最多选 9 张图,这个参数可以根据动态功能设计成 1 张或 6 张。

后端接收图片并不难:

@PostMapping("/image/upload") public Result uploadImage(@RequestParam("file") MultipartFile file) { String originalFilename = file.getOriginalFilename(); String ext = originalFilename.substring(originalFilename.lastIndexOf(".")); String filename = UUID.randomUUID() + ext; file.transferTo(new File("/data/upload/" + filename)); return Result.ok("/files/" + filename); }

上传后的图片地址一般是相对路径,前端拼上当前域名即可访问。如果源码里用了 FastDFS、MinIO 或腾讯云 OSS,则不需要在本机保存,但你在本地跑通前,可以把上传目录改成临时目录。这里有一个容易翻车的点:transferTo使用了绝对路径,如果目录不存在,需要保证/data/upload/已经创建好,否则会抛 IOException。更稳妥的做法是用配置动态拼路径,比如在application.yml里配一个upload.path,然后通过@Value("${upload.path}")注入。图片访问也需要配置静态资源映射,否则上传成功但前端<image>打不开。

4.4 私聊接口:轮询能用,但 WebSocket 更接近“交友”的实时感

私聊是交友软件里最容易被“学生味”的地方。很多人为了省事,让前端每 3 秒拉一次最新消息,这在小项目里确实能跑,但消息延迟后体验很糟糕,而且对服务器压力极大。正确做法是用 WebSocket 建立一个长连接,后端收到消息后推送给接收方,前端 HBuilderX 里用uni.connectSocket就能建连。

后端 Spring Boot 提供 WebSocket 支持:

@Component public class ChatWebSocket { private static final Map<Long, WebSocketSession> SESSIONS = new ConcurrentHashMap<>(); public void sendMessage(Long toUserId, String message) throws IOException { WebSocketSession session = SESSIONS.get(toUserId); if (session != null) { session.sendMessage(new TextMessage(message)); } } }

这段代码用ConcurrentHashMap保存每个用户的会话,key 是用户 id。当 A 给 B 发消息时,后端先落库,再通过toUserId找到 B 的会话并推送。注意:WebSocket 会话是有状态的,用户断开连接后要记得移除这个 key,否则下次推送会报错。前端收到消息后触发列表刷新,就不用定时轮询了。如果源码里没有 WebSocket,而是用轮询,也可以接受,但你要知道它的实时性和性能都比长连接差一截。

一个折中方案是:历史消息用分页接口拉取,新消息走 WebSocket 推送。这样一进入聊天界面先读数据库,之后所有增量消息都通过长连接实时到达,体验和性能都能兼顾。在本地环境开发时,后端 WebSocket 的端口可以和 HTTP 相同,前端uni.connectSocket里地址写ws://192.168.1.100:8080/ws;如果前后端分离部署,就需要用 Nginx 把/ws路径反向代理到后端,并开启 upgrade 支持。没有配置好反向代理,小程序端 WebSocket 经常会出现一直 connecting 的状态,这是很多人卡住的坑。

5. 避坑:uniapp + Java 后端交友项目最容易翻车的 5 个点

5.1 真机预览时接口连不上:127.0.0.1 不是指向电脑

现象:USB 连接手机后,前端页面能打开,但所有列表数据加载不出来,后端控制台也看不到请求日志。

原因:前端代码里的接口地址写成了http://localhost:8080或http://127.0.0.1:8080。手机上的localhost指手机自己,不是电脑。

解决:把接口地址改成电脑的局域网 IP。Windows 上打开命令行输入ipconfig,macOS 输入ifconfig,找一个 192.168.x.x 的 IPv4 地址,替换 BASE_URL。要确保手机和电脑连的是同一个 WiFi,并关闭系统防火墙或放行 8080 端口。改完重新运行基座,后端控制台能看到请求即成功。如果家里路由器开了 AP 隔离,手机和电脑之间会互相 ping 不通,这会表现为“接口地址明明没问题,但手机就是访问不了”,需要暂时关闭 AP 隔离或换手机热点。

5.2 微信小程序上传图片提示“不在合法域名列表”

现象:在 HBuilderX 里运行到微信小程序,上传图片或请求接口时提示url not in domain list或校验失败。

原因:微信小程序要求网络请求必须走 HTTPS,并且在后台配置对应域名。开发调试时,本地 HTTP 接口默认被拦截。

解决:开发阶段打开微信开发者工具的“详情 -> 本地设置 -> 不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”选项。这一步只是给自己调试用的,不是上架的解决方式。真正上线必须使用 HTTPS 域名,并在小程序管理后台把域名加入白名单。HBuilderX 里也可以勾选“无证书调试”,但不推荐。小程序里上传图片的域名也要同步加白名单,否则会出现“接口正常但图片上传失败”的割裂现象。

5.3 后端的 Long 型 id 在前端精度丢失:雪花 ID 必须转 String

现象:用户列表或消息记录里,最后两位 id 变成 0,例如1722345678901234567变成1722345678901234500。

原因:Java 后端的Long类型是 64 位,最大可达 19 位,而前端 JavaScript 的Number只能精确表示到约 16 位。雪花算法生成的 id 超过了安全范围,JSON 序列化后数字被四舍五入。

解决:在后端实体类的 id 字段上加@JsonSerialize(using = ToStringSerializer.class),或者在配置类里统一配置Long转String。前端请求时拿到的是字符串,数据库主键和关联查询不受影响。这个坑不会导致接口报错,只会在“点击用户详情时参数错乱”暴露出问题,非常隐蔽。如果源码里使用了 MyBatis Plus 的主键策略IdType.ASSIGN_ID,从底层就是雪花 id,出现概率极高。统一转换比较简单,只需在 Jackson 配置里注册一个模块:

@Bean public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() { return builder -> builder.serializerByType(Long.class, ToStringSerializer.instance) .serializerByType(Long.TYPE, ToStringSerializer.instance); }

这段配置会让所有 Long 类型的响应都以字符串形式返回,前端拿去不会丢精度。代价是后端如果有些接口要求前端回传 Long 参数,需要用字符串形式提交,但 JSON 本身是弱类型,这个影响基本可以忽略。

5.4 数据库自动建表失败:字符集和时区不一致

现象:启动后端时报错Unknown collation: 'utf8mb4_0900_ai_ci',或者插入中文变成问号。

原因:MySQL 8 默认的排序规则是utf8mb4_0900_ai_ci,而项目里的 SQL 脚本可能针对 MySQL 5.7 写的,用了旧规则;也可能是数据库连接串没有指定字符集。

解决:统一把连接串改为characterEncoding=utf8,建表 SQL 明确加上DEFAULT CHARSET=utf8mb4。如果已经导入老脚本,可以手动执行ALTER DATABASE dating_db CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,再运行项目。字符集不统一,比数据库连不上更麻烦,因为报错往往不明显。还有一个连带坑:MySQL 8 后的驱动包版本要大于 8.0.11,老驱动可能不认识com.mysql.cj.jdbc.Driver,启动时提示找不到驱动类,检查一下 Pom 里的 mysql-connector-java 版本即可。

5.5 H5 端接口跨域:前后端端口不一样,被浏览器拦了

现象:HBuilderX 运行到 H5 时,控制台出现Access-Control-Allow-Origin提示,接口无法访问;但 App 端和小程序端正常。

原因:H5 页面运行在 8081 端口,后端是 8080 端口,跨域。浏览器默认不允许跨域请求。

解决:在后端配置全局 CORS。Spring Boot 最简单的做法是增加一个配置类:

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowCredentials(true) .maxAge(3600); } }

这段配置放行所有来源的 HTTP 方法,仅供开发测试使用。生产环境不要用*,应该写死为你的正式域名。也可以不用 CORS 方案,直接让 Nginx 把/api反向代理到后端,前端代码里同样用同源地址,但作为本地测试,CORS 是最快的后悔药。注意allowCredentials(true)和allowedOriginPatterns("*")在 Spring Boot 2.4 之后才允许这样组合,旧版本只能指定具体 origin。

6. 上线前的检查与后续还能怎么改:从能跑到能用

6.1 用真机做一次完整的“脱敏测试”

把功能跑通不算完,还要做一次接近真实用户的操作测试。找一个测试手机,安装 HBuilderX 打包的测试包,从注册开始,依次执行:注册、登录、完善资料、上传头像、滑动 20 张卡片、触发互相喜欢、发起私聊、发送图片、发布一条带图动态、退出登录。每做一步,对应查一次数据库,确认数据落库正确。很多源码在模拟器上看着正常,一到真机就暴露了相册权限、相机权限、定位权限问题,这些只能在真机上验证。建议测试时打开手机自带的流量限制,确认弱网环境下滑动加载和图片上传不会卡死。

6.2 进一步能加的功能与必须补的安全项

如果这是毕业设计,把基础功能做完后,再选一个亮点做深度优化即可。推荐三个方向:基于标签相似度的推荐算法、聊天消息已读回执、动态流量换成短视频。其中“已读回执”最容易出效果,只需要在消息表加一个read_time字段,前端展示消息时调用一次接口即可。不要试图同时做多个点,答辩时反而讲不清楚。

安全方面至少要确认:密码有没有用 BCrypt 加密、文件上传有没有做后缀校验、token 解析失败时有没有返回统一错误、数据库连接串里的密码是否明文暴露在代码中。如果这几个点都没做,即使答辩过了,项目也会被面试官追问到破功。Java 后端的安全项就这么多,补起来的成本远低于写一个冷启动的推荐系统。

最后提醒一句:不要迷信源码里的“完整可用”,一定要自己从头把数据表和接口跑一遍。我在帮别人排查这类项目时,最常遇到的情况就是源码作者没把application.yml里 Redis 地址改成用户本机,导致用户卡在登录环节一整天。养成收到新代码先看配置、再跑接口的习惯,比会写任何框架都值钱。希望帮到你。

本文还有配套的精品资源,点击获取

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

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

立即咨询