后台异常处理优化

This commit is contained in:
wh
2026-05-08 16:07:12 +08:00
parent 83a412d3fd
commit 7fbe76559c
12 changed files with 1135 additions and 736 deletions

View File

@@ -3,44 +3,78 @@ package com.labelsys.backend.common.exception;
import com.labelsys.backend.common.Result; import com.labelsys.backend.common.Result;
import com.labelsys.backend.common.ResultCode; import com.labelsys.backend.common.ResultCode;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException; import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.stream.Collectors;
/**
* 全局异常处理器
* <p>
* 处理策略:
* 1. 业务异常BusinessException记录 INFO 级别日志,返回详细错误信息给前端
* 2. 参数校验异常:记录 WARN 级别日志,返回字段错误信息
* 3. 系统异常Exception记录 ERROR 级别日志,隐藏详细信息,返回通用错误提示
*/
@Slf4j
@RestControllerAdvice @RestControllerAdvice
public class GlobalExceptionHandler { public class GlobalExceptionHandler {
/**
* 处理业务异常
* 业务异常是预期内的错误,需要详细返回给前端
*/
@ExceptionHandler(BusinessException.class) @ExceptionHandler(BusinessException.class)
public Result<Void> handleBusiness(BusinessException exception, HttpServletResponse response) { public Result<Void> handleBusiness(BusinessException exception, HttpServletResponse response) {
// 记录 INFO 级别日志(业务异常属于预期内错误)
log.info("Business exception occurred: code={}, message={}",
exception.getResultCode().getCode(), exception.getMessage());
response.setStatus(toHttpStatus(exception.getResultCode()).value()); response.setStatus(toHttpStatus(exception.getResultCode()).value());
return new Result<>(exception.getResultCode().getCode(), exception.getMessage(), null); return new Result<>(exception.getResultCode().getCode(), exception.getMessage(), null);
} }
@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class}) /**
* 处理参数校验异常
*/
@ExceptionHandler({ MethodArgumentNotValidException.class, BindException.class })
public Result<Void> handleValidation(Exception exception, HttpServletResponse response) { public Result<Void> handleValidation(Exception exception, HttpServletResponse response) {
response.setStatus(HttpStatus.BAD_REQUEST.value());
String message; String message;
if (exception instanceof MethodArgumentNotValidException methodArgumentNotValidException) { if (exception instanceof MethodArgumentNotValidException methodException) {
message = methodArgumentNotValidException.getBindingResult().getFieldErrors().stream() message = methodException.getBindingResult().getFieldErrors().stream()
.map(error -> error.getField() + error.getDefaultMessage()) .map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.joining(";")); .collect(Collectors.joining("; "));
} else if (exception instanceof BindException bindException) { } else if (exception instanceof BindException bindException) {
message = bindException.getBindingResult().getFieldErrors().stream() message = bindException.getBindingResult().getFieldErrors().stream()
.map(error -> error.getField() + error.getDefaultMessage()) .map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.joining(";")); .collect(Collectors.joining("; "));
} else { } else {
message = ResultCode.BAD_REQUEST.getMessage(); 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); return new Result<>(ResultCode.BAD_REQUEST.getCode(), message, null);
} }
/**
* 处理系统异常
* 系统异常是预期外的错误,需要隐藏详细信息
*/
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
public Result<Void> handleUnexpected(Exception exception, HttpServletResponse response) { public Result<Void> handleUnexpected(Exception exception, HttpServletResponse response) {
// 记录 ERROR 级别日志(包含完整堆栈)
log.error("Unexpected exception occurred", exception);
// 返回通用错误信息,不暴露内部细节
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); 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) { private HttpStatus toHttpStatus(ResultCode resultCode) {

View File

@@ -47,6 +47,7 @@ public class AnnotationResultArchiveService {
public PageResult<AnnotationResultHistoryResponse> pageHistory(LoginUser currentUser, public PageResult<AnnotationResultHistoryResponse> pageHistory(LoginUser currentUser,
AnnotationResultHistoryPageQuery query) { AnnotationResultHistoryPageQuery query) {
try {
List<String> allowedRoles = dataPermissionService.getAllowedRoles(currentUser); List<String> allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser); boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
@@ -71,15 +72,26 @@ public class AnnotationResultArchiveService {
return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(), return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
(int) resultPage.getSize()); (int) resultPage.getSize());
} catch (Exception e) {
log.error("pageHistory failed, companyId={}, userId={}, error={}",
currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
throw e;
}
} }
public AnnotationResultHistoryResponse getHistory(LoginUser currentUser, Long historyId) { public AnnotationResultHistoryResponse getHistory(LoginUser currentUser, Long historyId) {
try {
AnnotationResultHistory history = annotationResultHistoryMapper.selectById(historyId); AnnotationResultHistory history = annotationResultHistoryMapper.selectById(historyId);
if (history == null || !history.getCompanyId().equals(currentUser.companyId())) { if (history == null || !history.getCompanyId().equals(currentUser.companyId())) {
throw new BusinessException(ResultCode.NOT_FOUND, "历史记录不存在"); throw new BusinessException(ResultCode.NOT_FOUND, "历史记录不存在");
} }
assertHistoryPermission(currentUser, history); assertHistoryPermission(currentUser, history);
return toResponse(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;
}
} }
private void assertHistoryPermission(LoginUser currentUser, AnnotationResultHistory history) { private void assertHistoryPermission(LoginUser currentUser, AnnotationResultHistory history) {
@@ -110,6 +122,7 @@ public class AnnotationResultArchiveService {
@Transactional @Transactional
public int autoArchiveEligibleResults() { public int autoArchiveEligibleResults() {
try {
LocalDateTime cutoff = LocalDateTime.now().minus(autoArchiveTimeout); LocalDateTime cutoff = LocalDateTime.now().minus(autoArchiveTimeout);
List<AnnotationResult> results = annotationResultMapper.selectList(new LambdaQueryWrapper<AnnotationResult>() List<AnnotationResult> results = annotationResultMapper.selectList(new LambdaQueryWrapper<AnnotationResult>()
.eq(AnnotationResult::getIsDeleted, false) .eq(AnnotationResult::getIsDeleted, false)
@@ -122,6 +135,10 @@ public class AnnotationResultArchiveService {
} }
} }
return archivedCount; return archivedCount;
} catch (Exception e) {
log.error("autoArchiveEligibleResults failed, error={}", e.getMessage(), e);
throw e;
}
} }
private void assertReviewer(LoginUser currentUser) { private void assertReviewer(LoginUser currentUser) {
@@ -227,6 +244,7 @@ public class AnnotationResultArchiveService {
* @return 文件内容响应 * @return 文件内容响应
*/ */
public FileContentResponse loadFileContent(LoginUser currentUser, Long historyId) { public FileContentResponse loadFileContent(LoginUser currentUser, Long historyId) {
try {
AnnotationResultHistory history = annotationResultHistoryMapper.selectById(historyId); AnnotationResultHistory history = annotationResultHistoryMapper.selectById(historyId);
if (history == null || !history.getCompanyId().equals(currentUser.companyId())) { if (history == null || !history.getCompanyId().equals(currentUser.companyId())) {
throw new BusinessException(ResultCode.NOT_FOUND, "历史记录不存在"); throw new BusinessException(ResultCode.NOT_FOUND, "历史记录不存在");
@@ -238,15 +256,17 @@ public class AnnotationResultArchiveService {
throw new BusinessException(ResultCode.ERROR, "文件路径为空"); throw new BusinessException(ResultCode.ERROR, "文件路径为空");
} }
try {
String bucketName = extractBucketName(filePath); String bucketName = extractBucketName(filePath);
String objectKey = extractObjectKey(filePath); String objectKey = extractObjectKey(filePath);
byte[] content = objectStorageService.download(bucketName, objectKey); byte[] content = objectStorageService.download(bucketName, objectKey);
String contentStr = new String(content, StandardCharsets.UTF_8); String contentStr = new String(content, StandardCharsets.UTF_8);
return new FileContentResponse(filePath, contentStr, content.length); return new FileContentResponse(filePath, contentStr, content.length);
} catch (BusinessException e) {
throw e;
} catch (Exception 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, "加载文件内容失败"); throw new BusinessException(ResultCode.ERROR, "加载文件内容失败");
} }
} }

View File

@@ -43,6 +43,7 @@ public class AnnotationResultService {
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
public PageResult<AnnotationResultResponse> pageResults(LoginUser currentUser, AnnotationResultPageQuery query) { public PageResult<AnnotationResultResponse> pageResults(LoginUser currentUser, AnnotationResultPageQuery query) {
try {
List<String> allowedRoles = dataPermissionService.getAllowedRoles(currentUser); List<String> allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser); boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
@@ -72,23 +73,41 @@ public class AnnotationResultService {
return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(), return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
(int) resultPage.getSize()); (int) resultPage.getSize());
} catch (Exception e) {
log.error("pageResults failed, companyId={}, userId={}, error={}",
currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
throw e;
}
} }
public AnnotationResultResponse getResult(LoginUser currentUser, Long resultId) { public AnnotationResultResponse getResult(LoginUser currentUser, Long resultId) {
AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId, currentUser.companyId()); try {
AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId,
currentUser.companyId());
if (result == null) { if (result == null) {
log.warn("Result not found or cross-tenant access attempt: resultId={}, companyId={}, userId={}", resultId, log.warn("Result not found or cross-tenant access attempt: resultId={}, companyId={}, userId={}",
resultId,
currentUser.companyId(), currentUser.userId()); currentUser.companyId(), currentUser.userId());
throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在"); throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在");
} }
//assertResultPermission(currentUser, result); //assertResultPermission(currentUser, result);
return toResponse(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;
}
} }
public AnnotationResultCompareResponse compareResult(LoginUser currentUser, Long resultId) { public AnnotationResultCompareResponse compareResult(LoginUser currentUser, Long resultId) {
AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId, currentUser.companyId()); try {
AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId,
currentUser.companyId());
if (result == null) { if (result == null) {
log.warn("Result not found or cross-tenant access attempt: resultId={}, companyId={}, userId={}", resultId, log.warn("Result not found or cross-tenant access attempt: resultId={}, companyId={}, userId={}",
resultId,
currentUser.companyId(), currentUser.userId()); currentUser.companyId(), currentUser.userId());
throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在"); throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在");
} }
@@ -129,11 +148,20 @@ public class AnnotationResultService {
diffRecords, diffRecords,
resource == null ? null : resource.getFilePath() 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;
}
} }
@Transactional @Transactional
public void mergeReviewResult(LoginUser currentUser, Long resultId, MergeReviewResultRequest request) { public void mergeReviewResult(LoginUser currentUser, Long resultId, MergeReviewResultRequest request) {
AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId, currentUser.companyId()); try {
AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId,
currentUser.companyId());
if (result == null) { if (result == null) {
throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在"); throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在");
} }
@@ -182,6 +210,13 @@ public class AnnotationResultService {
log.info("merged review result, companyId={}, userId={}, resultId={}", log.info("merged review result, companyId={}, userId={}, resultId={}",
currentUser.companyId(), currentUser.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;
}
} }
private AnnotationResultResponse toResponse(AnnotationResult result) { private AnnotationResultResponse toResponse(AnnotationResult result) {
@@ -267,12 +302,14 @@ public class AnnotationResultService {
/** /**
* 归档到历史表 * 归档到历史表
*
* @param result 标注结果 * @param result 标注结果
* @param currentUser 当前用户 * @param currentUser 当前用户
* @param archiveReason 归档原因 * @param archiveReason 归档原因
* @param isAutoArchive 是否自动归档true=自动归档false=人工审核后归档) * @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 { try {
// 读取 qa.json 内容用于归档 // 读取 qa.json 内容用于归档
QaContent qaContent = loadQaContent(result); QaContent qaContent = loadQaContent(result);

View File

@@ -45,6 +45,7 @@ public class AnnotationTaskService {
@Transactional @Transactional
public AnnotationTaskResponse createTask(LoginUser currentUser, CreateAnnotationTaskRequest request) { public AnnotationTaskResponse createTask(LoginUser currentUser, CreateAnnotationTaskRequest request) {
try {
List<SourceResource> resources = loadAndValidateResources(currentUser, request.resourceIds()); List<SourceResource> resources = loadAndValidateResources(currentUser, request.resourceIds());
AnnotationTask task = AnnotationTask.builder() AnnotationTask task = AnnotationTask.builder()
@@ -66,10 +67,16 @@ public class AnnotationTaskService {
currentUser.companyId(), currentUser.userId(), task.getId(), resources.size()); 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 @Transactional
public AnnotationTaskResponse updateTask(LoginUser currentUser, Long taskId, UpdateAnnotationTaskRequest request) { public AnnotationTaskResponse updateTask(LoginUser currentUser, Long taskId, UpdateAnnotationTaskRequest request) {
try {
AnnotationTask task = annotationTaskMapper.findByIdAndCompanyId(taskId, currentUser.companyId()); AnnotationTask task = annotationTaskMapper.findByIdAndCompanyId(taskId, currentUser.companyId());
if (task == null) { if (task == null) {
throw new BusinessException(ResultCode.NOT_FOUND, "任务不存在"); throw new BusinessException(ResultCode.NOT_FOUND, "任务不存在");
@@ -80,7 +87,8 @@ public class AnnotationTaskService {
List<SourceResource> resources = null; List<SourceResource> resources = null;
if (request.resourceIds() != null && !request.resourceIds().isEmpty()) { if (request.resourceIds() != null && !request.resourceIds().isEmpty()) {
List<Long> currentResourceIds = normalizeIds(annotationTaskResourceMapper.listResourceIdsByTaskId(taskId)); List<Long> currentResourceIds = normalizeIds(
annotationTaskResourceMapper.listResourceIdsByTaskId(taskId));
List<Long> targetResourceIds = normalizeIds(request.resourceIds()); List<Long> targetResourceIds = normalizeIds(request.resourceIds());
resourcesChanged = !currentResourceIds.equals(targetResourceIds); resourcesChanged = !currentResourceIds.equals(targetResourceIds);
@@ -112,18 +120,30 @@ public class AnnotationTaskService {
: normalizeIds(annotationTaskResourceMapper.listResourceIdsByTaskId(taskId)); : normalizeIds(annotationTaskResourceMapper.listResourceIdsByTaskId(taskId));
return buildTaskResponse(task, finalResourceIds); 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;
}
} }
public AnnotationTaskResponse getTask(LoginUser currentUser, Long taskId) { public AnnotationTaskResponse getTask(LoginUser currentUser, Long taskId) {
try {
AnnotationTask task = annotationTaskMapper.findByIdAndCompanyId(taskId, currentUser.companyId()); AnnotationTask task = annotationTaskMapper.findByIdAndCompanyId(taskId, currentUser.companyId());
if (task == null) { if (task == null) {
throw new BusinessException(ResultCode.NOT_FOUND, "任务不存在"); throw new BusinessException(ResultCode.NOT_FOUND, "任务不存在");
} }
assertTaskPermission(currentUser, task); assertTaskPermission(currentUser, task);
return buildTaskResponse(task, normalizeIds(annotationTaskResourceMapper.listResourceIdsByTaskId(taskId))); 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;
}
} }
public PageResult<AnnotationTaskResponse> pageTasks(LoginUser currentUser, AnnotationTaskPageQuery query) { public PageResult<AnnotationTaskResponse> pageTasks(LoginUser currentUser, AnnotationTaskPageQuery query) {
try {
List<String> allowedRoles = dataPermissionService.getAllowedRoles(currentUser); List<String> allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser); boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
@@ -155,10 +175,16 @@ public class AnnotationTaskService {
return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(), return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
(int) resultPage.getSize()); (int) resultPage.getSize());
} catch (Exception e) {
log.error("pageTasks failed, companyId={}, userId={}, error={}",
currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
throw e;
}
} }
@Transactional @Transactional
public void deleteTask(LoginUser currentUser, Long taskId) { public void deleteTask(LoginUser currentUser, Long taskId) {
try {
AnnotationTask task = annotationTaskMapper.findByIdAndCompanyId(taskId, currentUser.companyId()); AnnotationTask task = annotationTaskMapper.findByIdAndCompanyId(taskId, currentUser.companyId());
if (task == null) { if (task == null) {
throw new BusinessException(ResultCode.NOT_FOUND, "任务不存在"); throw new BusinessException(ResultCode.NOT_FOUND, "任务不存在");
@@ -171,6 +197,11 @@ public class AnnotationTaskService {
annotationTaskMapper.updateById(task); annotationTaskMapper.updateById(task);
log.info("deleted annotation task logically, companyId={}, userId={}, taskId={}", currentUser.companyId(), log.info("deleted annotation task logically, companyId={}, userId={}, taskId={}", currentUser.companyId(),
currentUser.userId(), taskId); currentUser.userId(), taskId);
} catch (Exception e) {
log.error("deleteTask failed, companyId={}, userId={}, taskId={}, error={}",
currentUser.companyId(), currentUser.userId(), taskId, e.getMessage(), e);
throw e;
}
} }
private List<SourceResource> loadAndValidateResources(LoginUser currentUser, List<Long> resourceIds) { private List<SourceResource> loadAndValidateResources(LoginUser currentUser, List<Long> resourceIds) {

View File

@@ -15,15 +15,18 @@ import com.labelsys.backend.enums.UserStatus;
import com.labelsys.backend.mapper.SysCompanyMapper; import com.labelsys.backend.mapper.SysCompanyMapper;
import com.labelsys.backend.mapper.SysUserMapper; import com.labelsys.backend.mapper.SysUserMapper;
import com.labelsys.backend.service.session.TokenSessionRepository; import com.labelsys.backend.service.session.TokenSessionRepository;
import java.time.Duration;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.time.Duration;
import java.util.List;
import java.util.UUID;
@Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class AuthService { public class AuthService {
@@ -37,12 +40,18 @@ public class AuthService {
private Duration sessionTtl; private Duration sessionTtl;
public List<CompanyOptionResponse> listAvailableCompanies(String phone) { public List<CompanyOptionResponse> listAvailableCompanies(String phone) {
try {
return sysCompanyMapper.findEnabledCompaniesByPhone(phone).stream() return sysCompanyMapper.findEnabledCompaniesByPhone(phone).stream()
.map(CompanyOptionResponse::from) .map(CompanyOptionResponse::from)
.toList(); .toList();
} catch (Exception e) {
log.error("listAvailableCompanies failed, phone={}, error={}", phone, e.getMessage(), e);
throw e;
}
} }
public LoginResponse login(LoginRequest request) { public LoginResponse login(LoginRequest request) {
try {
SysCompany company = loadEnabledCompany(request.companyCode()); SysCompany company = loadEnabledCompany(request.companyCode());
SysUser user = loadEnabledUser(company.getId(), request.phone()); SysUser user = loadEnabledUser(company.getId(), request.phone());
if (!passwordEncoder.matches(request.password(), user.getPasswordHash())) { if (!passwordEncoder.matches(request.password(), user.getPasswordHash())) {
@@ -52,15 +61,30 @@ public class AuthService {
String token = UUID.randomUUID().toString(); String token = UUID.randomUUID().toString();
tokenSessionRepository.save(token, loginUser, sessionTtl); tokenSessionRepository.save(token, loginUser, sessionTtl);
return LoginResponse.from(token, loginUser, company); 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;
}
} }
public LoginUser getCurrentUser(String token) { public LoginUser getCurrentUser(String token) {
try {
return tokenSessionRepository.find(token) return tokenSessionRepository.find(token)
.orElseThrow(() -> new UnauthorizedException("未登录或登录已过期")); .orElseThrow(() -> new UnauthorizedException("未登录或登录已过期"));
} catch (UnauthorizedException e) {
throw e;
} catch (Exception e) {
log.error("getCurrentUser failed, token={}, error={}", token, e.getMessage(), e);
throw e;
}
} }
@Transactional @Transactional
public void changePassword(LoginUser currentUser, ChangePasswordRequest request) { public void changePassword(LoginUser currentUser, ChangePasswordRequest request) {
try {
if (!request.newPassword().equals(request.confirmPassword())) { if (!request.newPassword().equals(request.confirmPassword())) {
throw new BusinessException(ResultCode.BAD_REQUEST, "两次输入的新密码不一致"); throw new BusinessException(ResultCode.BAD_REQUEST, "两次输入的新密码不一致");
} }
@@ -71,13 +95,26 @@ public class AuthService {
if (!passwordEncoder.matches(request.oldPassword(), user.getPasswordHash())) { if (!passwordEncoder.matches(request.oldPassword(), user.getPasswordHash())) {
throw new BusinessException(ResultCode.BAD_REQUEST, "旧密码错误"); throw new BusinessException(ResultCode.BAD_REQUEST, "旧密码错误");
} }
sysUserMapper.updatePassword(user.getId(), user.getCompanyId(), passwordEncoder.encode(request.newPassword()), false); sysUserMapper.updatePassword(user.getId(), user.getCompanyId(),
passwordEncoder.encode(request.newPassword()), false);
sysUserMapper.bumpSessionVersion(user.getId(), user.getCompanyId()); sysUserMapper.bumpSessionVersion(user.getId(), user.getCompanyId());
tokenSessionRepository.removeAll(user.getId()); 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;
}
} }
public void logout(String token) { public void logout(String token) {
try {
tokenSessionRepository.remove(token); tokenSessionRepository.remove(token);
} catch (Exception e) {
log.error("logout failed, token={}, error={}", token, e.getMessage(), e);
throw e;
}
} }
private SysCompany loadEnabledCompany(String companyCode) { private SysCompany loadEnabledCompany(String companyCode) {

View File

@@ -9,10 +9,13 @@ import com.labelsys.backend.dto.request.UpdateCompanyStatusRequest;
import com.labelsys.backend.entity.SysCompany; import com.labelsys.backend.entity.SysCompany;
import com.labelsys.backend.mapper.SysCompanyMapper; import com.labelsys.backend.mapper.SysCompanyMapper;
import com.labelsys.backend.util.IdGenerator; import com.labelsys.backend.util.IdGenerator;
import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class CompanyService { public class CompanyService {
@@ -20,11 +23,20 @@ public class CompanyService {
private final SysCompanyMapper sysCompanyMapper; private final SysCompanyMapper sysCompanyMapper;
public List<SysCompany> listCompanies(LoginUser currentUser) { public List<SysCompany> listCompanies(LoginUser currentUser) {
try {
assertPlatformAdmin(currentUser); assertPlatformAdmin(currentUser);
return sysCompanyMapper.selectList(null); 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) { public SysCompany createCompany(LoginUser currentUser, CreateCompanyRequest request) {
try {
assertPlatformAdmin(currentUser); assertPlatformAdmin(currentUser);
if (sysCompanyMapper.findByCompanyCode(request.companyCode()) != null) { if (sysCompanyMapper.findByCompanyCode(request.companyCode()) != null) {
throw new BusinessException(ResultCode.CONFLICT, "公司编码已存在"); throw new BusinessException(ResultCode.CONFLICT, "公司编码已存在");
@@ -37,13 +49,28 @@ public class CompanyService {
.build(); .build();
sysCompanyMapper.insert(company); sysCompanyMapper.insert(company);
return 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;
}
} }
public void updateStatus(LoginUser currentUser, Long companyId, UpdateCompanyStatusRequest request) { public void updateStatus(LoginUser currentUser, Long companyId, UpdateCompanyStatusRequest request) {
try {
assertPlatformAdmin(currentUser); assertPlatformAdmin(currentUser);
if (sysCompanyMapper.updateStatus(companyId, request.status()) == 0) { if (sysCompanyMapper.updateStatus(companyId, request.status()) == 0) {
throw new BusinessException(ResultCode.NOT_FOUND, "公司不存在"); 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;
}
} }
private void assertPlatformAdmin(LoginUser currentUser) { private void assertPlatformAdmin(LoginUser currentUser) {

View File

@@ -3,13 +3,16 @@ package com.labelsys.backend.service;
import com.labelsys.backend.context.LoginUser; import com.labelsys.backend.context.LoginUser;
import com.labelsys.backend.entity.BizDataRecord; import com.labelsys.backend.entity.BizDataRecord;
import com.labelsys.backend.enums.UserRole; 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.List;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.jdbc.core.JdbcTemplate;
@Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class DataPermissionService { public class DataPermissionService {
@@ -17,22 +20,25 @@ public class DataPermissionService {
private final JdbcTemplate jdbcTemplate; private final JdbcTemplate jdbcTemplate;
public boolean canAccessCreator(LoginUser currentUser, Long creatorId, UserRole creatorRole) { public boolean canAccessCreator(LoginUser currentUser, Long creatorId, UserRole creatorRole) {
try {
return switch (currentUser.role()) { return switch (currentUser.role()) {
case EMPLOYEE -> currentUser.userId().equals(creatorId); case EMPLOYEE -> currentUser.userId().equals(creatorId);
case MANAGER -> creatorRole == UserRole.EMPLOYEE || creatorRole == UserRole.MANAGER; case MANAGER -> creatorRole == UserRole.EMPLOYEE || creatorRole == UserRole.MANAGER;
case ENGINEER -> true; 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 <T> List<T> filterByRole( public <T> List<T> filterByRole(
LoginUser currentUser, LoginUser currentUser,
List<T> allRecords, List<T> allRecords,
Function<T, UserRole> roleExtractor, Function<T, UserRole> roleExtractor,
Function<T, Long> ownerIdExtractor) { Function<T, Long> ownerIdExtractor) {
try {
if (allRecords == null || allRecords.isEmpty()) { if (allRecords == null || allRecords.isEmpty()) {
return List.of(); return List.of();
} }
@@ -52,27 +58,39 @@ public class DataPermissionService {
}; };
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
} catch (Exception e) {
log.error("filterByRole failed, companyId={}, userId={}, error={}",
currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
throw e;
}
} }
/**
* Returns the creator roles visible to the current user for SQL-side filtering.
*/
public List<String> getAllowedRoles(LoginUser currentUser) { public List<String> getAllowedRoles(LoginUser currentUser) {
try {
return switch (currentUser.role()) { return switch (currentUser.role()) {
case EMPLOYEE -> List.of(); case EMPLOYEE -> List.of();
case MANAGER -> List.of("EMPLOYEE", "MANAGER"); case MANAGER -> List.of("EMPLOYEE", "MANAGER");
case ENGINEER -> List.of("EMPLOYEE", "MANAGER", "ENGINEER"); 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) { public boolean shouldFilterByUserId(LoginUser currentUser) {
try {
return currentUser.role() == UserRole.EMPLOYEE; 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<BizDataRecord> listVisibleRecords(LoginUser currentUser) { public List<BizDataRecord> listVisibleRecords(LoginUser currentUser) {
try {
List<BizDataRecord> allRecords = jdbcTemplate.query(""" List<BizDataRecord> allRecords = jdbcTemplate.query("""
select id, company_id, creator_id, creator_role, record_name, created_at, updated_at select id, company_id, creator_id, creator_role, record_name, created_at, updated_at
from biz_data_record from biz_data_record
@@ -85,11 +103,20 @@ public class DataPermissionService {
.creatorId(rs.getLong("creator_id")) .creatorId(rs.getLong("creator_id"))
.creatorRole(UserRole.valueOf(rs.getString("creator_role"))) .creatorRole(UserRole.valueOf(rs.getString("creator_role")))
.recordName(rs.getString("record_name")) .recordName(rs.getString("record_name"))
.createdAt(rs.getTimestamp("created_at") == null ? null : rs.getTimestamp("created_at").toLocalDateTime()) .createdAt(rs.getTimestamp("created_at") == null ?
.updatedAt(rs.getTimestamp("updated_at") == null ? null : rs.getTimestamp("updated_at").toLocalDateTime()) null :
rs.getTimestamp("created_at").toLocalDateTime())
.updatedAt(rs.getTimestamp("updated_at") == null ?
null :
rs.getTimestamp("updated_at").toLocalDateTime())
.build(), .build(),
currentUser.companyId()); 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;
}
} }
} }

View File

@@ -54,6 +54,7 @@ public class SourceResourceService {
@Transactional @Transactional
public SourceUploadResponse upload(LoginUser currentUser, SourceUploadRequest request) { public SourceUploadResponse upload(LoginUser currentUser, SourceUploadRequest request) {
try {
MultipartFile file = request.getFile(); MultipartFile file = request.getFile();
if (file == null || file.isEmpty()) { if (file == null || file.isEmpty()) {
throw new BusinessException(ResultCode.BAD_REQUEST, "上传文件不能为空"); throw new BusinessException(ResultCode.BAD_REQUEST, "上传文件不能为空");
@@ -62,7 +63,9 @@ public class SourceResourceService {
throw new BusinessException(ResultCode.BAD_REQUEST, "资源类型非法"); throw new BusinessException(ResultCode.BAD_REQUEST, "资源类型非法");
} }
String resourceName = String resourceName =
StringUtils.hasText(request.getResourceName()) ? request.getResourceName() : file.getOriginalFilename(); StringUtils.hasText(request.getResourceName()) ?
request.getResourceName() :
file.getOriginalFilename();
SourceResource existingResource = SourceResource existingResource =
sourceResourceMapper.selectByCompanyIdAndResourceName(currentUser.companyId(), resourceName); sourceResourceMapper.selectByCompanyIdAndResourceName(currentUser.companyId(), resourceName);
if (existingResource != null) { if (existingResource != null) {
@@ -71,7 +74,8 @@ public class SourceResourceService {
long resourceId = IdGenerator.nextId(); long resourceId = IdGenerator.nextId();
String extension = resolveExtension(file.getOriginalFilename(), request.getResourceType()); String extension = resolveExtension(file.getOriginalFilename(), request.getResourceType());
String objectKey = ObjectStoragePathBuilder.sourceObjectKey(currentUser.companyId(), request.getResourceType(), String objectKey = ObjectStoragePathBuilder.sourceObjectKey(currentUser.companyId(),
request.getResourceType(),
resourceId, extension); resourceId, extension);
try { try {
objectStorageService.upload(objectStorageProperties.getSourceBucket(), objectKey, file.getBytes(), objectStorageService.upload(objectStorageProperties.getSourceBucket(), objectKey, file.getBytes(),
@@ -93,11 +97,20 @@ public class SourceResourceService {
log.info("uploaded source resource, companyId={}, userId={}, resourceId={}", currentUser.companyId(), log.info("uploaded source resource, companyId={}, userId={}, resourceId={}", currentUser.companyId(),
currentUser.userId(), resourceId); currentUser.userId(), resourceId);
return new SourceUploadResponse(resource.getId(), resource.getResourceName(), resource.getResourceType(), return new SourceUploadResponse(resource.getId(), resource.getResourceName(), resource.getResourceType(),
resource.getBucketName(), resource.getFilePath(), resource.getFileSize(), resource.getSourceStatus(), resource.getBucketName(), resource.getFilePath(), resource.getFileSize(),
resource.getSourceStatus(),
resource.getCreatedAt()); 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<SourceResourceResponse> pageResources(LoginUser currentUser, SourceResourcePageQuery query) { public PageResult<SourceResourceResponse> pageResources(LoginUser currentUser, SourceResourcePageQuery query) {
try {
List<String> allowedRoles = dataPermissionService.getAllowedRoles(currentUser); List<String> allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser); boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
@@ -107,7 +120,8 @@ public class SourceResourceService {
query.resourceType()) query.resourceType())
.eq(StringUtils.hasText(query.sourceStatus()), SourceResource::getSourceStatus, .eq(StringUtils.hasText(query.sourceStatus()), SourceResource::getSourceStatus,
query.sourceStatus()) query.sourceStatus())
.like(StringUtils.hasText(query.keyword()), SourceResource::getResourceName, query.keyword()); .like(StringUtils.hasText(query.keyword()), SourceResource::getResourceName,
query.keyword());
if (shouldFilterByUserId) { if (shouldFilterByUserId) {
wrapper.eq(SourceResource::getCreatorId, currentUser.userId()); wrapper.eq(SourceResource::getCreatorId, currentUser.userId());
@@ -130,9 +144,15 @@ public class SourceResourceService {
List<SourceResourceResponse> responseList = records.stream().map(this::toResponse).toList(); List<SourceResourceResponse> responseList = records.stream().map(this::toResponse).toList();
return new PageResult<>(responseList, (long) responseList.size(), 1, responseList.size()); 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) { public SourceResourceResponse getResource(LoginUser currentUser, Long resourceId) {
try {
SourceResource resource = sourceResourceMapper.selectById(resourceId); SourceResource resource = sourceResourceMapper.selectById(resourceId);
if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) { if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
log.warn("Resource not found or cross-tenant access attempt: resourceId={}, companyId={}, userId={}", log.warn("Resource not found or cross-tenant access attempt: resourceId={}, companyId={}, userId={}",
@@ -140,6 +160,13 @@ public class SourceResourceService {
throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在"); throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
} }
return toResponse(resource); 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;
}
} }
/** /**
@@ -149,16 +176,23 @@ public class SourceResourceService {
* @return 资源实体 * @return 资源实体
*/ */
public SourceResource getResourceEntity(Long resourceId) { public SourceResource getResourceEntity(Long resourceId) {
try {
return sourceResourceMapper.selectById(resourceId); return sourceResourceMapper.selectById(resourceId);
} catch (Exception e) {
log.error("getResourceEntity failed, resourceId={}, error={}", resourceId, e.getMessage(), e);
throw e;
}
} }
@Transactional @Transactional
public void deleteResource(LoginUser currentUser, Long resourceId) { public void deleteResource(LoginUser currentUser, Long resourceId) {
try {
SourceResource resource = sourceResourceMapper.selectById(resourceId); SourceResource resource = sourceResourceMapper.selectById(resourceId);
if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) { if (resource == null || !currentUser.companyId().equals(resource.getCompanyId())) {
throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在"); throw new BusinessException(ResultCode.NOT_FOUND, "资源不存在");
} }
if (!dataPermissionService.canAccessCreator(currentUser, resource.getCreatorId(), resource.getCreatorRole())) { if (!dataPermissionService.canAccessCreator(currentUser, resource.getCreatorId(),
resource.getCreatorRole())) {
throw new BusinessException(ResultCode.FORBIDDEN, "无权删除资源"); throw new BusinessException(ResultCode.FORBIDDEN, "无权删除资源");
} }
int bindCount = annotationTaskResourceMapper.countByResourceId(resourceId); int bindCount = annotationTaskResourceMapper.countByResourceId(resourceId);
@@ -173,6 +207,170 @@ public class SourceResourceService {
sourceResourceMapper.deleteById(resourceId); sourceResourceMapper.deleteById(resourceId);
log.info("deleted source resource, companyId={}, userId={}, resourceId={}", currentUser.companyId(), log.info("deleted source resource, companyId={}, userId={}, resourceId={}", currentUser.companyId(),
currentUser.userId(), resourceId); 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;
}
}
/**
* 下载资源(支持 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;
}
}
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<ImageBboxResponse.BboxCoordinateResponse> 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<ImageBboxResponse.BboxCoordinateResponse> parseBboxJson(String bboxJson) {
if (!StringUtils.hasText(bboxJson)) {
return List.of();
}
try {
return objectMapper.readValue(bboxJson,
new TypeReference<List<ImageBboxResponse.BboxCoordinateResponse>>() {
});
} catch (JsonProcessingException e) {
log.warn("Failed to parse bbox json: {}", e.getMessage());
return List.of();
}
} }
private SourceResourceResponse toResponse(SourceResource resource) { 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 * 获取资源的Content-Type支持 TEXT、IMAGE、VIDEO
* *
@@ -269,110 +447,4 @@ public class SourceResourceService {
default -> "application/octet-stream"; 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<ImageBboxResponse.BboxCoordinateResponse> 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<ImageBboxResponse.BboxCoordinateResponse> parseBboxJson(String bboxJson) {
if (!StringUtils.hasText(bboxJson)) {
return List.of();
}
try {
return objectMapper.readValue(bboxJson,
new TypeReference<List<ImageBboxResponse.BboxCoordinateResponse>>() {
});
} catch (JsonProcessingException e) {
log.warn("Failed to parse bbox json: {}", e.getMessage());
return List.of();
}
}
} }

View File

@@ -33,6 +33,7 @@ public class SysConfigService {
@Transactional @Transactional
public SysConfig saveConfig(LoginUser currentUser, SaveSysConfigRequest request) { public SysConfig saveConfig(LoginUser currentUser, SaveSysConfigRequest request) {
try {
validateConfigType(request.configType()); validateConfigType(request.configType());
SysConfig existing = sysConfigMapper.findByCompanyIdAndConfigName(currentUser.companyId(), SysConfig existing = sysConfigMapper.findByCompanyIdAndConfigName(currentUser.companyId(),
request.configName()); request.configName());
@@ -54,10 +55,18 @@ public class SysConfigService {
currentUser.companyId(), currentUser.userId(), currentUser.role().name(), currentUser.companyId(), currentUser.userId(), currentUser.role().name(),
request.configName(), request.configType()); request.configName(), request.configType());
return config; 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;
}
} }
@Transactional @Transactional
public SysConfig updateConfig(LoginUser currentUser, Long configId, UpdateSysConfigRequest request) { public SysConfig updateConfig(LoginUser currentUser, Long configId, UpdateSysConfigRequest request) {
try {
validateConfigType(request.configType()); validateConfigType(request.configType());
SysConfig existing = getConfigEntity(currentUser, configId); SysConfig existing = getConfigEntity(currentUser, configId);
@@ -77,18 +86,34 @@ public class SysConfigService {
log.info("updated sys config, companyId={}, userId={}, configId={}", log.info("updated sys config, companyId={}, userId={}, configId={}",
currentUser.companyId(), currentUser.userId(), configId); currentUser.companyId(), currentUser.userId(), configId);
return existing; 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;
}
} }
public SysConfigResponse getConfig(LoginUser currentUser, Long configId) { public SysConfigResponse getConfig(LoginUser currentUser, Long configId) {
try {
SysConfig config = getConfigEntity(currentUser, configId); SysConfig config = getConfigEntity(currentUser, configId);
if (!dataPermissionService.canAccessCreator(currentUser, config.getCreatorId(), if (!dataPermissionService.canAccessCreator(currentUser, config.getCreatorId(),
UserRole.valueOf(config.getCreatorRole()))) { UserRole.valueOf(config.getCreatorRole()))) {
throw new BusinessException(ResultCode.FORBIDDEN, "无权访问配置"); throw new BusinessException(ResultCode.FORBIDDEN, "无权访问配置");
} }
return toResponse(config); 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;
}
} }
public PageResult<SysConfigResponse> pageConfigs(LoginUser currentUser, SysConfigPageQuery query) { public PageResult<SysConfigResponse> pageConfigs(LoginUser currentUser, SysConfigPageQuery query) {
try {
List<String> allowedRoles = dataPermissionService.getAllowedRoles(currentUser); List<String> allowedRoles = dataPermissionService.getAllowedRoles(currentUser);
boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser); boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser);
@@ -115,6 +140,11 @@ public class SysConfigService {
return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(), return new PageResult<>(records, resultPage.getTotal(), (int) resultPage.getCurrent(),
(int) resultPage.getSize()); (int) resultPage.getSize());
} catch (Exception e) {
log.error("pageConfigs failed, companyId={}, userId={}, error={}",
currentUser.companyId(), currentUser.userId(), e.getMessage(), e);
throw e;
}
} }
public SysConfigResponse toResponse(SysConfig config) { public SysConfigResponse toResponse(SysConfig config) {

View File

@@ -1,11 +1,5 @@
package com.labelsys.backend.service; 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.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.labelsys.backend.common.ResultCode; import com.labelsys.backend.common.ResultCode;
import com.labelsys.backend.common.exception.BusinessException; import com.labelsys.backend.common.exception.BusinessException;
@@ -26,9 +20,15 @@ import com.labelsys.backend.mapper.SysCompanyMapper;
import com.labelsys.backend.mapper.SysUserMapper; import com.labelsys.backend.mapper.SysUserMapper;
import com.labelsys.backend.service.session.TokenSessionRepository; import com.labelsys.backend.service.session.TokenSessionRepository;
import com.labelsys.backend.util.IdGenerator; import com.labelsys.backend.util.IdGenerator;
import lombok.RequiredArgsConstructor; 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 @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class UserService { public class UserService {
@@ -41,31 +41,65 @@ public class UserService {
private final TokenSessionRepository tokenSessionRepository; private final TokenSessionRepository tokenSessionRepository;
public List<SysUser> listAllUsers(LoginUser currentUser) { public List<SysUser> listAllUsers(LoginUser currentUser) {
try {
assertSystemAdmin(currentUser); assertSystemAdmin(currentUser);
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<SysUser>().orderByAsc(SysUser::getId); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<SysUser>().orderByAsc(SysUser::getId);
return sysUserMapper.selectList(wrapper); 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<SysUser> listCompanyUsers(LoginUser currentUser) { public List<SysUser> listCompanyUsers(LoginUser currentUser) {
try {
assertCompanyAdmin(currentUser); assertCompanyAdmin(currentUser);
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<SysUser>() LambdaQueryWrapper wrapper = new LambdaQueryWrapper<SysUser>()
.eq(SysUser::getCompanyId, currentUser.companyId()).orderByAsc(SysUser::getId); .eq(SysUser::getCompanyId, currentUser.companyId()).orderByAsc(SysUser::getId);
return sysUserMapper.selectList(wrapper); 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<SysUser> listCompanyAdmins(LoginUser currentUser, Long companyId) { public List<SysUser> listCompanyAdmins(LoginUser currentUser, Long companyId) {
try {
assertSystemAdmin(currentUser); assertSystemAdmin(currentUser);
return sysUserMapper.listCompanyAdmins(companyId); 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) { public SysUser createCompanyAdmin(LoginUser currentUser, CreateCompanyAdminRequest request) {
try {
assertSystemAdmin(currentUser); assertSystemAdmin(currentUser);
ensureEnabledCompany(request.companyId()); ensureEnabledCompany(request.companyId());
return createUser(request.companyId(), new CreateUserRequest(request.phone(), request.username(), return createUser(request.companyId(), new CreateUserRequest(request.phone(), request.username(),
request.realName(), UserRole.EMPLOYEE, UserPosition.ADMIN)); 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) { public SysUser createSystemEngineerAdmin(LoginUser currentUser, CreateSystemEngineerAdminRequest request) {
try {
assertSystemAdmin(currentUser); assertSystemAdmin(currentUser);
Long systemCompanyId = 1L; Long systemCompanyId = 1L;
ensureEnabledCompany(systemCompanyId); ensureEnabledCompany(systemCompanyId);
@@ -80,45 +114,94 @@ public class UserService {
.mustChangePassword(true).status(UserStatus.ENABLED).sessionVersion(1).build(); .mustChangePassword(true).status(UserStatus.ENABLED).sessionVersion(1).build();
sysUserMapper.insert(user); sysUserMapper.insert(user);
return 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;
}
} }
public SysUser createCompanyUser(LoginUser currentUser, CreateUserRequest request) { public SysUser createCompanyUser(LoginUser currentUser, CreateUserRequest request) {
try {
assertCompanyAdmin(currentUser); assertCompanyAdmin(currentUser);
return createUser(currentUser.companyId(), request); 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) { public SysUser createCompanyUser(LoginUser currentUser, Long companyId, CreateUserRequest request) {
try {
assertSystemAdmin(currentUser); assertSystemAdmin(currentUser);
ensureEnabledCompany(companyId); ensureEnabledCompany(companyId);
return createUser(companyId, request); 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 @Transactional
public void updateAssignment(LoginUser currentUser, Long userId, UpdateUserAssignmentRequest request) { public void updateAssignment(LoginUser currentUser, Long userId, UpdateUserAssignmentRequest request) {
try {
assertCompanyAdmin(currentUser); assertCompanyAdmin(currentUser);
if (sysUserMapper.updateAssignment(userId, currentUser.companyId(), request.role(), request.position()) == 0) { if (sysUserMapper.updateAssignment(userId, currentUser.companyId(), request.role(), request.position())
== 0) {
throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在"); throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在");
} }
tokenSessionRepository.removeAll(userId); 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;
}
} }
@Transactional @Transactional
public void updateStatus(LoginUser currentUser, Long userId, UpdateUserStatusRequest request) { public void updateStatus(LoginUser currentUser, Long userId, UpdateUserStatusRequest request) {
try {
assertCompanyAdmin(currentUser); assertCompanyAdmin(currentUser);
if (sysUserMapper.updateStatus(userId, currentUser.companyId(), request.status()) == 0) { if (sysUserMapper.updateStatus(userId, currentUser.companyId(), request.status()) == 0) {
throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在"); throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在");
} }
tokenSessionRepository.removeAll(userId); 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;
}
} }
@Transactional @Transactional
public void updateCompanyAdminStatus(LoginUser currentUser, Long companyId, Long userId, public void updateCompanyAdminStatus(LoginUser currentUser, Long companyId, Long userId,
UpdateUserStatusRequest request) { UpdateUserStatusRequest request) {
try {
assertSystemAdmin(currentUser); assertSystemAdmin(currentUser);
if (sysUserMapper.updateStatus(userId, companyId, request.status()) == 0) { if (sysUserMapper.updateStatus(userId, companyId, request.status()) == 0) {
throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在"); throw new BusinessException(ResultCode.NOT_FOUND, "用户不存在");
} }
tokenSessionRepository.removeAll(userId); 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;
}
} }
private SysUser createUser(Long companyId, CreateUserRequest request) { private SysUser createUser(Long companyId, CreateUserRequest request) {
@@ -126,8 +209,10 @@ public class UserService {
throw new BusinessException(ResultCode.CONFLICT, "同一公司内手机号已存在"); throw new BusinessException(ResultCode.CONFLICT, "同一公司内手机号已存在");
} }
SysUser user = SysUser.builder().id(IdGenerator.nextId()).companyId(companyId).phone(request.phone()) SysUser user = SysUser.builder().id(IdGenerator.nextId()).companyId(companyId).phone(request.phone())
.username(request.username()).realName(request.realName()).role(request.role()).position(request.position()) .username(request.username()).realName(request.realName()).role(request.role())
.passwordHash(passwordEncoder.encode(DEFAULT_PASSWORD)).mustChangePassword(true).status(UserStatus.ENABLED) .position(request.position())
.passwordHash(passwordEncoder.encode(DEFAULT_PASSWORD)).mustChangePassword(true)
.status(UserStatus.ENABLED)
.sessionVersion(1).build(); .sessionVersion(1).build();
sysUserMapper.insert(user); sysUserMapper.insert(user);
return user; return user;

View File

@@ -69,9 +69,9 @@ INSERT INTO annotation_task (
id, company_id, creator_id, creator_role, task_name, industry_type, task_type, id, company_id, creator_id, creator_role, task_name, industry_type, task_type,
task_status, is_deleted, started_at, finished_at, error_message task_status, is_deleted, started_at, finished_at, error_message
) VALUES ) VALUES
(701, 2, 4, 'EMPLOYEE', '多资源问答抽取任务', 'electricity', 'EXTRACT_QA', (701, 2, 4, 'EMPLOYEE', '多资源问答抽取任务', 'ELECTRICITY', 'EXTRACT_QA',
'PENDING', FALSE, NULL, NULL, NULL), '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) 'COMPLETED', FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL)
ON CONFLICT DO NOTHING; ON CONFLICT DO NOTHING;

View File

@@ -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.resource_id IS '资源ID。';
COMMENT ON COLUMN annotation_task_resource.created_at IS '创建时间。'; COMMENT ON COLUMN annotation_task_resource.created_at IS '创建时间。';
drop table if exists annotation_result;
CREATE TABLE IF NOT EXISTS annotation_result CREATE TABLE IF NOT EXISTS annotation_result
( (
id BIGINT PRIMARY KEY, id BIGINT PRIMARY KEY,