diff --git a/src/main/java/com/labelsys/backend/common/exception/GlobalExceptionHandler.java b/src/main/java/com/labelsys/backend/common/exception/GlobalExceptionHandler.java
index 7300d91..8234307 100644
--- a/src/main/java/com/labelsys/backend/common/exception/GlobalExceptionHandler.java
+++ b/src/main/java/com/labelsys/backend/common/exception/GlobalExceptionHandler.java
@@ -3,44 +3,78 @@ package com.labelsys.backend.common.exception;
import com.labelsys.backend.common.Result;
import com.labelsys.backend.common.ResultCode;
import jakarta.servlet.http.HttpServletResponse;
-import java.util.stream.Collectors;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
+import java.util.stream.Collectors;
+
+/**
+ * 全局异常处理器
+ *
+ * 处理策略:
+ * 1. 业务异常(BusinessException):记录 INFO 级别日志,返回详细错误信息给前端
+ * 2. 参数校验异常:记录 WARN 级别日志,返回字段错误信息
+ * 3. 系统异常(Exception):记录 ERROR 级别日志,隐藏详细信息,返回通用错误提示
+ */
+@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
+ /**
+ * 处理业务异常
+ * 业务异常是预期内的错误,需要详细返回给前端
+ */
@ExceptionHandler(BusinessException.class)
public Result handleBusiness(BusinessException exception, HttpServletResponse response) {
+ // 记录 INFO 级别日志(业务异常属于预期内错误)
+ log.info("Business exception occurred: code={}, message={}",
+ exception.getResultCode().getCode(), exception.getMessage());
+
response.setStatus(toHttpStatus(exception.getResultCode()).value());
return new Result<>(exception.getResultCode().getCode(), exception.getMessage(), null);
}
- @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
+ /**
+ * 处理参数校验异常
+ */
+ @ExceptionHandler({ MethodArgumentNotValidException.class, BindException.class })
public Result handleValidation(Exception exception, HttpServletResponse response) {
- response.setStatus(HttpStatus.BAD_REQUEST.value());
String message;
- if (exception instanceof MethodArgumentNotValidException methodArgumentNotValidException) {
- message = methodArgumentNotValidException.getBindingResult().getFieldErrors().stream()
- .map(error -> error.getField() + error.getDefaultMessage())
- .collect(Collectors.joining(";"));
+ if (exception instanceof MethodArgumentNotValidException methodException) {
+ message = methodException.getBindingResult().getFieldErrors().stream()
+ .map(error -> error.getField() + ": " + error.getDefaultMessage())
+ .collect(Collectors.joining("; "));
} else if (exception instanceof BindException bindException) {
message = bindException.getBindingResult().getFieldErrors().stream()
- .map(error -> error.getField() + error.getDefaultMessage())
- .collect(Collectors.joining(";"));
+ .map(error -> error.getField() + ": " + error.getDefaultMessage())
+ .collect(Collectors.joining("; "));
} else {
message = ResultCode.BAD_REQUEST.getMessage();
}
+
+ // 记录 WARN 级别日志
+ log.warn("Validation failed: {}", message);
+
+ response.setStatus(HttpStatus.BAD_REQUEST.value());
return new Result<>(ResultCode.BAD_REQUEST.getCode(), message, null);
}
+ /**
+ * 处理系统异常
+ * 系统异常是预期外的错误,需要隐藏详细信息
+ */
@ExceptionHandler(Exception.class)
public Result handleUnexpected(Exception exception, HttpServletResponse response) {
+ // 记录 ERROR 级别日志(包含完整堆栈)
+ log.error("Unexpected exception occurred", exception);
+
+ // 返回通用错误信息,不暴露内部细节
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
- return new Result<>(ResultCode.ERROR.getCode(), exception.getMessage(), null);
+ return new Result<>(ResultCode.ERROR.getCode(), "系统内部错误,请稍后重试", null);
}
private HttpStatus toHttpStatus(ResultCode resultCode) {
@@ -53,4 +87,4 @@ public class GlobalExceptionHandler {
default -> HttpStatus.INTERNAL_SERVER_ERROR;
};
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/com/labelsys/backend/service/AnnotationResultArchiveService.java b/src/main/java/com/labelsys/backend/service/AnnotationResultArchiveService.java
index 63f453c..4570421 100644
--- a/src/main/java/com/labelsys/backend/service/AnnotationResultArchiveService.java
+++ b/src/main/java/com/labelsys/backend/service/AnnotationResultArchiveService.java
@@ -47,39 +47,51 @@ public class AnnotationResultArchiveService {
public PageResult pageHistory(LoginUser currentUser,
AnnotationResultHistoryPageQuery query) {
- List allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
- boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
+ try {
+ List allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
+ boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
- var wrapper = new LambdaQueryWrapper()
- .eq(AnnotationResultHistory::getCompanyId, currentUser.companyId())
- .eq(query.taskId() != null, AnnotationResultHistory::getTaskId, query.taskId())
- .eq(query.resourceId() != null, AnnotationResultHistory::getResourceId, query.resourceId())
- .orderByDesc(AnnotationResultHistory::getCreatedAt);
+ var wrapper = new LambdaQueryWrapper()
+ .eq(AnnotationResultHistory::getCompanyId, currentUser.companyId())
+ .eq(query.taskId() != null, AnnotationResultHistory::getTaskId, query.taskId())
+ .eq(query.resourceId() != null, AnnotationResultHistory::getResourceId, query.resourceId())
+ .orderByDesc(AnnotationResultHistory::getCreatedAt);
- if (shouldFilterByUserId) {
- wrapper.eq(AnnotationResultHistory::getCreatorId, currentUser.userId());
- } else if (!allowedRoles.isEmpty()) {
- wrapper.in(AnnotationResultHistory::getCreatorRole, allowedRoles);
+ if (shouldFilterByUserId) {
+ wrapper.eq(AnnotationResultHistory::getCreatorId, currentUser.userId());
+ } else if (!allowedRoles.isEmpty()) {
+ wrapper.in(AnnotationResultHistory::getCreatorRole, allowedRoles);
+ }
+
+ var page = new Page(query.pageNo(), query.pageSize());
+ var resultPage = annotationResultHistoryMapper.selectPage(page, wrapper);
+
+ var records = resultPage.getRecords().stream()
+ .map(this::toResponse)
+ .toList();
+
+ return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
+ (int) resultPage.getSize());
+ } catch (Exception e) {
+ log.error("pageHistory failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
}
-
- var page = new Page(query.pageNo(), query.pageSize());
- var resultPage = annotationResultHistoryMapper.selectPage(page, wrapper);
-
- var records = resultPage.getRecords().stream()
- .map(this::toResponse)
- .toList();
-
- return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
- (int) resultPage.getSize());
}
public AnnotationResultHistoryResponse getHistory(LoginUser currentUser, Long historyId) {
- AnnotationResultHistory history = annotationResultHistoryMapper.selectById(historyId);
- if (history == null || !history.getCompanyId().equals(currentUser.companyId())) {
- throw new BusinessException(ResultCode.NOT_FOUND, "历史记录不存在");
+ try {
+ AnnotationResultHistory history = annotationResultHistoryMapper.selectById(historyId);
+ if (history == null || !history.getCompanyId().equals(currentUser.companyId())) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "历史记录不存在");
+ }
+ assertHistoryPermission(currentUser, history);
+ return toResponse(history);
+ } catch (Exception e) {
+ log.error("getHistory failed, companyId={}, userId={}, historyId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), historyId, e.getMessage(), e);
+ throw e;
}
- assertHistoryPermission(currentUser, history);
- return toResponse(history);
}
private void assertHistoryPermission(LoginUser currentUser, AnnotationResultHistory history) {
@@ -110,18 +122,23 @@ public class AnnotationResultArchiveService {
@Transactional
public int autoArchiveEligibleResults() {
- LocalDateTime cutoff = LocalDateTime.now().minus(autoArchiveTimeout);
- List results = annotationResultMapper.selectList(new LambdaQueryWrapper()
- .eq(AnnotationResult::getIsDeleted, false)
- .eq(AnnotationResult::getRequiresManualReview, false)
- .lt(AnnotationResult::getCreatedAt, cutoff));
- int archivedCount = 0;
- for (AnnotationResult result : results) {
- if (archiveRuntimeResult(result, null, "AUTO_ARCHIVE", null) != null) {
- archivedCount++;
+ try {
+ LocalDateTime cutoff = LocalDateTime.now().minus(autoArchiveTimeout);
+ List results = annotationResultMapper.selectList(new LambdaQueryWrapper()
+ .eq(AnnotationResult::getIsDeleted, false)
+ .eq(AnnotationResult::getRequiresManualReview, false)
+ .lt(AnnotationResult::getCreatedAt, cutoff));
+ int archivedCount = 0;
+ for (AnnotationResult result : results) {
+ if (archiveRuntimeResult(result, null, "AUTO_ARCHIVE", null) != null) {
+ archivedCount++;
+ }
}
+ return archivedCount;
+ } catch (Exception e) {
+ log.error("autoArchiveEligibleResults failed, error={}", e.getMessage(), e);
+ throw e;
}
- return archivedCount;
}
private void assertReviewer(LoginUser currentUser) {
@@ -227,26 +244,29 @@ public class AnnotationResultArchiveService {
* @return 文件内容响应
*/
public FileContentResponse loadFileContent(LoginUser currentUser, Long historyId) {
- AnnotationResultHistory history = annotationResultHistoryMapper.selectById(historyId);
- if (history == null || !history.getCompanyId().equals(currentUser.companyId())) {
- throw new BusinessException(ResultCode.NOT_FOUND, "历史记录不存在");
- }
- //assertHistoryPermission(currentUser, history);
-
- String filePath = history.getQaContentFilePath();
- if (filePath == null || filePath.isEmpty()) {
- throw new BusinessException(ResultCode.ERROR, "文件路径为空");
- }
-
try {
+ AnnotationResultHistory history = annotationResultHistoryMapper.selectById(historyId);
+ if (history == null || !history.getCompanyId().equals(currentUser.companyId())) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "历史记录不存在");
+ }
+ //assertHistoryPermission(currentUser, history);
+
+ String filePath = history.getQaContentFilePath();
+ if (filePath == null || filePath.isEmpty()) {
+ throw new BusinessException(ResultCode.ERROR, "文件路径为空");
+ }
+
String bucketName = extractBucketName(filePath);
String objectKey = extractObjectKey(filePath);
byte[] content = objectStorageService.download(bucketName, objectKey);
String contentStr = new String(content, StandardCharsets.UTF_8);
return new FileContentResponse(filePath, contentStr, content.length);
+ } catch (BusinessException e) {
+ throw e;
} catch (Exception e) {
- log.error("Failed to load file content, historyId={}, filePath={}", historyId, filePath, e);
+ log.error("loadFileContent failed, companyId={}, userId={}, historyId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), historyId, e.getMessage(), e);
throw new BusinessException(ResultCode.ERROR, "加载文件内容失败");
}
}
diff --git a/src/main/java/com/labelsys/backend/service/AnnotationResultService.java b/src/main/java/com/labelsys/backend/service/AnnotationResultService.java
index a3f3346..1e6f845 100644
--- a/src/main/java/com/labelsys/backend/service/AnnotationResultService.java
+++ b/src/main/java/com/labelsys/backend/service/AnnotationResultService.java
@@ -43,145 +43,180 @@ public class AnnotationResultService {
private final ObjectMapper objectMapper;
public PageResult pageResults(LoginUser currentUser, AnnotationResultPageQuery query) {
- List allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
- boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
+ try {
+ List allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
+ boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
- var wrapper = new LambdaQueryWrapper()
- .eq(AnnotationResult::getIsDeleted, Boolean.FALSE)
- .eq(AnnotationResult::getCompanyId, currentUser.companyId())
- .eq(query.taskId() != null, AnnotationResult::getTaskId, query.taskId())
- .eq(query.resourceId() != null, AnnotationResult::getResourceId, query.resourceId())
- .eq(query.requiresManualReview() != null, AnnotationResult::getRequiresManualReview,
- query.requiresManualReview())
- .orderByDesc(AnnotationResult::getCreatedAt);
+ var wrapper = new LambdaQueryWrapper()
+ .eq(AnnotationResult::getIsDeleted, Boolean.FALSE)
+ .eq(AnnotationResult::getCompanyId, currentUser.companyId())
+ .eq(query.taskId() != null, AnnotationResult::getTaskId, query.taskId())
+ .eq(query.resourceId() != null, AnnotationResult::getResourceId, query.resourceId())
+ .eq(query.requiresManualReview() != null, AnnotationResult::getRequiresManualReview,
+ query.requiresManualReview())
+ .orderByDesc(AnnotationResult::getCreatedAt);
- if (shouldFilterByUserId) {
- wrapper.eq(AnnotationResult::getCreatorId, currentUser.userId());
- } else if (!allowedRoles.isEmpty()) {
- wrapper.in(AnnotationResult::getCreatorRole, allowedRoles);
+ if (shouldFilterByUserId) {
+ wrapper.eq(AnnotationResult::getCreatorId, currentUser.userId());
+ } else if (!allowedRoles.isEmpty()) {
+ wrapper.in(AnnotationResult::getCreatorRole, allowedRoles);
+ }
+
+ var page = new Page(query.pageNo(), query.pageSize());
+ var resultPage = annotationResultMapper.selectPage(page, wrapper);
+
+ var records = resultPage.getRecords().stream()
+ .map(this::toResponse)
+ .filter(response -> query.runtimeStatus() == null
+ || query.runtimeStatus().equals(response.runtimeStatus()))
+ .toList();
+
+ return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
+ (int) resultPage.getSize());
+ } catch (Exception e) {
+ log.error("pageResults failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
}
-
- var page = new Page(query.pageNo(), query.pageSize());
- var resultPage = annotationResultMapper.selectPage(page, wrapper);
-
- var records = resultPage.getRecords().stream()
- .map(this::toResponse)
- .filter(response -> query.runtimeStatus() == null
- || query.runtimeStatus().equals(response.runtimeStatus()))
- .toList();
-
- return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
- (int) resultPage.getSize());
}
public AnnotationResultResponse getResult(LoginUser currentUser, Long resultId) {
- AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId, currentUser.companyId());
- if (result == null) {
- log.warn("Result not found or cross-tenant access attempt: resultId={}, companyId={}, userId={}", resultId,
- currentUser.companyId(), currentUser.userId());
- throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在");
+ try {
+ AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId,
+ currentUser.companyId());
+ if (result == null) {
+ log.warn("Result not found or cross-tenant access attempt: resultId={}, companyId={}, userId={}",
+ resultId,
+ currentUser.companyId(), currentUser.userId());
+ throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在");
+ }
+ //assertResultPermission(currentUser, result);
+ return toResponse(result);
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("getResult failed, companyId={}, userId={}, resultId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), resultId, e.getMessage(), e);
+ throw e;
}
- //assertResultPermission(currentUser, result);
- return toResponse(result);
}
public AnnotationResultCompareResponse compareResult(LoginUser currentUser, Long resultId) {
- AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId, currentUser.companyId());
- if (result == null) {
- log.warn("Result not found or cross-tenant access attempt: resultId={}, companyId={}, userId={}", resultId,
- currentUser.companyId(), currentUser.userId());
- throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在");
+ try {
+ AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId,
+ currentUser.companyId());
+ if (result == null) {
+ log.warn("Result not found or cross-tenant access attempt: resultId={}, companyId={}, userId={}",
+ resultId,
+ currentUser.companyId(), currentUser.userId());
+ throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在");
+ }
+ //assertResultPermission(currentUser, result);
+
+ QaContent qaContent = loadQaContent(result);
+ DiffContent diffContent = Boolean.TRUE.equals(result.getRequiresManualReview()) ?
+ loadDiffSummary(result) : null;
+
+ SourceResource resource = sourceResourceMapper.selectById(result.getResourceId());
+
+ // 转换 QA 记录
+ List qaRecords = qaContent.records().stream()
+ .map(qa -> new AnnotationResultCompareResponse.QaRecord(
+ qa.id(),
+ qa.question(),
+ qa.answer(),
+ qa.requiresReview()
+ )).toList();
+
+ // 转换差异记录
+ List diffRecords = diffContent != null ?
+ diffContent.records().stream()
+ .map(diff -> new AnnotationResultCompareResponse.DiffRecord(
+ diff.qaId(),
+ diff.question(),
+ diff.extractAnswer(),
+ diff.verifyAnswer(),
+ diff.diffReason(),
+ diff.mergedAnswer()
+ )).toList() : List.of();
+
+ return new AnnotationResultCompareResponse(
+ result.getId(),
+ result.getTaskId(),
+ result.getResourceId(),
+ qaRecords,
+ diffRecords,
+ resource == null ? null : resource.getFilePath()
+ );
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("compareResult failed, companyId={}, userId={}, resultId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), resultId, e.getMessage(), e);
+ throw e;
}
- //assertResultPermission(currentUser, result);
-
- QaContent qaContent = loadQaContent(result);
- DiffContent diffContent = Boolean.TRUE.equals(result.getRequiresManualReview()) ?
- loadDiffSummary(result) : null;
-
- SourceResource resource = sourceResourceMapper.selectById(result.getResourceId());
-
- // 转换 QA 记录
- List qaRecords = qaContent.records().stream()
- .map(qa -> new AnnotationResultCompareResponse.QaRecord(
- qa.id(),
- qa.question(),
- qa.answer(),
- qa.requiresReview()
- )).toList();
-
- // 转换差异记录
- List diffRecords = diffContent != null ?
- diffContent.records().stream()
- .map(diff -> new AnnotationResultCompareResponse.DiffRecord(
- diff.qaId(),
- diff.question(),
- diff.extractAnswer(),
- diff.verifyAnswer(),
- diff.diffReason(),
- diff.mergedAnswer()
- )).toList() : List.of();
-
- return new AnnotationResultCompareResponse(
- result.getId(),
- result.getTaskId(),
- result.getResourceId(),
- qaRecords,
- diffRecords,
- resource == null ? null : resource.getFilePath()
- );
}
@Transactional
public void mergeReviewResult(LoginUser currentUser, Long resultId, MergeReviewResultRequest request) {
- AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId, currentUser.companyId());
- if (result == null) {
- throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在");
+ try {
+ AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId,
+ currentUser.companyId());
+ if (result == null) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在");
+ }
+ //assertResultPermission(currentUser, result);
+
+ // 读取当前 qa.json
+ QaContent qaContent = loadQaContent(result);
+
+ // 更新 qa.json 的 answer 字段
+ List updatedQaRecords = qaContent.records().stream()
+ .map(record -> {
+ String mergedAnswer = request.mergedAnswers().get(record.id());
+ if (mergedAnswer != null) {
+ return new QaContent.QaRecord(
+ record.id(),
+ record.question(),
+ mergedAnswer,
+ false
+ );
+ }
+ return record;
+ })
+ .toList();
+
+ QaContent updatedQaContent = new QaContent(
+ qaContent.taskId(),
+ qaContent.resourceId(),
+ updatedQaRecords,
+ new QaContent.Metadata(
+ qaContent.metadata().createdAt(),
+ LocalDateTime.now().toString()
+ )
+ );
+ saveQaContent(result, updatedQaContent);
+
+ // 更新数据库记录
+ result.setIsDeleted(Boolean.TRUE);
+ result.setReviewerId(currentUser.userId());
+ result.setReviewComment(request.reviewComment());
+ result.setReviewedAt(LocalDateTime.now());
+ result.setRequiresManualReview(false);
+ annotationResultMapper.updateById(result);
+
+ // 归档到历史表(人工审核后归档)
+ archiveToHistory(result, currentUser, "审核通过后归档", false);
+
+ log.info("merged review result, companyId={}, userId={}, resultId={}",
+ currentUser.companyId(), currentUser.userId(), resultId);
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("mergeReviewResult failed, companyId={}, userId={}, resultId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), resultId, e.getMessage(), e);
+ throw e;
}
- //assertResultPermission(currentUser, result);
-
- // 读取当前 qa.json
- QaContent qaContent = loadQaContent(result);
-
- // 更新 qa.json 的 answer 字段
- List updatedQaRecords = qaContent.records().stream()
- .map(record -> {
- String mergedAnswer = request.mergedAnswers().get(record.id());
- if (mergedAnswer != null) {
- return new QaContent.QaRecord(
- record.id(),
- record.question(),
- mergedAnswer,
- false
- );
- }
- return record;
- })
- .toList();
-
- QaContent updatedQaContent = new QaContent(
- qaContent.taskId(),
- qaContent.resourceId(),
- updatedQaRecords,
- new QaContent.Metadata(
- qaContent.metadata().createdAt(),
- LocalDateTime.now().toString()
- )
- );
- saveQaContent(result, updatedQaContent);
-
- // 更新数据库记录
- result.setIsDeleted(Boolean.TRUE);
- result.setReviewerId(currentUser.userId());
- result.setReviewComment(request.reviewComment());
- result.setReviewedAt(LocalDateTime.now());
- result.setRequiresManualReview(false);
- annotationResultMapper.updateById(result);
-
- // 归档到历史表(人工审核后归档)
- archiveToHistory(result, currentUser, "审核通过后归档", false);
-
- log.info("merged review result, companyId={}, userId={}, resultId={}",
- currentUser.companyId(), currentUser.userId(), resultId);
}
private AnnotationResultResponse toResponse(AnnotationResult result) {
@@ -267,12 +302,14 @@ public class AnnotationResultService {
/**
* 归档到历史表
- * @param result 标注结果
- * @param currentUser 当前用户
+ *
+ * @param result 标注结果
+ * @param currentUser 当前用户
* @param archiveReason 归档原因
* @param isAutoArchive 是否自动归档(true=自动归档,false=人工审核后归档)
*/
- private void archiveToHistory(AnnotationResult result, LoginUser currentUser, String archiveReason, boolean isAutoArchive) {
+ private void archiveToHistory(AnnotationResult result, LoginUser currentUser, String archiveReason,
+ boolean isAutoArchive) {
try {
// 读取 qa.json 内容用于归档
QaContent qaContent = loadQaContent(result);
@@ -312,7 +349,7 @@ public class AnnotationResultService {
annotationResultHistoryMapper.insert(historyBuilder.build());
- log.info("archived result to history, resultId={}, historyId={}, isAutoArchive={}",
+ log.info("archived result to history, resultId={}, historyId={}, isAutoArchive={}",
result.getId(), historyBuilder.build().getId(), isAutoArchive);
} catch (Exception e) {
log.error("Failed to archive result to history, resultId={}", result.getId(), e);
diff --git a/src/main/java/com/labelsys/backend/service/AnnotationTaskService.java b/src/main/java/com/labelsys/backend/service/AnnotationTaskService.java
index d63788a..956aa12 100644
--- a/src/main/java/com/labelsys/backend/service/AnnotationTaskService.java
+++ b/src/main/java/com/labelsys/backend/service/AnnotationTaskService.java
@@ -45,132 +45,163 @@ public class AnnotationTaskService {
@Transactional
public AnnotationTaskResponse createTask(LoginUser currentUser, CreateAnnotationTaskRequest request) {
- List resources = loadAndValidateResources(currentUser, request.resourceIds());
+ try {
+ List resources = loadAndValidateResources(currentUser, request.resourceIds());
- AnnotationTask task = AnnotationTask.builder()
- .id(IdGenerator.nextId())
- .companyId(currentUser.companyId())
- .creatorId(currentUser.userId())
- .creatorRole(currentUser.role())
- .taskName(request.taskName())
- .industryType(defaultIndustryType(request.industryType()))
- .taskType(defaultTaskType(request.taskType()))
- .taskStatus(TaskStatus.PENDING.name())
- .isDeleted(false)
- .build();
+ AnnotationTask task = AnnotationTask.builder()
+ .id(IdGenerator.nextId())
+ .companyId(currentUser.companyId())
+ .creatorId(currentUser.userId())
+ .creatorRole(currentUser.role())
+ .taskName(request.taskName())
+ .industryType(defaultIndustryType(request.industryType()))
+ .taskType(defaultTaskType(request.taskType()))
+ .taskStatus(TaskStatus.PENDING.name())
+ .isDeleted(false)
+ .build();
- annotationTaskMapper.insert(task);
- saveTaskBindings(task.getId(), currentUser.companyId(), resources);
+ annotationTaskMapper.insert(task);
+ saveTaskBindings(task.getId(), currentUser.companyId(), resources);
- log.info("created annotation task, companyId={}, userId={}, taskId={}, resourceCount={}",
- currentUser.companyId(), currentUser.userId(), task.getId(), resources.size());
+ log.info("created annotation task, companyId={}, userId={}, taskId={}, resourceCount={}",
+ currentUser.companyId(), currentUser.userId(), task.getId(), resources.size());
- return buildTaskResponse(task, resourceIds(resources));
+ return buildTaskResponse(task, resourceIds(resources));
+ } catch (Exception e) {
+ log.error("createTask failed, companyId={}, userId={}, taskName={}, error={}",
+ currentUser.companyId(), currentUser.userId(), request.taskName(), e.getMessage(), e);
+ throw e;
+ }
}
@Transactional
public AnnotationTaskResponse updateTask(LoginUser currentUser, Long taskId, UpdateAnnotationTaskRequest request) {
- AnnotationTask task = annotationTaskMapper.findByIdAndCompanyId(taskId, currentUser.companyId());
- if (task == null) {
- throw new BusinessException(ResultCode.NOT_FOUND, "任务不存在");
- }
- assertTaskPermission(currentUser, task);
-
- boolean resourcesChanged = false;
- List resources = null;
-
- if (request.resourceIds() != null && !request.resourceIds().isEmpty()) {
- List currentResourceIds = normalizeIds(annotationTaskResourceMapper.listResourceIdsByTaskId(taskId));
- List targetResourceIds = normalizeIds(request.resourceIds());
- resourcesChanged = !currentResourceIds.equals(targetResourceIds);
-
- if (TaskStatus.RUNNING.name().equals(task.getTaskStatus()) && resourcesChanged) {
- throw new BusinessException(ResultCode.CONFLICT, "运行中的任务不允许修改资源");
+ try {
+ AnnotationTask task = annotationTaskMapper.findByIdAndCompanyId(taskId, currentUser.companyId());
+ if (task == null) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "任务不存在");
}
- resources = loadAndValidateResources(currentUser, request.resourceIds());
+ assertTaskPermission(currentUser, task);
+
+ boolean resourcesChanged = false;
+ List resources = null;
+
+ if (request.resourceIds() != null && !request.resourceIds().isEmpty()) {
+ List currentResourceIds = normalizeIds(
+ annotationTaskResourceMapper.listResourceIdsByTaskId(taskId));
+ List targetResourceIds = normalizeIds(request.resourceIds());
+ resourcesChanged = !currentResourceIds.equals(targetResourceIds);
+
+ if (TaskStatus.RUNNING.name().equals(task.getTaskStatus()) && resourcesChanged) {
+ throw new BusinessException(ResultCode.CONFLICT, "运行中的任务不允许修改资源");
+ }
+ resources = loadAndValidateResources(currentUser, request.resourceIds());
+ }
+
+ if (request.industryType() != null) {
+ task.setIndustryType(request.industryType());
+ }
+
+ if (request.taskType() != null) {
+ task.setTaskType(request.taskType());
+ }
+
+ annotationTaskMapper.updateById(task);
+
+ if (resourcesChanged && resources != null) {
+ annotationTaskResourceMapper.deleteByTaskId(taskId);
+ saveTaskBindings(taskId, currentUser.companyId(), resources);
+ }
+
+ log.info("updated annotation task, companyId={}, userId={}, taskId={}, resourcesChanged={}",
+ currentUser.companyId(), currentUser.userId(), taskId, resourcesChanged);
+
+ List finalResourceIds = resources != null ? resourceIds(resources)
+ : normalizeIds(annotationTaskResourceMapper.listResourceIdsByTaskId(taskId));
+
+ return buildTaskResponse(task, finalResourceIds);
+ } catch (Exception e) {
+ log.error("updateTask failed, companyId={}, userId={}, taskId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), taskId, e.getMessage(), e);
+ throw e;
}
-
- if (request.industryType() != null) {
- task.setIndustryType(request.industryType());
- }
-
- if (request.taskType() != null) {
- task.setTaskType(request.taskType());
- }
-
- annotationTaskMapper.updateById(task);
-
- if (resourcesChanged && resources != null) {
- annotationTaskResourceMapper.deleteByTaskId(taskId);
- saveTaskBindings(taskId, currentUser.companyId(), resources);
- }
-
- log.info("updated annotation task, companyId={}, userId={}, taskId={}, resourcesChanged={}",
- currentUser.companyId(), currentUser.userId(), taskId, resourcesChanged);
-
- List finalResourceIds = resources != null ? resourceIds(resources)
- : normalizeIds(annotationTaskResourceMapper.listResourceIdsByTaskId(taskId));
-
- return buildTaskResponse(task, finalResourceIds);
}
public AnnotationTaskResponse getTask(LoginUser currentUser, Long taskId) {
- AnnotationTask task = annotationTaskMapper.findByIdAndCompanyId(taskId, currentUser.companyId());
- if (task == null) {
- throw new BusinessException(ResultCode.NOT_FOUND, "任务不存在");
+ try {
+ AnnotationTask task = annotationTaskMapper.findByIdAndCompanyId(taskId, currentUser.companyId());
+ if (task == null) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "任务不存在");
+ }
+ assertTaskPermission(currentUser, task);
+ return buildTaskResponse(task, normalizeIds(annotationTaskResourceMapper.listResourceIdsByTaskId(taskId)));
+ } catch (Exception e) {
+ log.error("getTask failed, companyId={}, userId={}, taskId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), taskId, e.getMessage(), e);
+ throw e;
}
- assertTaskPermission(currentUser, task);
- return buildTaskResponse(task, normalizeIds(annotationTaskResourceMapper.listResourceIdsByTaskId(taskId)));
}
public PageResult pageTasks(LoginUser currentUser, AnnotationTaskPageQuery query) {
- List allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
- boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
+ try {
+ List allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
+ boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
- LambdaQueryWrapper wrapper = new LambdaQueryWrapper()
- .eq(AnnotationTask::getCompanyId, currentUser.companyId())
- .eq(query.taskType() != null, AnnotationTask::getTaskType, query.taskType())
- .eq(StringUtils.hasText(query.taskStatus()), AnnotationTask::getTaskStatus, query.taskStatus())
- .eq(query.isDeleted() != null, AnnotationTask::getIsDeleted, query.isDeleted())
- .like(StringUtils.hasText(query.keyword()), AnnotationTask::getTaskName, query.keyword());
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper()
+ .eq(AnnotationTask::getCompanyId, currentUser.companyId())
+ .eq(query.taskType() != null, AnnotationTask::getTaskType, query.taskType())
+ .eq(StringUtils.hasText(query.taskStatus()), AnnotationTask::getTaskStatus, query.taskStatus())
+ .eq(query.isDeleted() != null, AnnotationTask::getIsDeleted, query.isDeleted())
+ .like(StringUtils.hasText(query.keyword()), AnnotationTask::getTaskName, query.keyword());
- if (shouldFilterByUserId) {
- wrapper.eq(AnnotationTask::getCreatorId, currentUser.userId());
- } else if (!allowedRoles.isEmpty()) {
- wrapper.in(AnnotationTask::getCreatorRole, allowedRoles);
+ if (shouldFilterByUserId) {
+ wrapper.eq(AnnotationTask::getCreatorId, currentUser.userId());
+ } else if (!allowedRoles.isEmpty()) {
+ wrapper.in(AnnotationTask::getCreatorRole, allowedRoles);
+ }
+
+ wrapper.orderByDesc(AnnotationTask::getCreatedAt);
+
+ Page page = new Page<>(query.pageNo(), query.pageSize());
+ Page resultPage = annotationTaskMapper.selectPage(page, wrapper);
+
+ List records = resultPage.getRecords().stream()
+ .filter(task -> query.resourceId() == null
+ || annotationTaskResourceMapper.listResourceIdsByTaskId(task.getId())
+ .contains(query.resourceId()))
+ .map(task -> buildTaskResponse(task,
+ normalizeIds(annotationTaskResourceMapper.listResourceIdsByTaskId(task.getId()))))
+ .toList();
+
+ return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
+ (int) resultPage.getSize());
+ } catch (Exception e) {
+ log.error("pageTasks failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
}
-
- wrapper.orderByDesc(AnnotationTask::getCreatedAt);
-
- Page page = new Page<>(query.pageNo(), query.pageSize());
- Page resultPage = annotationTaskMapper.selectPage(page, wrapper);
-
- List records = resultPage.getRecords().stream()
- .filter(task -> query.resourceId() == null
- || annotationTaskResourceMapper.listResourceIdsByTaskId(task.getId())
- .contains(query.resourceId()))
- .map(task -> buildTaskResponse(task,
- normalizeIds(annotationTaskResourceMapper.listResourceIdsByTaskId(task.getId()))))
- .toList();
-
- return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
- (int) resultPage.getSize());
}
@Transactional
public void deleteTask(LoginUser currentUser, Long taskId) {
- AnnotationTask task = annotationTaskMapper.findByIdAndCompanyId(taskId, currentUser.companyId());
- if (task == null) {
- throw new BusinessException(ResultCode.NOT_FOUND, "任务不存在");
+ try {
+ AnnotationTask task = annotationTaskMapper.findByIdAndCompanyId(taskId, currentUser.companyId());
+ if (task == null) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "任务不存在");
+ }
+ assertTaskPermission(currentUser, task);
+ if (TaskStatus.RUNNING.name().equals(task.getTaskStatus())) {
+ throw new BusinessException(ResultCode.CONFLICT, "运行中的任务不允许删除");
+ }
+ task.setIsDeleted(true);
+ annotationTaskMapper.updateById(task);
+ log.info("deleted annotation task logically, companyId={}, userId={}, taskId={}", currentUser.companyId(),
+ currentUser.userId(), taskId);
+ } catch (Exception e) {
+ log.error("deleteTask failed, companyId={}, userId={}, taskId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), taskId, e.getMessage(), e);
+ throw e;
}
- assertTaskPermission(currentUser, task);
- if (TaskStatus.RUNNING.name().equals(task.getTaskStatus())) {
- throw new BusinessException(ResultCode.CONFLICT, "运行中的任务不允许删除");
- }
- task.setIsDeleted(true);
- annotationTaskMapper.updateById(task);
- log.info("deleted annotation task logically, companyId={}, userId={}, taskId={}", currentUser.companyId(),
- currentUser.userId(), taskId);
}
private List loadAndValidateResources(LoginUser currentUser, List resourceIds) {
diff --git a/src/main/java/com/labelsys/backend/service/AuthService.java b/src/main/java/com/labelsys/backend/service/AuthService.java
index a407f35..4fc36fd 100644
--- a/src/main/java/com/labelsys/backend/service/AuthService.java
+++ b/src/main/java/com/labelsys/backend/service/AuthService.java
@@ -15,69 +15,106 @@ import com.labelsys.backend.enums.UserStatus;
import com.labelsys.backend.mapper.SysCompanyMapper;
import com.labelsys.backend.mapper.SysUserMapper;
import com.labelsys.backend.service.session.TokenSessionRepository;
-import java.time.Duration;
-import java.util.List;
-import java.util.UUID;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import java.time.Duration;
+import java.util.List;
+import java.util.UUID;
+
+@Slf4j
@Service
@RequiredArgsConstructor
public class AuthService {
- private final SysCompanyMapper sysCompanyMapper;
- private final SysUserMapper sysUserMapper;
- private final PasswordEncoder passwordEncoder;
+ private final SysCompanyMapper sysCompanyMapper;
+ private final SysUserMapper sysUserMapper;
+ private final PasswordEncoder passwordEncoder;
private final TokenSessionRepository tokenSessionRepository;
@Value("${labelsys.session.ttl:PT2H}")
private Duration sessionTtl;
public List listAvailableCompanies(String phone) {
- return sysCompanyMapper.findEnabledCompaniesByPhone(phone).stream()
- .map(CompanyOptionResponse::from)
- .toList();
+ try {
+ return sysCompanyMapper.findEnabledCompaniesByPhone(phone).stream()
+ .map(CompanyOptionResponse::from)
+ .toList();
+ } catch (Exception e) {
+ log.error("listAvailableCompanies failed, phone={}, error={}", phone, e.getMessage(), e);
+ throw e;
+ }
}
public LoginResponse login(LoginRequest request) {
- SysCompany company = loadEnabledCompany(request.companyCode());
- SysUser user = loadEnabledUser(company.getId(), request.phone());
- if (!passwordEncoder.matches(request.password(), user.getPasswordHash())) {
- throw new UnauthorizedException("手机号、公司或密码错误");
+ try {
+ SysCompany company = loadEnabledCompany(request.companyCode());
+ SysUser user = loadEnabledUser(company.getId(), request.phone());
+ if (!passwordEncoder.matches(request.password(), user.getPasswordHash())) {
+ throw new UnauthorizedException("手机号、公司或密码错误");
+ }
+ LoginUser loginUser = LoginUser.from(user, company);
+ String token = UUID.randomUUID().toString();
+ tokenSessionRepository.save(token, loginUser, sessionTtl);
+ return LoginResponse.from(token, loginUser, company);
+ } catch (UnauthorizedException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("login failed, companyCode={}, phone={}, error={}",
+ request.companyCode(), request.phone(), e.getMessage(), e);
+ throw e;
}
- LoginUser loginUser = LoginUser.from(user, company);
- String token = UUID.randomUUID().toString();
- tokenSessionRepository.save(token, loginUser, sessionTtl);
- return LoginResponse.from(token, loginUser, company);
}
public LoginUser getCurrentUser(String token) {
- return tokenSessionRepository.find(token)
- .orElseThrow(() -> new UnauthorizedException("未登录或登录已过期"));
+ try {
+ return tokenSessionRepository.find(token)
+ .orElseThrow(() -> new UnauthorizedException("未登录或登录已过期"));
+ } catch (UnauthorizedException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("getCurrentUser failed, token={}, error={}", token, e.getMessage(), e);
+ throw e;
+ }
}
@Transactional
public void changePassword(LoginUser currentUser, ChangePasswordRequest request) {
- if (!request.newPassword().equals(request.confirmPassword())) {
- throw new BusinessException(ResultCode.BAD_REQUEST, "两次输入的新密码不一致");
+ try {
+ if (!request.newPassword().equals(request.confirmPassword())) {
+ throw new BusinessException(ResultCode.BAD_REQUEST, "两次输入的新密码不一致");
+ }
+ SysUser user = sysUserMapper.findByIdAndCompanyId(currentUser.userId(), currentUser.companyId());
+ if (user == null || user.getStatus() != UserStatus.ENABLED) {
+ throw new UnauthorizedException("未登录或登录已过期");
+ }
+ if (!passwordEncoder.matches(request.oldPassword(), user.getPasswordHash())) {
+ throw new BusinessException(ResultCode.BAD_REQUEST, "旧密码错误");
+ }
+ sysUserMapper.updatePassword(user.getId(), user.getCompanyId(),
+ passwordEncoder.encode(request.newPassword()), false);
+ sysUserMapper.bumpSessionVersion(user.getId(), user.getCompanyId());
+ tokenSessionRepository.removeAll(user.getId());
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("changePassword failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
}
- SysUser user = sysUserMapper.findByIdAndCompanyId(currentUser.userId(), currentUser.companyId());
- if (user == null || user.getStatus() != UserStatus.ENABLED) {
- throw new UnauthorizedException("未登录或登录已过期");
- }
- if (!passwordEncoder.matches(request.oldPassword(), user.getPasswordHash())) {
- throw new BusinessException(ResultCode.BAD_REQUEST, "旧密码错误");
- }
- sysUserMapper.updatePassword(user.getId(), user.getCompanyId(), passwordEncoder.encode(request.newPassword()), false);
- sysUserMapper.bumpSessionVersion(user.getId(), user.getCompanyId());
- tokenSessionRepository.removeAll(user.getId());
}
public void logout(String token) {
- tokenSessionRepository.remove(token);
+ try {
+ tokenSessionRepository.remove(token);
+ } catch (Exception e) {
+ log.error("logout failed, token={}, error={}", token, e.getMessage(), e);
+ throw e;
+ }
}
private SysCompany loadEnabledCompany(String companyCode) {
diff --git a/src/main/java/com/labelsys/backend/service/CompanyService.java b/src/main/java/com/labelsys/backend/service/CompanyService.java
index e73ad1f..4cd8765 100644
--- a/src/main/java/com/labelsys/backend/service/CompanyService.java
+++ b/src/main/java/com/labelsys/backend/service/CompanyService.java
@@ -9,10 +9,13 @@ import com.labelsys.backend.dto.request.UpdateCompanyStatusRequest;
import com.labelsys.backend.entity.SysCompany;
import com.labelsys.backend.mapper.SysCompanyMapper;
import com.labelsys.backend.util.IdGenerator;
-import java.util.List;
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
+import java.util.List;
+
+@Slf4j
@Service
@RequiredArgsConstructor
public class CompanyService {
@@ -20,29 +23,53 @@ public class CompanyService {
private final SysCompanyMapper sysCompanyMapper;
public List listCompanies(LoginUser currentUser) {
- assertPlatformAdmin(currentUser);
- return sysCompanyMapper.selectList(null);
+ try {
+ assertPlatformAdmin(currentUser);
+ return sysCompanyMapper.selectList(null);
+ } catch (ForbiddenException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("listCompanies failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
+ }
}
public SysCompany createCompany(LoginUser currentUser, CreateCompanyRequest request) {
- assertPlatformAdmin(currentUser);
- if (sysCompanyMapper.findByCompanyCode(request.companyCode()) != null) {
- throw new BusinessException(ResultCode.CONFLICT, "公司编码已存在");
+ try {
+ assertPlatformAdmin(currentUser);
+ if (sysCompanyMapper.findByCompanyCode(request.companyCode()) != null) {
+ throw new BusinessException(ResultCode.CONFLICT, "公司编码已存在");
+ }
+ SysCompany company = SysCompany.builder()
+ .id(IdGenerator.nextId())
+ .companyCode(request.companyCode())
+ .companyName(request.companyName())
+ .status(com.labelsys.backend.enums.CompanyStatus.ENABLED)
+ .build();
+ sysCompanyMapper.insert(company);
+ return company;
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("createCompany failed, companyId={}, userId={}, companyCode={}, error={}",
+ currentUser.companyId(), currentUser.userId(), request.companyCode(), e.getMessage(), e);
+ throw e;
}
- SysCompany company = SysCompany.builder()
- .id(IdGenerator.nextId())
- .companyCode(request.companyCode())
- .companyName(request.companyName())
- .status(com.labelsys.backend.enums.CompanyStatus.ENABLED)
- .build();
- sysCompanyMapper.insert(company);
- return company;
}
public void updateStatus(LoginUser currentUser, Long companyId, UpdateCompanyStatusRequest request) {
- assertPlatformAdmin(currentUser);
- if (sysCompanyMapper.updateStatus(companyId, request.status()) == 0) {
- throw new BusinessException(ResultCode.NOT_FOUND, "公司不存在");
+ try {
+ assertPlatformAdmin(currentUser);
+ if (sysCompanyMapper.updateStatus(companyId, request.status()) == 0) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "公司不存在");
+ }
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("updateStatus failed, companyId={}, userId={}, targetCompanyId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), companyId, e.getMessage(), e);
+ throw e;
}
}
diff --git a/src/main/java/com/labelsys/backend/service/DataPermissionService.java b/src/main/java/com/labelsys/backend/service/DataPermissionService.java
index 43c3c3a..243dda8 100644
--- a/src/main/java/com/labelsys/backend/service/DataPermissionService.java
+++ b/src/main/java/com/labelsys/backend/service/DataPermissionService.java
@@ -3,13 +3,16 @@ package com.labelsys.backend.service;
import com.labelsys.backend.context.LoginUser;
import com.labelsys.backend.entity.BizDataRecord;
import com.labelsys.backend.enums.UserRole;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Service;
+
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
-import lombok.RequiredArgsConstructor;
-import org.springframework.stereotype.Service;
-import org.springframework.jdbc.core.JdbcTemplate;
+@Slf4j
@Service
@RequiredArgsConstructor
public class DataPermissionService {
@@ -17,79 +20,103 @@ public class DataPermissionService {
private final JdbcTemplate jdbcTemplate;
public boolean canAccessCreator(LoginUser currentUser, Long creatorId, UserRole creatorRole) {
- return switch (currentUser.role()) {
- case EMPLOYEE -> currentUser.userId().equals(creatorId);
- case MANAGER -> creatorRole == UserRole.EMPLOYEE || creatorRole == UserRole.MANAGER;
- case ENGINEER -> true;
- };
+ try {
+ return switch (currentUser.role()) {
+ case EMPLOYEE -> currentUser.userId().equals(creatorId);
+ case MANAGER -> creatorRole == UserRole.EMPLOYEE || creatorRole == UserRole.MANAGER;
+ case ENGINEER -> true;
+ };
+ } catch (Exception e) {
+ log.error("canAccessCreator failed, companyId={}, userId={}, creatorId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), creatorId, e.getMessage(), e);
+ throw e;
+ }
}
- /**
- * Generic in-memory role-based data filter for records already loaded in memory.
- */
public List filterByRole(
LoginUser currentUser,
List allRecords,
Function roleExtractor,
Function ownerIdExtractor) {
+ try {
+ if (allRecords == null || allRecords.isEmpty()) {
+ return List.of();
+ }
- if (allRecords == null || allRecords.isEmpty()) {
- return List.of();
+ UserRole currentRole = currentUser.role();
+ Long currentUserId = currentUser.userId();
+
+ return allRecords.stream()
+ .filter(record -> {
+ UserRole recordRole = roleExtractor.apply(record);
+ Long recordOwnerId = ownerIdExtractor.apply(record);
+
+ return switch (currentRole) {
+ case EMPLOYEE -> currentUserId.equals(recordOwnerId);
+ case MANAGER -> recordRole == UserRole.EMPLOYEE || recordRole == UserRole.MANAGER;
+ case ENGINEER -> true;
+ };
+ })
+ .collect(Collectors.toList());
+ } catch (Exception e) {
+ log.error("filterByRole failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
}
-
- UserRole currentRole = currentUser.role();
- Long currentUserId = currentUser.userId();
-
- return allRecords.stream()
- .filter(record -> {
- UserRole recordRole = roleExtractor.apply(record);
- Long recordOwnerId = ownerIdExtractor.apply(record);
-
- return switch (currentRole) {
- case EMPLOYEE -> currentUserId.equals(recordOwnerId);
- case MANAGER -> recordRole == UserRole.EMPLOYEE || recordRole == UserRole.MANAGER;
- case ENGINEER -> true;
- };
- })
- .collect(Collectors.toList());
}
- /**
- * Returns the creator roles visible to the current user for SQL-side filtering.
- */
public List getAllowedRoles(LoginUser currentUser) {
- return switch (currentUser.role()) {
- case EMPLOYEE -> List.of();
- case MANAGER -> List.of("EMPLOYEE", "MANAGER");
- case ENGINEER -> List.of("EMPLOYEE", "MANAGER", "ENGINEER");
- };
+ try {
+ return switch (currentUser.role()) {
+ case EMPLOYEE -> List.of();
+ case MANAGER -> List.of("EMPLOYEE", "MANAGER");
+ case ENGINEER -> List.of("EMPLOYEE", "MANAGER", "ENGINEER");
+ };
+ } catch (Exception e) {
+ log.error("getAllowedRoles failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
+ }
}
- /**
- * Whether SQL queries should additionally restrict by creator/user id.
- */
public boolean shouldFilterByUserId(LoginUser currentUser) {
- return currentUser.role() == UserRole.EMPLOYEE;
+ try {
+ return currentUser.role() == UserRole.EMPLOYEE;
+ } catch (Exception e) {
+ log.error("shouldFilterByUserId failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
+ }
}
public List listVisibleRecords(LoginUser currentUser) {
- List allRecords = jdbcTemplate.query("""
- select id, company_id, creator_id, creator_role, record_name, created_at, updated_at
- from biz_data_record
- where company_id = ?
- order by id
- """,
- (rs, rowNum) -> BizDataRecord.builder()
- .id(rs.getLong("id"))
- .companyId(rs.getLong("company_id"))
- .creatorId(rs.getLong("creator_id"))
- .creatorRole(UserRole.valueOf(rs.getString("creator_role")))
- .recordName(rs.getString("record_name"))
- .createdAt(rs.getTimestamp("created_at") == null ? null : rs.getTimestamp("created_at").toLocalDateTime())
- .updatedAt(rs.getTimestamp("updated_at") == null ? null : rs.getTimestamp("updated_at").toLocalDateTime())
- .build(),
- currentUser.companyId());
+ try {
+ List allRecords = jdbcTemplate.query("""
+ select id, company_id, creator_id, creator_role, record_name, created_at, updated_at
+ from biz_data_record
+ where company_id = ?
+ order by id
+ """,
+ (rs, rowNum) -> BizDataRecord.builder()
+ .id(rs.getLong("id"))
+ .companyId(rs.getLong("company_id"))
+ .creatorId(rs.getLong("creator_id"))
+ .creatorRole(UserRole.valueOf(rs.getString("creator_role")))
+ .recordName(rs.getString("record_name"))
+ .createdAt(rs.getTimestamp("created_at") == null ?
+ null :
+ rs.getTimestamp("created_at").toLocalDateTime())
+ .updatedAt(rs.getTimestamp("updated_at") == null ?
+ null :
+ rs.getTimestamp("updated_at").toLocalDateTime())
+ .build(),
+ currentUser.companyId());
- return filterByRole(currentUser, allRecords, BizDataRecord::getCreatorRole, BizDataRecord::getCreatorId);
+ return filterByRole(currentUser, allRecords, BizDataRecord::getCreatorRole, BizDataRecord::getCreatorId);
+ } catch (Exception e) {
+ log.error("listVisibleRecords failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
+ }
}
}
diff --git a/src/main/java/com/labelsys/backend/service/SourceResourceService.java b/src/main/java/com/labelsys/backend/service/SourceResourceService.java
index 9a6960e..7d52d16 100644
--- a/src/main/java/com/labelsys/backend/service/SourceResourceService.java
+++ b/src/main/java/com/labelsys/backend/service/SourceResourceService.java
@@ -54,92 +54,119 @@ public class SourceResourceService {
@Transactional
public SourceUploadResponse upload(LoginUser currentUser, SourceUploadRequest request) {
- MultipartFile file = request.getFile();
- if (file == null || file.isEmpty()) {
- throw new BusinessException(ResultCode.BAD_REQUEST, "上传文件不能为空");
- }
- if (!ResourceType.isValid(request.getResourceType())) {
- throw new BusinessException(ResultCode.BAD_REQUEST, "资源类型非法");
- }
- String resourceName =
- StringUtils.hasText(request.getResourceName()) ? request.getResourceName() : file.getOriginalFilename();
- SourceResource existingResource =
- sourceResourceMapper.selectByCompanyIdAndResourceName(currentUser.companyId(), resourceName);
- if (existingResource != null) {
- throw new BusinessException(ResultCode.BAD_REQUEST, "资源名称已存在:" + resourceName);
- }
-
- long resourceId = IdGenerator.nextId();
- String extension = resolveExtension(file.getOriginalFilename(), request.getResourceType());
- String objectKey = ObjectStoragePathBuilder.sourceObjectKey(currentUser.companyId(), request.getResourceType(),
- resourceId, extension);
try {
- objectStorageService.upload(objectStorageProperties.getSourceBucket(), objectKey, file.getBytes(),
- file.getContentType());
- } catch (IOException ex) {
- throw new BusinessException(ResultCode.BAD_REQUEST, "读取上传文件失败");
- }
+ MultipartFile file = request.getFile();
+ if (file == null || file.isEmpty()) {
+ throw new BusinessException(ResultCode.BAD_REQUEST, "上传文件不能为空");
+ }
+ if (!ResourceType.isValid(request.getResourceType())) {
+ throw new BusinessException(ResultCode.BAD_REQUEST, "资源类型非法");
+ }
+ String resourceName =
+ StringUtils.hasText(request.getResourceName()) ?
+ request.getResourceName() :
+ file.getOriginalFilename();
+ SourceResource existingResource =
+ sourceResourceMapper.selectByCompanyIdAndResourceName(currentUser.companyId(), resourceName);
+ if (existingResource != null) {
+ throw new BusinessException(ResultCode.BAD_REQUEST, "资源名称已存在:" + resourceName);
+ }
- SourceResource resource = SourceResource.builder().id(resourceId).companyId(currentUser.companyId())
- .creatorId(currentUser.userId()).creatorRole(currentUser.role())
- .resourceName(
- StringUtils.hasText(request.getResourceName()) ?
- request.getResourceName() :
- file.getOriginalFilename())
- .resourceType(request.getResourceType()).bucketName(objectStorageProperties.getSourceBucket())
- .filePath(objectKey).fileSize(file.getSize()).sourceStatus(SourceStatus.READY.name())
- .storageProvider("rustfs").remark(request.getRemark()).build();
- sourceResourceMapper.insert(resource);
- log.info("uploaded source resource, companyId={}, userId={}, resourceId={}", currentUser.companyId(),
- currentUser.userId(), resourceId);
- return new SourceUploadResponse(resource.getId(), resource.getResourceName(), resource.getResourceType(),
- resource.getBucketName(), resource.getFilePath(), resource.getFileSize(), resource.getSourceStatus(),
- resource.getCreatedAt());
+ long resourceId = IdGenerator.nextId();
+ String extension = resolveExtension(file.getOriginalFilename(), request.getResourceType());
+ String objectKey = ObjectStoragePathBuilder.sourceObjectKey(currentUser.companyId(),
+ request.getResourceType(),
+ resourceId, extension);
+ try {
+ objectStorageService.upload(objectStorageProperties.getSourceBucket(), objectKey, file.getBytes(),
+ file.getContentType());
+ } catch (IOException ex) {
+ throw new BusinessException(ResultCode.BAD_REQUEST, "读取上传文件失败");
+ }
+
+ SourceResource resource = SourceResource.builder().id(resourceId).companyId(currentUser.companyId())
+ .creatorId(currentUser.userId()).creatorRole(currentUser.role())
+ .resourceName(
+ StringUtils.hasText(request.getResourceName()) ?
+ request.getResourceName() :
+ file.getOriginalFilename())
+ .resourceType(request.getResourceType()).bucketName(objectStorageProperties.getSourceBucket())
+ .filePath(objectKey).fileSize(file.getSize()).sourceStatus(SourceStatus.READY.name())
+ .storageProvider("rustfs").remark(request.getRemark()).build();
+ sourceResourceMapper.insert(resource);
+ log.info("uploaded source resource, companyId={}, userId={}, resourceId={}", currentUser.companyId(),
+ currentUser.userId(), resourceId);
+ return new SourceUploadResponse(resource.getId(), resource.getResourceName(), resource.getResourceType(),
+ resource.getBucketName(), resource.getFilePath(), resource.getFileSize(),
+ resource.getSourceStatus(),
+ resource.getCreatedAt());
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("upload failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
+ }
}
public PageResult pageResources(LoginUser currentUser, SourceResourcePageQuery query) {
- List allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
- boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
+ try {
+ List allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
+ boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
- LambdaQueryWrapper wrapper =
- new LambdaQueryWrapper().eq(SourceResource::getCompanyId, currentUser.companyId())
- .eq(StringUtils.hasText(query.resourceType()), SourceResource::getResourceType,
- query.resourceType())
- .eq(StringUtils.hasText(query.sourceStatus()), SourceResource::getSourceStatus,
- query.sourceStatus())
- .like(StringUtils.hasText(query.keyword()), SourceResource::getResourceName, query.keyword());
+ LambdaQueryWrapper wrapper =
+ new LambdaQueryWrapper().eq(SourceResource::getCompanyId, currentUser.companyId())
+ .eq(StringUtils.hasText(query.resourceType()), SourceResource::getResourceType,
+ query.resourceType())
+ .eq(StringUtils.hasText(query.sourceStatus()), SourceResource::getSourceStatus,
+ query.sourceStatus())
+ .like(StringUtils.hasText(query.keyword()), SourceResource::getResourceName,
+ query.keyword());
- if (shouldFilterByUserId) {
- wrapper.eq(SourceResource::getCreatorId, currentUser.userId());
- } else if (!allowedRoles.isEmpty()) {
- wrapper.in(SourceResource::getCreatorRole, allowedRoles);
- }
+ if (shouldFilterByUserId) {
+ wrapper.eq(SourceResource::getCreatorId, currentUser.userId());
+ } else if (!allowedRoles.isEmpty()) {
+ wrapper.in(SourceResource::getCreatorRole, allowedRoles);
+ }
- wrapper.orderByDesc(SourceResource::getCreatedAt);
+ wrapper.orderByDesc(SourceResource::getCreatedAt);
- // 判断是否需要分页
- if (query.needPagination()) {
- Page page = new Page<>(query.pageNo(), query.pageSize());
- Page resultPage = sourceResourceMapper.selectPage(page, wrapper);
- List records = resultPage.getRecords().stream().map(this::toResponse).toList();
- return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
- (int) resultPage.getSize());
- } else {
- // 不分页,查询全部
- List records = sourceResourceMapper.selectList(wrapper);
- List responseList = records.stream().map(this::toResponse).toList();
- return new PageResult<>(responseList, (long) responseList.size(), 1, responseList.size());
+ // 判断是否需要分页
+ if (query.needPagination()) {
+ Page page = new Page<>(query.pageNo(), query.pageSize());
+ Page resultPage = sourceResourceMapper.selectPage(page, wrapper);
+ List records = resultPage.getRecords().stream().map(this::toResponse).toList();
+ return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
+ (int) resultPage.getSize());
+ } else {
+ // 不分页,查询全部
+ List records = sourceResourceMapper.selectList(wrapper);
+ List responseList = records.stream().map(this::toResponse).toList();
+ return new PageResult<>(responseList, (long) responseList.size(), 1, responseList.size());
+ }
+ } catch (Exception e) {
+ log.error("pageResources failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
}
}
public SourceResourceResponse getResource(LoginUser currentUser, Long resourceId) {
- SourceResource resource = sourceResourceMapper.selectById(resourceId);
- if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
- log.warn("Resource not found or cross-tenant access attempt: resourceId={}, companyId={}, userId={}",
- resourceId, currentUser.companyId(), currentUser.userId());
- throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
+ try {
+ SourceResource resource = sourceResourceMapper.selectById(resourceId);
+ if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
+ log.warn("Resource not found or cross-tenant access attempt: resourceId={}, companyId={}, userId={}",
+ resourceId, currentUser.companyId(), currentUser.userId());
+ throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
+ }
+ return toResponse(resource);
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("getResource failed, companyId={}, userId={}, resourceId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), resourceId, e.getMessage(), e);
+ throw e;
}
- return toResponse(resource);
}
/**
@@ -149,30 +176,201 @@ public class SourceResourceService {
* @return 资源实体
*/
public SourceResource getResourceEntity(Long resourceId) {
- return sourceResourceMapper.selectById(resourceId);
+ try {
+ return sourceResourceMapper.selectById(resourceId);
+ } catch (Exception e) {
+ log.error("getResourceEntity failed, resourceId={}, error={}", resourceId, e.getMessage(), e);
+ throw e;
+ }
}
@Transactional
public void deleteResource(LoginUser currentUser, Long resourceId) {
- SourceResource resource = sourceResourceMapper.selectById(resourceId);
- if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
- throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
+ try {
+ SourceResource resource = sourceResourceMapper.selectById(resourceId);
+ if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
+ }
+ if (!dataPermissionService.canAccessCreator(currentUser, resource.getCreatorId(),
+ resource.getCreatorRole())) {
+ throw new BusinessException(ResultCode.FORBIDDEN, "无权删除资源");
+ }
+ int bindCount = annotationTaskResourceMapper.countByResourceId(resourceId);
+ if (bindCount > 0) {
+ resource.setSourceStatus(SourceStatus.ARCHIVED.name());
+ sourceResourceMapper.updateById(resource);
+ log.info("archived referenced source resource, companyId={}, userId={}, resourceId={}",
+ currentUser.companyId(), currentUser.userId(), resourceId);
+ return;
+ }
+ objectStorageService.delete(resource.getBucketName(), resource.getFilePath());
+ sourceResourceMapper.deleteById(resourceId);
+ log.info("deleted source resource, companyId={}, userId={}, resourceId={}", currentUser.companyId(),
+ currentUser.userId(), resourceId);
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("deleteResource failed, companyId={}, userId={}, resourceId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), resourceId, e.getMessage(), e);
+ throw e;
}
- if (!dataPermissionService.canAccessCreator(currentUser, resource.getCreatorId(), resource.getCreatorRole())) {
- throw new BusinessException(ResultCode.FORBIDDEN, "无权删除资源");
+ }
+
+ /**
+ * 下载资源(支持 TEXT、IMAGE、VIDEO)
+ *
+ * @param currentUser 当前用户
+ * @param resourceId 资源ID
+ * @return 资源字节数组
+ */
+ public byte[] downloadResource(LoginUser currentUser, Long resourceId) {
+ try {
+ SourceResource resource = sourceResourceMapper.selectById(resourceId);
+ if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
+ log.warn("Resource not found or cross-tenant access attempt: resourceId={}, companyId={}, userId={}",
+ resourceId, currentUser.companyId(), currentUser.userId());
+ throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
+ }
+ if (!"READY".equals(resource.getSourceStatus())) {
+ throw new BusinessException(ResultCode.BAD_REQUEST, "资源未就绪");
+ }
+ return objectStorageService.download(resource.getBucketName(), resource.getFilePath());
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("downloadResource failed, companyId={}, userId={}, resourceId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), resourceId, e.getMessage(), e);
+ throw e;
}
- int bindCount = annotationTaskResourceMapper.countByResourceId(resourceId);
- if (bindCount > 0) {
- resource.setSourceStatus(SourceStatus.ARCHIVED.name());
- sourceResourceMapper.updateById(resource);
- log.info("archived referenced source resource, companyId={}, userId={}, resourceId={}",
- currentUser.companyId(), currentUser.userId(), resourceId);
- return;
+ }
+
+ public ImageBboxResponse getImageBbox(LoginUser currentUser, Long resourceId) {
+ try {
+ SourceResource resource = sourceResourceMapper.selectById(resourceId);
+ if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
+ }
+ if (!"IMAGE".equals(resource.getResourceType())) {
+ throw new BusinessException(ResultCode.BAD_REQUEST, "仅图片资源支持BBOX标注");
+ }
+
+ ImageBboxAnnotation annotation = imageBboxAnnotationMapper.selectByResourceId(resourceId);
+ if (annotation == null) {
+ return new ImageBboxResponse(null, resourceId, List.of(), null, null, null, null);
+ }
+
+ List bboxes = parseBboxJson(annotation.getBboxJson());
+ SysUser creator = sysUserMapper.selectById(annotation.getCreatorId());
+
+ return new ImageBboxResponse(
+ annotation.getId(),
+ annotation.getResourceId(),
+ bboxes,
+ annotation.getRemark(),
+ creator == null ? null : creator.getRealName(),
+ annotation.getCreatedAt(),
+ annotation.getUpdatedAt()
+ );
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("getImageBbox failed, companyId={}, userId={}, resourceId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), resourceId, e.getMessage(), e);
+ throw e;
+ }
+ }
+
+ @Transactional
+ public ImageBboxResponse saveImageBbox(LoginUser currentUser, Long resourceId, SaveImageBboxRequest request) {
+ try {
+ SourceResource resource = sourceResourceMapper.selectById(resourceId);
+ if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
+ }
+ if (!"IMAGE".equals(resource.getResourceType())) {
+ throw new BusinessException(ResultCode.BAD_REQUEST, "仅图片资源支持BBOX标注");
+ }
+
+ String bboxJson;
+ try {
+ bboxJson = objectMapper.writeValueAsString(request.bboxes());
+ } catch (JsonProcessingException e) {
+ throw new BusinessException(ResultCode.BAD_REQUEST, "BBOX数据序列化失败");
+ }
+
+ boolean isNewAnnotation = imageBboxAnnotationMapper.selectByResourceId(resourceId) == null;
+
+ ImageBboxAnnotation existing = imageBboxAnnotationMapper.selectByResourceId(resourceId);
+ if (existing != null) {
+ existing.setBboxJson(bboxJson);
+ existing.setRemark(request.remark());
+ existing.setUpdatedAt(LocalDateTime.now());
+ imageBboxAnnotationMapper.updateById(existing);
+ } else {
+ long annotationId = IdGenerator.nextId();
+ ImageBboxAnnotation annotation = ImageBboxAnnotation.builder()
+ .id(annotationId)
+ .companyId(currentUser.companyId())
+ .resourceId(resourceId)
+ .bboxJson(bboxJson)
+ .remark(request.remark())
+ .creatorId(currentUser.userId())
+ .creatorRole(currentUser.role())
+ .build();
+ imageBboxAnnotationMapper.insert(annotation);
+ }
+
+ // 更新资源表的has_bbox字段
+ if (isNewAnnotation || Boolean.FALSE.equals(resource.getHasBbox())) {
+ resource.setHasBbox(true);
+ sourceResourceMapper.updateById(resource);
+ }
+
+ return getImageBbox(currentUser, resourceId);
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("saveImageBbox failed, companyId={}, userId={}, resourceId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), resourceId, e.getMessage(), e);
+ throw e;
+ }
+ }
+
+ @Transactional
+ public void deleteImageBbox(LoginUser currentUser, Long resourceId) {
+ try {
+ SourceResource resource = sourceResourceMapper.selectById(resourceId);
+ if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
+ }
+ imageBboxAnnotationMapper.deleteByResourceId(resourceId);
+
+ // 更新资源表的has_bbox字段为false
+ if (Boolean.TRUE.equals(resource.getHasBbox())) {
+ resource.setHasBbox(false);
+ sourceResourceMapper.updateById(resource);
+ }
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("deleteImageBbox failed, companyId={}, userId={}, resourceId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), resourceId, e.getMessage(), e);
+ throw e;
+ }
+ }
+
+ private List parseBboxJson(String bboxJson) {
+ if (!StringUtils.hasText(bboxJson)) {
+ return List.of();
+ }
+ try {
+ return objectMapper.readValue(bboxJson,
+ new TypeReference>() {
+ });
+ } catch (JsonProcessingException e) {
+ log.warn("Failed to parse bbox json: {}", e.getMessage());
+ return List.of();
}
- objectStorageService.delete(resource.getBucketName(), resource.getFilePath());
- sourceResourceMapper.deleteById(resourceId);
- log.info("deleted source resource, companyId={}, userId={}, resourceId={}", currentUser.companyId(),
- currentUser.userId(), resourceId);
}
private SourceResourceResponse toResponse(SourceResource resource) {
@@ -195,26 +393,6 @@ public class SourceResourceService {
};
}
- /**
- * 下载资源(支持 TEXT、IMAGE、VIDEO)
- *
- * @param currentUser 当前用户
- * @param resourceId 资源ID
- * @return 资源字节数组
- */
- public byte[] downloadResource(LoginUser currentUser, Long resourceId) {
- SourceResource resource = sourceResourceMapper.selectById(resourceId);
- if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
- log.warn("Resource not found or cross-tenant access attempt: resourceId={}, companyId={}, userId={}",
- resourceId, currentUser.companyId(), currentUser.userId());
- throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
- }
- if (!"READY".equals(resource.getSourceStatus())) {
- throw new BusinessException(ResultCode.BAD_REQUEST, "资源未就绪");
- }
- return objectStorageService.download(resource.getBucketName(), resource.getFilePath());
- }
-
/**
* 获取资源的Content-Type(支持 TEXT、IMAGE、VIDEO)
*
@@ -224,7 +402,7 @@ public class SourceResourceService {
public String getContentType(SourceResource resource) {
String filePath = resource.getFilePath();
String resourceType = resource.getResourceType();
-
+
// 优先根据文件扩展名判断
if (filePath != null && filePath.contains(".")) {
String extension = filePath.substring(filePath.lastIndexOf('.') + 1).toLowerCase();
@@ -250,11 +428,11 @@ public class SourceResourceService {
default -> getContentTypeByResourceType(resourceType);
};
}
-
+
// 如果没有扩展名,根据资源类型判断
return getContentTypeByResourceType(resourceType);
}
-
+
/**
* 根据资源类型获取默认Content-Type
*
@@ -269,110 +447,4 @@ public class SourceResourceService {
default -> "application/octet-stream";
};
}
-
- public ImageBboxResponse getImageBbox(LoginUser currentUser, Long resourceId) {
- SourceResource resource = sourceResourceMapper.selectById(resourceId);
- if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
- throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
- }
- if (!"IMAGE".equals(resource.getResourceType())) {
- throw new BusinessException(ResultCode.BAD_REQUEST, "仅图片资源支持BBOX标注");
- }
-
- ImageBboxAnnotation annotation = imageBboxAnnotationMapper.selectByResourceId(resourceId);
- if (annotation == null) {
- return new ImageBboxResponse(null, resourceId, List.of(), null, null, null, null);
- }
-
- List bboxes = parseBboxJson(annotation.getBboxJson());
- SysUser creator = sysUserMapper.selectById(annotation.getCreatorId());
-
- return new ImageBboxResponse(
- annotation.getId(),
- annotation.getResourceId(),
- bboxes,
- annotation.getRemark(),
- creator == null ? null : creator.getRealName(),
- annotation.getCreatedAt(),
- annotation.getUpdatedAt()
- );
- }
-
- @Transactional
- public ImageBboxResponse saveImageBbox(LoginUser currentUser, Long resourceId, SaveImageBboxRequest request) {
- SourceResource resource = sourceResourceMapper.selectById(resourceId);
- if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
- throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
- }
- if (!"IMAGE".equals(resource.getResourceType())) {
- throw new BusinessException(ResultCode.BAD_REQUEST, "仅图片资源支持BBOX标注");
- }
-
- String bboxJson;
- try {
- bboxJson = objectMapper.writeValueAsString(request.bboxes());
- } catch (JsonProcessingException e) {
- throw new BusinessException(ResultCode.BAD_REQUEST, "BBOX数据序列化失败");
- }
-
- boolean isNewAnnotation = imageBboxAnnotationMapper.selectByResourceId(resourceId) == null;
-
- ImageBboxAnnotation existing = imageBboxAnnotationMapper.selectByResourceId(resourceId);
- if (existing != null) {
- existing.setBboxJson(bboxJson);
- existing.setRemark(request.remark());
- existing.setUpdatedAt(LocalDateTime.now());
- imageBboxAnnotationMapper.updateById(existing);
- } else {
- long annotationId = IdGenerator.nextId();
- ImageBboxAnnotation annotation = ImageBboxAnnotation.builder()
- .id(annotationId)
- .companyId(currentUser.companyId())
- .resourceId(resourceId)
- .bboxJson(bboxJson)
- .remark(request.remark())
- .creatorId(currentUser.userId())
- .creatorRole(currentUser.role())
- .build();
- imageBboxAnnotationMapper.insert(annotation);
- }
-
- // 更新资源表的has_bbox字段
- if (isNewAnnotation || Boolean.FALSE.equals(resource.getHasBbox())) {
- resource.setHasBbox(true);
- sourceResourceMapper.updateById(resource);
- }
-
- return getImageBbox(currentUser, resourceId);
- }
-
- @Transactional
- public void deleteImageBbox(LoginUser currentUser, Long resourceId) {
- SourceResource resource = sourceResourceMapper.selectById(resourceId);
- if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
- throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
- }
- imageBboxAnnotationMapper.deleteByResourceId(resourceId);
-
- // 更新资源表的has_bbox字段为false
- if (Boolean.TRUE.equals(resource.getHasBbox())) {
- resource.setHasBbox(false);
- sourceResourceMapper.updateById(resource);
- }
- }
-
- private List parseBboxJson(String bboxJson) {
- if (!StringUtils.hasText(bboxJson)) {
- return List.of();
- }
- try {
- return objectMapper.readValue(bboxJson,
- new TypeReference>() {
- });
- } catch (JsonProcessingException e) {
- log.warn("Failed to parse bbox json: {}", e.getMessage());
- return List.of();
- }
- }
-
}
\ No newline at end of file
diff --git a/src/main/java/com/labelsys/backend/service/SysConfigService.java b/src/main/java/com/labelsys/backend/service/SysConfigService.java
index 46c9eaa..b8e17ef 100644
--- a/src/main/java/com/labelsys/backend/service/SysConfigService.java
+++ b/src/main/java/com/labelsys/backend/service/SysConfigService.java
@@ -33,88 +33,118 @@ public class SysConfigService {
@Transactional
public SysConfig saveConfig(LoginUser currentUser, SaveSysConfigRequest request) {
- validateConfigType(request.configType());
- SysConfig existing = sysConfigMapper.findByCompanyIdAndConfigName(currentUser.companyId(),
- request.configName());
- if (existing != null) {
- throw new BusinessException(ResultCode.CONFLICT, "配置名称已存在");
+ try {
+ validateConfigType(request.configType());
+ SysConfig existing = sysConfigMapper.findByCompanyIdAndConfigName(currentUser.companyId(),
+ request.configName());
+ if (existing != null) {
+ throw new BusinessException(ResultCode.CONFLICT, "配置名称已存在");
+ }
+ SysConfig config = SysConfig.builder()
+ .id(IdGenerator.nextId())
+ .companyId(currentUser.companyId())
+ .configType(request.configType())
+ .configName(request.configName())
+ .configValue(request.configValue())
+ .status(request.status())
+ .creatorId(currentUser.userId())
+ .creatorRole(currentUser.role().name())
+ .build();
+ sysConfigMapper.insert(config);
+ log.info("saved sys config, companyId={}, userId={}, userRole={}, configName={}, configType={}",
+ currentUser.companyId(), currentUser.userId(), currentUser.role().name(),
+ request.configName(), request.configType());
+ return config;
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("saveConfig failed, companyId={}, userId={}, configName={}, error={}",
+ currentUser.companyId(), currentUser.userId(), request.configName(), e.getMessage(), e);
+ throw e;
}
- SysConfig config = SysConfig.builder()
- .id(IdGenerator.nextId())
- .companyId(currentUser.companyId())
- .configType(request.configType())
- .configName(request.configName())
- .configValue(request.configValue())
- .status(request.status())
- .creatorId(currentUser.userId())
- .creatorRole(currentUser.role().name())
- .build();
- sysConfigMapper.insert(config);
- log.info("saved sys config, companyId={}, userId={}, userRole={}, configName={}, configType={}",
- currentUser.companyId(), currentUser.userId(), currentUser.role().name(),
- request.configName(), request.configType());
- return config;
}
@Transactional
public SysConfig updateConfig(LoginUser currentUser, Long configId, UpdateSysConfigRequest request) {
- validateConfigType(request.configType());
- SysConfig existing = getConfigEntity(currentUser, configId);
+ try {
+ validateConfigType(request.configType());
+ SysConfig existing = getConfigEntity(currentUser, configId);
- if (StringUtils.hasText(request.configName())) {
- existing.setConfigName(request.configName());
+ if (StringUtils.hasText(request.configName())) {
+ existing.setConfigName(request.configName());
+ }
+ if (StringUtils.hasText(request.configType())) {
+ existing.setConfigType(request.configType());
+ }
+ if (StringUtils.hasText(request.configValue())) {
+ existing.setConfigValue(request.configValue());
+ }
+ if (StringUtils.hasText(request.status())) {
+ existing.setStatus(request.status());
+ }
+ sysConfigMapper.updateById(existing);
+ log.info("updated sys config, companyId={}, userId={}, configId={}",
+ currentUser.companyId(), currentUser.userId(), configId);
+ return existing;
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("updateConfig failed, companyId={}, userId={}, configId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), configId, e.getMessage(), e);
+ throw e;
}
- if (StringUtils.hasText(request.configType())) {
- existing.setConfigType(request.configType());
- }
- if (StringUtils.hasText(request.configValue())) {
- existing.setConfigValue(request.configValue());
- }
- if (StringUtils.hasText(request.status())) {
- existing.setStatus(request.status());
- }
- sysConfigMapper.updateById(existing);
- log.info("updated sys config, companyId={}, userId={}, configId={}",
- currentUser.companyId(), currentUser.userId(), configId);
- return existing;
}
public SysConfigResponse getConfig(LoginUser currentUser, Long configId) {
- SysConfig config = getConfigEntity(currentUser, configId);
- if (!dataPermissionService.canAccessCreator(currentUser, config.getCreatorId(),
- UserRole.valueOf(config.getCreatorRole()))) {
- throw new BusinessException(ResultCode.FORBIDDEN, "无权访问配置");
+ try {
+ SysConfig config = getConfigEntity(currentUser, configId);
+ if (!dataPermissionService.canAccessCreator(currentUser, config.getCreatorId(),
+ UserRole.valueOf(config.getCreatorRole()))) {
+ throw new BusinessException(ResultCode.FORBIDDEN, "无权访问配置");
+ }
+ return toResponse(config);
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("getConfig failed, companyId={}, userId={}, configId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), configId, e.getMessage(), e);
+ throw e;
}
- return toResponse(config);
}
public PageResult pageConfigs(LoginUser currentUser, SysConfigPageQuery query) {
- List allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
- boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
+ try {
+ List allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
+ boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
- LambdaQueryWrapper wrapper = new LambdaQueryWrapper()
- .eq(SysConfig::getCompanyId, currentUser.companyId())
- .eq(StringUtils.hasText(query.configType()), SysConfig::getConfigType, query.configType())
- .eq(StringUtils.hasText(query.status()), SysConfig::getStatus, query.status())
- .like(StringUtils.hasText(query.configName()), SysConfig::getConfigName, query.configName());
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper()
+ .eq(SysConfig::getCompanyId, currentUser.companyId())
+ .eq(StringUtils.hasText(query.configType()), SysConfig::getConfigType, query.configType())
+ .eq(StringUtils.hasText(query.status()), SysConfig::getStatus, query.status())
+ .like(StringUtils.hasText(query.configName()), SysConfig::getConfigName, query.configName());
- if (shouldFilterByUserId) {
- wrapper.eq(SysConfig::getCreatorId, currentUser.userId());
- } else if (!allowedRoles.isEmpty()) {
- wrapper.in(SysConfig::getCreatorRole, allowedRoles);
+ if (shouldFilterByUserId) {
+ wrapper.eq(SysConfig::getCreatorId, currentUser.userId());
+ } else if (!allowedRoles.isEmpty()) {
+ wrapper.in(SysConfig::getCreatorRole, allowedRoles);
+ }
+
+ wrapper.orderByDesc(SysConfig::getCreatedAt);
+
+ Page page = new Page<>(query.pageNo(), query.pageSize());
+ Page resultPage = sysConfigMapper.selectPage(page, wrapper);
+
+ List records = resultPage.getRecords().stream()
+ .map(this::toResponse)
+ .toList();
+
+ return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
+ (int) resultPage.getSize());
+ } catch (Exception e) {
+ log.error("pageConfigs failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
}
-
- wrapper.orderByDesc(SysConfig::getCreatedAt);
-
- Page page = new Page<>(query.pageNo(), query.pageSize());
- Page resultPage = sysConfigMapper.selectPage(page, wrapper);
-
- List records = resultPage.getRecords().stream()
- .map(this::toResponse)
- .toList();
-
- return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
- (int) resultPage.getSize());
}
public SysConfigResponse toResponse(SysConfig config) {
diff --git a/src/main/java/com/labelsys/backend/service/UserService.java b/src/main/java/com/labelsys/backend/service/UserService.java
index 59e2b5b..29ced5a 100644
--- a/src/main/java/com/labelsys/backend/service/UserService.java
+++ b/src/main/java/com/labelsys/backend/service/UserService.java
@@ -1,11 +1,5 @@
package com.labelsys.backend.service;
-import java.util.List;
-
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.labelsys.backend.common.ResultCode;
import com.labelsys.backend.common.exception.BusinessException;
@@ -26,99 +20,188 @@ import com.labelsys.backend.mapper.SysCompanyMapper;
import com.labelsys.backend.mapper.SysUserMapper;
import com.labelsys.backend.service.session.TokenSessionRepository;
import com.labelsys.backend.util.IdGenerator;
-
import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import java.util.List;
+
+@Slf4j
@Service
@RequiredArgsConstructor
public class UserService {
private static final String DEFAULT_PASSWORD = "123456";
- private final SysUserMapper sysUserMapper;
- private final SysCompanyMapper sysCompanyMapper;
- private final PasswordEncoder passwordEncoder;
+ private final SysUserMapper sysUserMapper;
+ private final SysCompanyMapper sysCompanyMapper;
+ private final PasswordEncoder passwordEncoder;
private final TokenSessionRepository tokenSessionRepository;
public List listAllUsers(LoginUser currentUser) {
- assertSystemAdmin(currentUser);
- LambdaQueryWrapper wrapper = new LambdaQueryWrapper().orderByAsc(SysUser::getId);
- return sysUserMapper.selectList(wrapper);
+ try {
+ assertSystemAdmin(currentUser);
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper().orderByAsc(SysUser::getId);
+ return sysUserMapper.selectList(wrapper);
+ } catch (ForbiddenException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("listAllUsers failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
+ }
}
public List listCompanyUsers(LoginUser currentUser) {
- assertCompanyAdmin(currentUser);
- LambdaQueryWrapper wrapper = new LambdaQueryWrapper()
- .eq(SysUser::getCompanyId, currentUser.companyId()).orderByAsc(SysUser::getId);
- return sysUserMapper.selectList(wrapper);
+ try {
+ assertCompanyAdmin(currentUser);
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper()
+ .eq(SysUser::getCompanyId, currentUser.companyId()).orderByAsc(SysUser::getId);
+ return sysUserMapper.selectList(wrapper);
+ } catch (ForbiddenException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("listCompanyUsers failed, companyId={}, userId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
+ throw e;
+ }
}
public List listCompanyAdmins(LoginUser currentUser, Long companyId) {
- assertSystemAdmin(currentUser);
- return sysUserMapper.listCompanyAdmins(companyId);
+ try {
+ assertSystemAdmin(currentUser);
+ return sysUserMapper.listCompanyAdmins(companyId);
+ } catch (ForbiddenException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("listCompanyAdmins failed, companyId={}, userId={}, targetCompanyId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), companyId, e.getMessage(), e);
+ throw e;
+ }
}
public SysUser createCompanyAdmin(LoginUser currentUser, CreateCompanyAdminRequest request) {
- assertSystemAdmin(currentUser);
- ensureEnabledCompany(request.companyId());
- return createUser(request.companyId(), new CreateUserRequest(request.phone(), request.username(),
- request.realName(), UserRole.EMPLOYEE, UserPosition.ADMIN));
+ try {
+ assertSystemAdmin(currentUser);
+ ensureEnabledCompany(request.companyId());
+ return createUser(request.companyId(), new CreateUserRequest(request.phone(), request.username(),
+ request.realName(), UserRole.EMPLOYEE, UserPosition.ADMIN));
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("createCompanyAdmin failed, companyId={}, userId={}, targetCompanyId={}, phone={}, error={}",
+ currentUser.companyId(), currentUser.userId(), request.companyId(), request.phone(), e.getMessage(),
+ e);
+ throw e;
+ }
}
public SysUser createSystemEngineerAdmin(LoginUser currentUser, CreateSystemEngineerAdminRequest request) {
- assertSystemAdmin(currentUser);
- Long systemCompanyId = 1L;
- ensureEnabledCompany(systemCompanyId);
+ try {
+ assertSystemAdmin(currentUser);
+ Long systemCompanyId = 1L;
+ ensureEnabledCompany(systemCompanyId);
- if (sysUserMapper.findByCompanyIdAndPhone(systemCompanyId, request.phone()) != null) {
- throw new BusinessException(ResultCode.CONFLICT, "同一公司内手机号已存在");
+ if (sysUserMapper.findByCompanyIdAndPhone(systemCompanyId, request.phone()) != null) {
+ throw new BusinessException(ResultCode.CONFLICT, "同一公司内手机号已存在");
+ }
+
+ SysUser user = SysUser.builder().id(IdGenerator.nextId()).companyId(systemCompanyId).phone(request.phone())
+ .username(request.username()).realName(request.realName()).role(UserRole.ENGINEER)
+ .position(UserPosition.SUPER_ADMIN).passwordHash(passwordEncoder.encode(DEFAULT_PASSWORD))
+ .mustChangePassword(true).status(UserStatus.ENABLED).sessionVersion(1).build();
+ sysUserMapper.insert(user);
+ return user;
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("createSystemEngineerAdmin failed, companyId={}, userId={}, phone={}, error={}",
+ currentUser.companyId(), currentUser.userId(), request.phone(), e.getMessage(), e);
+ throw e;
}
-
- SysUser user = SysUser.builder().id(IdGenerator.nextId()).companyId(systemCompanyId).phone(request.phone())
- .username(request.username()).realName(request.realName()).role(UserRole.ENGINEER)
- .position(UserPosition.SUPER_ADMIN).passwordHash(passwordEncoder.encode(DEFAULT_PASSWORD))
- .mustChangePassword(true).status(UserStatus.ENABLED).sessionVersion(1).build();
- sysUserMapper.insert(user);
- return user;
}
public SysUser createCompanyUser(LoginUser currentUser, CreateUserRequest request) {
- assertCompanyAdmin(currentUser);
- return createUser(currentUser.companyId(), request);
+ try {
+ assertCompanyAdmin(currentUser);
+ return createUser(currentUser.companyId(), request);
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("createCompanyUser failed, companyId={}, userId={}, phone={}, error={}",
+ currentUser.companyId(), currentUser.userId(), request.phone(), e.getMessage(), e);
+ throw e;
+ }
}
public SysUser createCompanyUser(LoginUser currentUser, Long companyId, CreateUserRequest request) {
- assertSystemAdmin(currentUser);
- ensureEnabledCompany(companyId);
- return createUser(companyId, request);
+ try {
+ assertSystemAdmin(currentUser);
+ ensureEnabledCompany(companyId);
+ return createUser(companyId, request);
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("createCompanyUser failed, companyId={}, userId={}, targetCompanyId={}, phone={}, error={}",
+ currentUser.companyId(), currentUser.userId(), companyId, request.phone(), e.getMessage(), e);
+ throw e;
+ }
}
@Transactional
public void updateAssignment(LoginUser currentUser, Long userId, UpdateUserAssignmentRequest request) {
- assertCompanyAdmin(currentUser);
- if (sysUserMapper.updateAssignment(userId, currentUser.companyId(), request.role(), request.position()) == 0) {
- throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在");
+ try {
+ assertCompanyAdmin(currentUser);
+ if (sysUserMapper.updateAssignment(userId, currentUser.companyId(), request.role(), request.position())
+ == 0) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在");
+ }
+ tokenSessionRepository.removeAll(userId);
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("updateAssignment failed, companyId={}, userId={}, targetUserId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), userId, e.getMessage(), e);
+ throw e;
}
- tokenSessionRepository.removeAll(userId);
}
@Transactional
public void updateStatus(LoginUser currentUser, Long userId, UpdateUserStatusRequest request) {
- assertCompanyAdmin(currentUser);
- if (sysUserMapper.updateStatus(userId, currentUser.companyId(), request.status()) == 0) {
- throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在");
+ try {
+ assertCompanyAdmin(currentUser);
+ if (sysUserMapper.updateStatus(userId, currentUser.companyId(), request.status()) == 0) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在");
+ }
+ tokenSessionRepository.removeAll(userId);
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("updateStatus failed, companyId={}, userId={}, targetUserId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), userId, e.getMessage(), e);
+ throw e;
}
- tokenSessionRepository.removeAll(userId);
}
@Transactional
public void updateCompanyAdminStatus(LoginUser currentUser, Long companyId, Long userId,
- UpdateUserStatusRequest request) {
- assertSystemAdmin(currentUser);
- if (sysUserMapper.updateStatus(userId, companyId, request.status()) == 0) {
- throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在");
+ UpdateUserStatusRequest request) {
+ try {
+ assertSystemAdmin(currentUser);
+ if (sysUserMapper.updateStatus(userId, companyId, request.status()) == 0) {
+ throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在");
+ }
+ tokenSessionRepository.removeAll(userId);
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error(
+ "updateCompanyAdminStatus failed, companyId={}, userId={}, targetCompanyId={}, targetUserId={}, error={}",
+ currentUser.companyId(), currentUser.userId(), companyId, userId, e.getMessage(), e);
+ throw e;
}
- tokenSessionRepository.removeAll(userId);
}
private SysUser createUser(Long companyId, CreateUserRequest request) {
@@ -126,9 +209,11 @@ public class UserService {
throw new BusinessException(ResultCode.CONFLICT, "同一公司内手机号已存在");
}
SysUser user = SysUser.builder().id(IdGenerator.nextId()).companyId(companyId).phone(request.phone())
- .username(request.username()).realName(request.realName()).role(request.role()).position(request.position())
- .passwordHash(passwordEncoder.encode(DEFAULT_PASSWORD)).mustChangePassword(true).status(UserStatus.ENABLED)
- .sessionVersion(1).build();
+ .username(request.username()).realName(request.realName()).role(request.role())
+ .position(request.position())
+ .passwordHash(passwordEncoder.encode(DEFAULT_PASSWORD)).mustChangePassword(true)
+ .status(UserStatus.ENABLED)
+ .sessionVersion(1).build();
sysUserMapper.insert(user);
return user;
}
diff --git a/src/main/resources/sql/data.sql b/src/main/resources/sql/data.sql
index 800944e..60ab227 100644
--- a/src/main/resources/sql/data.sql
+++ b/src/main/resources/sql/data.sql
@@ -69,9 +69,9 @@ INSERT INTO annotation_task (
id, company_id, creator_id, creator_role, task_name, industry_type, task_type,
task_status, is_deleted, started_at, finished_at, error_message
) VALUES
- (701, 2, 4, 'EMPLOYEE', '多资源问答抽取任务', 'electricity', 'EXTRACT_QA',
+ (701, 2, 4, 'EMPLOYEE', '多资源问答抽取任务', 'ELECTRICITY', 'EXTRACT_QA',
'PENDING', FALSE, NULL, NULL, NULL),
- (702, 2, 4, 'EMPLOYEE', '图片问答抽取任务', 'transport', 'EXTRACT_QA',
+ (702, 2, 4, 'EMPLOYEE', '图片问答抽取任务', 'TRANSPORT', 'EXTRACT_QA',
'COMPLETED', FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL)
ON CONFLICT DO NOTHING;
diff --git a/src/main/resources/sql/schema.sql b/src/main/resources/sql/schema.sql
index c015a0c..52dfa20 100644
--- a/src/main/resources/sql/schema.sql
+++ b/src/main/resources/sql/schema.sql
@@ -244,7 +244,6 @@ COMMENT ON COLUMN annotation_task_resource.task_id IS '任务ID。';
COMMENT ON COLUMN annotation_task_resource.resource_id IS '资源ID。';
COMMENT ON COLUMN annotation_task_resource.created_at IS '创建时间。';
-drop table if exists annotation_result;
CREATE TABLE IF NOT EXISTS annotation_result
(
id BIGINT PRIMARY KEY,