后端实现步骤
1. 创建 Spring Boot 项目
添加依赖:
<dependencies>
<!-- Web & REST -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 百度AI SDK -->
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.16.1</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
2. 配置百度 AI 参数
在application.properties
中添加:
baidu.face.appId=APP_ID
baidu.face.apiKey=API_KEY
baidu.face.secretKey=SECRET_KEY
baidu.face.imageType=BASE64
baidu.face.groupId=user_group
3. 创建百度 AI 工具类
package com.example.demo.utils;
import com.baidu.aip.face.AipFace;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.HashMap;
@Component
public class BaiduAiUtils {
@Value("${baidu.face.appId}")
private String APP_ID;
@Value("${baidu.face.apiKey}")
private String API_KEY;
@Value("${baidu.face.secretKey}")
private String SECRET_KEY;
@Value("${baidu.face.imageType}")
private String IMAGE_TYPE;
@Value("${baidu.face.groupId}")
private String GROUP_ID;
private AipFace client;
private HashMap<String, Object> options = new HashMap<>();
@PostConstruct
public void init() {
// 初始化AipFace客户端
client = new AipFace(APP_ID, API_KEY, SECRET_KEY);
// 设置人脸检测参数
options.put("quality_control", "NORMAL"); // 图像质量控制
options.put("liveness_control", "LOW"); // 活体检测等级
}
// 人脸搜索(用于登录)
public String faceSearch(String imageBase64) {
try {
JSONObject res = client.search(imageBase64, IMAGE_TYPE, GROUP_ID, options);
if (res.getInt("error_code") == 0) {
JSONObject result = res.getJSONObject("result");
if (result.has("user_list")) {
var userList = result.getJSONArray("user_list");
if (userList.length() > 0) {
var user = userList.getJSONObject(0);
double score = user.getDouble("score");
if (score > 80) { // 相似度阈值
return user.getString("user_id");
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 人脸注册(用于首次绑定)
public boolean faceRegister(String userId, String imageBase64) {
try {
JSONObject res = client.addUser(imageBase64, IMAGE_TYPE, GROUP_ID, userId, options);
return res.getInt("error_code") == 0;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
1. 类定义与依赖注入
@Component
public class BaiduAiUtils {
@Value("${baidu.face.appId}")
private String APP_ID;
@Value("${baidu.face.apiKey}")
private String API_KEY;
@Value("${baidu.face.secretKey}")
private String SECRET_KEY;
@Value("${baidu.face.imageType}")
private String IMAGE_TYPE;
@Value("${baidu.face.groupId}")
private String GROUP_ID;
private AipFace client;
private HashMap<String, Object> options = new HashMap<>();
@Component
:将此类标记为 Spring 组件,由 Spring 容器管理@Value
:从配置文件读取百度 AI 相关的认证信息和参数AipFace client
:百度人脸识别 API 的客户端options
:API 调用时的可选参数配置
APP_ID
、API_KEY
、SECRET_KEY
- 用途:百度 AI 开放平台的认证凭证,用于身份验证和 API 调用授权。
- 对应配置示例:
baidu.face.appId=你的AppID baidu.face.apiKey=你的API Key baidu.face.secretKey=你的Secret Key
- 说明:这些值需要在 百度 AI 开放平台 注册并创建人脸识别应用后获取。
IMAGE_TYPE
- 用途:指定图片的格式类型,告诉 API 如何解析传入的图像数据。
- 可选值:
BASE64
:图像数据为 Base64 编码字符串(常用)。URL
:图像数据为网络 URL 地址。FACE_TOKEN
:图像数据为人脸标识(face_token)。
- 对应配置示例:
baidu.face.imageType=BASE64
GROUP_ID
- 用途:指定人脸库的用户组 ID,用于在人脸搜索或注册时区分不同用户群体。
- 说明:百度人脸识别 API 允许将用户分组管理(例如按部门、角色等),每个组有唯一的
GROUP_ID
。 - 对应配置示例:
baidu.face.groupId=users_group_001
2. 核心组件
AipFace client
- 类型:百度 AI SDK 提供的人脸识别客户端类。
- 用途:封装了与百度人脸识别 API 的通信逻辑,通过它可以调用具体的 API 接口(如人脸搜索、注册等)。
- 初始化:在
@PostConstruct
注解的init()
方法中完成初始化:java
client = new AipFace(APP_ID, API_KEY, SECRET_KEY);
HashMap<String, Object> options
- 用途:存储调用百度 API 时的可选参数,用于控制 API 的行为(如活体检测等级、图像质量要求等)。
- 初始化与设置:在
init()
方法中预配置了两个常用参数:java
options.put("quality_control", "NORMAL"); // 图像质量控制(NORMAL表示中等质量) options.put("liveness_control", "LOW"); // 活体检测等级(LOW表示低等级检测)
- 常见可选参数:
quality_control
:图像质量控制,可选值为NONE
(不控制)、LOW
(低)、NORMAL
(中)、HIGH
(高)。liveness_control
:活体检测等级,可选值为NONE
、LOW
、MEDIUM
、HIGH
。max_user_num
:人脸搜索时返回的最大用户数。
2. 初始化方法
@PostConstruct
public void init() {
// 初始化AipFace客户端
client = new AipFace(APP_ID, API_KEY, SECRET_KEY);
// 设置人脸检测参数
options.put("quality_control", "NORMAL"); // 图像质量控制
options.put("liveness_control", "LOW"); // 活体检测等级
}
@PostConstruct
:在 Bean 初始化完成后执行此方法- 初始化百度人脸识别客户端
- 设置两个关键参数:
quality_control
:控制图像质量,防止模糊或光照不佳的图片liveness_control
:活体检测等级,防止照片 / 视频欺骗
3. 人脸搜索方法(用于登录)
public String faceSearch(String imageBase64) {
try {
JSONObject res = client.search(imageBase64, IMAGE_TYPE, GROUP_ID, options);
if (res.getInt("error_code") == 0) {
JSONObject result = res.getJSONObject("result");
if (result.has("user_list")) {
var userList = result.getJSONArray("user_list");
if (userList.length() > 0) {
var user = userList.getJSONObject(0);
double score = user.getDouble("score");
if (score > 80) { // 相似度阈值
return user.getString("user_id");
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
- 功能:在指定用户组中搜索最相似的人脸
- 流程:
- 调用百度 API 进行人脸搜索
- 检查返回结果是否成功(error_code=0)
- 获取相似度最高的用户信息
- 验证相似度得分是否超过阈值(80 分)
- 返回匹配的用户 ID 或 null
1. 方法签名与参数
public String faceSearch(String imageBase64)
功能:在指定用户组(GROUP_ID
)中搜索与输入人脸最相似的用户。
参数:imageBase64
:待搜索的人脸图像的 Base64 编码字符串。
2. API 调用与结果处理
JSONObject res = client.search(imageBase64, IMAGE_TYPE, GROUP_ID, options);
关键参数:
imageBase64
:人脸图像数据。IMAGE_TYPE
:图像类型(如BASE64
)。GROUP_ID
:用户组 ID,指定在哪个用户组中搜索。options
:可选参数(如活体检测、质量控制)。返回值:百度 API 返回的 JSON 结果,包含错误码和匹配结果。
3. 结果解析流程
if (res.getInt("error_code") == 0) { ... }
错误码检查:
error_code == 0
表示 API 调用成功。- 其他错误码(如 110、111)表示认证失败或参数错误。
JSONObject result = res.getJSONObject("result");
if (result.has("user_list")) { ... }
结果结构:
result
:API 返回的结果数据。user_list
:匹配到的用户列表(按相似度降序排列)。
var userList = result.getJSONArray("user_list");
if (userList.length() > 0) { ... }
- 用户列表检查:
- 若列表为空,说明未找到匹配人脸。
var user = userList.getJSONObject(0);
double score = user.getDouble("score");
if (score > 80) { ... }
- 相似度评分:
score
:人脸相似度得分(范围 0-100)。score > 80
:自定义阈值,仅当相似度高于 80 分时才认为匹配成功。
4. 异常处理
catch (Exception e) {
e.printStackTrace();
}
return null;
- 异常捕获:
- 捕获网络异常、JSON 解析异常等,并打印堆栈信息。
- 发生异常时返回
null
,表示搜索失败。
百度 API 返回结果示例
API 成功调用时返回的 JSON 结构示例:
{
"error_code": 0,
"error_msg": "SUCCESS",
"log_id": 4255671843335,
"timestamp": 1695352327,
"cached": 0,
"result": {
"face_token": "6c6a5f5d7a5e5f4b5d3e2c1a0b9c8d",
"user_list": [
{
"group_id": "users_group_001",
"user_id": "user123",
"user_info": "",
"score": 92.5 // 相似度得分
}
]
}
}
4. 人脸注册方法(用于首次绑定)
public boolean faceRegister(String userId, String imageBase64) {
try {
JSONObject res = client.addUser(imageBase64, IMAGE_TYPE, GROUP_ID, userId, options);
return res.getInt("error_code") == 0;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
- 功能:将用户人脸图像注册到指定用户组
- 流程:
- 调用百度 API 添加用户人脸
- 检查返回结果是否成功
- 返回操作结果(成功 / 失败)
4. 创建用户服务与控制器
package com.example.demo.service;
import com.example.demo.entity.SysUser;
import com.example.demo.utils.BaiduAiUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class FaceLoginService {
@Autowired
private BaiduAiUtils baiduAiUtils;
@Autowired
private UserService userService; // 假设已有用户服务
// 人脸登录验证
public SysUser loginByFace(String imageBase64) {
// 1. 调用百度AI人脸搜索
String userId = baiduAiUtils.faceSearch(imageBase64);
if (userId != null) {
// 2. 查询用户信息
return userService.getUserById(Long.valueOf(userId));
}
return null;
}
// 人脸注册
public boolean registerFace(Long userId, String imageBase64) {
return baiduAiUtils.faceRegister(userId.toString(), imageBase64);
}
}
package com.example.demo.controller;
import com.example.demo.entity.SysUser;
import com.example.demo.service.FaceLoginService;
import com.example.demo.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/face")
public class FaceLoginController {
@Autowired
private FaceLoginService faceLoginService;
@PostMapping("/login")
public Map<String, Object> faceLogin(@RequestBody Map<String, String> params) {
String imageBase64 = params.get("image");
SysUser user = faceLoginService.loginByFace(imageBase64);
Map<String, Object> result = new HashMap<>();
if (user != null) {
// 生成JWT Token
String token = JwtUtils.generateToken(user.getId());
result.put("code", 200);
result.put("message", "登录成功");
result.put("token", token);
result.put("user", user);
} else {
result.put("code", 401);
result.put("message", "人脸识别失败");
}
return result;
}
@PostMapping("/register")
public Map<String, Object> faceRegister(@RequestBody Map<String, String> params) {
Long userId = Long.valueOf(params.get("userId"));
String imageBase64 = params.get("image");
boolean success = faceLoginService.registerFace(userId, imageBase64);
return success ?
Map.of("code", 200, "message", "人脸注册成功") :
Map.of("code", 500, "message", "人脸注册失败");
}
}