From 767bea7da50ca406ccd41b64dd110de6053070c5 Mon Sep 17 00:00:00 2001 From: DanielLee <198891672+sanghyeonhd@users.noreply.github.com> Date: Wed, 14 Jan 2026 11:57:49 +0900 Subject: [PATCH] =?UTF-8?q?Detail=20=EB=8B=A4=EC=A4=91=EC=A1=B0=ED=9A=8C,?= =?UTF-8?q?=20ploygon=20=EB=8B=A4=EC=A4=91=EC=A0=80=EC=9E=A5=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TrainingDataLabelRepositoryImpl.java | 24 ++- .../TrainingDataReviewRepositoryImpl.java | 24 ++- .../TrainingDataLabelApiController.java | 158 +++++++++++++++++- .../TrainingDataReviewApiController.java | 158 +++++++++++++++++- 4 files changed, 350 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataLabelRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataLabelRepositoryImpl.java index daf56651..9a0b3f34 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataLabelRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataLabelRepositoryImpl.java @@ -638,6 +638,16 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport + " new polygon(s) for mapSheetNum: " + request.getMapSheetNum()); + // mapSheetNum을 Long으로 변환 + Long mapSheetNumLong = null; + try { + if (request.getMapSheetNum() != null && !request.getMapSheetNum().isEmpty()) { + mapSheetNumLong = Long.parseLong(request.getMapSheetNum()); + } + } catch (NumberFormatException e) { + System.err.println("Invalid mapSheetNum format: " + request.getMapSheetNum()); + } + int savedCount = 0; for (TrainingDataLabelDto.NewPolygonRequest.PolygonFeature feature : request.getFeatures()) { try { @@ -650,6 +660,8 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport mapSheetAnalDataInferenceGeomEntity.targetYyyy, mapSheetAnalDataInferenceGeomEntity.classBeforeCd, mapSheetAnalDataInferenceGeomEntity.classAfterCd, + mapSheetAnalDataInferenceGeomEntity.dataUid, + mapSheetAnalDataInferenceGeomEntity.mapSheetNum, mapSheetAnalDataInferenceGeomEntity.createdDttm, mapSheetAnalDataInferenceGeomEntity.updatedDttm, mapSheetAnalDataInferenceGeomEntity.labelState) @@ -659,20 +671,25 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport request.getTargetYyyy(), feature.getProperties().getBeforeClass().toLowerCase(), feature.getProperties().getAfterClass().toLowerCase(), + request.getAnalUid(), + mapSheetNumLong, ZonedDateTime.now(), ZonedDateTime.now(), "DONE") .execute(); - // 2. 생성된 geoUid 조회 + // 2. 생성된 geoUid 조회 (가장 최근에 삽입된 레코드) Long geoUid = queryFactory .select(mapSheetAnalDataInferenceGeomEntity.geoUid) .from(mapSheetAnalDataInferenceGeomEntity) .where( - mapSheetAnalDataInferenceGeomEntity.geom.eq(feature.getGeometry()), mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(request.getCompareYyyy()), - mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(request.getTargetYyyy())) + mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(request.getTargetYyyy()), + mapSheetAnalDataInferenceGeomEntity.classBeforeCd.eq( + feature.getProperties().getBeforeClass().toLowerCase()), + mapSheetAnalDataInferenceGeomEntity.classAfterCd.eq( + feature.getProperties().getAfterClass().toLowerCase())) .orderBy(mapSheetAnalDataInferenceGeomEntity.geoUid.desc()) .fetchFirst(); @@ -710,6 +727,7 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport } catch (Exception e) { System.err.println("Error saving polygon #" + (savedCount + 1) + ": " + e.getMessage()); + e.printStackTrace(); // 개별 polygon 저장 실패해도 계속 진행 } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataReviewRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataReviewRepositoryImpl.java index 7a25d32e..fd3e8e4c 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataReviewRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/trainingdata/TrainingDataReviewRepositoryImpl.java @@ -660,6 +660,16 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport + " new polygon(s) for mapSheetNum: " + request.getMapSheetNum()); + // mapSheetNum을 Long으로 변환 + Long mapSheetNumLong = null; + try { + if (request.getMapSheetNum() != null && !request.getMapSheetNum().isEmpty()) { + mapSheetNumLong = Long.parseLong(request.getMapSheetNum()); + } + } catch (NumberFormatException e) { + System.err.println("Invalid mapSheetNum format: " + request.getMapSheetNum()); + } + int savedCount = 0; for (TrainingDataReviewDto.NewPolygonRequest.PolygonFeature feature : request.getFeatures()) { try { @@ -672,6 +682,8 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport mapSheetAnalDataInferenceGeomEntity.targetYyyy, mapSheetAnalDataInferenceGeomEntity.classBeforeCd, mapSheetAnalDataInferenceGeomEntity.classAfterCd, + mapSheetAnalDataInferenceGeomEntity.dataUid, + mapSheetAnalDataInferenceGeomEntity.mapSheetNum, mapSheetAnalDataInferenceGeomEntity.createdDttm, mapSheetAnalDataInferenceGeomEntity.updatedDttm, mapSheetAnalDataInferenceGeomEntity.labelState) @@ -681,20 +693,25 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport request.getTargetYyyy(), feature.getProperties().getBeforeClass().toLowerCase(), feature.getProperties().getAfterClass().toLowerCase(), + request.getAnalUid(), + mapSheetNumLong, ZonedDateTime.now(), ZonedDateTime.now(), "DONE") .execute(); - // 2. 생성된 geoUid 조회 + // 2. 생성된 geoUid 조회 (가장 최근에 삽입된 레코드) Long geoUid = queryFactory .select(mapSheetAnalDataInferenceGeomEntity.geoUid) .from(mapSheetAnalDataInferenceGeomEntity) .where( - mapSheetAnalDataInferenceGeomEntity.geom.eq(feature.getGeometry()), mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(request.getCompareYyyy()), - mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(request.getTargetYyyy())) + mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(request.getTargetYyyy()), + mapSheetAnalDataInferenceGeomEntity.classBeforeCd.eq( + feature.getProperties().getBeforeClass().toLowerCase()), + mapSheetAnalDataInferenceGeomEntity.classAfterCd.eq( + feature.getProperties().getAfterClass().toLowerCase())) .orderBy(mapSheetAnalDataInferenceGeomEntity.geoUid.desc()) .fetchFirst(); @@ -732,6 +749,7 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport } catch (Exception e) { System.err.println("Error saving polygon #" + (savedCount + 1) + ": " + e.getMessage()); + e.printStackTrace(); // 개별 polygon 저장 실패해도 계속 진행 } } diff --git a/src/main/java/com/kamco/cd/kamcoback/trainingdata/TrainingDataLabelApiController.java b/src/main/java/com/kamco/cd/kamcoback/trainingdata/TrainingDataLabelApiController.java index 3bc98ff1..76f6b710 100644 --- a/src/main/java/com/kamco/cd/kamcoback/trainingdata/TrainingDataLabelApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/trainingdata/TrainingDataLabelApiController.java @@ -132,7 +132,9 @@ public class TrainingDataLabelApiController { } } - @Operation(summary = "변화탐지정보 및 실태조사결과 조회", description = "선택한 작업의 변화탐지정보 및 실태조사결과를 조회합니다.") + @Operation( + summary = "변화탐지정보 및 실태조사결과 조회", + description = "선택한 작업의 변화탐지정보 및 실태조사결과를 조회합니다. 저장된 여러 개의 polygon을 조회할 수 있습니다.") @ApiResponses( value = { @ApiResponse( @@ -141,7 +143,155 @@ public class TrainingDataLabelApiController { content = @Content( mediaType = "application/json", - schema = @Schema(implementation = TrainingDataLabelDto.DetailRes.class))), + schema = @Schema(implementation = TrainingDataLabelDto.DetailRes.class), + examples = { + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "단일 polygon 조회", + description = "1개의 polygon이 저장된 경우 응답 예시", + value = + """ + { + "code": "OK", + "message": null, + "data": { + "assignmentUid": "4f9ebc8b-6635-4177-b42f-7efc9c7b4c02", + "changeDetectionInfo": { + "mapSheetInfo": "NI52-3-13-1", + "detectionYear": "2023-2024", + "beforeClass": { + "classification": "waste", + "probability": 0.95 + }, + "afterClass": { + "classification": "land", + "probability": 0.98 + }, + "area": 1250.5, + "detectionAccuracy": 0.96, + "pnu": 1234567890 + }, + "inspectionResultInfo": { + "verificationResult": "완료", + "inappropriateReason": "" + }, + "geom": { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[126.663, 34.588], [126.662, 34.587], [126.664, 34.589], [126.663, 34.588]]] + }, + "properties": { + "beforeClass": "waste", + "afterClass": "land" + } + }, + "beforeCogUrl": "https://storage.example.com/cog/2023/NI52-3-13-1.tif", + "afterCogUrl": "https://storage.example.com/cog/2024/NI52-3-13-1.tif", + "mapBox": { + "type": "Polygon", + "coordinates": [[[126.65, 34.58], [126.67, 34.58], [126.67, 34.60], [126.65, 34.60], [126.65, 34.58]]] + }, + "learnGeometries": [ + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[126.663, 34.588], [126.662, 34.587], [126.664, 34.589], [126.663, 34.588]]] + }, + "properties": { + "beforeClass": "waste", + "afterClass": "land" + } + } + ] + } + } + """), + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "여러 polygon 조회", + description = "3개의 polygon이 저장된 경우 응답 예시", + value = + """ + { + "code": "OK", + "message": null, + "data": { + "assignmentUid": "4f9ebc8b-6635-4177-b42f-7efc9c7b4c02", + "changeDetectionInfo": { + "mapSheetInfo": "NI52-3-13-1", + "detectionYear": "2023-2024", + "beforeClass": { + "classification": "waste", + "probability": 0.95 + }, + "afterClass": { + "classification": "land", + "probability": 0.98 + }, + "area": 1250.5, + "detectionAccuracy": 0.96, + "pnu": 1234567890 + }, + "inspectionResultInfo": { + "verificationResult": "완료", + "inappropriateReason": "" + }, + "geom": { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[126.663, 34.588], [126.662, 34.587], [126.664, 34.589], [126.663, 34.588]]] + }, + "properties": { + "beforeClass": "waste", + "afterClass": "land" + } + }, + "beforeCogUrl": "https://storage.example.com/cog/2023/NI52-3-13-1.tif", + "afterCogUrl": "https://storage.example.com/cog/2024/NI52-3-13-1.tif", + "mapBox": { + "type": "Polygon", + "coordinates": [[[126.65, 34.58], [126.67, 34.58], [126.67, 34.60], [126.65, 34.60], [126.65, 34.58]]] + }, + "learnGeometries": [ + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[126.663, 34.588], [126.662, 34.587], [126.664, 34.589], [126.663, 34.588]]] + }, + "properties": { + "beforeClass": "waste", + "afterClass": "land" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[126.665, 34.585], [126.664, 34.584], [126.666, 34.586], [126.665, 34.585]]] + }, + "properties": { + "beforeClass": "forest", + "afterClass": "building" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[126.660, 34.590], [126.659, 34.589], [126.661, 34.591], [126.660, 34.590]]] + }, + "properties": { + "beforeClass": "grassland", + "afterClass": "concrete" + } + } + ] + } + } + """) + })), @ApiResponse(responseCode = "400", description = "잘못된 요청", content = @Content), @ApiResponse(responseCode = "404", description = "데이터를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @@ -151,8 +301,8 @@ public class TrainingDataLabelApiController { @io.swagger.v3.oas.annotations.Parameter( description = "작업 배정 ID (UUID)", required = true, - example = "93c56be8-0246-4b22-b976-2476549733cc") - @RequestParam + example = "4f9ebc8b-6635-4177-b42f-7efc9c7b4c02") + @RequestParam(defaultValue = "4f9ebc8b-6635-4177-b42f-7efc9c7b4c02") java.util.UUID assignmentUid) { return ApiResponseDto.ok(trainingDataLabelService.getDetail(assignmentUid)); } diff --git a/src/main/java/com/kamco/cd/kamcoback/trainingdata/TrainingDataReviewApiController.java b/src/main/java/com/kamco/cd/kamcoback/trainingdata/TrainingDataReviewApiController.java index 8febf996..2b26ef3b 100644 --- a/src/main/java/com/kamco/cd/kamcoback/trainingdata/TrainingDataReviewApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/trainingdata/TrainingDataReviewApiController.java @@ -132,7 +132,9 @@ public class TrainingDataReviewApiController { } } - @Operation(summary = "변화탐지정보 및 실태조사결과 조회", description = "선택한 작업의 변화탐지정보 및 실태조사결과를 조회합니다.") + @Operation( + summary = "변화탐지정보 및 실태조사결과 조회", + description = "선택한 작업의 변화탐지정보 및 실태조사결과를 조회합니다. 저장된 여러 개의 polygon을 조회할 수 있습니다.") @ApiResponses( value = { @ApiResponse( @@ -141,7 +143,155 @@ public class TrainingDataReviewApiController { content = @Content( mediaType = "application/json", - schema = @Schema(implementation = TrainingDataReviewDto.DetailRes.class))), + schema = @Schema(implementation = TrainingDataReviewDto.DetailRes.class), + examples = { + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "단일 polygon 조회", + description = "1개의 polygon이 저장된 경우 응답 예시", + value = + """ + { + "code": "OK", + "message": null, + "data": { + "operatorUid": "4f9ebc8b-6635-4177-b42f-7efc9c7b4c02", + "changeDetectionInfo": { + "mapSheetInfo": "NI52-3-13-1", + "detectionYear": "2023-2024", + "beforeClass": { + "classification": "waste", + "probability": 0.95 + }, + "afterClass": { + "classification": "land", + "probability": 0.98 + }, + "area": 1250.5, + "detectionAccuracy": 0.96, + "pnu": 1234567890 + }, + "inspectionResultInfo": { + "verificationResult": "완료", + "inappropriateReason": "" + }, + "geom": { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[126.663, 34.588], [126.662, 34.587], [126.664, 34.589], [126.663, 34.588]]] + }, + "properties": { + "beforeClass": "waste", + "afterClass": "land" + } + }, + "beforeCogUrl": "https://storage.example.com/cog/2023/NI52-3-13-1.tif", + "afterCogUrl": "https://storage.example.com/cog/2024/NI52-3-13-1.tif", + "mapBox": { + "type": "Polygon", + "coordinates": [[[126.65, 34.58], [126.67, 34.58], [126.67, 34.60], [126.65, 34.60], [126.65, 34.58]]] + }, + "learnGeometries": [ + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[126.663, 34.588], [126.662, 34.587], [126.664, 34.589], [126.663, 34.588]]] + }, + "properties": { + "beforeClass": "waste", + "afterClass": "land" + } + } + ] + } + } + """), + @io.swagger.v3.oas.annotations.media.ExampleObject( + name = "여러 polygon 조회", + description = "3개의 polygon이 저장된 경우 응답 예시", + value = + """ + { + "code": "OK", + "message": null, + "data": { + "operatorUid": "4f9ebc8b-6635-4177-b42f-7efc9c7b4c02", + "changeDetectionInfo": { + "mapSheetInfo": "NI52-3-13-1", + "detectionYear": "2023-2024", + "beforeClass": { + "classification": "waste", + "probability": 0.95 + }, + "afterClass": { + "classification": "land", + "probability": 0.98 + }, + "area": 1250.5, + "detectionAccuracy": 0.96, + "pnu": 1234567890 + }, + "inspectionResultInfo": { + "verificationResult": "완료", + "inappropriateReason": "" + }, + "geom": { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[126.663, 34.588], [126.662, 34.587], [126.664, 34.589], [126.663, 34.588]]] + }, + "properties": { + "beforeClass": "waste", + "afterClass": "land" + } + }, + "beforeCogUrl": "https://storage.example.com/cog/2023/NI52-3-13-1.tif", + "afterCogUrl": "https://storage.example.com/cog/2024/NI52-3-13-1.tif", + "mapBox": { + "type": "Polygon", + "coordinates": [[[126.65, 34.58], [126.67, 34.58], [126.67, 34.60], [126.65, 34.60], [126.65, 34.58]]] + }, + "learnGeometries": [ + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[126.663, 34.588], [126.662, 34.587], [126.664, 34.589], [126.663, 34.588]]] + }, + "properties": { + "beforeClass": "waste", + "afterClass": "land" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[126.665, 34.585], [126.664, 34.584], [126.666, 34.586], [126.665, 34.585]]] + }, + "properties": { + "beforeClass": "forest", + "afterClass": "building" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [[[126.660, 34.590], [126.659, 34.589], [126.661, 34.591], [126.660, 34.590]]] + }, + "properties": { + "beforeClass": "grassland", + "afterClass": "concrete" + } + } + ] + } + } + """) + })), @ApiResponse(responseCode = "400", description = "잘못된 요청", content = @Content), @ApiResponse(responseCode = "404", description = "데이터를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @@ -151,8 +301,8 @@ public class TrainingDataReviewApiController { @io.swagger.v3.oas.annotations.Parameter( description = "검수 작업 ID (UUID)", required = true, - example = "93c56be8-0246-4b22-b976-2476549733cc") - @RequestParam + example = "4f9ebc8b-6635-4177-b42f-7efc9c7b4c02") + @RequestParam(defaultValue = "4f9ebc8b-6635-4177-b42f-7efc9c7b4c02") java.util.UUID operatorUid) { return ApiResponseDto.ok(trainingDataReviewService.getDetail(operatorUid)); }