라벨 할당,이관 리턴형식 수정

This commit is contained in:
2026-01-05 08:54:01 +09:00
parent dc2b9286f4
commit d87048b4c6
5 changed files with 114 additions and 104 deletions

View File

@@ -129,4 +129,12 @@ public class ApiLogFunction {
return m != null ? m.getMenuUid() : "SYSTEM"; return m != null ? m.getMenuUid() : "SYSTEM";
} }
public static String cutRequestBody(String value) {
int MAX_LEN = 255;
if (value == null) {
return null;
}
return value.length() <= MAX_LEN ? value : value.substring(0, MAX_LEN);
}
} }

View File

@@ -9,6 +9,7 @@ import com.kamco.cd.kamcoback.postgres.repository.log.AuditLogRepository;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@@ -26,6 +27,7 @@ import org.springframework.web.util.ContentCachingRequestWrapper;
* *
* <p>createOK() → 201 CREATED ok() → 200 OK deleteOk() → 204 NO_CONTENT * <p>createOK() → 201 CREATED ok() → 200 OK deleteOk() → 204 NO_CONTENT
*/ */
@Slf4j
@RestControllerAdvice @RestControllerAdvice
public class ApiResponseAdvice implements ResponseBodyAdvice<Object> { public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
@@ -110,7 +112,7 @@ public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
ApiLogFunction.getUriMenuInfo(result, servletRequest.getRequestURI()), ApiLogFunction.getUriMenuInfo(result, servletRequest.getRequestURI()),
ip, ip,
servletRequest.getRequestURI(), servletRequest.getRequestURI(),
requestBody, ApiLogFunction.cutRequestBody(requestBody),
apiResponse.getErrorLogUid()); apiResponse.getErrorLogUid());
auditLogRepository.save(log); auditLogRepository.save(log);
} }

View File

@@ -10,11 +10,11 @@ import com.kamco.cd.kamcoback.label.service.LabelAllocateService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.util.List; import java.util.List;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -109,63 +109,24 @@ public class LabelAllocateApiController {
content = content =
@Content( @Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = Long.class), schema = @Schema(implementation = Long.class))),
examples = {
@ExampleObject(
name = "라벨러 할당 예시",
description = "라벨러 할당 예시",
value =
"""
{
"autoType": "AUTO",
"stage": 4,
"labelers": [
{
"userId": "123456",
"demand": 1000
},
{
"userId": "010222297501",
"demand": 400
},
{
"userId": "01022223333",
"demand": 440
}
],
"inspectors": [
{
"inspectorUid": "K20251216001",
"userCount": 1000
},
{
"inspectorUid": "01022225555",
"userCount": 340
},
{
"inspectorUid": "K20251212001",
"userCount": 500
}
]
}
""")
})),
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
}) })
@PostMapping("/allocate") @PostMapping("/allocate")
public ApiResponseDto<Void> labelAllocate(@RequestBody LabelAllocateDto.AllocateDto dto) { public ApiResponseDto<ApiResponseDto.ResponseObj> labelAllocate(
labelAllocateService.allocateAsc( @RequestBody @Valid LabelAllocateDto.AllocateDto dto) {
dto.getAutoType(),
dto.getStage(),
dto.getLabelers(),
dto.getInspectors(),
dto.getCompareYyyy(),
dto.getTargetYyyy());
return ApiResponseDto.ok(null); return ApiResponseDto.okObject(
labelAllocateService.allocateAsc(
dto.getLabelerAutoType(),
dto.getInspectorAutoType(),
dto.getStage(),
dto.getLabelers(),
dto.getInspectors(),
dto.getCompareYyyy(),
dto.getTargetYyyy()));
} }
@Operation(summary = "추론 상세 조회", description = "분석 ID에 해당하는 추론 상세 정보를 조회합니다.") @Operation(summary = "추론 상세 조회", description = "분석 ID에 해당하는 추론 상세 정보를 조회합니다.")
@@ -208,35 +169,13 @@ public class LabelAllocateApiController {
content = content =
@Content( @Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = Long.class), schema = @Schema(implementation = Long.class))),
examples = {
@ExampleObject(
name = "라벨러 할당 예시",
description = "라벨러 할당 예시",
value =
"""
{
"autoType": "AUTO",
"stage": 4,
"labelers": [
{
"userId": "123456",
"demand": 10
},
{
"userId": "010222297501",
"demand": 5
}
]
}
""")
})),
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
}) })
@PostMapping("/allocate-move") @PostMapping("/allocate-move")
public ApiResponseDto<Void> labelAllocateMove( public ApiResponseDto<ApiResponseDto.ResponseObj> labelAllocateMove(
@io.swagger.v3.oas.annotations.parameters.RequestBody( @io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "라벨링 이관", description = "라벨링 이관",
required = true, required = true,
@@ -247,13 +186,12 @@ public class LabelAllocateApiController {
@RequestBody @RequestBody
LabelAllocateDto.AllocateMoveDto dto) { LabelAllocateDto.AllocateMoveDto dto) {
labelAllocateService.allocateMove( return ApiResponseDto.okObject(
dto.getAutoType(), labelAllocateService.allocateMove(
dto.getStage(), dto.getAutoType(),
dto.getLabelers(), dto.getStage(),
dto.getCompareYyyy(), dto.getLabelers(),
dto.getTargetYyyy()); dto.getCompareYyyy(),
dto.getTargetYyyy()));
return ApiResponseDto.ok(null);
} }
} }

