From 4c80017fc5b701438c66609ae127967b79a94cf9 Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 3 Feb 2026 18:46:00 +0900 Subject: [PATCH 1/3] =?UTF-8?q?dataset=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cd/training/postgres/entity/ModelDatasetEntity.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/kamco/cd/training/postgres/entity/ModelDatasetEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/ModelDatasetEntity.java index d78c038..a5e98f7 100644 --- a/src/main/java/com/kamco/cd/training/postgres/entity/ModelDatasetEntity.java +++ b/src/main/java/com/kamco/cd/training/postgres/entity/ModelDatasetEntity.java @@ -38,6 +38,12 @@ public class ModelDatasetEntity { @Column(name = "container_cnt") private Long containerCnt; + @Column(name = "waste_cnt") + private Long wasteCnt; + + @Column(name = "land_cover_cnt") + private Long landCoverCnt; + @ColumnDefault("now()") @Column(name = "created_dttm") private OffsetDateTime createdDttm; From 19644e5c9fe56bae5fe28a4e0e6881a9af3e97c7 Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 3 Feb 2026 18:51:35 +0900 Subject: [PATCH 2/3] =?UTF-8?q?dataset=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../postgres/entity/ModelConfigEntity.java | 14 ++++++++++++-- .../postgres/entity/ModelDatasetEntity.java | 4 ++-- .../postgres/entity/ModelHistoryEntity.java | 12 ++++++------ .../postgres/entity/ModelMatricsTestEntity.java | 4 ++-- .../postgres/entity/ModelMatricsTrainEntity.java | 4 ++-- .../entity/ModelMatricsValidationEntity.java | 4 ++-- 6 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/kamco/cd/training/postgres/entity/ModelConfigEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/ModelConfigEntity.java index a03e024..0f5acbd 100644 --- a/src/main/java/com/kamco/cd/training/postgres/entity/ModelConfigEntity.java +++ b/src/main/java/com/kamco/cd/training/postgres/entity/ModelConfigEntity.java @@ -10,7 +10,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; -import java.time.OffsetDateTime; +import java.time.ZonedDateTime; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.ColumnDefault; @@ -43,10 +43,20 @@ public class ModelConfigEntity { @Column(name = "test_percent") private Float testPercent; + @Column(name = "memo") + private String memo; + @ColumnDefault("now()") @Column(name = "created_dttm") - private OffsetDateTime createdDttm; + private ZonedDateTime createdDttm; @Column(name = "created_uid") private Long createdUid; + + @ColumnDefault("now()") + @Column(name = "updated_dttm") + private ZonedDateTime updatedDttm; + + @Column(name = "updated_uid") + private Long updatedUid; } diff --git a/src/main/java/com/kamco/cd/training/postgres/entity/ModelDatasetEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/ModelDatasetEntity.java index a5e98f7..e7c9255 100644 --- a/src/main/java/com/kamco/cd/training/postgres/entity/ModelDatasetEntity.java +++ b/src/main/java/com/kamco/cd/training/postgres/entity/ModelDatasetEntity.java @@ -8,7 +8,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; -import java.time.OffsetDateTime; +import java.time.ZonedDateTime; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.ColumnDefault; @@ -46,7 +46,7 @@ public class ModelDatasetEntity { @ColumnDefault("now()") @Column(name = "created_dttm") - private OffsetDateTime createdDttm; + private ZonedDateTime createdDttm; @Column(name = "created_uid") private Long createdUid; diff --git a/src/main/java/com/kamco/cd/training/postgres/entity/ModelHistoryEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/ModelHistoryEntity.java index 5f2a900..7c33e69 100644 --- a/src/main/java/com/kamco/cd/training/postgres/entity/ModelHistoryEntity.java +++ b/src/main/java/com/kamco/cd/training/postgres/entity/ModelHistoryEntity.java @@ -11,7 +11,7 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; -import java.time.OffsetDateTime; +import java.time.ZonedDateTime; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.ColumnDefault; @@ -43,20 +43,20 @@ public class ModelHistoryEntity { private Short modelStep; @Column(name = "step1_strt_dttm") - private OffsetDateTime step1StrtDttm; + private ZonedDateTime step1StrtDttm; @Column(name = "step1_end_dttm") - private OffsetDateTime step1EndDttm; + private ZonedDateTime step1EndDttm; @Size(max = 20) @Column(name = "step1_state", length = 20) private String step1State; @Column(name = "step2_strt_dttm") - private OffsetDateTime step2StrtDttm; + private ZonedDateTime step2StrtDttm; @Column(name = "step2_end_dttm") - private OffsetDateTime step2EndDttm; + private ZonedDateTime step2EndDttm; @Size(max = 20) @Column(name = "step2_state", length = 20) @@ -67,7 +67,7 @@ public class ModelHistoryEntity { @ColumnDefault("now()") @Column(name = "created_dttm") - private OffsetDateTime createdDttm; + private ZonedDateTime createdDttm; @Column(name = "created_uid") private Long createdUid; diff --git a/src/main/java/com/kamco/cd/training/postgres/entity/ModelMatricsTestEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/ModelMatricsTestEntity.java index ad0084a..37e97e3 100644 --- a/src/main/java/com/kamco/cd/training/postgres/entity/ModelMatricsTestEntity.java +++ b/src/main/java/com/kamco/cd/training/postgres/entity/ModelMatricsTestEntity.java @@ -11,7 +11,7 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; -import java.time.OffsetDateTime; +import java.time.ZonedDateTime; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.ColumnDefault; @@ -68,7 +68,7 @@ public class ModelMatricsTestEntity { @ColumnDefault("now()") @Column(name = "created_dttm") - private OffsetDateTime createdDttm; + private ZonedDateTime createdDttm; @Column(name = "created_uid") private Long createdUid; diff --git a/src/main/java/com/kamco/cd/training/postgres/entity/ModelMatricsTrainEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/ModelMatricsTrainEntity.java index 2415c25..53537c5 100644 --- a/src/main/java/com/kamco/cd/training/postgres/entity/ModelMatricsTrainEntity.java +++ b/src/main/java/com/kamco/cd/training/postgres/entity/ModelMatricsTrainEntity.java @@ -10,7 +10,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; -import java.time.OffsetDateTime; +import java.time.ZonedDateTime; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.ColumnDefault; @@ -48,7 +48,7 @@ public class ModelMatricsTrainEntity { @ColumnDefault("now()") @Column(name = "created_dttm") - private OffsetDateTime createdDttm; + private ZonedDateTime createdDttm; @Column(name = "created_uid") private Long createdUid; diff --git a/src/main/java/com/kamco/cd/training/postgres/entity/ModelMatricsValidationEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/ModelMatricsValidationEntity.java index ce4f465..bcbdeb4 100644 --- a/src/main/java/com/kamco/cd/training/postgres/entity/ModelMatricsValidationEntity.java +++ b/src/main/java/com/kamco/cd/training/postgres/entity/ModelMatricsValidationEntity.java @@ -10,7 +10,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; -import java.time.OffsetDateTime; +import java.time.ZonedDateTime; import lombok.Getter; import lombok.Setter; import org.hibernate.annotations.ColumnDefault; @@ -72,7 +72,7 @@ public class ModelMatricsValidationEntity { @ColumnDefault("now()") @Column(name = "created_dttm") - private OffsetDateTime createdDttm; + private ZonedDateTime createdDttm; @Column(name = "created_uid") private Long createdUid; From f1ad59d0b17f7abd14c43ddfba4339dfa1426bcb Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Tue, 3 Feb 2026 18:51:56 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=EC=85=8B=20API?= =?UTF-8?q?=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/enums/DetectionClassification.java | 31 ++--- .../dataset/DatasetApiController.java | 93 +++++++++++++-- .../cd/training/dataset/dto/DatasetDto.java | 66 ++++++++++- .../training/dataset/dto/DatasetObjDto.java | 111 ++++++++++++++++++ .../dataset/service/DatasetService.java | 20 ++++ .../postgres/core/DatasetCoreService.java | 43 ++++++- .../postgres/entity/DatasetEntity.java | 27 ----- .../postgres/entity/DatasetObjEntity.java | 100 ++++++++++++++++ .../dataset/DatasetObjRepository.java | 7 ++ .../dataset/DatasetObjRepositoryCustom.java | 14 +++ .../dataset/DatasetObjRepositoryImpl.java | 97 +++++++++++++++ .../dataset/DatasetRepositoryCustom.java | 6 + .../dataset/DatasetRepositoryImpl.java | 102 ++++++++++++++++ 13 files changed, 658 insertions(+), 59 deletions(-) create mode 100644 src/main/java/com/kamco/cd/training/dataset/dto/DatasetObjDto.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/entity/DatasetObjEntity.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetObjRepository.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetObjRepositoryCustom.java create mode 100644 src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetObjRepositoryImpl.java diff --git a/src/main/java/com/kamco/cd/training/common/enums/DetectionClassification.java b/src/main/java/com/kamco/cd/training/common/enums/DetectionClassification.java index 9551feb..24260be 100644 --- a/src/main/java/com/kamco/cd/training/common/enums/DetectionClassification.java +++ b/src/main/java/com/kamco/cd/training/common/enums/DetectionClassification.java @@ -6,21 +6,22 @@ import lombok.Getter; @Getter @AllArgsConstructor public enum DetectionClassification { - BUILDING("building", "건물", 10), - CONTAINER("container", "컨테이너", 20), - FIELD("field", "경작지", 30), - FOREST("forest", "숲", 40), - GRASS("grass", "초지", 50), - GREENHOUSE("greenhouse", "비닐하우스", 60), - LAND("land", "일반토지", 70), - ORCHARD("orchard", "과수원", 80), - ROAD("road", "도로", 90), - STONE("stone", "모래/자갈", 100), - TANK("tank", "물탱크", 110), - TUMULUS("tumulus", "토분(무덤)", 120), - WASTE("waste", "폐기물", 130), - WATER("water", "물", 140), - ETC("ETC", "기타", 200); // For 'etc' (miscellaneous/other) + ROAD("road", "도로", 10), + BUILDING("building", "건물", 20), + GREENHOUSE("greenhouse", "비닐하우스", 30), + FIELD("field", "논/밭", 40), + ORCHARD("orchard", "과수원", 50), + GRASS("grass", "초지", 60), + FOREST("forest", "숲", 70), + WATER("water", "물", 80), + STONE("stone", "모래/자갈", 90), + WASTE("waste", "적치물", 100), + CONTAINER("container", "컨테이너", 110), + LAND("land", "일반토지", 120), + SOLAR("solar", "태양광", 130), + TANK("tank", "물탱크", 140), + NDC("NDC", "미분류", 150), + ETC("ETC", "기타", 160); private final String id; private final String desc; diff --git a/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java b/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java index 5b9b902..1f113b3 100644 --- a/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java +++ b/src/main/java/com/kamco/cd/training/dataset/DatasetApiController.java @@ -2,6 +2,8 @@ package com.kamco.cd.training.dataset; import com.kamco.cd.training.config.api.ApiResponseDto; import com.kamco.cd.training.dataset.dto.DatasetDto; +import com.kamco.cd.training.dataset.dto.DatasetDto.SelectDataSet; +import com.kamco.cd.training.dataset.dto.DatasetObjDto; import com.kamco.cd.training.dataset.service.DatasetService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -11,6 +13,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; +import java.util.List; import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; @@ -39,7 +42,10 @@ public class DatasetApiController { }) @GetMapping public ApiResponseDto> searchDatasets( - @Parameter(description = "구분", example = "DELIVER(납품), PRODUCTION(제작)") + @Parameter( + description = "구분", + example = "", + schema = @Schema(allowableValues = {"DELIVER", "PRODUCTION"})) @RequestParam(required = false) String groupTitle, @Parameter(description = "제목", example = "") @RequestParam(required = false) String title, @@ -129,8 +135,7 @@ public class DatasetApiController { return ApiResponseDto.ok(uuid); } - /* - @Operation(summary = "데이터셋 통계 요약", description = "선택 데이터셋의 통계를 요약합니다.") + @Operation(summary = "학습데이터 관리 목록 조회", description = "학습데이터 목록을 조회합니다.") @ApiResponses( value = { @ApiResponse( @@ -139,16 +144,84 @@ public class DatasetApiController { content = @Content( mediaType = "application/json", - schema = @Schema(implementation = DatasetDto.Summary.class))), - @ApiResponse(responseCode = "400", description = "잘못된 요청", content = @Content), + schema = @Schema(implementation = Page.class))), + @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content), @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) }) - @PostMapping("/summary") - public ApiResponseDto getDatasetSummary( - @RequestBody @Valid DatasetDto.SummaryReq summaryReq) { - return ApiResponseDto.ok(datasetService.getDatasetSummary(summaryReq)); + @GetMapping("/obj-list") + public ApiResponseDto> searchDatasetObjectList( + @Parameter(description = "회차 uuid", example = "35e20bb2-9014-4c9d-abe2-9046db5f930c") + @RequestParam(required = true) + UUID uuid, + @Parameter(description = "비교년도", example = "2021") @RequestParam(required = false) + Integer compareYyyy, + @Parameter(description = "비교년도분류", example = "container") @RequestParam(required = false) + String compareClassCd, + @Parameter(description = "기준년도", example = "2022") @RequestParam(required = false) + Integer targetYyyy, + @Parameter(description = "기준년도분류", example = "waste") @RequestParam(required = false) + String targetClassCd, + @Parameter(description = "도엽번호", example = "36713060") @RequestParam(required = false) + String mapSheetNum, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "20") int size) { + DatasetObjDto.SearchReq searchReq = new DatasetObjDto.SearchReq(); + searchReq.setUuid(uuid); + searchReq.setCompareYyyy(compareYyyy); + searchReq.setCompareClassCd(compareClassCd); + searchReq.setTargetYyyy(targetYyyy); + searchReq.setTargetClassCd(targetClassCd); + searchReq.setMapSheetNum(mapSheetNum); + searchReq.setPage(page); + searchReq.setSize(size); + return ApiResponseDto.ok(datasetService.searchDatasetObjectList(searchReq)); } - */ + @Operation(summary = "학습데이터 관리 목록 조회", description = "학습데이터 목록을 조회합니다.") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = Page.class))), + @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @DeleteMapping("/obj/{uuid}") + public ApiResponseDto deleteDatasetObjByUuid(@PathVariable UUID uuid) { + return ApiResponseDto.ok(datasetService.deleteDatasetObjByUuid(uuid)); + } + @Operation(summary = "학습데이터관리 상세 조회", description = "학습데이터관리 상세 정보를 조회합니다.") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = DatasetDto.Basic.class))), + @ApiResponse(responseCode = "404", description = "데이터셋을 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping("/select-dataset-list") + public ApiResponseDto> getDatasetSelectList( + @Parameter( + description = "모델 구분", + example = "", + schema = @Schema(allowableValues = {"M1", "M2", "M3"})) + @RequestParam + String modelType, + @Parameter( + description = "선택 구분", + example = "", + schema = @Schema(allowableValues = {"CURRENT", "DELIVER", "PRODUCTION"})) + @RequestParam + String selectType) { + return ApiResponseDto.ok(datasetService.getDatasetSelectList(modelType, selectType)); + } } diff --git a/src/main/java/com/kamco/cd/training/dataset/dto/DatasetDto.java b/src/main/java/com/kamco/cd/training/dataset/dto/DatasetDto.java index d1bfaa9..8f70d9c 100644 --- a/src/main/java/com/kamco/cd/training/dataset/dto/DatasetDto.java +++ b/src/main/java/com/kamco/cd/training/dataset/dto/DatasetDto.java @@ -1,5 +1,6 @@ package com.kamco.cd.training.dataset.dto; +import com.fasterxml.jackson.annotation.JsonInclude; import com.kamco.cd.training.common.enums.LearnDataRegister; import com.kamco.cd.training.common.enums.LearnDataType; import com.kamco.cd.training.common.utils.enums.Enums; @@ -15,10 +16,12 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; +@Slf4j public class DatasetDto { @Schema(name = "Dataset Basic", description = "데이터셋 기본 정보") @@ -108,7 +111,7 @@ public class DatasetDto { @AllArgsConstructor public static class SearchReq { - @Schema(description = "구분", example = "DELIVER(납품), PRODUCTION(제작)") + @Schema(description = "구분") private String groupTitle; @Schema(description = "제목 (부분 검색)", example = "1차") @@ -209,4 +212,65 @@ public class DatasetDto { @Schema(description = "평균 도엽 수", example = "750") private double averageMapSheets; } + + @Schema(name = "SelectDataSet", description = "데이터셋 선택 리스트") + @Getter + @Setter + @NoArgsConstructor + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class SelectDataSet { + + private Long datasetId; + private UUID uuid; + private String groupTitle; + private String yyyy; + private Long roundNo; + private String memo; + private Long classCount; + private Integer buildingCount; + private Integer containerCount; + private String groupTitleCd; + + public SelectDataSet( + Long datasetId, + UUID uuid, + String groupTitle, + String yyyy, + Long roundNo, + String memo, + Long classCount) { + this.datasetId = datasetId; + this.uuid = uuid; + this.groupTitle = groupTitle; + this.yyyy = yyyy; + this.roundNo = roundNo; + this.memo = memo; + this.classCount = classCount; + } + + public SelectDataSet( + Long datasetId, + UUID uuid, + String groupTitle, + String yyyy, + Long roundNo, + String memo, + Integer buildingCount, + Integer containerCount) { + this.datasetId = datasetId; + this.uuid = uuid; + this.groupTitle = getGroupTitle(groupTitle); + this.groupTitleCd = groupTitle; + this.yyyy = yyyy; + this.roundNo = roundNo; + this.memo = memo; + this.buildingCount = buildingCount; + this.containerCount = containerCount; + } + + public String getGroupTitle(String groupTitleCd) { + LearnDataType type = Enums.fromId(LearnDataType.class, groupTitleCd); + return type == null ? null : type.getText(); + } + } } diff --git a/src/main/java/com/kamco/cd/training/dataset/dto/DatasetObjDto.java b/src/main/java/com/kamco/cd/training/dataset/dto/DatasetObjDto.java new file mode 100644 index 0000000..0e56457 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/dataset/dto/DatasetObjDto.java @@ -0,0 +1,111 @@ +package com.kamco.cd.training.dataset.dto; + +import com.kamco.cd.training.common.utils.interfaces.JsonFormatDttm; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.ZonedDateTime; +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; + +@Slf4j +public class DatasetObjDto { + + @Schema(name = "DatasetObj Basic", description = "데이터셋 객체 Obj 기본 정보") + @Getter + @Setter + @NoArgsConstructor + public static class Basic { + + private Long objId; + private Long datasetUid; + private Integer targetYyyy; + private String targetClassCd; + private Integer compareYyyy; + private String compareClassCd; + private String targetPath; + private String comparePath; + private String labelPath; + private String geojsonPath; + private String mapSheetNum; + @JsonFormatDttm private ZonedDateTime createdDttm; + private Long createdUid; + private Boolean deleted; + private UUID uuid; + + public Basic( + Long objId, + Long datasetUid, + Integer targetYyyy, + String targetClassCd, + Integer compareYyyy, + String compareClassCd, + String targetPath, + String comparePath, + String labelPath, + String geojsonPath, + String mapSheetNum, + ZonedDateTime createdDttm, + Long createdUid, + Boolean deleted, + UUID uuid) { + this.objId = objId; + this.datasetUid = datasetUid; + this.targetYyyy = targetYyyy; + this.targetClassCd = targetClassCd; + this.compareYyyy = compareYyyy; + this.compareClassCd = compareClassCd; + this.targetPath = targetPath; + this.comparePath = comparePath; + this.labelPath = labelPath; + this.geojsonPath = geojsonPath; + this.mapSheetNum = mapSheetNum; + this.createdDttm = createdDttm; + this.createdUid = createdUid; + this.deleted = deleted; + this.uuid = uuid; + } + } + + @Schema(name = "DatasetSearchReq", description = "데이터셋 상세 도엽목록 조회 요청") + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class SearchReq { + @Schema(description = "회차 uuid", example = "35e20bb2-9014-4c9d-abe2-9046db5f930c") + private UUID uuid; + + @Schema(description = "비교년도", example = "2021") + private Integer compareYyyy; + + @Schema(description = "비교년도분류", example = "waste") + private String compareClassCd; + + @Schema(description = "기준년도", example = "2022") + private Integer targetYyyy; + + @Schema(description = "기준년도분류", example = "land") + private String targetClassCd; + + @Schema(description = "도엽번호", example = "36713060") + private String mapSheetNum; + + @Schema(description = "페이지 번호 (0부터 시작)", example = "0") + private int page = 0; + + @Schema(description = "페이지 크기", example = "20") + private int size = 20; + + public Pageable toPageable() { + // API에서는 1부터 시작하지만 내부적으로는 0부터 시작 + int pageIndex = Math.max(0, page - 1); + return PageRequest.of(pageIndex, size, Sort.by(Sort.Direction.DESC, "createdDttm")); + } + } +} diff --git a/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java b/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java index 7a80166..2e5e4a1 100644 --- a/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java +++ b/src/main/java/com/kamco/cd/training/dataset/service/DatasetService.java @@ -1,7 +1,11 @@ package com.kamco.cd.training.dataset.service; import com.kamco.cd.training.dataset.dto.DatasetDto; +import com.kamco.cd.training.dataset.dto.DatasetDto.SelectDataSet; +import com.kamco.cd.training.dataset.dto.DatasetObjDto; +import com.kamco.cd.training.dataset.dto.DatasetObjDto.SearchReq; import com.kamco.cd.training.postgres.core.DatasetCoreService; +import java.util.List; import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -83,4 +87,20 @@ public class DatasetService { log.info("데이터셋 통계 요약 - 요청: {}", summaryReq); return datasetCoreService.getDatasetSummary(summaryReq); } + + public Page searchDatasetObjectList(SearchReq searchReq) { + return datasetCoreService.searchDatasetObjectList(searchReq); + } + + public UUID deleteDatasetObjByUuid(UUID uuid) { + return datasetCoreService.deleteDatasetObjByUuid(uuid); + } + + public List getDatasetSelectList(String modelType, String selectType) { + if (modelType.equals("M1")) { + return datasetCoreService.getDatasetSelectM1List(modelType, selectType); + } else { + return datasetCoreService.getDatasetSelectM2M3List(modelType, selectType); + } + } } diff --git a/src/main/java/com/kamco/cd/training/postgres/core/DatasetCoreService.java b/src/main/java/com/kamco/cd/training/postgres/core/DatasetCoreService.java index 19be62a..47c39b4 100644 --- a/src/main/java/com/kamco/cd/training/postgres/core/DatasetCoreService.java +++ b/src/main/java/com/kamco/cd/training/postgres/core/DatasetCoreService.java @@ -2,11 +2,18 @@ package com.kamco.cd.training.postgres.core; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.kamco.cd.training.common.enums.LearnDataRegister; +import com.kamco.cd.training.common.enums.LearnDataType; import com.kamco.cd.training.common.exception.NotFoundException; import com.kamco.cd.training.common.service.BaseCoreService; import com.kamco.cd.training.dataset.dto.DatasetDto; +import com.kamco.cd.training.dataset.dto.DatasetDto.SelectDataSet; +import com.kamco.cd.training.dataset.dto.DatasetObjDto.Basic; +import com.kamco.cd.training.dataset.dto.DatasetObjDto.SearchReq; import com.kamco.cd.training.model.dto.ModelMngDto; import com.kamco.cd.training.postgres.entity.DatasetEntity; +import com.kamco.cd.training.postgres.entity.DatasetObjEntity; +import com.kamco.cd.training.postgres.repository.dataset.DatasetObjRepository; import com.kamco.cd.training.postgres.repository.dataset.DatasetRepository; import java.time.ZonedDateTime; import java.util.HashMap; @@ -25,6 +32,7 @@ import org.springframework.stereotype.Service; public class DatasetCoreService implements BaseCoreService { private final DatasetRepository datasetRepository; + private final DatasetObjRepository datasetObjRepository; private final ObjectMapper objectMapper; /** @@ -99,25 +107,25 @@ public class DatasetCoreService // 먼저 id1 필드를 임시값(0)으로 설정하여 저장 DatasetEntity entity = new DatasetEntity(); entity.setTitle(registerReq.getTitle()); - entity.setYear(registerReq.getYear()); - entity.setGroupTitle("PRODUCTION"); + // entity.setYear(registerReq.getYear()); + entity.setGroupTitle(LearnDataType.PRODUCTION.getId()); entity.setDataYear(registerReq.getYear()); entity.setRoundNo(registerReq.getRoundNo() != null ? registerReq.getRoundNo() : 1L); entity.setMemo(registerReq.getMemo()); - entity.setStatus("READY"); + entity.setStatus(LearnDataRegister.READY.getId()); entity.setDataType("CREATE"); entity.setTotalItems(0L); entity.setTotalSize(0L); entity.setItemCount(0L); entity.setDeleted(false); entity.setCreatedDttm(ZonedDateTime.now()); - entity.setId1(0L); // 임시값 + // entity.setId1(0L); // 임시값 DatasetEntity savedEntity = datasetRepository.save(entity); // 저장 후 id1을 dataset_uid와 동일하게 업데이트 - savedEntity.setId1(savedEntity.getId()); - savedEntity = datasetRepository.save(savedEntity); + // savedEntity.setId1(savedEntity.getId()); + // savedEntity = datasetRepository.save(savedEntity); return savedEntity.toDto(); } @@ -273,4 +281,27 @@ public class DatasetCoreService double kb = size / 1024.0; return String.format("%.2f KB", kb); } + + public Page searchDatasetObjectList(SearchReq searchReq) { + Page entityPage = datasetObjRepository.searchDatasetObjectList(searchReq); + return entityPage.map(DatasetObjEntity::toDto); + } + + public UUID deleteDatasetObjByUuid(UUID uuid) { + DatasetObjEntity entity = + datasetObjRepository + .findByUuid(uuid) + .orElseThrow(() -> new NotFoundException("데이터셋 obj를 찾을 수 없습니다. ID: " + uuid)); + entity.setDeleted(true); + datasetObjRepository.save(entity); + return entity.getUuid(); + } + + public List getDatasetSelectM1List(String modelType, String selectType) { + return datasetRepository.getDatasetSelectM1List(modelType, selectType); + } + + public List getDatasetSelectM2M3List(String modelType, String selectType) { + return datasetRepository.getDatasetSelectM2M3List(modelType, selectType); + } } diff --git a/src/main/java/com/kamco/cd/training/postgres/entity/DatasetEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/DatasetEntity.java index 026becc..a29d6f3 100644 --- a/src/main/java/com/kamco/cd/training/postgres/entity/DatasetEntity.java +++ b/src/main/java/com/kamco/cd/training/postgres/entity/DatasetEntity.java @@ -9,7 +9,6 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; -import java.time.Instant; import java.time.ZonedDateTime; import java.util.Map; import java.util.UUID; @@ -66,24 +65,6 @@ public class DatasetEntity { @Column(name = "status", length = 20) private String status; - @Size(max = 50) - @Column(name = "reg_user_id", length = 50) - private String regUserId; - - @ColumnDefault("now()") - @Column(name = "reg_dttm") - private Instant regDttm; - - @Column(name = "mod_dttm") - private Instant modDttm; - - @Column(name = "id") - private Long id1; - - @Size(max = 50) - @Column(name = "created_by", length = 50) - private String createdBy; - @NotNull @ColumnDefault("now()") @Column(name = "created_dttm", nullable = false) @@ -101,17 +82,9 @@ public class DatasetEntity { @Column(name = "total_items") private Long totalItems; - @Size(max = 50) - @Column(name = "updated_by", length = 50) - private String updatedBy; - @Column(name = "updated_dttm") private ZonedDateTime updatedDttm; - @Size(max = 4) - @Column(name = "year", length = 4) - private String year; - @Column(name = "class_counts", columnDefinition = "jsonb") @JdbcTypeCode(SqlTypes.JSON) private Map classCounts; diff --git a/src/main/java/com/kamco/cd/training/postgres/entity/DatasetObjEntity.java b/src/main/java/com/kamco/cd/training/postgres/entity/DatasetObjEntity.java new file mode 100644 index 0000000..08da4d4 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/entity/DatasetObjEntity.java @@ -0,0 +1,100 @@ +package com.kamco.cd.training.postgres.entity; + +import com.kamco.cd.training.dataset.dto.DatasetObjDto; +import com.kamco.cd.training.dataset.dto.DatasetObjDto.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.time.ZonedDateTime; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; + +@Getter +@Setter +@Entity +@Table(name = "tb_dataset_obj") +public class DatasetObjEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "obj_id", nullable = false) + private Long objId; + + @NotNull + @Column(name = "dataset_uid", nullable = false) + private Long datasetUid; + + @Column(name = "target_yyyy") + private Integer targetYyyy; + + @Size(max = 255) + @Column(name = "target_class_cd") + private String targetClassCd; + + @Column(name = "compare_yyyy") + private Integer compareYyyy; + + @Size(max = 255) + @Column(name = "compare_class_cd") + private String compareClassCd; + + @Size(max = 255) + @Column(name = "target_path") + private String targetPath; + + @Size(max = 255) + @Column(name = "compare_path") + private String comparePath; + + @Size(max = 255) + @Column(name = "label_path") + private String labelPath; + + @Size(max = 255) + @Column(name = "geojson_path") + private String geojsonPath; + + @Size(max = 255) + @Column(name = "map_sheet_num") + private String mapSheetNum; + + @ColumnDefault("now()") + @Column(name = "created_dttm") + private ZonedDateTime createdDttm; + + @Column(name = "created_uid") + private Long createdUid; + + @ColumnDefault("false") + @Column(name = "deleted") + private Boolean deleted; + + @Column(name = "uuid") + private UUID uuid; + + public Basic toDto() { + return new DatasetObjDto.Basic( + this.objId, + this.datasetUid, + this.targetYyyy, + this.targetClassCd, + this.compareYyyy, + this.compareClassCd, + this.targetPath, + this.comparePath, + this.labelPath, + this.geojsonPath, + this.mapSheetNum, + this.createdDttm, + this.createdUid, + this.deleted, + this.uuid); + } +} diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetObjRepository.java b/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetObjRepository.java new file mode 100644 index 0000000..040ae80 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetObjRepository.java @@ -0,0 +1,7 @@ +package com.kamco.cd.training.postgres.repository.dataset; + +import com.kamco.cd.training.postgres.entity.DatasetObjEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface DatasetObjRepository + extends JpaRepository, DatasetObjRepositoryCustom {} diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetObjRepositoryCustom.java b/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetObjRepositoryCustom.java new file mode 100644 index 0000000..6ba4674 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetObjRepositoryCustom.java @@ -0,0 +1,14 @@ +package com.kamco.cd.training.postgres.repository.dataset; + +import com.kamco.cd.training.dataset.dto.DatasetObjDto.SearchReq; +import com.kamco.cd.training.postgres.entity.DatasetObjEntity; +import java.util.Optional; +import java.util.UUID; +import org.springframework.data.domain.Page; + +public interface DatasetObjRepositoryCustom { + + Optional findByUuid(UUID id); + + Page searchDatasetObjectList(SearchReq searchReq); +} diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetObjRepositoryImpl.java b/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetObjRepositoryImpl.java new file mode 100644 index 0000000..a3402d0 --- /dev/null +++ b/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetObjRepositoryImpl.java @@ -0,0 +1,97 @@ +package com.kamco.cd.training.postgres.repository.dataset; + +import static com.kamco.cd.training.postgres.entity.QDatasetEntity.datasetEntity; +import static com.kamco.cd.training.postgres.entity.QDatasetObjEntity.datasetObjEntity; + +import com.kamco.cd.training.dataset.dto.DatasetObjDto.SearchReq; +import com.kamco.cd.training.postgres.entity.DatasetEntity; +import com.kamco.cd.training.postgres.entity.DatasetObjEntity; +import com.kamco.cd.training.postgres.entity.QDatasetEntity; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityNotFoundException; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class DatasetObjRepositoryImpl implements DatasetObjRepositoryCustom { + + private final JPAQueryFactory queryFactory; + private final QDatasetEntity dataset = datasetEntity; + + @Override + public Optional findByUuid(UUID id) { + return Optional.ofNullable( + queryFactory + .select(datasetObjEntity) + .from(datasetObjEntity) + .where(datasetObjEntity.uuid.eq(id), datasetObjEntity.deleted.isFalse()) + .fetchOne()); + } + + @Override + public Page searchDatasetObjectList(SearchReq searchReq) { + Pageable pageable = searchReq.toPageable(); + BooleanBuilder builder = new BooleanBuilder(); + + if (searchReq.getCompareYyyy() != null) { + builder.and(datasetObjEntity.compareYyyy.eq(searchReq.getCompareYyyy())); + } + if (searchReq.getTargetYyyy() != null) { + builder.and(datasetObjEntity.targetYyyy.eq(searchReq.getTargetYyyy())); + } + if (StringUtils.isNotBlank(searchReq.getCompareClassCd())) { + builder.and(datasetObjEntity.compareClassCd.eq(searchReq.getCompareClassCd())); + } + if (StringUtils.isNotBlank(searchReq.getTargetClassCd())) { + builder.and(datasetObjEntity.targetClassCd.eq(searchReq.getTargetClassCd())); + } + if (StringUtils.isNotBlank(searchReq.getMapSheetNum())) { + builder.and(datasetObjEntity.mapSheetNum.eq(searchReq.getMapSheetNum())); + } + + DatasetEntity entity = + queryFactory + .selectFrom(datasetEntity) + .where(datasetEntity.uuid.eq(searchReq.getUuid())) + .fetchOne(); + + if (Objects.isNull(entity)) { + throw new EntityNotFoundException("DatasetEntity not found for uuid: " + searchReq.getUuid()); + } + + List content = + queryFactory + .selectFrom(datasetObjEntity) + .where( + datasetObjEntity + .deleted + .isFalse() + .and(datasetObjEntity.datasetUid.eq(entity.getId())) + .and(builder)) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); + + // Count 쿼리 별도 실행 (null safe handling) + long total = + Optional.ofNullable( + queryFactory + .select(datasetObjEntity.count()) + .from(datasetObjEntity) + .where(datasetObjEntity.deleted.isFalse().and(builder)) + .fetchOne()) + .orElse(0L); + + return new PageImpl<>(content, pageable, total); + } +} diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetRepositoryCustom.java b/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetRepositoryCustom.java index 80831bc..33a2624 100644 --- a/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetRepositoryCustom.java @@ -1,7 +1,9 @@ package com.kamco.cd.training.postgres.repository.dataset; import com.kamco.cd.training.dataset.dto.DatasetDto; +import com.kamco.cd.training.dataset.dto.DatasetDto.SelectDataSet; import com.kamco.cd.training.postgres.entity.DatasetEntity; +import java.util.List; import java.util.Optional; import java.util.UUID; import org.springframework.data.domain.Page; @@ -10,4 +12,8 @@ public interface DatasetRepositoryCustom { Page findDatasetList(DatasetDto.SearchReq searchReq); Optional findByUuid(UUID id); + + List getDatasetSelectM1List(String modelType, String selectType); + + List getDatasetSelectM2M3List(String modelType, String selectType); } diff --git a/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetRepositoryImpl.java b/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetRepositoryImpl.java index daca00d..aa6a54e 100644 --- a/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/training/postgres/repository/dataset/DatasetRepositoryImpl.java @@ -1,9 +1,15 @@ package com.kamco.cd.training.postgres.repository.dataset; +import static com.kamco.cd.training.postgres.entity.QDatasetObjEntity.datasetObjEntity; + import com.kamco.cd.training.dataset.dto.DatasetDto; +import com.kamco.cd.training.dataset.dto.DatasetDto.SelectDataSet; import com.kamco.cd.training.postgres.entity.DatasetEntity; import com.kamco.cd.training.postgres.entity.QDatasetEntity; import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.CaseBuilder; +import com.querydsl.core.types.dsl.NumberExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.List; import java.util.Optional; @@ -72,4 +78,100 @@ public class DatasetRepositoryImpl implements DatasetRepositoryCustom { .where(dataset.uuid.eq(id), dataset.deleted.isFalse()) .fetchOne()); } + + @Override + public List getDatasetSelectM1List(String modelType, String selectType) { + + BooleanBuilder builder = new BooleanBuilder(); + + if (StringUtils.isNotBlank(selectType) && !"CURRENT".equals(selectType)) { + builder.and(dataset.groupTitle.eq(selectType)); + } + + return queryFactory + .select( + Projections.constructor( + SelectDataSet.class, + dataset.id, + dataset.uuid, + dataset.groupTitle, + dataset.title, + dataset.roundNo, + dataset.memo, + new CaseBuilder() + .when(datasetObjEntity.targetClassCd.eq("building")) + .then(1) + .otherwise(0) + .sum(), + new CaseBuilder() + .when(datasetObjEntity.targetClassCd.eq("container")) + .then(1) + .otherwise(0) + .sum())) + .from(dataset) + .leftJoin(datasetObjEntity) + .on(dataset.id.eq(datasetObjEntity.datasetUid)) + .where(builder) // datasetObjEntity.targetClassCd.in("building", "container").and( + .groupBy( + dataset.id, + dataset.uuid, + dataset.groupTitle, + dataset.title, + dataset.roundNo, + dataset.memo) + .orderBy(dataset.createdDttm.desc()) + .fetch(); + } + + @Override + public List getDatasetSelectM2M3List(String modelType, String selectType) { + + BooleanBuilder builder = new BooleanBuilder(); + + NumberExpression selectedCnt; + NumberExpression wasteCnt = + datasetObjEntity.targetClassCd.when("waste").then(1L).otherwise(0L).sum(); + + NumberExpression elseCnt = + new CaseBuilder() + .when(datasetObjEntity.targetClassCd.notIn("building", "container", "waste")) + .then(1L) + .otherwise(0L) + .sum(); + + if (modelType.equals("M2")) { + selectedCnt = wasteCnt; + } else { + selectedCnt = elseCnt; + } + + if (StringUtils.isNotBlank(selectType) && !"CURRENT".equals(selectType)) { + builder.and(dataset.groupTitle.eq(selectType)); + } + + return queryFactory + .select( + Projections.constructor( + SelectDataSet.class, + dataset.id, + dataset.uuid, + dataset.groupTitle, + dataset.title, + dataset.roundNo, + dataset.memo, + selectedCnt.as("cnt"))) + .from(dataset) + .leftJoin(datasetObjEntity) + .on(dataset.id.eq(datasetObjEntity.datasetUid)) + .where(builder) + .groupBy( + dataset.id, + dataset.uuid, + dataset.groupTitle, + dataset.title, + dataset.roundNo, + dataset.memo) + .orderBy(dataset.createdDttm.desc()) + .fetch(); + } }