ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于SpringBoot+Vue的人脸识别校园门禁系统设计与实现

基于SpringBoot+Vue的人脸识别校园门禁系统设计与实现 这几个月一直在折腾一个校园门禁项目从需求梳理到最终落地踩了不少坑也攒了不少经验。正好最近把整个系统完整重构了一遍主题就是“SpringBoot Vue 基于 Web 的人脸识别互联网智能校园门禁管理系统”从技术选型到前后端实现再到硬件对接这里把我自己的完整思路和实测过程整理出来。做校园门禁和类似人脸识别系统的朋友这篇应该能帮你少走不少弯路。先说结论整个项目采用前后端分离架构后端用 SpringBoot 提供 RESTful API前端用 Vue 3 搭建管理后台人脸识别引擎选了虹软 ArcFace 离线 SDK配合摄像头 RTSP 视频流和 WebSocket 实时推流实现刷脸通行、陌生人告警、考勤统计等完整闭环。这套方案最大的价值在于“互联网化”——设备端、管理端、用户端数据全部在线互通门禁记录实时入库管理者在浏览器上就能看到全部门岗的通行情况而不再需要本地跑客户端。适合谁来参考如果你是做智慧校园、企业门禁、访客系统的开发者或者正准备从传统单体项目转做前后端分离的人脸识别应用这篇的内容基本覆盖了你要知道的所有关键点。1. 项目整体设计与技术选型思路1.1 传统门禁方案的问题出在哪咱们先聊清楚做这个项目到底要解决什么问题。很多学校现在还在用一卡通门禁你我都清楚那套体验学生忘带卡只能等别人帮忙开门卡丢了补办要等一周门岗保安得天天盯着有没有人尾随通过。后来部分学校换了指纹门禁但冬季指纹识别率骤降手指脏了湿了也经常触发失败高峰期门口排长队。更麻烦的是这些设备的考勤数据大多存在本地管理人员想看某栋楼的通行情况还得跑到设备上导数据。人脸识别门禁正好把这几个问题一次解决不需要带卡、不需要接触、识别速度快、数据自动上传。但纯靠一台人脸识别门禁机也无法满足学校的管理需求学校需要的是信息化的后台能管理人员名单、查看通行记录、统计迟到早退、处理访客预约。这时候就需要一套 Web 系统来承载整个业务逻辑光有设备是不够的。1.2 为什么最终选定了 SpringBoot Vue 前后端分离人脸识别门禁管理系统本质上是一个典型的业务管理系统包含人员管理、设备管理、记录查询、统计分析、权限控制等模块。这类系统的开发模式前后端分离是现在最成熟的选择关键看服务端和前端框架怎么配。后端我选 SpringBoot理由很简单团队里 Java 技术栈最稳SpringBoot 的自动装配和内置容器让项目启动、部署都非常顺手不需要像传统 SSM 那样写大量 XML 配置。配合 MyBatis-Plus数据层开发效率极高单表 CRUD 基本不用写 SQL。很多人担心 SpringBoot 太重但校园门禁这种系统本身就不需要极致的性能表现业务复杂度和团队维护成本才是首要考虑因素。前端选择 Vue看中的是它的组件化开发方式和响应式数据绑定。门禁后台页面里实时通行弹窗、记录表格刷新、统计图表联动这些交互用 Vue 写起来非常顺手。配合 Element Plus 组件库表格、弹窗、表单这些后台常用组件开箱即用界面做出来也比较清爽。前后端分离还有一个实际好处同一个后端 API 不仅服务 Web 管理后台还能服务后续的小程序端、移动端 App。门禁系统后续免不了要做家长端、教师端接口层提前独立出来省去后面重复开发的成本。1.3 人脸识别引擎选型离线方案才是关键人脸识别是整个系统的技术心脏选型时我对比了四个主流方案各有优劣方案运行方式精度成本适合场景虹软 ArcFace离线 SDK高免费额度校园私有化部署百度 AI 开放平台在线 API高按量付费快速开发验证OpenCV 深度学习模型离线自训中完全免费学习研究云从/商汤在线 API / 软硬一体很高较高大型安防项目最终我选了虹软 ArcFace 离线 SDK核心原因是“数据不出内网”。校园人脸数据属于高度敏感的个人信息如果调用在线 API意味着要把全校师生的人脸图片上传到第三方服务器无论是数据合规还是家长接受度上都有风险。虹软提供的是本地运行的动态库在服务器上计算人脸特征和比对分数没有外网请求数据安全性有保障。另外在开发调试阶段离线 SDK 不依赖网络本地起个 SpringBoot 服务就能测通全流程效率高很多。而且虹软的个人开发授权免费适合学习和技术验证。等真正要商用再购买商用授权成本可控。2. 系统核心模块拆解与数据库设计2.1 功能模块划分门禁系统不只是刷脸开门把整个系统拆开来看核心模块有六个每个模块解决的问题不一样人员管理维护学生、教师、访客三类人员的基础信息支持 Excel 批量导入导出人员状态支持启用/停用。人脸采集支持摄像头实时拍摄和照片批量导入两种方式采集后自动提取人脸特征并建档。门禁通行识别到人脸后系统判定身份匹配成功则控制闸机开锁陌生人记录并触发告警。通行记录展示所有设备的人脸识别记录带照片截图支持按时间、人员、设备、结果筛选。考勤统计根据通行记录按日/周/月汇总统计迟到、早退、缺勤等情况支持导出报表。系统管理用户权限、角色分配、门禁设备管理、系统参数配置。每个模块之间不是孤立的。比如考勤统计必须依赖通行记录的准确性通行记录又依赖人员管理中的排班信息。所以设计的时候我会把数据流捋清楚从人建档、人脸采集、设备绑定到通行上报、数据统计这是一条完整链路。2.2 数据库表结构的关键设计数据库我用的 MySQL 8.0核心表一共六张。这里重点说几张关键表的设计思路-- 人员表 CREATE TABLE sys_user ( id bigint(20) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL COMMENT 登录账号, password varchar(100) NOT NULL COMMENT BCrypt加密密码, role varchar(20) NOT NULL COMMENT ADMIN/TEACHER/STUDENT/VISITOR, real_name varchar(50) DEFAULT NULL, status tinyint(1) DEFAULT 1 COMMENT 1正常 0停用, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 人脸特征表 CREATE TABLE face_feature ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL COMMENT 对应用户ID, feature_data blob COMMENT 512字节特征数据, face_image varchar(255) DEFAULT NULL COMMENT 人脸照片URL, update_time datetime DEFAULT NULL, PRIMARY KEY (id), KEY idx_user_id (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 通行记录表 CREATE TABLE access_record ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) DEFAULT NULL COMMENT 识别到的用户ID陌生人则NULL, device_id varchar(50) NOT NULL, device_name varchar(100) DEFAULT NULL, result tinyint(1) NOT NULL COMMENT 1通过 0拒绝, score float DEFAULT NULL COMMENT 人脸比对相似度分数, capture_image varchar(255) DEFAULT NULL, create_time datetime DEFAULT NULL, PRIMARY KEY (id), KEY idx_user_id (user_id), KEY idx_create_time (create_time) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;比较核心的设计点是face_feature 表独立建表不要跟用户表放一起。原因有两个第一人脸特征数据是二进制 blob长度数百字节跟用户基础信息混在一张表会影响查询性能第二后续如果接入不同算法厂商特征数据结构可能不一样独立建表方便扩展。通行记录表则单独加了 create_time 索引和 user_id 索引因为这是系统里数据量增长最快的表查询也最频繁没有索引一个月后就会明显卡顿。2.3 Redis 在门禁场景里的两个核心用途这个项目除了 MySQL我还引入了 Redis主要解决两个问题。第一个是人脸特征缓存。人脸比对的时候后端需要把摄像头抓拍的脸跟库里的所有人脸特征进行匹配。如果每次比对都查 MySQLN 个人就至少要 N 次磁盘 IO响应时间会明显变长。我的做法是应用启动时把全部人脸特征加载到 Redis 里用 Hash 结构存储key 是 user_idvalue 是特征二进制数据。比对时直接从内存里取速度能快一个数量级。当有人脸更新、新增、删除时同步刷新 Redis 缓存保证数据一致。第二个是防重复开闸。实际场景中摄像头会持续抓帧同一张脸在 2 秒内可能被识别到 10 次以上如果每次都触发开闸不仅浪费资源还可能出现闸机刚开又要开的情况。我用 Redis 的 SETNX 命令做分布式锁以 user_id 为 key设置 10 秒过期时间。如果 10 秒内已经识别通过就跳过本次开闸操作只更新记录。3. 人脸识别的技术方案与实现细节3.1 人脸识别的完整流程拆解人脸识别这个环节很多人一开始以为就是“拍个照对比一下”其实拆开来看有六步人脸检测从摄像头帧中定位到人脸位置返回人脸框坐标。人脸对齐根据眼睛、鼻子等关键点把人脸校正到标准角度。特征提取将人脸图像转化为固定维度比如 128 维的特征向量。特征比对将当前特征向量与数据库中的人脸特征计算相似度。阈值判断相似度超过设定阈值则认定为同一个人。结果响应返回用户信息触发开闸、记录、告警等动作。这六步中前两步由虹软 SDK 的检测接口完成中间两步由特征提取接口完成后两步由我们的业务逻辑完成。逻辑并不复杂但因为多个步骤都在处理图像数据对服务器 CPU 有一定占用我建议至少给服务器配 4 核 CPU否则并发识别时会出现明显延迟。3.2 人脸注册环节的注意事项一个人脸要能识别前提是系统里得有他的特征模板。注册环节我在项目里实现了两种方式方式一摄像头实时拍照注册。用户在 Web 端打开授权摄像头前端实时展示画面系统自动检测到人脸后截取一张清晰度最高的照片上传后端。后端调用 SDK 提取特征后存库。方式二图片批量导入。学校手里常有统一的证件照可以用 Excel 模板批量导入姓名、学号/工号、照片路径系统依次读取图片、提取特征、建档。这个方式对存量人员建档非常高效我们导入全校 8000 名学生大约花了 20 分钟。这里有一个非常关键的注册质量要求特征提取要确保底库里每张脸都是清晰的、正面的、光线均匀的。如果底库照片质量差上线后识别率会非常难看。我在注册接口里加了一个清晰度校验逻辑如果图片亮度偏低或者模糊度过高直接返回“照片质量不合格”提醒用户重新上传入库前就把问题挡掉。3.3 阈值怎么定这个参数藏了不少学问人脸比对最终输出的是一个相似度分数虹软是 0~100 的浮点数分数超过阈值才算同一个人。阈值设置多少直接决定了系统的误识率和拒识率两个指标此消彼长。在校园场景我把阈值设为 83 分。这个数值不是拍脑袋定的是根据实际环境做的测试在正常白天光线、距离摄像头 0.5~1.5 米的场景下同一个人的比对分数通常在 88~97 之间家人或同班同学等相似脸型的分数在 65~78 之间。83 分可以保留大约 15 分的缓冲区既不影响正常通过率又能有效隔离陌生人。但不同现场环境阈值一定不同。比如门口背光严重正常识别的分数会掉到 75~85此时如果还用 83 分老师把好几个学生都挡在门外。我的建议是上线前用现场摄像头采集 100 个正样本和 100 个负样本做测试画出 ROC 曲线取误识率低于 0.1% 对应的最大阈值点。这个工作前期看起来费时间但能省掉后期无尽的客诉。3.4 活体检测为什么必须有人脸识别系统最怕什么一张打印照片、一段录制视频、一个 3D 打印面模就能骗过。在校园场景学生之间拿手机里同学的帅照开门这种事不是没发生过。为了挡住这种伪造攻击系统必须加活体检测。虹软 SDK 提供两套活体检测方案静默 RGB 活体检测和红外活体检测。RGB 活体检测通过分析皮肤纹理、明暗变化来判断是否为真实人脸优点是普通摄像头就能用但对分辨率要求高。红外活体检测依赖红外摄像头利用红外光下活体皮肤和照片的反射差异做判断准确率高很多。我在项目里做了策略配置门禁设备端默认开启静默 RGB 活体检测。如果后续校园环境安全要求提高直接切换到红外方案即可上层业务代码不用动。实际测试下来RGB 活体检测在正常光照下对手机屏幕照片的拦截率接近 100%但低光照场景误拒率会升高这也是要用阈值和活体阈值分开调优的原因。4. 后端 SpringBoot 实现与接口设计4.1 项目结构规划后端项目我按照功能分包结构清晰团队协作时也能减少冲突。com.campus.gate ├── config # 配置类Jackson、CORS、JWT拦截器 ├── controller # 接口层user、face、record、device、stats ├── service # 业务逻辑层 ├── mapper # MyBatis-Plus 数据访问层 ├── entity # 实体类 ├── dto # 接收参数对象 ├── vo # 返回视图对象 ├── common # 统一返回结果、异常处理、常量 ├── util # 工具类JWT、RSA、文件上传 └── engine # 人脸识别引擎封装虹软SDK这里要重点说一下 engine 包我把虹软 SDK 的调用全部封装在这一层controller 和 service 完全不感知底层算法实现。这样做的直接好处是如果有天项目要换人脸识别引擎比如换百度 API只需要重写 engine 包的实现类其他代码一行都不用改。4.2 核心接口设计与调用链接口设计遵循 RESTful 规范核心接口如下接口方法说明权限/api/auth/loginPOST登录返回 JWT Token公开/api/face/registerPOST人脸注册上传图片管理员/api/face/recognizePOST人脸识别上传图片返回用户信息管理员/设备/api/record/pageGET分页查询通行记录管理员/api/record/exportGET导出通行记录 Excel管理员/api/device/listGET获取门禁设备列表管理员/api/stats/hourGET按小时统计通行人数管理员以 /api/face/recognize 为例这个接口是系统的心脏完整调用链是设备端或 Web 端把抓拍到的图片 Base64 上传到后端后端先做人脸检测失败则返回“未检测到人脸”检测成功则提取特征与 Redis 中的所有特征做 1:N 比对取最高分最高分超过阈值且通过活体检测则返回用户信息并记录通行记录否则返回“陌生人”并触发告警。整个流程平均耗时在 300ms 以内实测并发 20 个请求时响应时间基本稳定。4.3 JWT 鉴权与接口安全设计门禁系统涉及出入记录和个人敏感信息接口安全不能马虎。认证方案我用的 JWT Spring 拦截器没有引入 Spring Security因为校园后台的角色模型比较简单管理员、教师、访客JWT 拦截器完全够用而且代码量少更容易控制。JWT 的有效期我设置为 8 小时这是考虑到教师和门卫经常长时间开着后台页面如果 token 过期太勤影响使用体验。但长时间 token 被窃取的风险也更大所以我在 token 里只保存用户 ID 和角色不保存任何敏感信息。涉及人脸图片的接口统一要求 HTTPS 部署防止传输过程被中间人截获。人脸识别接口 /api/face/recognize 的特殊之处在于它不光被 Web 管理后台调用还要被门禁设备调用。门禁设备没有用户交互界面没法像人一样登录获取 token。我的解决方案是为每台设备生成唯一的 appId appSecret设备端调用接口时带上这两个参数后端校验通过后颁发一个短期 token 给设备。4.4 实时视频流Web 端如何实现“看见”摄像头画面校园门禁管理后台有一个实时监控页面管理员希望看到每个门岗的实时画面。这里就涉及 Web 端实时视频的接入问题。我调研了三个方案HLSm3u8 切片流、WebRTC、WebSocket 推流。HLS 延迟一般在 3~10 秒播放器兼容性好但对实时性要求高的门禁场景明显不合适WebRTC 延迟低但信令协商复杂后端要用 Java 做 WebRTC 网关比较麻烦最终我选了 WebSocket MJPEG 方案实现简单延迟可以控制在 1 秒内兼容所有浏览器。具体做法是后端用 JavaCV 的 FFmpegFrameGrabber 拉取摄像头的 RTSP 流抽取视频帧压缩编码为 JPEG 图片通过 WebSocket 以固定频率15 帧/秒推送给前端前端在 Canvas 上实时绘制图片。这个方案对带宽要求高一些一帧 720P 的 JPEG 大约 60KB15 帧就是 900KB/s内网环境下完全没问题但通过公网查看实时画面时就无法满足只能降帧率或者改走 H.264。5. 前端 Vue 实现与交互体验优化5.1 Vue 工程搭建与目录规划前端用的 Vue 3 Vite Element Plus Pinia Vue Router构建工具选了 Vite因为它的冷启动速度快开发体验比市面其他方案好太多。Node 环境建议用 18 或 20 LTSVite 7 对 Node 版本有要求太老的版本直接起不来。目录结构按模块划分src ├── api # 接口请求封装 │ ├── auth.js │ ├── face.js │ ├── record.js │ └── device.js ├── assets # 静态资源 ├── components # 通用组件人脸采集弹窗、视频播放器 ├── router # 路由配置 ├── store # Pinia 状态管理 ├── views # 页面组件 │ ├── login.vue │ ├── layout.vue │ ├── student.vue │ ├── teacher.vue │ ├── visitor.vue │ ├── record.vue │ ├── monitor.vue │ └── dashboard.vue └── utils # 工具类request封装、WebSocket封装5.2 路由与权限控制实现管理后台的权限控制是标配能力我用 Vue Router 的全局前置守卫 Pinia 里存储的用户角色信息来实现。路由配置里需要权限的页面通过 meta.roles 字段声明允许访问的角色{ path: /record, name: Record, component: () import(../views/record.vue), meta: { title: 通行记录, roles: [ADMIN, TEACHER] } }全局守卫每次跳转前检查是否存在 token没有则强制跳转登录页有 token 则校验当前用户角色是否在 meta.roles 中不在就提示“无权限访问”。这里要注意一个坑刷新页面后 Pinia 里的用户信息会丢失所以我做了刷新时重新调用 /api/auth/info 接口获取用户信息的逻辑避免刷新后所有带权限的路由全部失效。5.3 人脸采集弹窗的交互设计人脸注册页面是整个系统前端开发中交互最复杂的部分。用户需要点击“开始采集”浏览器弹出摄像头授权画面实时显示在 video 元素里然后系统自动检测人脸。我用的方案是基于浏览器原生 API 的 getUserMedia 获取摄像头流然后通过 Canvas 定时截帧每帧调用后端的人脸检测接口。检测到人脸后前端判断人脸框是否在画面中心区域并且人脸位置稳定连续 5 帧位置变化小于 20 像素再抓取当前帧作为注册照片上传。这套交互逻辑的好处是用户不需要手动按快门站到摄像头前自动完成采集体验很顺。实际开发中还要处理好几个边界情况用户拒绝摄像头授权、摄像头被其他应用占用、检测不到人脸时长时间无反馈。我的处理是授权失败弹窗提示引导检查浏览器设置检测不到人脸时在画面上绘制扫描框动画让用户感知到系统在工作超过 30 秒无结果则自动弹出提示。5.4 实时监控页与通行动态滚动展示管理后台的驾驶舱页面除了常规的统计卡片和 ECharts 图表最直观的模块是“实时通行记录”新识别成功或陌生人告警会以动态卡片的形式从右侧滑入展示照片、姓名、时间、门禁点、识别分数。这个功能用 WebSocket 推送实现后端识别接口完成后通过 WebSocket 广播一条记录事件前端监听后把最新记录插入列表顶部。WebSocket 前端的实现要注意几个问题断线自动重连用指数退避策略、页面隐藏时暂停渲染以降低资源占用、消息频率过高时做节流。我在工具类里封装了一个带心跳检测和自动重连的 WebSocket 客户端断线后每 2 秒重试一次最多重试 5 次最大程度保证展示的实时性。6. 硬件设备对接与部署落地6.1 摄像头与闸机控制的两种对接方案校园门禁的硬件对接有两种典型方案实际项目里我两种都用过各有适用场景。方案一普通网络摄像头 继电器控制电磁锁。这种方案适合已经有模拟摄像头或网络摄像头的旧闸机改造。摄像头负责采集视频流继电器模块负责控制电磁锁的通断电。后端识别成功后通过 HTTP 请求给继电器控制板发送开锁指令。优点是硬件成本低可以复用现有摄像头缺点是摄像头画质、角度和灯光条件不可控识别率容易受影响。方案二一体式人脸识别门禁机。设备自带双目摄像头带红外补光、人脸检测芯片、闸机控制接口本身就是一台小计算机。这种方案识别由设备本地完成再把结果上报到后端系统。优点是识别速度极快、精度高、环境适应性强缺点是单台设备成本高布点数量多时整体预算需要认真评估。我在项目里采用了混合部署主要出入口用一体式门禁机保障高峰时段的识别效率室内会议室、实验室等次要点位用网络摄像头 继电器方案控制成本。6.2 门禁机的 HTTP 对接接口一体式门禁机通常提供 HTTP 协议接口给上层平台调用。我们需要对接的核心动作有两个一是把服务器的人脸特征下发到设备端这样设备才能本地识别二是接收设备的识别结果上报。标准对接流程大概是管理人员在 Web 端录入学生人脸后端把人脸特征打包成 base64 字符串调用门禁机的“新增用户”接口把特征下发到设备。当有人刷脸时设备本地完成识别然后通过自定义回调接口把识别结果 POST 到我们的后端后端解析后写入通行记录。这里是两个方向的接口对接开发时最容易忽略的是设备离线时的数据补偿——设备断网期间产生的通行记录无法实时上报需要设备端缓存恢复网络后批量补传这块逻辑要对设备厂商的协议做额外的数据处理兼容。6.3 Linux Docker 部署全流程系统交付时用的是 Docker 部署把整个环境搭成镜像迁移非常方便。服务器我选 Ubuntu 22.04 Docker Compose容器划分情况mysql:8.0业务数据库redis:7.0缓存和分布式锁backendSpringBoot 后端镜像含虹软 SDK 动态库frontendNginx 镜像构建后前端静态资源SpringBoot 应用依赖虹软的原生动态库Docker 镜像构建时需要把 so 文件 COPY 到指定目录还要确保系统库依赖完整。我第一次构建镜像时漏了 libX11.so 这个依赖应用启动报 UnsatisfiedLinkError排查了半天后来在 Dockerfile 里显式安装了依赖库问题解决。Docker Compose 配置文件里几个注意点总结如下services: backend: image: campus-gate-backend:1.0 ports: - 8080:8080 environment: SPRING_PROFILES_ACTIVE: prod MYSQL_HOST: mysql REDIS_HOST: redis volumes: - ./logs:/app/logs - ./upload:/app/upload depends_on: - mysql - redisupload 目录必须挂载到宿主机因为用户上传的人脸照片要持久化存储容器重建时不能丢失。日志目录同样要挂载出来排障时需要到宿主机上直接查看日志文件。7. 常见问题与排查技巧实录7.1 人脸识别率低先查环境再查参数实际部署过程中识别率不达标是最常见的投诉。我统计过反馈识别失败的问题80% 跟环境有关只有 20% 是算法参数问题。环境问题主要是三类一是光线问题背光或者强逆光时人脸太暗摄像头拍不清二是角度问题摄像头安装位置太高或太低人脸成像倾斜角度大三是距离问题人脸离摄像头太远五官关键点像素不够。排查步骤我建议固定一套流程先看抓拍的原图看人脸区域是否清晰再看识别时的相似度分数如果分数在 80 分边缘但没通过阈值说明底库质量还行调整阈值或补光能改善如果分数很低甚至没检测到人脸大概率是抓拍图太差或者角度太大需要调整摄像头位置和光照。不要一上来就调算法参数那是在错误的方向上努力。7.2 视频流卡顿问题不止在网络Web 端实时画面偶尔卡顿很多人第一个想到的就是带宽不够。但实际测试发现后端用 JavaCV 拉 RTSP 流时如果解码线程和推流线程共用阻塞队列一旦队列满解码线程就会阻塞导致画面越来越卡。我最后把抓帧、压缩、推送拆成三个线程池中间用有界队列连接满了主动丢弃旧帧保证推流端始终拿到最新画面延迟和卡顿问题基本消失。如果你的项目走公网查看实时视频建议把 WebSocket 推流改为 H.264 编码流MJPEG 单帧大跨公网带宽根本扛不住。实在要用 MJPEG就把帧率降到 5 帧画质调低勉强能用。7.3 SpringBoot 版本踩坑新版本不等于好用这是很多新手容易踩的大坑。SpringBoot 3.x 已经发布但如果你还在用 JDK 8千万别顺手就引入了 3.x 版本。SpringBoot 3 强制要求 JDK 17且底层是 Jakarta EEjavax 包名全部变了老项目迁移工作量巨大。我做这个项目时用的是 SpringBoot 2.7.x JDK 8这是目前最稳定的组合。另外虹软 SDK 的是用 JNI 调用的本地库版本兼容性上不会随 SpringBoot 版本升级而优化所以不用盲目追新。团队里面试或者学习时聊“最强技术栈”没关系但做交付项目稳定优先能用就尽量别动。7.4 前端常见问题刷新 404 和跨域Vue 项目如果用 history 模式路由部署在 Nginx 下刷新子路由页面会报 404这是单页应用的老问题。解决方法是 Nginx 配置一个 try_files把路由请求全部转发到 index.htmllocation / { root /usr/share/nginx/html; index index.html; try_files $uri $uri/ /index.html; }开发模式下前后端跨域我在 Vite 里配置了 devServer 的 proxy 代理把 /api 路径代理到后端 8080 端口避免本地调试时的跨域问题。生产环境则是用 Nginx 反向代理把 /api 转发到后端服务表现上没有任何跨域问题。7.5 人脸数据安全这个坑大家都要重视人脸特征数据是不可逆的但它仍然是敏感数据泄露了会造成非常大的风险。系统做了三层防护数据库中人脸特征字段加密存储即使数据库被拖走也无法直接还原成人脸模板人脸图片统一放在单独的文件目录并通过鉴权接口访问不能直接通过 URL 裸访问操作日志记录所有对人脸数据的增删改行为关键操作需要管理员二次验证。这里要特别提醒人脸特征数据的备份策略。很多项目把数据库定期备份了但人脸照片目录没有纳入备份体系一旦磁盘损坏所有底库照片和特征就全没了重新采集全校几千人脸的代价非常大。我建议把 upload 目录和 feature 表一起纳入备份计划异地备份更加稳妥。写在最后的一点心得这个项目从搭建到落地整个周期接近两个月最深的体会是技术选型只是骨架真正决定项目成败的往往是一些容易被忽略的细节。比如阈值参数测试、底库照片质量把控、设备断线重连、数据备份策略这些看起来不起眼的事情实际运行中才是稳定性的关键。最后再分享一个小技巧上线的第一个月我每天都会抽时间看一遍陌生人告警记录和识别失败日志这些数据能帮你快速发现哪些点位、哪些时段、哪些人群的识别体验有问题及时调到最优。等工作稳定后这套系统基本就是“无感”的存在了老师和学生只会记得“刷个脸就进去了”不再觉得门禁是个麻烦这大概就是智能门禁系统最好的状态。
返回列表