package com.code2roc.fastface.controller;
|
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import com.code2roc.fastface.bizlogic.FaceRegistLogic;
|
import com.code2roc.fastface.model.*;
|
import com.code2roc.fastface.service.IFaceRegistService;
|
import com.code2roc.fastface.util.ConvertOp;
|
import com.code2roc.fastface.util.StringUtil;
|
import lombok.extern.slf4j.Slf4j;
|
import net.coobird.thumbnailator.Thumbnails;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.transaction.annotation.Isolation;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.multipart.MultipartFile;
|
|
import java.io.ByteArrayOutputStream;
|
import java.io.File;
|
import java.io.FileInputStream;
|
import java.io.InputStream;
|
import java.nio.file.Files;
|
import java.nio.file.Path;
|
import java.nio.file.Paths;
|
import java.nio.file.StandardCopyOption;
|
import java.util.Base64;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
|
@RestController
|
@RequestMapping("/faceApi")
|
@Slf4j
|
public class FaceRegist2Controller {
|
@Autowired
|
private IFaceRegistService faceRegistService;
|
@Autowired
|
private FaceRegistLogic faceRegistLogic;
|
@Autowired
|
private String localIpAddress;
|
@Value("8081")
|
private String imagesPort;
|
|
//用于初始化人脸库测试使用
|
@ResponseBody
|
@PostMapping("/init")
|
public Result2 init(@RequestBody Map<String, Object> params) {
|
log.info("集体注册人脸信息");
|
long begin = System.currentTimeMillis();
|
File imageDir = new File(ConvertOp.convert2String(params.get("url")));
|
for (File file : imageDir.listFiles()) {
|
Path tempDir = Paths.get(System.getProperty("user.dir"), "images");
|
try {
|
// 确保目录存在
|
if (!Files.exists(tempDir)) {
|
Files.createDirectories(tempDir);
|
log.info("创建图片目录: {}", tempDir.toAbsolutePath());
|
}
|
String userCode = file.getName().substring(0, file.getName().lastIndexOf("."));
|
if (faceRegistService.checkExist("userID", userCode)) {
|
return ResultGenerator.genFailResult("用户ID已注册");
|
}
|
String base64Image = convert(file, true);
|
RegistResult queryResult = faceRegistLogic.queryFace(base64Image);
|
if (queryResult.getStatus() == 0) {
|
FaceRegistDO faceRegistDO = faceRegistService.selectOneByField("registIndex", queryResult.getMessage());
|
if (faceRegistDO != null) {
|
return ResultGenerator.genFailResult("用户照片已注册");
|
}
|
}
|
String userName = "/images/" + userCode + ".jpg";
|
RegistResult registResult = faceRegistLogic.addFace(userCode, userName, base64Image);
|
if (registResult.getStatus() != 0) {
|
return ResultGenerator.genFailResult(registResult.getMessage());
|
}
|
Path targetPath = tempDir.resolve(userCode + ".jpg");
|
Files.copy(file.toPath(), targetPath, StandardCopyOption.REPLACE_EXISTING);
|
JSONObject result = getSuccessResultJson();
|
result.getJSONObject("data").put("faceUrl", "http://" + localIpAddress + ":" + imagesPort + "/images/" + userCode + ".jpg");
|
long end = System.currentTimeMillis();
|
log.info("user[{}],time addFace is:{}", userCode, (end - begin));
|
return ResultGenerator.genSuccessResult(result);
|
} catch (Exception e) {
|
log.warn("addFace-文件上传失败");
|
return ResultGenerator.genFailResult(e.getMessage());
|
} finally {
|
continue;
|
}
|
}
|
return ResultGenerator.genSuccessResult();
|
}
|
|
//用于删除人脸库测试使用
|
@ResponseBody
|
@PostMapping("/deleteAll")
|
@Transactional(rollbackFor = {Exception.class}, isolation = Isolation.READ_UNCOMMITTED)
|
public Object deleteAll(@RequestBody Map<String, Object> params) throws Exception {
|
Result result = Result.okResult();
|
faceRegistLogic.deleteAllFace();
|
return result;
|
}
|
|
@ResponseBody
|
@PostMapping("/list")
|
public Object list(@RequestBody Map<String, Object> params) {
|
Result result = Result.okResult();
|
HashMap<String, Object> paramMap = new HashMap<>();
|
String sql = "1=1";
|
String userName = ConvertOp.convert2String(params.get("userName"));
|
if (!StringUtil.isEmpty(userName)) {
|
sql += " and userName like #{userName}";
|
paramMap.put("userName", "%" + userName + "%");
|
}
|
String userID = ConvertOp.convert2String(params.get("userID"));
|
if (!StringUtil.isEmpty(userID)) {
|
sql += " and userID like #{userID}";
|
paramMap.put("userID", "%" + userID + "%");
|
}
|
List<FaceRegistDO> rows = faceRegistService.selectPageList("userID,userName,registDate,updateDate", sql, "id desc", paramMap);
|
int count = faceRegistService.selectCount(sql, paramMap);
|
result.add("rows", rows);
|
result.add("total", count);
|
return result;
|
}
|
|
/**
|
* 注册人脸
|
*
|
* @param image
|
* @param userCode
|
* @return
|
*/
|
@ResponseBody
|
@PostMapping("/addFace")
|
public Result2 insert(@RequestParam("image") MultipartFile image, String userCode) {
|
log.info("注册人脸信息");
|
long begin = System.currentTimeMillis();
|
File tempFile = null;
|
Path tempDir = Paths.get(System.getProperty("user.dir"), "images");
|
String base64Image;
|
try {
|
// 确保目录存在
|
if (!Files.exists(tempDir)) {
|
Files.createDirectories(tempDir);
|
log.info("创建图片目录: {}", tempDir.toAbsolutePath());
|
}
|
tempFile = Files.createTempFile(tempDir, "temp-addFace", ".jpg").toFile();
|
try (InputStream inputStream = image.getInputStream()) {
|
Files.copy(inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
}
|
base64Image = convert(image, true);
|
} catch (Exception e) {
|
// 确保临时文件被删除
|
if (tempFile != null && tempFile.exists()) {
|
try {
|
if (!tempFile.delete()) {
|
log.warn("Failed to delete temp file: {}", tempFile.getAbsolutePath());
|
}
|
} catch (Exception e2) {
|
log.warn("Error deleting temp file", e2);
|
}
|
}
|
return ResultGenerator.genFailResult("addFace-文件上传失败");
|
}
|
try {
|
if (faceRegistService.checkExist("userID", userCode)) {
|
return ResultGenerator.genFailResult("用户ID已注册");
|
}
|
RegistResult queryResult = faceRegistLogic.queryFace(base64Image);
|
if (queryResult.getStatus() == 0) {
|
FaceRegistDO faceRegistDO = faceRegistService.selectOneByField("registIndex", queryResult.getMessage());
|
if (faceRegistDO != null) {
|
return ResultGenerator.genFailResult("用户照片已注册");
|
}
|
}
|
String userName = "/images/" + userCode + ".jpg";
|
RegistResult registResult = faceRegistLogic.addFace(userCode, userName, base64Image);
|
if (registResult.getStatus() != 0) {
|
return ResultGenerator.genFailResult(registResult.getMessage());
|
}
|
Path targetPath = tempDir.resolve(userCode + ".jpg");
|
Files.copy(tempFile.toPath(), targetPath, StandardCopyOption.REPLACE_EXISTING);
|
JSONObject result = getSuccessResultJson();
|
result.getJSONObject("data").put("faceUrl", "http://" + localIpAddress + ":" + imagesPort + "/images/" + userCode + ".jpg");
|
long end = System.currentTimeMillis();
|
log.info("user[{}],time addFace is:{}", userCode, (end - begin));
|
return ResultGenerator.genSuccessResult(result);
|
} catch (Exception e) {
|
log.warn("addFace-文件上传失败");
|
return ResultGenerator.genFailResult(e.getMessage());
|
} finally {
|
// 确保临时文件被删除
|
if (tempFile != null && tempFile.exists()) {
|
try {
|
if (!tempFile.delete()) {
|
log.warn("Failed to delete temp file: {}", tempFile.getAbsolutePath());
|
}
|
} catch (Exception e) {
|
log.warn("Error deleting temp file", e);
|
}
|
}
|
}
|
|
}
|
|
/**
|
* 获取人脸地址
|
*
|
* @param userCode
|
* @return
|
*/
|
@ResponseBody
|
@PostMapping("/getUserFaceUrl")
|
public Result2 getUserFaceUrl(String userCode) {
|
log.info("获取人脸信息");
|
long begin = System.currentTimeMillis();
|
FaceRegistDO faceRegistDO = faceRegistService.selectOne(userCode);
|
long end = System.currentTimeMillis();
|
log.info("user[{}],time getUserFaceUrl is:{}", userCode, (end - begin));
|
if (faceRegistDO == null) {
|
return ResultGenerator.genFailResult("获取不到数据");
|
}
|
return ResultGenerator.genSuccessResult("http://" + localIpAddress + ":" + imagesPort + "/images/" + userCode + ".jpg");
|
}
|
|
@ResponseBody
|
@PostMapping("/identifyFace")
|
public Result2 identifyFace(@RequestParam("image") MultipartFile image) {
|
log.info("人脸识别");
|
long begin = System.currentTimeMillis();
|
String base64Image = null;
|
try {
|
base64Image = convert(image, true);
|
long end = System.currentTimeMillis();
|
log.info("time identifyFace 压缩图片is:{}", (end - begin));
|
RegistResult registResult = faceRegistLogic.queryFace(base64Image);
|
if (registResult.getStatus() != 0) {
|
return ResultGenerator.genSuccessResult(registResult.getMessage());
|
}
|
FaceRegistDO faceRegistDO = faceRegistService.selectOneByField("registIndex", registResult.getMessage());
|
String userId = faceRegistDO.getUserID();
|
JSONObject result = getSuccessResultJson();
|
JSONArray jsonArray = new JSONArray();
|
JSONObject jsonObject = new JSONObject();
|
jsonArray.add(jsonObject);
|
jsonObject.put("score", 100);
|
jsonObject.put("user_id", userId);
|
result.getJSONObject("data").put("result", jsonArray);
|
end = System.currentTimeMillis();
|
log.info("user[{}],time identifyFace is:{}", userId, (end - begin));
|
return ResultGenerator.genSuccessResult(result);
|
} catch (Exception e) {
|
log.warn("identifyFace Exception", e);
|
return ResultGenerator.genSuccessResult(e.getMessage());
|
}
|
}
|
|
@ResponseBody
|
@PostMapping("/delFace")
|
public Result2 delFace(String userCode) {
|
String userID = userCode;
|
if (!faceRegistService.checkExist("userID", userID)) {
|
return ResultGenerator.genFailResult("用户ID不存在");
|
}
|
RegistResult registResult = faceRegistLogic.deleteFace(userID);
|
if (registResult.getStatus() != 0) {
|
return ResultGenerator.genFailResult("");
|
}
|
return ResultGenerator.genSuccessResult();
|
}
|
|
/**
|
* 将MultipartFile转换为Data URL格式的字符串
|
*
|
* @param image 要转换的MultipartFile
|
* @return 符合Data URL规范的字符串
|
* @throws Exception 当读取文件或转换过程中发生错误时抛出
|
*/
|
public static String convert(MultipartFile image, boolean needYs) throws Exception {
|
if (needYs) {
|
byte[] compressedBytes = null;
|
// 1. 图片压缩处理
|
// 对于小图片(小于1M)直接使用原图,大图片进行压缩
|
if (image.getSize() > 1024 * 1024) {
|
log.info("图片大小: {}KB,需要压缩", image.getSize() / 1024);
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
// 使用Thumbnails进行压缩,限制最大尺寸为1920x1080,质量0.7
|
Thumbnails.of(image.getInputStream())
|
.size(1920, 1080) // 按比例缩放,最大尺寸限制
|
.outputFormat("jpg") // 明确输出格式
|
// .outputQuality(0.80f) // 质量压缩,平衡大小和清晰度
|
.toOutputStream(outputStream);
|
compressedBytes = outputStream.toByteArray();
|
log.info("压缩后图片大小: {}KB", compressedBytes.length / 1024);
|
} else {
|
log.info("图片大小: {}KB,无需压缩", image.getSize() / 1024);
|
compressedBytes = image.getBytes();
|
}
|
return "data:jpg;base64," + Base64.getEncoder().encodeToString(compressedBytes);
|
} else {
|
if (image == null || image.isEmpty()) {
|
throw new IllegalArgumentException("文件不能为空");
|
}
|
|
// 获取文件的MIME类型
|
String contentType = image.getContentType();
|
if (contentType == null || !contentType.startsWith("image/")) {
|
throw new IllegalArgumentException("不支持的文件类型,必须是图像文件");
|
}
|
|
// 读取文件字节并编码为Base64
|
byte[] fileBytes = image.getBytes();
|
String base64Encoded = Base64.getEncoder().encodeToString(fileBytes);
|
|
// 构建Data URL格式的字符串
|
return "data:" + contentType + ";base64," + base64Encoded;
|
}
|
}
|
|
public static String convert(File imageFile, boolean needYs) throws Exception {
|
// 验证文件合法性
|
if (imageFile == null || !imageFile.exists() || !imageFile.isFile()) {
|
throw new IllegalArgumentException("文件不存在或不是有效的文件");
|
}
|
|
if (needYs) {
|
byte[] processedBytes = null;
|
long fileSize = imageFile.length();
|
|
// 图片压缩处理(大于1M的文件才压缩)
|
if (fileSize > 1024 * 1024) {
|
log.info("图片大小: {}KB,需要压缩", fileSize / 1024);
|
|
try (InputStream inputStream = new FileInputStream(imageFile);
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
|
// 使用Thumbnails进行压缩处理
|
Thumbnails.of(inputStream)
|
.size(1920, 1080) // 按比例缩放,最大尺寸限制
|
.outputFormat("jpg") // 明确输出格式
|
// .outputQuality(0.80f) // 质量压缩参数
|
.toOutputStream(outputStream);
|
|
processedBytes = outputStream.toByteArray();
|
log.info("压缩后图片大小: {}KB", processedBytes.length / 1024);
|
}
|
} else {
|
log.info("图片大小: {}KB,无需压缩", fileSize / 1024);
|
// 小文件直接读取字节
|
processedBytes = Files.readAllBytes(imageFile.toPath());
|
}
|
|
// 返回压缩后的Data URL(统一为jpg格式)
|
return "data:image/jpg;base64," + Base64.getEncoder().encodeToString(processedBytes);
|
} else {
|
// 不压缩的情况,保留原始格式
|
String contentType = Files.probeContentType(imageFile.toPath());
|
if (contentType == null || !contentType.startsWith("image/")) {
|
throw new IllegalArgumentException("不支持的文件类型,必须是图像文件");
|
}
|
|
// 读取文件字节并编码为Base64
|
byte[] fileBytes = Files.readAllBytes(imageFile.toPath());
|
String base64Encoded = Base64.getEncoder().encodeToString(fileBytes);
|
|
// 构建Data URL格式的字符串
|
return "data:" + contentType + ";base64," + base64Encoded;
|
}
|
}
|
|
private JSONObject getSuccessResultJson() {
|
JSONObject jsonObject = new JSONObject();
|
jsonObject.put("error", 0);
|
jsonObject.put("msg", "success");
|
JSONObject data = new JSONObject();
|
jsonObject.put("data", data);
|
return jsonObject;
|
}
|
|
private JSONObject getIdentifyFaceSuccessResultJson() {
|
JSONObject jsonObject = new JSONObject();
|
jsonObject.put("error", 0);
|
jsonObject.put("msg", "success");
|
JSONObject data = new JSONObject();
|
JSONArray resultArray = new JSONArray();
|
JSONObject resultObject = new JSONObject();
|
resultArray.add(resultObject);
|
data.put("result", resultArray);
|
jsonObject.put("data", data);
|
return jsonObject;
|
}
|
}
|