|
|
@@ -0,0 +1,213 @@
|
|
|
+package com.github.microservice.auth.server.core.service.local;
|
|
|
+
|
|
|
+import com.github.microservice.auth.client.content.ResultContent;
|
|
|
+import com.github.microservice.auth.client.content.ResultState;
|
|
|
+import com.github.microservice.auth.client.model.UserFaceQueryModel;
|
|
|
+import com.github.microservice.auth.client.model.UserFaceUploadModel;
|
|
|
+import com.github.microservice.auth.client.service.UserFaceService;
|
|
|
+import com.github.microservice.auth.server.core.dao.UserDao;
|
|
|
+import com.github.microservice.auth.server.core.domain.User;
|
|
|
+import com.mongodb.client.gridfs.GridFSFindIterable;
|
|
|
+import com.mongodb.client.gridfs.model.GridFSFile;
|
|
|
+import jakarta.validation.constraints.NotNull;
|
|
|
+import lombok.Cleanup;
|
|
|
+import lombok.SneakyThrows;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.data.mongodb.core.query.Criteria;
|
|
|
+import org.springframework.data.mongodb.core.query.Query;
|
|
|
+import org.springframework.data.mongodb.gridfs.GridFsResource;
|
|
|
+import org.springframework.data.mongodb.gridfs.GridFsTemplate;
|
|
|
+import org.springframework.security.crypto.password.PasswordEncoder;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.web.client.RestTemplate;
|
|
|
+
|
|
|
+import javax.imageio.ImageIO;
|
|
|
+import java.awt.*;
|
|
|
+import java.awt.image.BufferedImage;
|
|
|
+import java.io.ByteArrayInputStream;
|
|
|
+import java.io.ByteArrayOutputStream;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.util.*;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class UserFaceServiceImpl implements UserFaceService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ UserDao userDao;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ GridFsTemplate gridFsTemplate;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ RestTemplate restTemplate;
|
|
|
+
|
|
|
+ @Value("${faceImage.width}")
|
|
|
+ private int width;
|
|
|
+
|
|
|
+ @Value("${faceImage.height}")
|
|
|
+ private int height;
|
|
|
+ @Autowired
|
|
|
+ private PasswordEncoder passwordEncoder;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 上传人脸图片
|
|
|
+ *
|
|
|
+ * @param userFaceUploadModel
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @SneakyThrows
|
|
|
+ public ResultContent<String> upload(UserFaceUploadModel userFaceUploadModel) {
|
|
|
+ User user = userDao.findTop1ById(userFaceUploadModel.getUserId());
|
|
|
+ if (user == null) {
|
|
|
+ return ResultContent.build(ResultState.UserNotExists);
|
|
|
+ }
|
|
|
+ //TODO 调整图片大小
|
|
|
+ byte[] bytes = imageResizer(userFaceUploadModel.getUserFace());
|
|
|
+ //TODO 上传人脸库,对比成功后入库
|
|
|
+ @Cleanup ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
|
|
|
+ String fileId = gridFsTemplate.store(byteArrayInputStream, UUID.randomUUID().toString(),Map.of("userId", userFaceUploadModel.getUserId())).toHexString();
|
|
|
+
|
|
|
+ List<String> facePic = user.getFacePic();
|
|
|
+ if (facePic == null || facePic.isEmpty()) {
|
|
|
+ facePic = new ArrayList<>();
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(userFaceUploadModel.getUpdateFaceFileId())){
|
|
|
+ //替换原人脸图片
|
|
|
+ if (!facePic.contains(userFaceUploadModel.getUpdateFaceFileId())){
|
|
|
+ return ResultContent.build(ResultState.FaceNotExists);
|
|
|
+ }
|
|
|
+ int index = facePic.indexOf(userFaceUploadModel.getUpdateFaceFileId());
|
|
|
+ facePic.set(index, fileId);
|
|
|
+ }else {
|
|
|
+ facePic.add(fileId);
|
|
|
+ }
|
|
|
+ user.setFacePic(facePic);
|
|
|
+ userDao.save(user);
|
|
|
+ return ResultContent.buildContent(fileId);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 删除用户指定人脸图片
|
|
|
+ * @param userId
|
|
|
+ * @param faceFileId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public ResultContent delete(@NotNull String userId, @NotNull String faceFileId) {
|
|
|
+ User user = userDao.findTop1ById(userId);
|
|
|
+ if (user == null) {
|
|
|
+ return ResultContent.build(ResultState.UserNotExists);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<String> facePic = user.getFacePic();
|
|
|
+ if (facePic == null || facePic.isEmpty()) {
|
|
|
+ return ResultContent.build(ResultState.FaceNotExists);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!facePic.contains(faceFileId)) {
|
|
|
+ return ResultContent.build(ResultState.FaceNotExists);
|
|
|
+ }
|
|
|
+
|
|
|
+ facePic.remove(faceFileId);
|
|
|
+ user.setFacePic(facePic);
|
|
|
+ userDao.save(user);
|
|
|
+ return ResultContent.build(ResultState.Success);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取用户人脸认证图片
|
|
|
+ * @param userId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @SneakyThrows
|
|
|
+ public ResultContent<List<UserFaceQueryModel>> get(String userId){
|
|
|
+ User user = userDao.findTop1ById(userId);
|
|
|
+ if (user == null) {
|
|
|
+ return ResultContent.build(ResultState.UserNotExists);
|
|
|
+ }
|
|
|
+ //初始化返回结果
|
|
|
+ List<UserFaceQueryModel> userFaceBase64List = new ArrayList<>();
|
|
|
+
|
|
|
+ List<String> facePic = user.getFacePic();
|
|
|
+ if (facePic != null && !facePic.isEmpty()) {
|
|
|
+ Query query = new Query(Criteria.where("_id").in(facePic));
|
|
|
+ GridFSFindIterable gridFSFiles = gridFsTemplate.find(query);
|
|
|
+ for (GridFSFile gridFS : gridFSFiles) {
|
|
|
+ @Cleanup InputStream inputStream = gridFsTemplate.getResource(gridFS).getContent();
|
|
|
+ UserFaceQueryModel userFaceQueryModel = new UserFaceQueryModel();
|
|
|
+ String userFace = convertInputStreamToBase64(inputStream);
|
|
|
+ userFaceQueryModel.setFaceFileId(gridFS.getObjectId().toHexString());
|
|
|
+ userFaceQueryModel.setUserFace(userFace);
|
|
|
+ userFaceBase64List.add(userFaceQueryModel);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ResultContent.buildContent(userFaceBase64List);
|
|
|
+ }
|
|
|
+
|
|
|
+ public ResultContent<String> matches(String userFace){
|
|
|
+
|
|
|
+ return ResultContent.buildContent("userId");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将 InputStream 转换为 Base64 字符串
|
|
|
+ *
|
|
|
+ * @param inputStream 输入流
|
|
|
+ * @return Base64 编码的字符串
|
|
|
+ * @throws IOException 如果发生 I/O 错误
|
|
|
+ */
|
|
|
+ @SneakyThrows
|
|
|
+ public static String convertInputStreamToBase64(InputStream inputStream){
|
|
|
+ @Cleanup ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
|
|
+ byte[] buffer = new byte[1024];
|
|
|
+ int bytesRead;
|
|
|
+ while ((bytesRead = inputStream.read(buffer)) != -1) {
|
|
|
+ outputStream.write(buffer, 0, bytesRead);
|
|
|
+ }
|
|
|
+ byte[] bytes = outputStream.toByteArray();
|
|
|
+ return Base64.getEncoder().encodeToString(bytes);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private byte[] imageResizer(String base64Image){
|
|
|
+ // 解码 Base64 字符串为 BufferedImage
|
|
|
+ BufferedImage originalImage = decodeBase64ToImage(base64Image);
|
|
|
+
|
|
|
+ // 调整图像大小
|
|
|
+ BufferedImage resizedImage = resizeImage(originalImage, width, height);
|
|
|
+
|
|
|
+ // 将调整后的图像转换为字节组
|
|
|
+ return encodeImageToBytes(resizedImage);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private static BufferedImage resizeImage(BufferedImage originalImage, int width, int height) {
|
|
|
+ BufferedImage resizedImage = new BufferedImage(width, height, originalImage.getType());
|
|
|
+ Graphics2D g = resizedImage.createGraphics();
|
|
|
+ g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
|
+ g.drawImage(originalImage, 0, 0, width, height, null);
|
|
|
+ g.dispose();
|
|
|
+
|
|
|
+ return resizedImage;
|
|
|
+ }
|
|
|
+
|
|
|
+ @SneakyThrows
|
|
|
+ private static BufferedImage decodeBase64ToImage(String base64Image) {
|
|
|
+ byte[] imageBytes = Base64.getDecoder().decode(base64Image);
|
|
|
+ @Cleanup ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes);
|
|
|
+ return ImageIO.read(bais);
|
|
|
+ }
|
|
|
+
|
|
|
+ @SneakyThrows
|
|
|
+ private static byte[] encodeImageToBytes(BufferedImage image) {
|
|
|
+ @Cleanup ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
|
+ ImageIO.write(image, "png", baos);
|
|
|
+ return baos.toByteArray();
|
|
|
+ }
|
|
|
+}
|