View File

@@ -87,8 +87,8 @@ public class LabelAllocateDto {
@AllArgsConstructor @AllArgsConstructor
public static class AllocateDto { public static class AllocateDto {
@Schema(description = "분석 ID", example = "3") // @Schema(description = "분석 ID", example = "3")
private Long analUid; // private Long analUid;
@Schema(description = "비교년도", example = "2022", required = true) @Schema(description = "비교년도", example = "2022", required = true)
private Integer compareYyyy; private Integer compareYyyy;
@@ -96,16 +96,55 @@ public class LabelAllocateDto {
@Schema(description = "기준년도", example = "2024", required = true) @Schema(description = "기준년도", example = "2024", required = true)
private Integer targetYyyy; private Integer targetYyyy;
@Schema(description = "자동/수동여부(AUTO/MANUAL)", example = "AUTO") @Schema(description = "라벨러 자동/수동여부(AUTO/MANUAL)", example = "AUTO")
private String autoType; private String labelerAutoType;
@Schema(description = "검수자 자동/수동여부(AUTO/MANUAL)", example = "AUTO")
private String inspectorAutoType;
@Schema(description = "회차", example = "4") @Schema(description = "회차", example = "4")
private Integer stage; private Integer stage;
@Schema(description = "라벨러 할당 목록") @Schema(
description = "라벨러 할당 목록",
example =
"""
[
{
"userId": "123456",
"demand": 1000
},
{
"userId": "010222297501",
"demand": 400
},
{
"userId": "01022223333",
"demand": 440
}
]
""")
private List<TargetUser> labelers; private List<TargetUser> labelers;
@Schema(description = "검수자 할당 목록") @Schema(
description = "검수자 할당 목록",
example =
"""
[
{
"inspectorUid": "K20251216001",
"userCount": 1000
},
{
"inspectorUid": "01022225555",
"userCount": 340
},
{
"inspectorUid": "K20251212001",
"userCount": 500
}
]
""")
private List<TargetInspector> inspectors; private List<TargetInspector> inspectors;
} }
@@ -201,7 +240,21 @@ public class LabelAllocateDto {
@Schema(description = "회차", example = "4") @Schema(description = "회차", example = "4")
private Integer stage; private Integer stage;
@Schema(description = "라벨러 할당 목록") @Schema(
description = "라벨러 할당 목록",
example =
"""
[
{
"userId": "123456",
"demand": 10
},
{
"userId": "010222297501",
"demand": 5
}
]
""")
private List<TargetUser> labelers; private List<TargetUser> labelers;
@Schema(description = "비교년도", example = "2022") @Schema(description = "비교년도", example = "2022")

View File

@@ -1,5 +1,7 @@
package com.kamco.cd.kamcoback.label.service; package com.kamco.cd.kamcoback.label.service;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail; import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail;
@@ -12,6 +14,7 @@ import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerStatistics;
import com.kamco.cd.kamcoback.postgres.core.LabelAllocateCoreService; import com.kamco.cd.kamcoback.postgres.core.LabelAllocateCoreService;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -34,14 +37,16 @@ public class LabelAllocateService {
/** /**
* 도엽 기준 asc sorting 해서 할당 수만큼 배정하는 로직 * 도엽 기준 asc sorting 해서 할당 수만큼 배정하는 로직
* *
* @param autoType 자동/수동 배정 타입 * @param labelerAutoType 라벨러 자동/수동 배정 타입
* @param inspectorAutoType 검수자 자동/수동 배정 타입
* @param stage 회차 * @param stage 회차
* @param targetUsers 라벨러 목록 * @param targetUsers 라벨러 목록
* @param targetInspectors 검수자 목록 * @param targetInspectors 검수자 목록
*/ */
@Transactional @Transactional
public void allocateAsc( public ApiResponseDto.ResponseObj allocateAsc(
String autoType, String labelerAutoType,
String inspectorAutoType,
Integer stage, Integer stage,
List<TargetUser> targetUsers, List<TargetUser> targetUsers,
List<TargetInspector> targetInspectors, List<TargetInspector> targetInspectors,
@@ -52,14 +57,14 @@ public class LabelAllocateService {
// geom 잔여건수 조회 // geom 잔여건수 조회
Long chargeCnt = Long chargeCnt =
labelAllocateCoreService.findLabelUnAssignedCnt(stage, compareYyyy, targetYyyy); labelAllocateCoreService.findLabelUnAssignedCnt(stage, compareYyyy, targetYyyy);
// Long totalDemand = targetUsers.stream().mapToLong(TargetUser::getDemand).sum();
// if (!Objects.equals(chargeCnt, totalDemand)) {
// log.info("chargeCnt != totalDemand");
// return;
// }
if (chargeCnt <= 0) { if (chargeCnt <= 0) {
return; return new ApiResponseDto.ResponseObj(ApiResponseCode.DUPLICATE_DATA, "이미 배정완료된 회차 입니다.");
}
Long totalDemand = targetUsers.stream().mapToLong(TargetUser::getDemand).sum();
if (!Objects.equals(chargeCnt, totalDemand)) {
return new ApiResponseDto.ResponseObj(
ApiResponseCode.BAD_REQUEST, "총 잔여건수와 요청 값의 합계가 맞지 않습니다.");
} }
List<Long> allIds = List<Long> allIds =
@@ -92,6 +97,8 @@ public class LabelAllocateService {
from = to; from = to;
} }
return new ApiResponseDto.ResponseObj(ApiResponseCode.OK, "배정이 완료되었습니다.");
} }
public List<UserList> availUserList(String role) { public List<UserList> availUserList(String role) {
@@ -162,7 +169,7 @@ public class LabelAllocateService {
return labelAllocateCoreService.findInferenceDetail(compareYyyy, targetYyyy, stage); return labelAllocateCoreService.findInferenceDetail(compareYyyy, targetYyyy, stage);
} }
public void allocateMove( public ApiResponseDto.ResponseObj allocateMove(
String autoType, String autoType,
Integer stage, Integer stage,
List<TargetUser> targetUsers, List<TargetUser> targetUsers,
@@ -173,7 +180,7 @@ public class LabelAllocateService {
Long chargeCnt = targetUsers.stream().mapToLong(TargetUser::getDemand).sum(); Long chargeCnt = targetUsers.stream().mapToLong(TargetUser::getDemand).sum();
if (chargeCnt <= 0) { if (chargeCnt <= 0) {
return; return new ApiResponseDto.ResponseObj(ApiResponseCode.BAD_REQUEST, "이관할 데이터를 입력해주세요.");
} }
List<Long> allIds = List<Long> allIds =
@@ -187,6 +194,8 @@ public class LabelAllocateService {
labelAllocateCoreService.assignOwnerMove(sub, target.getUserId()); labelAllocateCoreService.assignOwnerMove(sub, target.getUserId());
index = end; index = end;
} }
return new ApiResponseDto.ResponseObj(ApiResponseCode.OK, "이관을 완료하였습니다.");
} }
public LabelerDetail findLabelerDetail( public LabelerDetail findLabelerDetail(