在社区安全管理日益智能化的背景下,传统的人工登记方式已难以满足高效、精准的管理需求。本文将详细介绍一套基于人脸识别技术的社区出入管理系统,该系统通过整合腾讯云 AI 接口、数据库设计与业务逻辑,实现了居民出入自动识别、记录追踪与访客管理的全流程数字化,为社区安全管理提供了高效解决方案。
系统核心模块概述
系统主要包含三大功能模块:
- 人脸识别出入管理:通过调用第三方人脸识别 API,实现居民身份自动核验与出入状态记录
- 出入记录查询统计:对居民出入数据进行多条件查询、分页展示与统计分析
- 访客登记管理:支持访客信息的增删改查,补充非居民出入的管理场景
一、人脸识别出入管理模块
1.1 实现思路
人脸识别是系统的核心功能,其设计目标是实现 "刷脸" 即可完成身份核验与出入记录,核心流程如下:
- 小区信息加载:前端通过接口获取所有小区列表,供用户选择当前操作的小区(用于后续权限校验)
- 人脸信息核验:调用腾讯云人脸识别 API,验证传入图片中是否包含有效人脸(且仅一张)
- 身份匹配:将人脸信息与系统人员库比对,确认是否为已登记居民
- 权限校验:验证该居民是否属于当前选择的小区,确保仅本小区居民可正常出入
- 出入状态记录 :根据居民当前的出入状态(通过
outTime
字段是否为空判断),更新或创建出入记录,同时保存出入时的人脸图片
1.2 核心代码实现
1.2.1 小区列表接口
小区列表是权限校验的基础,接口通过查询数据库返回所有小区信息,供前端下拉选择:
java
/**
* 获取小区列表(用于前端选择与权限校验)
* @return 包含小区列表的响应结果
*/
@GetMapping("/communityList")
public Result communityList() {
// 查询所有小区信息(社区名称、ID等核心字段)
List<Community> communityList = communityService.list();
return Result.ok().put("data", communityList);
}
该接口直接调用 MyBatis-Plus 的list()
方法查询全量小区数据,确保前端能实时获取最新的小区信息,为后续 "居民 - 小区" 权限匹配提供基础。
1.2.2 人脸识别核心接口
该接口是整个模块的核心,整合了人脸比对、权限校验、记录更新等全流程逻辑:
java
/**
* 人脸识别与出入记录处理
* @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 出入记录分页查询
支持按时间范围、小区、居民等条件查询,返回分页结果:
java
/**
* 出入记录多条件查询
* @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 数据统计分析
提供小区出入数据的统计图表(如每日出入次数、高峰时段等):
java
/**
* 小区出入数据统计
* @return 统计结果(按天/按时段的出入次数等)
*/
@GetMapping("/chart")
public Result chart() {
Map<String, Object> stats = inOutRecordService.chart();
return Result.ok().put("data", stats);
}
通过 SQL 聚合查询(如按日期分组统计in_time
数量),生成可视化所需的数据,辅助社区管理人员掌握出入规律。
三、访客登记管理模块
对于非小区居民的访客,系统提供专门的访客登记模块,通过manual_record
表管理访客信息,核心功能包括:
- 访客信息添加:登记访客姓名、身份证号、到访事由、访问时间等信息
- 访客记录查询:支持按时间、姓名、小区等条件查询历史访客
- 记录维护:提供访客信息的修改、删除功能,满足管理需求
