在社区安全管理日益智能化的背景下,传统的人工登记方式已难以满足高效、精准的管理需求。本文将详细介绍一套基于人脸识别技术的社区出入管理系统,该系统通过整合腾讯云 AI 接口、数据库设计与业务逻辑,实现了居民出入自动识别、记录追踪与访客管理的全流程数字化,为社区安全管理提供了高效解决方案。
系统核心模块概述
系统主要包含三大功能模块:
- 人脸识别出入管理:通过调用第三方人脸识别 API,实现居民身份自动核验与出入状态记录
- 出入记录查询统计:对居民出入数据进行多条件查询、分页展示与统计分析
- 访客登记管理:支持访客信息的增删改查,补充非居民出入的管理场景
一、人脸识别出入管理模块
1.1 实现思路
人脸识别是系统的核心功能,其设计目标是实现 "刷脸" 即可完成身份核验与出入记录,核心流程如下:
- 小区信息加载:前端通过接口获取所有小区列表,供用户选择当前操作的小区(用于后续权限校验)
- 人脸信息核验:调用腾讯云人脸识别 API,验证传入图片中是否包含有效人脸(且仅一张)
- 身份匹配:将人脸信息与系统人员库比对,确认是否为已登记居民
- 权限校验:验证该居民是否属于当前选择的小区,确保仅本小区居民可正常出入
- 出入状态记录:根据居民当前的出入状态(通过
outTime
字段是否为空判断),更新或创建出入记录,同时保存出入时的人脸图片
1.2 核心代码实现
1.2.1 小区列表接口
小区列表是权限校验的基础,接口通过查询数据库返回所有小区信息,供前端下拉选择:
/*** 获取小区列表(用于前端选择与权限校验)* @return 包含小区列表的响应结果*/
@GetMapping("/communityList")
public Result communityList() {// 查询所有小区信息(社区名称、ID等核心字段)List<Community> communityList = communityService.list();return Result.ok().put("data", communityList);
}
该接口直接调用 MyBatis-Plus 的list()
方法查询全量小区数据,确保前端能实时获取最新的小区信息,为后续 "居民 - 小区" 权限匹配提供基础。
1.2.2 人脸识别核心接口
该接口是整个模块的核心,整合了人脸比对、权限校验、记录更新等全流程逻辑:
/*** 人脸识别与出入记录处理* @param inOutFaceForm 包含人脸图片Base64编码、文件格式、小区ID的表单* @return 识别结果与操作状态*/
@PostMapping("/add")
public Result add(@RequestBody InOutFaceForm inOutFaceForm) {// 1. 调用腾讯云人脸识别API,在人员库中搜索匹配人脸FaceApi faceApi = new FaceApi();RootResp resp = faceApi.searchPersonsReturnsByGroup(apiConfiguration, inOutFaceForm.getFileBase64());// 2. 处理API响应结果if (resp.getRet() == 0) { // 接口调用成功// 解析API返回的JSON数据,提取匹配的人员信息JSONObject object = JSONObject.parseObject(resp.getData().toString());JSONArray resultsReturnsByGroup = object.getJSONArray("ResultsReturnsByGroup");JSONObject returnsByGroup = resultsReturnsByGroup.getJSONObject(0);JSONArray groupCandidates = returnsByGroup.getJSONArray("GroupCandidates");JSONObject candidatesObj = groupCandidates.getJSONObject(0);JSONArray candidates = candidatesObj.getJSONArray("Candidates");// 3. 匹配系统中的居民信息(人员库ID与本地数据库关联)Person targetPerson = null;for (int i = 0; i < candidates.size(); i++) {JSONObject personInfo = candidates.getJSONObject(i);String personId = personInfo.getString("PersonId").substring(4); // 截取实际ID(去除前缀)long pid = Integer.parseInt(personId);Person person = personService.getById(pid);// 校验人脸ID与本地存储的人脸图片ID是否匹配(确保身份唯一)if (person != null) {String faceUrl = person.getFaceUrl();if (faceUrl != null && !faceUrl.isEmpty()) {String faceId = personInfo.getString("FaceId");String localFaceId = faceUrl.substring(faceUrl.lastIndexOf("/") + 1, faceUrl.lastIndexOf("."));if (faceId.equals(localFaceId)) {targetPerson = person;break;}}}}// 4. 身份与权限校验if (targetPerson == null) {return Result.ok().put("data", "人员信息不存在(未登记)");}// 校验当前选择的小区是否与居民所属小区一致if (inOutFaceForm.getCommunityId() != targetPerson.getCommunityId()) {return Result.ok().put("data", "非本小区居民,请联系管理员");}// 5. 处理出入记录(判断是"进入"还是"离开")InOutRecord record = new InOutRecord();record.setCommunityId(targetPerson.getCommunityId());record.setPersonId(targetPerson.getPersonId());// 保存人脸图片(Base64解码为文件,存储到服务器)String newFileName = UUID.randomUUID() + "." + inOutFaceForm.getExtName();String filePath = face + newFileName; // 本地存储路径Base64Util.decoderBase64File(inOutFaceForm.getFileBase64(), filePath);String picUrl = urlPrefix + "community/upload/face/" + newFileName; // 访问URL// 查询该居民是否有未完成的出入记录(outTime为空表示"在小区内")InOutRecord existingRecord = inOutRecordMapper.getInOutRecord(record);if (existingRecord == null) {// 无未完成记录 → 新增"进入"记录record.setInPic(picUrl);record.setInTime(LocalDateTime.now());inOutRecordMapper.insert(record);return Result.ok().put("data", "【" + targetPerson.getUserName() + "】进入小区");} else {// 有未完成记录 → 更新"离开"记录existingRecord.setOutPic(picUrl);existingRecord.setOutTime(LocalDateTime.now());inOutRecordMapper.updateById(existingRecord);return Result.ok().put("data", "【" + targetPerson.getUserName() + "】离开小区");}} else {// API调用失败(如人脸不清晰、无有效人脸等)return Result.ok().put("data", "人脸识别失败:错误码=" + resp.getRet() + ",原因=" + resp.getMsg());}
}
1.3 技术细节说明
- 人脸图片处理:前端传入的人脸图片以 Base64 编码格式传输,后端通过
Base64Util
解码为文件,存储到服务器指定目录,并生成可访问的 URL(用于记录与后续查看) - 腾讯云 API 封装:通过
FaceApi
类统一封装人脸识别相关接口(如searchPersonsReturnsByGroup
用于人脸搜索),简化业务层调用 - 出入状态判断:通过查询
in_out_record
表中是否存在outTime
为空的记录,判断居民当前是 "进入" 还是 "离开",确保记录的连续性与准确性 - 权限校验逻辑:通过比对居民所属小区 ID 与当前选择的小区 ID,防止非本小区居民随意出入,增强社区安全性
二、出入记录查询统计模块
2.1 表结构设计
in_out_record
表用于存储居民出入的详细信息,核心字段设计如下:
字段名 | 类型 | 说明 |
---|---|---|
in_out_record_id | int | 主键 ID(自增) |
person_id | int | 关联居民 ID(外键) |
community_id | int | 关联小区 ID(外键) |
in_time | datetime | 进入时间 |
out_time | datetime | 离开时间(可为空,标识未离开) |
in_pic | varchar | 进入时人脸图片 URL |
out_pic | varchar | 离开时人脸图片 URL |
2.2 核心功能实现
2.2.1 出入记录分页查询
支持按时间范围、小区、居民等条件查询,返回分页结果:
/*** 出入记录多条件查询* @param form 包含查询条件(开始时间、结束时间、小区ID等)* @return 分页的出入记录列表*/
@GetMapping("/list")
public Result getInOutList(InOutRecordListForm form) {PageVO pageVO = inOutRecordService.getInOutRecordList(form);return Result.ok().put("data", Collections.singletonMap("pageList", pageVO));
}
服务层通过InOutRecordListForm
接收前端参数,整合 MyBatis-Plus 的分页插件,实现带条件的分页查询,支持前端表格展示与分页交互。
2.2.2 数据统计分析
提供小区出入数据的统计图表(如每日出入次数、高峰时段等):
/*** 小区出入数据统计* @return 统计结果(按天/按时段的出入次数等)*/
@GetMapping("/chart")
public Result chart() {Map<String, Object> stats = inOutRecordService.chart();return Result.ok().put("data", stats);
}
通过 SQL 聚合查询(如按日期分组统计in_time
数量),生成可视化所需的数据,辅助社区管理人员掌握出入规律。
三、访客登记管理模块
对于非小区居民的访客,系统提供专门的访客登记模块,通过manual_record
表管理访客信息,核心功能包括:
- 访客信息添加:登记访客姓名、身份证号、到访事由、访问时间等信息
- 访客记录查询:支持按时间、姓名、小区等条件查询历史访客
- 记录维护:提供访客信息的修改、删除功能,满足管理需求