
校园论坛这类项目说实话在毕业设计和实际开发里都挺常见的但大多数思路还停留在注册-发帖-回帖的老三样上。这个题目有意思的地方在于把人脸识别和实名认证硬塞进了论坛体系里本质上要解决的是一个信任问题——校园论坛一旦放开匿名广告贴、辱骂贴、冒充身份这些乱象马上就来了。我基于 Spring Boot 结合人脸识别做了一版完整的校园论坛系统趁着项目收尾的热乎劲把整个设计思路和实现细节梳理一遍尤其是人脸识别接入、实名认证状态流转这几个核心环节给后面要做类似方向的朋友一个可参考的完整样本。这个系统能做什么呢简单说就是学生第一次登录必须先完成人脸采集和实名信息核验核验通过后账号才被激活之后发帖、评论、点赞都带着真实身份标签后台能追踪到具体是谁。管理员端有完整的审核和用户管理界面。整套流程跑下来论坛的灌水率和恶意发言率明显下降这个结果在校园场景里非常直观。1. 项目定位与方案选型1.1 为什么校园论坛必须做实名认证校园论坛的用户群体很特殊都是在校学生但身份核实一直是个老大难问题。传统做法是拿学号加密码登录但学号这东西在宿舍楼里几乎是公开的借学号注册、冒充他人发言的情况屡见不鲜。更麻烦的是论坛一旦能匿名或者伪造身份就会出现大量不负责任的言论比如恶意挂人、散布谣言、刷屏广告牵扯到辅导员介入时还查不到人这是校园论坛管理最头疼的部分。实名认证加上人脸识别的组合解决的正是这个痛点。学号可以被借用但人脸是生理特征没法轻易冒用。学生注册时必须提交真实的身份信息再配合人脸比对确认你就是你从源头阻断身份造假的可能。论坛里每个人的发言都对应到真实学生身份一旦出现违规行为管理员可以在后台定位到具体账号和真实学号这就构成了完整的威慑链条。在技术选型上人脸识别是核心但并不是为了炫技。实名认证本身可以靠身份证号加手机验证码但那只能验证信息真实性验证不了操作者身份。人脸识别的加入填补的正是人证合一这个关键环节——学生提交学号身份证号之后再刷一次脸三样信息对齐了账号才激活。这个人证合一校验逻辑是整个系统的基石。1.2 技术方案的取舍逻辑先把技术栈定下来Spring Boot 作为后端主框架MyBatis-Plus 做持久层Redis 缓存会话和人脸特征临时数据MySQL 存储业务数据前端用 Vue 3 加 Element Plus人脸识别部分采用在线 API 加本地 OpenCV 兜底的双通道方案。Spring Boot 没什么好纠结的校园论坛这种业务型项目它是最成熟的选项生态全、资料多、招人也好招。重点说人脸识别这部分市面上的方案大致分三类第一类是纯本地算法用 OpenCV 加 LBPH 特征或者深度模型推理好处是不依赖外网、数据不出校但准确率和开发成本不理想第二类是纯云 API比如百度、腾讯的人脸识别服务精度高、活体检测现成但每调用一次都要计费而且学生数据传到第三方平台隐私方面容易挨批第三类就是我这版用的混合方案——人脸检测和特征提取走云 API 保证精度但比对逻辑和特征管理自己实现关键数据留在本地。选型逻辑很直白纯本地方案在校园复杂光照环境下识别率达不到可用标准夜间宿舍、走廊逆光、戴眼镜这些场景全都拉胯纯云方案又绕不开隐私和数据出校的伦理问题。混合方案把特征提取这个最吃算力的环节交给云 API提取出来的人脸特征向量本地保存和比对比对了哪些人、存了哪些特征全部自己可控。另外加了一层 OpenCV 做人脸检测兜底云 API 不可用的时候至少能完成检测到人脸这个基础动作保证系统不直接瘫掉。1.3 核心流程的演进过程系统的核心流程最开始是很朴素的注册 → 填学号身份证 → 上传人脸照片 → 激活。但实际推演之后发现漏洞不少。比如上传照片这一步完全可以拿别人的照片来冒充连活体检测都没有。后来又加了眨眼、张嘴的随机动作活体检测这基本是行业标配了不然整个系统就是个摆设。第二版流程调整成填学号身份证号 → 调用实名信息校验接口核对学号与姓名是否匹配 → 摄像头实时采集人脸并做活体检测 → 提取特征值保存 → 账号激活。这里有一个细节容易忽略活体检测通过后提取的人脸特征值必须跟该学生提交的身份证号做绑定存储后续登录时再刷一次脸做一比一比对确认是本人。这样整个链路就是完整的闭环而不是只做一次人脸采集就完事。第三版又处理了一个边界场景——学生换发型、戴眼镜、季节性外貌变化。要是每次登录都按第一次采集的特征做严格比对误杀率会很高。解决方案是允许用户在个人中心重新采集人脸但重新采集时必须先通过学号密码登录同时保留历史特征做对比新特征入库后老特征进入冷备状态。这个小设计在实际上线后减少了大量我明明是我的申诉工单。2. 系统架构与数据层设计2.1 后端工程的整体模块划分工程结构没有用那种花里胡哨的微服务拆分一个单体应用加清晰的分层就够了。模块划分基于一个很朴素的理念人脸的采集、识别、特征管理这几个环节必须跟业务模块隔离不然以后换人脸算法或者调整实名策略的时候周边业务全要跟着动。├── auth-module # 登录认证、JWT签发、会话管理 ├── user-module # 用户资料、学籍信息、账号状态管理 ├── face-module # 人脸采集、特征提取、比对服务 ├── forum-module # 帖子、评论、点赞、版块管理 ├── audit-module # 内容审核、违规记录、举报处理 ├── admin-module # 管理员后台、数据统计 └── common-module # 通用工具、统一返回、异常处理每个模块内部遵循标准的 controller-service-mapper 三层结构模块之间通过 service 接口通信禁止跨模块直接操作 mapper。比如 forum-module 要显示用户昵称只能通过 user-module 暴露的 OpenFeign 风格的内部接口去查不允许自己 join user 表。这个约束在开发初期会让人觉得啰嗦但到了后期加需求的时候就体会到好处了。face-module 是整个系统的核心模块内部又拆了两层底层的 FaceClient 接口对接具体的人脸识别服务商支持云 API 和 OpenCV 本地实现两套策略上层是 FaceService封装了采集签名、特征比对、活体检测状态机这些业务逻辑。这样以后想换服务商只要新增一个 FaceClient 实现类就行上层完全不用动。2.2 数据库表设计的几个关键决策数据库一共十二张表核心表有用户表、实名认证记录表、人脸特征表、帖子表、评论表。这里挑几张关键的表展开说。用户表的设计有一个反直觉的决策实名信息跟账号信息不放在同一张表。账号表只有用户名、密码哈希、手机号、账号状态这些登录必需字段实名信息单独放到 user_realname 表字段包括学生姓名、学号、身份证号哈希、所在院系、专业、入学年份。这么拆的好处是账号体系跟实名体系是两套生命周期——账号可以被封禁、注销、申诉解封但实名记录一旦建立就永久保留哪怕账号注销了实名档案还在。这个设计在做违规追溯的时候起了大作用。人脸特征表的字段设计也值得单独说一下。每一条特征记录包含特征向量、特征版本、采集设备信息、采集时间、活体检测分数、状态字段。特征向量存储用的是 BLOB 类型没有存成 JSON 字符串主要原因是向量维度高转成 JSON 序列化之后体积膨胀得厉害而且比对的时候直接内存加载二进制数组比解析 JSON 快一个数量级。论坛帖子表在标准字段之外加了两列realname_status 和 audit_status。realname_status 标识发帖时用户的实名状态是否有效因为存在一种场景——用户发帖时是激活状态但后来人脸特征被标记异常这时候历史帖子要跟着一起标记。audit_status 就是内容审核状态帖子发出来先进审核队列管理员通过或驳回后才公开展示。这两个字段让内容追溯有了抓手出了问题能快速定位到具体帖子对应的实名状态。2.3 人脸特征的生命周期管理人脸特征不能简单地理解成注册的时候存一次就完了它是有生命周期的。一个学生从大一入学到大四毕业四年间外貌变化非常大大一采集的特征到大四可能已经比对不上了。所以我在系统里设计了特征版本机制。学生在校期间可以多次采集人脸每一次采集都会生成新版本的特征记录旧版本自动标记为历史版本。比对的时候有两个策略可选严格模式只用最新版本特征比对宽松模式会遍历最近三个版本的特征任何一个版本匹配成功就算通过。默认是宽松模式因为学生戴眼镜、换发型、痘痘爆发这些情况太常见了严格模式误杀率太高。安全性和易用性的平衡点需要通过实际跑一段数据来调最后发现三个版本是一个比较好的折中。特征还有过期机制。如果某个学生超过一年没有登录系统会将该账号的状态标记为需重新核验下次登录时强制要求重新采集人脸。这是为了防止账号被他人接管后长期不动等真正主人发现时已经晚了的情况。重新核验的流程比首次注册简单一些只要求活体检测加人脸比对不需要重新提交身份证信息。3. 核心功能实现与实操细节3.1 人脸识别接入的完整步骤人脸识别这块我选的是百度的在线人脸识别 API配合 OpenCV 做本地检测兜底。不要指望一个方案解决所有问题混合方案才是实际工程里最稳的做法。先说说为什么选百度而不是旷视或者腾讯。主要原因是百度的接口文档和 SDK 对 Java 的支持最完善Maven 坐标直接引入就能用而且人脸库的管理能力比较完整——可以创建独立的用户组每个用户组下面管理多张人脸这正好对应校园里按学院分组的场景。旷视的识别精度确实高但 Java SDK 维护得不上心腾讯的接口设计个人觉得没有百度顺手而且百度的 QPS 免费额度对校园这个量级足够用了。实际接入的步骤大概是这样先在百度智能云控制台创建人脸识别应用拿到 API Key 和 Secret Key然后用这两个 Key 去换取 access_token。access_token 的有效期是 30 天我写了一个定时任务每天凌晨自动刷新同时把 token 缓存在 Redis 里避免每次调用都去换一次。这里有个小坑百度返回的 access_token 有效期是按秒计算的但实际测试发现它的刷新接口有频率限制如果多个实例同时刷新会报错所以我加了一个分布式锁保证同一时间只有一个线程去刷新。活体检测部分用的百度的随机动作活体检测接口客户端采集视频服务端随机指定动作顺序眨眼、张嘴、点头用户按顺序完成后返回一个活体分数。阈值我调到了 0.8低于这个分数直接判定为活体检测不通过。这个阈值是跑了一百多个真实学生样本后调出来的低于 0.8 会出现拿照片也能过的情况高于 0.85 又会有同学因为动作幅度不够被误杀。本地 OpenCV 兜底通道是在云 API 不可用的时候才启用的。我写了一个 FaceLocalService用 OpenCV 的 Haar Cascade 检测人脸区域再通过直方图对比算相似度。说实话这个本地方案的精度跟云 API 没法比但它的价值在于保证系统在断网或者云服务故障的时候不至于完全锁死——至少管理员可以在后台确认确实有一个人脸在摄像头前面应急处理的时候够用了。3.2 实名认证的状态机设计实名认证不能只做一个认证过/没认证过的二值状态真实场景下会有各种中间态。我设计了一个状态机状态流转是整个系统里逻辑最复杂但也是最有价值的部分。初始状态是 PENDING_PROFILE代表学生提交了学籍信息但还没上传人脸。这时候后台会调用学籍系统的接口校验学号和姓名是否匹配不匹配的直接进入 REJECTED 状态匹配的才能进入下一步。这里校验逻辑有一个关键点学籍系统返回的数据不是百分百准确的有些院系的导入数据滞后严重新入学的学生可能在学籍系统里查不到所以校验失败不能一刀切拒绝而是进入 MANUAL_REVIEW 状态由管理员人工审核学生上传的学生证照片。进入 PENDING_FACE 状态后学生开始人脸采集。采集过程包括活体检测和特征提取两个环节任何一个环节失败就停留在当前状态并记录失败原因。这里有个细节失败次数超过五次就锁定人脸采集功能需要后台管理员手动解锁。这是为了防止有人反复尝试用照片、视频冒充锁定机制能有效阻断这种攻击尝试。采集成功后就进入 ACTIVE 状态账号正式激活可以发帖和评论了。但 ACTIVE 不是终点后面还有两个特殊状态EXPIRED 和 REVOKED。EXPIRED 是账号超过一年未登录自动进入的状态登录时需要重新采集人脸REVOKED 是后台管理员发现账号存在异常操作比如同一张人脸特征出现在多个账号下时手动置为的状态进入 REVOKED 后账号立刻冻结所有帖子隐藏需要学生本人携带证件到网络中心线下核验才能解封。状态机的实现用了 Spring StateMachine 框架一开始觉得引入这个框架有点重但写完之后发现状态流转的代码非常清晰每个状态的进入和退出动作都在配置里显式声明维护起来比到处写 if-else 判断舒服太多了。3.3 论坛核心业务的实现要点论坛的基础功能——发帖、回帖、点赞——没什么新鲜的我就不详细介绍了重点说说跟实名认证结合的部分。发帖流程里最关键的判断是用户当前实名状态是否为 ACTIVE。这里不能用前端传来的状态字段来判断必须走后端查询实时状态因为用户的实名状态可能在发帖前刚被管理员变更过前端展示的状态有延迟。我在 ForumService 里写了一个断言方法public void assertRealnameActive(Long userId) { Integer status userRealnameMapper.selectStatusByUserId(userId); if (status null || status ! RealnameStatus.ACTIVE.getCode()) { throw new BizException(ErrorCode.REALNAME_NOT_ACTIVE); } }这个方法在发帖、评论、私信三个入口都会被调用逻辑简单但能挡掉大部分问题。另外还有一个更深层的校验如果用户是 REVOKED 状态但历史帖子的 realname_status 字段仍然是有效这时候帖子要同步标记为实名状态异常。这个同步动作我用了消息队列异步处理避免在发帖接口里做一串级联更新拖慢响应。帖子审核模块的实现也有一点心得。审核动作本身不复杂就是管理员对帖子做通过或驳回的操作但审核队列的排序策略值得说一下。我的排序规则是新帖优先、被举报帖子优先、来自 REVOKED 边缘用户的帖子优先。这个排序规则写起来很简单但实际运营效果很好管理员每天打开后台看到的是最需要处理的内容而不是被海量正常帖子淹没。3.4 几个关键接口的代码实现人脸采集接口是整个系统里最敏感的接口它接收前端的视频流后端抽取帧后调用云 API 做检测和特征提取。这个接口有几个安全上的要求必须登录、必须带签名、接口限流。PostMapping(/face/collect) public ResultFaceCollectVO collect(RequestBody FaceCollectRequest request) { // 1. 校验当前用户实名状态是否允许采集 UserRealname realname realnameService.getCurrentRealname(); if (realname null || !realname.canCollectFace()) { return Result.error(当前状态不允许采集人脸); } // 2. 活体检测调用云API的检测接口 LivenessResult liveness faceClient.detectLiveness(request.getVideoBase64()); if (liveness.getScore() LIVENESS_THRESHOLD) { return Result.error(活体检测未通过); } // 3. 提取特征值 FaceFeature feature faceClient.extractFeature(request.getBestFrame()); // 4. 保存特征并更新实名状态 faceFeatureService.saveFeature(realname.getId(), feature); realnameService.transitionStatus(realname, RealnameEvent.FACE_COLLECTED); return Result.ok(FaceCollectVO.success()); }登录接口同样有特别设计。普通的账号密码登录之后系统会检查用户实名状态如果不是 ACTIVE 状态则要求走人脸比对流程。比对通过后签发 JWT tokentoken 里携带的不只是用户 ID还包括实名校验版本号。版本号的作用是后台修改了用户的实名状态后这个版本号会变前端下一次请求会拿到 401 错误码提示用户重新登录获取新的 token这样能快速踢掉非法状态的用户的会话。4. 性能优化与安全加固4.1 人脸比对的缓存策略人脸比对是系统里最耗时也最昂贵的操作不可能每一次请求都直接调云 API。我做了一个两级缓存策略把比对成本降了百分之八十以上。第一级缓存是本地内存缓存。系统启动的时候把最近七天内活跃用户的特征向量加载到 JVM 内存里用一个并发 HashMap 按用户 ID 索引。比对的时候先取请求用户的最新特征跟内存里的目标特征做比对匹配上了就直接返回结果完全不需要走网络。内存缓存的问题在于多实例部署时数据不一致所以这个方案只适合单实例部署的场景我目前的服务器配置是 4 核 8G单实例扛校园论坛的量完全够。第二级缓存是 Redis。用户量上来后内存装不下所有活跃用户特征就往 Redis 里放。Redis 里的 key 是用户 IDvalue 是特征向量的序列化字节数组。每次比对先查内存、再查 Redis、最后才走云 API。云 API 的调用频率被限得非常低只有两种场景才会触发一种是两个用户都是新用户本地和缓存里都没有特征另一种是比对相似度处于模糊区间比如分数在 0.7 到 0.85 之间需要云端做一次精确复核。这个分级缓存策略上线后生产环境的云 API 调用量从每天两千多次降到了三百次左右成本下降非常明显而且响应速度从平均九百毫秒降到了两百毫秒以内用户感知好了很多。4.2 接口防刷与人脸数据保护人脸数据属于个人敏感信息保护措施不能只是嘴上说说。我在系统里做了三层防护。第一层是传输层加密。前端把视频流和人脸图片传到后端之前先用国密 SM4 算法加密后端再用对应的密钥解密。密钥通过 HTTPS 连接下的额外握手机制分发不写在代码里也不存数据库而是在 Redis 里设置短时有效期。这个加密过程对性能的影响实测在 10% 到 15% 之间考虑到人脸数据的敏感性这个成本是值得的。第二层是存储加密。数据库里的人脸特征向量不用明文存储写入前用 AES-256 加密读出来比对前再解密。虽然特征向量本身就是一种不可逆的编码不是原始人脸照片但依然属于敏感数据多一层加密总归是好的。人脸原始照片我做了自动删除策略活体检测和特征提取完成后原始照片只在临时目录保存 10 分钟10 分钟后立刻删除只保留特征向量。第三层是接口防刷。人脸采集接口和实名信息提交接口都做了 IP 维度和用户维度的双重限流。IP 维度是每分钟最多三十次请求用户维度是每十分钟最多五次操作。超过限流阈值直接拒绝返回 429 状态码。这个限流用的是 Redis 的滑动窗口计数器实现没有引入 Sentinel 这类重量级组件因为限流场景简单没必要为了一个小功能引入一整套框架。4.3 敏感数据的脱敏与日志策略日志系统里最容易泄露隐私。开发阶段大家习惯直接打印参数这个习惯在涉及人脸数据和实名信息的系统里必须改掉。我写了一个统一的日志切面拦截所有 controller 层的请求参数和响应结果自动识别敏感字段并进行脱敏处理。具体脱敏规则是这样的身份证号只展示前三位和最后四位中间用星号代替手机号展示前三位和后两位人脸特征向量不打印内容只打印向量维度视频流参数直接不打印只打印帧数。这里有一个实践经验脱敏规则不要写在各个业务类里一定要收敛到一个公共组件中不然开发的时候漏一个地方排查问题的时候日志里就全是裸奔的敏感数据。我还给关键操作加了审计日志记录谁在什么时间、什么 IP 地址下对哪个账号做了什么样的敏感操作。审计日志表独立于业务日志只有管理员权限才能查询并且审计日志本身不能删除、不能修改最多只能归档。生产环境已经跑了一个多月审计日志帮我们定位过几次员工私自查学生信息的操作也帮学生找回了几次被恶意改密后的操作记录这个功能建议所有类似系统都加上。5. 踩坑记录与问题排查实录5.1 人脸采集在低光照环境下的适应性调整上线第一天就收到学生反馈说晚上在宿舍采集人脸一直失败。排查之后发现不是活体检测的问题而是人脸检测环节就没通过——宿舍灯关掉只剩屏幕光的时候摄像头的画面质量太差云 API 直接返回检测到人脸失败。这个问题的解决方案不是换更好的摄像头而是在前端采集阶段就做好质量检测。我在采集页面加了一个实时帧质量评估的步骤每一帧图像在传给后端之前前端先计算亮度均值、对比度、清晰度三个指标任何一项不达标就直接提示用户调整环境光线而不是把烂图传到后端等云 API 来拒绝。这样既减少了无效请求又提升了用户体验。后端也加了兜底策略。如果接收到的图片质量不达标不是直接拒绝而是做一次灰度拉伸和直方图均衡化改善图片质量后再调云端接口。这个图像预处理流程用 OpenCV 实现大概二三十行代码但大大降低了低光照环境下的失败率。实测数据是晚间的采集成功率从 76% 提升到了 93%效果非常明显。5.2 同一人脸匹配多个账号的碰撞排查系统跑了一个月左右后台报警了一次同一张人脸特征匹配到了两个不同的学生账号。这种问题在小规模测试阶段根本不会出现因为测试样本太少只有数据量上来了才会撞上。排查过程很曲折一开始以为是特征提取逻辑 bug查了半天发现不是。后来翻了两名学生的操作日志才搞明白原来是其中一名学生帮室友完成了人脸采集——室友还在宿舍睡觉这个学生拿着室友的手机对着室友的脸刷了一下就把室友的账号激活了。这个过程在系统层面完全合法因为活体检测检测到的是真人脸实名信息也是室友本人的系统没办法区分操作者跟被采集者是不是同一个人。这个问题的本质不是技术问题而是流程漏洞。我最终给出的解决方案有两个一是采集的时候要求录制一段两秒的短视频随机抓取其中的三帧做检测单纯对着脸拍一张照片是不行的二是检测采集设备是否反复出现异常行为比如同一设备短时间内采集了多个不同账号的人脸触发风控规则后这些账号全部进入人工复核流程。这个案例说明了再先进的技术也堵不住所有漏洞必须结合流程设计和运营规则才能把风险压到最低。5.3 Spring Boot 版本升级引发的序列化兼容问题项目中期把 Spring Boot 从 2.3 升到了 2.7结果人脸特征在 Redis 里反序列化直接报错排查了半天发现是序列化机制的变化——2.3 默认使用的 JDK 序列化在升级后兼容性出了问题Redis 里的老数据读不出来。问题的根因是老数据是用 JDK 序列化写入的新版本默认读的时候按新的序列化规则去解析两边对不上。解决方法是在 Redis 配置里显式指定序列化器不要依赖默认配置。我用 FastJson2 统一了 Redis 的序列化方式同时写了一个数据迁移脚本把老数据全部读出再重新写入。这个坑本身不大但它提醒我一个很重要的原则升级依赖的时候务必关注序列化兼容性尤其是用了 Redis 缓存、消息队列这种跨进程存储的组件时序列化协议的变更是个隐形炸弹。5.4 常见问题速查表问题现象可能原因解决方案活体检测一直失败环境光线太暗、动作幅度过小前端增加帧质量预检并提示调整光线人脸比对误杀率高特征版本积累太多启用最近三个版本特征比对宽松模式多实例部署时人脸比对不一致本地内存缓存无法同步切换为 Redis 二级缓存并加版本号云 API 调用量暴增缓存击穿、终端疯狂重试两级缓存加熔断降级限制 QPS数据库存储人脸向量空间增长快每次采集都新建特征版本对超过三个版本的历史特征做冷备归档账号注销后帖子仍关联实名信息实名表与账号表生命周期不一致设计时区分账号注销与实名吊销两类操作前端上传视频流过大采集帧分辨率过高前端压缩后上传服务端限制大小管理员审核队列积压排序策略不合理按新帖、被举报、风险用户优先级排序学生采集组件不兼容老旧浏览器调用了摄像头相关新 API使用 Browser Cam 类库兼容多内核换脸视频过活体检测单一静态活体检测被绕过随机动作 多帧抽帧 三帧一致性校验写在最后的一点体会整个系统从前期的方案设计到后期上线维护前后折腾了将近三个月。如果说有什么最核心的经验那就是人脸识别和实名认证这种功能千万不要当成一个纯粹的 API 调用来做它跟业务系统的耦合比你想象中深得多。实名状态跟账号状态怎么联动、帖子跟实名记录怎么关联、特征数据怎么管理生命周期这些才是系统设计的真正难点人脸识别本身反而是相对容易的部分。另外一点体会是关于安全的态度。校园系统看起来不像金融系统那么敏感但它一样涉及大量学生的真实身份信息一旦泄露后果非常严重。开发过程中始终把数据安全放在功能开发之上该加密的加密、该脱敏的脱敏、该审计的审计虽然前期会觉得麻烦但上线后你就知道这些投入是值得的。这套系统现在还在学院内部继续跑着后续计划做的方向是把人脸鉴权扩展到其他校园业务场景比如实验室门禁、考试签到、活动核销底层的实名认证和人脸特征管理可以直接复用到时候再写一篇扩展方案。如果你也在做类似方向希望这篇记录能帮你少踩几个坑。