在社區安全管理日益智能化的背景下,傳統的人工登記方式已難以滿足高效、精準的管理需求。本文將詳細介紹一套基于人臉識別技術的社區出入管理系統,該系統通過整合騰訊云 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
表管理訪客信息,核心功能包括:
- 訪客信息添加:登記訪客姓名、身份證號、到訪事由、訪問時間等信息
- 訪客記錄查詢:支持按時間、姓名、小區等條件查詢歷史訪客
- 記錄維護:提供訪客信息的修改、刪除功能,滿足管理需求