基于 Spring Boot + Vue 实现人脸采集功能全流程

一、技术栈与依赖引入

后端依赖 (pom.xml)

XML 复制代码
<!-- 百度AI SDK -->
<dependency>
    <groupId>com.baidu.aip</groupId>
    <artifactId>java-sdk</artifactId>
    <version>4.16.19</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!-- 文件处理 -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

前端依赖

无需额外依赖,利用原生 HTML5 API 和 Element UI 组件

二、配置文件设置

application.yml 配置

python 复制代码
# 百度云人脸识别配置
baidu:
  face:
    appId: //
    apiKey: //
    secretKey: //
    imageType: BASE64
    groupId: 04  # 人脸库分组名称

# 文件路径保存
file:
  upload-dir: D:/community/community-ui/src/photos(这里更改成自己的路径)

# 静态资源映射
spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB

资源映射配置 (WebConfig.java)

java 复制代码
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Value("${file.upload-dir}")
    private String uploadDir;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/photos/**")
                .addResourceLocations("file:" + uploadDir + "/");
    }
}

三、后端核心实现

1. 百度 AI 工具类 (BaiduAiUtils.java)

java 复制代码
@Component
@Slf4j
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 groupId;

    private AipFace client;
    private HashMap<String, Object> options = new HashMap<>();

    public BaiduAiUtils() {
        options.put("quality_control", "NORMAL");
        options.put("liveness_control", "LOW");
    }

    @PostConstruct
    public void init() {
        client = new AipFace(APP_ID, API_KEY, SECRET_KEY);
    }

    // 人脸注册
    public Boolean faceRegister(String userId, String image) {
        HashMap<String, String> stringOptions = convertToMapString(options);
        JSONObject res = client.addUser(image, IMAGE_TYPE, groupId, userId, stringOptions);
        log.info("addUser result :{}", res);
        return res.getInt("error_code") == 0;
    }

    // 人脸检测
    public Boolean faceCheck(String image) {
        JSONObject res = client.detect(image, IMAGE_TYPE, options);
        log.info("detect result :{}", res);
        if (res.has("error_code") && res.getInt("error_code") == 0) {
            JSONObject resultObject = res.getJSONObject("result");
            Integer faceNum = resultObject.getInt("face_num");
            return faceNum == 1;
        }
        return false;
    }

    private HashMap<String, String> convertToMapString(HashMap<String, Object> objectMap) {
        HashMap<String, String> stringMap = new HashMap<>();
        for (HashMap.Entry<String, Object> entry : objectMap.entrySet()) {
            stringMap.put(entry.getKey(), entry.getValue().toString());
        }
        return stringMap;
    }
}

2. 实体类 (FaceForm.java)

java 复制代码
@Data
public class FaceForm {
    private Integer personId;
    private String extName;
    private String fileBase64;
}

3. 控制器 (PersonController.java)

java 复制代码
@RestController
@RequestMapping("/sys/person")
public class PersonController {
    @Autowired
    private PersonService personService;
    @Autowired
    private BaiduAiUtils baiduAiUtils;
    @Value("${file.upload-dir}")
    private String uploadDir;

    @RequestMapping("/addPerson")
    public Result addPerson(@RequestBody FaceForm form) {
        try {
            Integer personId = form.getPersonId();
            String fileBase64 = form.getFileBase64();
            
            // 1.验证人员是否存在
            PersonEntity person = personService.getById(personId);
            if (person == null) {
                return Result.error("人员不存在");
            }
            
            // 2.人脸检测
            if (!baiduAiUtils.faceCheck(fileBase64)) {
                return Result.error("未检测到人脸或多人脸");
            }
            
            // 3.人脸注册到百度人脸库
            boolean aiResult = baiduAiUtils.faceRegister(personId.toString(), fileBase64);
            if (!aiResult) {
                return Result.error("人脸注册到人脸库失败");
            }
            
            // 4.保存图片到本地
            String fileName = "person_"+personId+"_"+System.currentTimeMillis()+".png";
            String filePath = Paths.get(uploadDir, fileName).toString();
            File file = new File(uploadDir);
            if (!file.exists()) {
                file.mkdirs();
            }
            
            // 处理Base64数据
            String base64Data = fileBase64.contains(",") ? fileBase64.split(",")[1] : fileBase64;
            byte[] imageBytes = Base64.getDecoder().decode(base64Data);
            Files.write(Paths.get(filePath), imageBytes);
            
            // 5.更新人员信息
            person.setFaceBase(fileBase64);
            String fullUrl = "http://localhost:8080/photos/" + fileName;
            person.setFaceUrl(fullUrl);
            person.setState(2); // 更新为已验证状态
            boolean updateResult = personService.updateById(person);
            
            return updateResult ? Result.ok() : Result.error("人脸录入失败");
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("系统异常:" + e.getMessage());
        }
    }
}

前端页面是如何展示出图片的,请参考
http://localhost:8080/photos/xxx.png的本地图片访问方案-CSDN博客

四、接口说明

人脸采集接口

  • 请求 URL: POST /sys/person/addPerson
  • 请求参数:

json

复制代码
{
    "personId": 98,
    "extName": "png",
    "fileBase64": "iVBORw0KGgoAAAANSUhEUgAAAJsAAAC4CAYAAAD0WZ4UAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJ8pt02jBn6wUmcy/39/xgi2nSFeQGzAAAAAElFTkSuQmCC"
}
  • 返回结果:

json

复制代码
{
    "msg": "操作成功",
    "code": 200
}