diff --git a/FaceFeatureExtractorAPI/face_feature_extractor.py b/FaceFeatureExtractorAPI/face_feature_extractor.py index 63e57b3..08adfe5 100644 --- a/FaceFeatureExtractorAPI/face_feature_extractor.py +++ b/FaceFeatureExtractorAPI/face_feature_extractor.py @@ -471,6 +471,15 @@ class FaceFeatureExtractor: processing_time) / self.stats['total_extractions'] ) + # Check if we detected faces but filtered them all out due to quality + if not face_infos and boxes: + return FeatureExtractionResult( + success=False, + faces=[], + processing_time=processing_time, + error_message="Face quality check failed (brightness/clarity/pose)" + ) + return FeatureExtractionResult( success=len(face_infos) > 0, faces=face_infos, diff --git a/backend-java/src/main/java/com/bonuos/face/controller/UserController.java b/backend-java/src/main/java/com/bonuos/face/controller/UserController.java index 6be24cf..9821e7d 100644 --- a/backend-java/src/main/java/com/bonuos/face/controller/UserController.java +++ b/backend-java/src/main/java/com/bonuos/face/controller/UserController.java @@ -33,8 +33,10 @@ public class UserController { } @GetMapping("/list") - public Map listUsers() { - List users = userService.getAllUsers(); + public Map listUsers( + @RequestParam(value = "name", required = false) String name, + @RequestParam(value = "groupId", required = false) Long groupId) { + List users = userService.getUsers(name, groupId); Map result = new HashMap<>(); result.put("code", 200); @@ -94,4 +96,14 @@ public class UserController { result.put("msg", "批量删除成功"); return result; } + + @GetMapping("/count") + public Map countUsers() { + long count = userService.countUsers(); + Map result = new HashMap<>(); + result.put("code", 200); + result.put("msg", "success"); + result.put("data", count); + return result; + } } diff --git a/backend-java/src/main/java/com/bonuos/face/handler/GlobalExceptionHandler.java b/backend-java/src/main/java/com/bonuos/face/handler/GlobalExceptionHandler.java new file mode 100644 index 0000000..d7899f9 --- /dev/null +++ b/backend-java/src/main/java/com/bonuos/face/handler/GlobalExceptionHandler.java @@ -0,0 +1,35 @@ +package com.bonuos.face.handler; + +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.HashMap; +import java.util.Map; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(RuntimeException.class) + public Map handleRuntimeException(RuntimeException e) { + Map result = new HashMap<>(); + result.put("code", 500); + + // 提取核心错误信息,去除 "java.lang.RuntimeException: " 前缀 + String msg = e.getMessage(); + if (msg != null && msg.contains(": ")) { + // 如果是包装过的异常,尝试提取更有意义的部分,但这里简单返回 message 即可, + // 因为我们在 Service 层已经精心构造了 message + } + + result.put("msg", msg != null ? msg : "系统内部错误"); + return result; + } + + @ExceptionHandler(Exception.class) + public Map handleException(Exception e) { + Map result = new HashMap<>(); + result.put("code", 500); + result.put("msg", "系统未知错误: " + e.getMessage()); + return result; + } +} diff --git a/backend-java/src/main/java/com/bonuos/face/service/UserService.java b/backend-java/src/main/java/com/bonuos/face/service/UserService.java index 6d68b3a..0a2ae99 100644 --- a/backend-java/src/main/java/com/bonuos/face/service/UserService.java +++ b/backend-java/src/main/java/com/bonuos/face/service/UserService.java @@ -17,11 +17,15 @@ public interface UserService { User addUser(String name, Long groupId, MultipartFile photo); /** - * 查询所有用户 + * 查询用户列表(支持过滤) * + * @param name 姓名(模糊查询) + * @param groupId 分组ID * @return 用户列表 */ - List getAllUsers(); + List getUsers(String name, Long groupId); + + long countUsers(); /** * 根据ID查询用户 diff --git a/backend-java/src/main/java/com/bonuos/face/service/impl/UserServiceImpl.java b/backend-java/src/main/java/com/bonuos/face/service/impl/UserServiceImpl.java index 3f2d8be..8e8d7c5 100644 --- a/backend-java/src/main/java/com/bonuos/face/service/impl/UserServiceImpl.java +++ b/backend-java/src/main/java/com/bonuos/face/service/impl/UserServiceImpl.java @@ -1,6 +1,5 @@ package com.bonuos.face.service.impl; -import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.IdUtil; import com.bonuos.face.entity.User; import com.bonuos.face.mapper.UserMapper; @@ -64,6 +63,13 @@ public class UserServiceImpl implements UserService { List features = faceFeatureExtractorClient.extractFeature(dest); featureJson = convertFeaturesToJson(features); } catch (IOException e) { + // 处理特征提取失败的异常 + if (e.getMessage().contains("No face detected") || + e.getMessage().contains("未检测到人脸") || + e.getMessage().contains("Face quality check failed") || + e.getMessage().toLowerCase().contains("feature extraction failed")) { + throw new RuntimeException("请上传正确且清晰的人脸照片", e); + } throw new RuntimeException("特征提取失败: " + e.getMessage(), e); } @@ -95,11 +101,28 @@ public class UserServiceImpl implements UserService { } @Override - public List getAllUsers() { + public List getUsers(String name, Long groupId) { + com.baomidou.mybatisplus.core.conditions.query.QueryWrapper queryWrapper = new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<>(); // 只返回活跃用户(status=1) - return userMapper.selectList( - new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper() - .eq("status", 1)); + queryWrapper.eq("status", 1); + + if (name != null && !name.isEmpty()) { + queryWrapper.like("name", name); + } + + if (groupId != null) { + queryWrapper.eq("group_id", groupId); + } + + queryWrapper.orderByDesc("create_time"); + + return userMapper.selectList(queryWrapper); + } + + @Override + public long countUsers() { + return userMapper + .selectCount(new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper().eq("status", 1)); } @Override @@ -142,6 +165,13 @@ public class UserServiceImpl implements UserService { List features = faceFeatureExtractorClient.extractFeature(dest); user.setFeatureData(convertFeaturesToJson(features)); } catch (IOException e) { + // 处理特征提取失败的异常 + if (e.getMessage().contains("No face detected") || + e.getMessage().contains("未检测到人脸") || + e.getMessage().contains("Face quality check failed") || + e.getMessage().toLowerCase().contains("feature extraction failed")) { + throw new RuntimeException("请上传正确且清晰的人脸照片", e); + } throw new RuntimeException("照片保存或特征提取失败: " + e.getMessage(), e); } } diff --git a/backend-java/src/main/java/com/bonuos/face/util/FaceFeatureExtractorClient.java b/backend-java/src/main/java/com/bonuos/face/util/FaceFeatureExtractorClient.java index 2d561cf..03bb6cb 100644 --- a/backend-java/src/main/java/com/bonuos/face/util/FaceFeatureExtractorClient.java +++ b/backend-java/src/main/java/com/bonuos/face/util/FaceFeatureExtractorClient.java @@ -100,6 +100,8 @@ public class FaceFeatureExtractorClient { } else { throw new IOException("API call failed with status: " + response.getStatusCode()); } + } catch (IOException e) { + throw e; } catch (Exception e) { throw new IOException("Error calling Face Feature Extractor API", e); } diff --git a/backend-java/src/main/resources/static/index.html b/backend-java/src/main/resources/static/index.html index ef4bacb..6605886 100644 --- a/backend-java/src/main/resources/static/index.html +++ b/backend-java/src/main/resources/static/index.html @@ -126,455 +126,498 @@ object-fit: cover; border: 1px solid #eee; } + + [v-cloak] { + display: none; + } -
- - -
- -
-
安徽博诺思
-
信息科技有限公司
-
-
- - - - - - 系统概览 - - - - - - 用户管理 - - - - 分组管理 - - -
- - - -
- - - - 管理员 - - - -
-
- - -
- - - - -

{{ users.length }}

-
-
- - - -

{{ groups.length }}

-
-
-
+ +
+ + +
+ +
+
安徽博诺思
+
信息科技有限公司
+
+ + + + + + 系统概览 + + + + + + 用户管理 + + + + 分组管理 + + +
+ + + +
+ + + + 管理员 + + + +
+
+ - -
-