코드 컨벤션 적용

This commit is contained in:
2025-11-28 09:39:11 +09:00
parent 8bab44d7e4
commit 4c1083067e
10 changed files with 211 additions and 161 deletions

View File

@@ -9,12 +9,10 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.transaction.Transactional;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.util.List;
@Tag(name = "변화탐지", description = "변화탐지 API")
@RequiredArgsConstructor
@RestController
@@ -33,34 +31,37 @@ public class ChangeDetectionApiController {
/**
* PolygonData -> JsonNode 변환 예제
*
* @return
*/
@Hidden
@GetMapping("/json-data")
public ApiResponseDto<List<JsonNode>> getPolygonToJson(){
public ApiResponseDto<List<JsonNode>> getPolygonToJson() {
return ApiResponseDto.ok(changeDetectionService.getPolygonToJson());
}
@Operation(summary = "변화탐지 분류별 건수", description = "변화탐지 분류별 건수")
@GetMapping("/class-count/{id}")
public ApiResponseDto<List<ChangeDetectionDto.CountDto>> getChangeDetectionClassCount(
@Parameter(description = "변화탐지 년도(차수) /year-list 의 analUid", example = "1") @PathVariable Long id){
@Parameter(description = "변화탐지 년도(차수) /year-list 의 analUid", example = "1") @PathVariable
Long id) {
return ApiResponseDto.ok(changeDetectionService.getChangeDetectionClassCount(id));
}
@Operation(summary = "변화탐지 COG Url", description = "변화탐지 COG Url")
@GetMapping("/cog-url")
public ApiResponseDto<ChangeDetectionDto.CogUrlDto> getChangeDetectionCogUrl(
@Parameter(description = "이전 년도", example = "2023") @RequestParam Integer beforeYear,
@Parameter(description = "이후 년도", example = "2024") @RequestParam Integer afterYear,
@Parameter(description = "도엽번호(5k)", example = "36809010") @RequestParam String mapSheetNum){
ChangeDetectionDto.CogUrlReq req = new ChangeDetectionDto.CogUrlReq(beforeYear, afterYear, mapSheetNum);
@Parameter(description = "이전 년도", example = "2023") @RequestParam Integer beforeYear,
@Parameter(description = "이후 년도", example = "2024") @RequestParam Integer afterYear,
@Parameter(description = "도엽번호(5k)", example = "36809010") @RequestParam String mapSheetNum) {
ChangeDetectionDto.CogUrlReq req =
new ChangeDetectionDto.CogUrlReq(beforeYear, afterYear, mapSheetNum);
return ApiResponseDto.ok(changeDetectionService.getChangeDetectionCogUrl(req));
}
@Operation(summary = "변화탐지 년도(차수) 목록", description = "변화탐지 년도(차수) 목록")
@GetMapping("/year-list")
public ApiResponseDto<List<ChangeDetectionDto.AnalYearList>> getChangeDetectionYearList(){
public ApiResponseDto<List<ChangeDetectionDto.AnalYearList>> getChangeDetectionYearList() {
return ApiResponseDto.ok(changeDetectionService.getChangeDetectionYearList());
}
}

View File

@@ -8,7 +8,7 @@ import lombok.NoArgsConstructor;
import lombok.Setter;
import org.locationtech.jts.geom.Geometry;
public class ChangeDetectionDto{
public class ChangeDetectionDto {
@Schema(name = "TestDto", description = "테스트용")
@Getter
@@ -18,7 +18,8 @@ public class ChangeDetectionDto{
public static class TestDto {
private Long id;
private Geometry polygon;
private Double centroidX;;
private Double centroidX;
;
private Double centroidY;
}
@@ -28,9 +29,9 @@ public class ChangeDetectionDto{
@NoArgsConstructor
@AllArgsConstructor
public static class CountDto {
private String classCd; //영문코드
private String className; //한글명
private Long count; //건수
private String classCd; // 영문코드
private String className; // 한글명
private Long count; // 건수
}
@Schema(name = "CogUrlReq", description = "COG Url Req")
@@ -73,12 +74,12 @@ public class ChangeDetectionDto{
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class PointGeometry{
public static class PointGeometry {
private Long geoUid;
private String type; // "Point"
private Geometry coordinates; //Point 값
private String before_class; //기준 분류
private String after_class; //비교 분류
private String type; // "Point"
private Geometry coordinates; // Point 값
private String before_class; // 기준 분류
private String after_class; // 비교 분류
}
@Schema(name = "PolygonGeometry", description = "폴리곤 리턴 객체")
@@ -86,12 +87,12 @@ public class ChangeDetectionDto{
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class PolygonGeometry{
public static class PolygonGeometry {
private Long geoUid;
private String type; // "MultiPolygon"
private Geometry coordinates; //Polygon 값
private Double center_latitude; //폴리곤 중심 위도
private Double center_longitude; //폴리곤 중심 경도
private String type; // "MultiPolygon"
private Geometry coordinates; // Polygon 값
private Double center_latitude; // 폴리곤 중심 위도
private Double center_longitude; // 폴리곤 중심 경도
}
@Schema(name = "PolygonProperties", description = "폴리곤 정보")
@@ -99,13 +100,13 @@ public class ChangeDetectionDto{
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class PolygonProperties{
private Double area; //면적
private String before_year; //기준년도
private Double before_confidence; //기준 신뢰도(확률)
private String before_class; //기준 분류
private String after_year; //비교년도
private Double after_confidence; //비교 신뢰도(확률)
private String after_class; //비교 분류
public static class PolygonProperties {
private Double area; // 면적
private String before_year; // 기준년도
private Double before_confidence; // 기준 신뢰도(확률)
private String before_class; // 기준 분류
private String after_year; // 비교년도
private Double after_confidence; // 비교 신뢰도(확률)
private String after_class; // 비교 분류
}
}

View File

@@ -3,7 +3,6 @@ package com.kamco.cd.kamcoback.inference.service;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetLearnDataEntity;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetLearnDataGeomEntity;
import com.kamco.cd.kamcoback.postgres.repository.MapSheetLearnDataGeomRepository;
import com.kamco.cd.kamcoback.postgres.repository.MapSheetLearnDataRepository;
import java.io.IOException;
@@ -15,7 +14,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.geojson.GeoJsonReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,9 +37,7 @@ public class LearningModelResultProcessor {
private final ObjectMapper objectMapper = new ObjectMapper();
private final GeoJsonReader geoJsonReader = new GeoJsonReader();
/**
* Process large learning model result files with optimized batch processing
*/
/** Process large learning model result files with optimized batch processing */
public int processLearningModelResultOptimized(Path geoJsonFilePath) {
try {
logger.info("Processing learning model result file (optimized): {}", geoJsonFilePath);
@@ -62,7 +58,8 @@ public class LearningModelResultProcessor {
// Extract metadata from file name and content
String fileName = geoJsonFilePath.getFileName().toString();
String mapSheetName = rootNode.has("name") ? rootNode.get("name").asText() : fileName.replace(".geojson", "");
String mapSheetName =
rootNode.has("name") ? rootNode.get("name").asText() : fileName.replace(".geojson", "");
// Parse years from filename
String[] parts = mapSheetName.split("_");
@@ -70,44 +67,58 @@ public class LearningModelResultProcessor {
if (parts.length >= 4) {
beforeYear = parts[1];
afterYear = parts[2];
afterYear = parts[2];
mapSheetNum = parts[3];
}
if (beforeYear == null || afterYear == null || mapSheetNum == null) {
throw new IllegalArgumentException("Cannot parse years and map sheet number from filename: " + fileName);
throw new IllegalArgumentException(
"Cannot parse years and map sheet number from filename: " + fileName);
}
int totalFeatures = features.size();
logger.info("Total features to process: {}", totalFeatures);
// Step 1: Create main data record first
MapSheetLearnDataEntity savedMainData = createMainDataRecord(geoJsonContent, fileName, geoJsonFilePath.toString(), beforeYear, afterYear, mapSheetNum);
MapSheetLearnDataEntity savedMainData =
createMainDataRecord(
geoJsonContent,
fileName,
geoJsonFilePath.toString(),
beforeYear,
afterYear,
mapSheetNum);
// Step 2: Process features in small batches to avoid transaction timeout
int totalProcessed = 0;
int batchSize = 25; // Smaller batch size for reliability
for (int i = 0; i < totalFeatures; i += batchSize) {
int endIndex = Math.min(i + batchSize, totalFeatures);
logger.info("Processing batch {}-{} of {}", i + 1, endIndex, totalFeatures);
List<JsonNode> batch = new ArrayList<>();
for (int j = i; j < endIndex; j++) {
batch.add(features.get(j));
}
try {
int processed = processBatchSafely(batch, savedMainData.getId(), beforeYear, afterYear, mapSheetNum);
int processed =
processBatchSafely(batch, savedMainData.getId(), beforeYear, afterYear, mapSheetNum);
totalProcessed += processed;
logger.info("Batch processed successfully. Total so far: {}/{}", totalProcessed, totalFeatures);
logger.info(
"Batch processed successfully. Total so far: {}/{}", totalProcessed, totalFeatures);
} catch (Exception e) {
logger.error("Failed to process batch {}-{}: {}", i + 1, endIndex, e.getMessage());
// Continue with next batch instead of failing completely
}
}
logger.info("Successfully processed {} out of {} features from file: {}", totalProcessed, totalFeatures, fileName);
logger.info(
"Successfully processed {} out of {} features from file: {}",
totalProcessed,
totalFeatures,
fileName);
return totalProcessed;
} catch (IOException e) {
@@ -120,32 +131,49 @@ public class LearningModelResultProcessor {
}
@Transactional
private MapSheetLearnDataEntity createMainDataRecord(String geoJsonContent, String fileName, String filePath, String beforeYear, String afterYear, String mapSheetNum) {
MapSheetLearnDataEntity mainData = createMainDataEntity(geoJsonContent, fileName, filePath, beforeYear, afterYear, mapSheetNum);
private MapSheetLearnDataEntity createMainDataRecord(
String geoJsonContent,
String fileName,
String filePath,
String beforeYear,
String afterYear,
String mapSheetNum) {
MapSheetLearnDataEntity mainData =
createMainDataEntity(
geoJsonContent, fileName, filePath, beforeYear, afterYear, mapSheetNum);
MapSheetLearnDataEntity saved = mapSheetLearnDataRepository.save(mainData);
logger.info("Created main data record with ID: {}", saved.getId());
return saved;
}
@Transactional
private int processBatchSafely(List<JsonNode> features, Long dataUid, String beforeYear, String afterYear, String mapSheetNum) {
private int processBatchSafely(
List<JsonNode> features,
Long dataUid,
String beforeYear,
String afterYear,
String mapSheetNum) {
int processed = 0;
for (JsonNode feature : features) {
try {
long geoUid = System.currentTimeMillis() + (long) (Math.random() * 10000);
insertFeatureWithPostGIS(feature, geoUid, dataUid, beforeYear, afterYear, mapSheetNum);
processed++;
// Small delay to prevent ID collisions
try { Thread.sleep(1); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
try {
Thread.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
} catch (Exception e) {
logger.warn("Failed to process individual feature: {}", e.getMessage());
// Continue processing other features in this batch
}
}
return processed;
}
@@ -214,32 +242,38 @@ public class LearningModelResultProcessor {
for (int i = 0; i < features.size(); i += batchSize) {
int endIndex = Math.min(i + batchSize, features.size());
logger.info("Processing batch {}-{} of {} features", i + 1, endIndex, features.size());
// Process each feature individually within this logging batch
for (int j = i; j < endIndex; j++) {
JsonNode feature = features.get(j);
try {
// Generate unique ID for this geometry entity
long geoUid = System.currentTimeMillis() + (long) (Math.random() * 10000) + j;
// Extract feature data and insert directly with PostGIS
insertFeatureWithPostGIS(feature, geoUid, savedMainData.getId(), beforeYear, afterYear, mapSheetNum);
insertFeatureWithPostGIS(
feature, geoUid, savedMainData.getId(), beforeYear, afterYear, mapSheetNum);
featureCount++;
// Small delay to prevent issues
if (j % 5 == 0) {
try { Thread.sleep(10); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
try {
Thread.sleep(10);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
} catch (Exception e) {
logger.warn("Failed to process feature {}: {}", j + 1, e.getMessage());
}
}
// Log progress after each batch
if (featureCount > 0 && endIndex % batchSize == 0) {
logger.info("Processed {} features so far, success rate: {:.1f}%",
featureCount, (featureCount * 100.0) / endIndex);
logger.info(
"Processed {} features so far, success rate: {:.1f}%",
featureCount, (featureCount * 100.0) / endIndex);
}
}
@@ -293,7 +327,12 @@ public class LearningModelResultProcessor {
/** Insert GeoJSON feature directly using PostGIS functions */
private void insertFeatureWithPostGIS(
JsonNode feature, Long geoUid, Long dataUid, String beforeYear, String afterYear, String mapSheetNum)
JsonNode feature,
Long geoUid,
Long dataUid,
String beforeYear,
String afterYear,
String mapSheetNum)
throws Exception {
JsonNode properties = feature.get("properties");
@@ -306,12 +345,12 @@ public class LearningModelResultProcessor {
// Extract properties
Double cdProb = properties.has("cd_prob") ? properties.get("cd_prob").asDouble() : null;
Double area = properties.has("area") ? properties.get("area").asDouble() : null;
String classBeforeName = null;
Double classBeforeProb = null;
String classAfterName = null;
Double classAfterProb = null;
// Classification data
JsonNode classNode = properties.get("class");
if (classNode != null) {
@@ -342,18 +381,26 @@ public class LearningModelResultProcessor {
// Get geometry type
String geoType = geometry.has("type") ? geometry.get("type").asText() : "Unknown";
// Convert geometry to JSON string for PostGIS
String geometryJson = geometry.toString();
// Insert using PostGIS functions
mapSheetLearnDataGeomRepository.insertWithPostGISGeometry(
geoUid, cdProb, classBeforeName, classBeforeProb,
classAfterName, classAfterProb, Long.parseLong(mapSheetNum),
Integer.parseInt(beforeYear), Integer.parseInt(afterYear),
area, geometryJson, geoType, dataUid
);
geoUid,
cdProb,
classBeforeName,
classBeforeProb,
classAfterName,
classAfterProb,
Long.parseLong(mapSheetNum),
Integer.parseInt(beforeYear),
Integer.parseInt(afterYear),
area,
geometryJson,
geoType,
dataUid);
logger.debug("Inserted geometry entity with ID: {} using PostGIS", geoUid);
}

View File

@@ -57,7 +57,8 @@ public class ChangeDetectionCoreService {
public ChangeDetectionDto.CogUrlDto getChangeDetectionCogUrl(ChangeDetectionDto.CogUrlReq req) {
ObjectMapper mapper = new ObjectMapper();
ChangeDetectionDto.CogUrlDto resultDto = changeDetectionRepository.getChangeDetectionCogUrl(req);
ChangeDetectionDto.CogUrlDto resultDto =
changeDetectionRepository.getChangeDetectionCogUrl(req);
try {
JsonNode geomNode = mapper.readTree(resultDto.getBbox().toString());

View File

@@ -1,21 +1,23 @@
package com.kamco.cd.kamcoback.postgres.entity;
import jakarta.persistence.*;
import java.time.ZonedDateTime;
import java.util.UUID;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.ColumnDefault;
import java.time.ZonedDateTime;
import java.util.UUID;
@Getter
@Setter
@Table(name = "imagery")
@Entity
public class ImageryEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "imagery_id_seq_gen")
@SequenceGenerator(name = "imagery_id_seq_gen",sequenceName = "imagery_id_seq",allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "imagery_id_seq_gen")
@SequenceGenerator(
name = "imagery_id_seq_gen",
sequenceName = "imagery_id_seq",
allocationSize = 1)
@Column(name = "id", nullable = false)
private Long id;

View File

@@ -13,9 +13,9 @@ public class MapInkx50kEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tb_map_inkx_50k_fid_seq_gen")
@SequenceGenerator(
name = "tb_map_inkx_50k_fid_seq_gen",
sequenceName = "tb_map_inkx_50k_fid_seq",
allocationSize = 1)
name = "tb_map_inkx_50k_fid_seq_gen",
sequenceName = "tb_map_inkx_50k_fid_seq",
allocationSize = 1)
private Integer fid;
@Column(name = "mapidcd_no")
@@ -29,5 +29,4 @@ public class MapInkx50kEntity {
@Column(name = "geom")
private Geometry geom;
}

View File

@@ -13,9 +13,9 @@ public class MapInkx5kEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tb_map_inkx_5k_fid_seq_gen")
@SequenceGenerator(
name = "tb_map_inkx_5k_fid_seq_gen",
sequenceName = "tb_map_inkx_5k_fid_seq",
allocationSize = 1)
name = "tb_map_inkx_5k_fid_seq_gen",
sequenceName = "tb_map_inkx_5k_fid_seq",
allocationSize = 1)
private Integer fid;
@Column(name = "mapidcd_no")

View File

@@ -29,26 +29,26 @@ public interface MapSheetLearnDataGeomRepository
/** 데이터 UID로 기존 지오메트리 데이터 삭제 (재생성 전에 사용) */
void deleteByDataUid(Long dataUid);
/**
* PostGIS 함수를 사용하여 geometry 데이터를 직접 삽입
* ST_SetSRID(ST_GeomFromGeoJSON(...), 5186) 형식으로 저장
*/
/** PostGIS 함수를 사용하여 geometry 데이터를 직접 삽입 ST_SetSRID(ST_GeomFromGeoJSON(...), 5186) 형식으로 저장 */
@Modifying
@Transactional
@Query(value = """
@Query(
value =
"""
INSERT INTO tb_map_sheet_learn_data_geom (
geo_uid, cd_prob, class_before_name, class_before_prob,
class_after_name, class_after_prob, map_sheet_num,
before_yyyy, after_yyyy, area, geom, geo_type, data_uid,
geo_uid, cd_prob, class_before_name, class_before_prob,
class_after_name, class_after_prob, map_sheet_num,
before_yyyy, after_yyyy, area, geom, geo_type, data_uid,
created_dttm, updated_dttm
) VALUES (
:geoUid, :cdProb, :classBeforeName, :classBeforeProb,
:classAfterName, :classAfterProb, :mapSheetNum,
:beforeYyyy, :afterYyyy, :area,
ST_SetSRID(ST_GeomFromGeoJSON(CAST(:geometryJson AS TEXT)), 5186),
:beforeYyyy, :afterYyyy, :area,
ST_SetSRID(ST_GeomFromGeoJSON(CAST(:geometryJson AS TEXT)), 5186),
:geoType, :dataUid, NOW(), NOW()
) ON CONFLICT (geo_uid) DO NOTHING
""", nativeQuery = true)
""",
nativeQuery = true)
void insertWithPostGISGeometry(
@Param("geoUid") Long geoUid,
@Param("cdProb") Double cdProb,
@@ -62,6 +62,5 @@ public interface MapSheetLearnDataGeomRepository
@Param("area") Double area,
@Param("geometryJson") String geometryJson,
@Param("geoType") String geoType,
@Param("dataUid") Long dataUid
);
@Param("dataUid") Long dataUid);
}

View File

@@ -1,8 +1,6 @@
package com.kamco.cd.kamcoback.postgres.repository.changedetection;
import com.kamco.cd.kamcoback.changedetection.dto.ChangeDetectionDto;
import com.querydsl.core.Tuple;
import java.util.List;
public interface ChangeDetectionRepositoryCustom {

View File

@@ -1,5 +1,12 @@
package com.kamco.cd.kamcoback.postgres.repository.changedetection;
import static com.kamco.cd.kamcoback.postgres.entity.QImageryEntity.imageryEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx5kEntity.mapInkx5kEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataEntity.mapSheetAnalDataEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataGeomEntity.mapSheetAnalDataGeomEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalEntity.mapSheetAnalEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalSttcEntity.mapSheetAnalSttcEntity;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -11,17 +18,9 @@ import com.querydsl.core.types.dsl.CaseBuilder;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.StringExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import java.util.List;
import java.util.Objects;
import static com.kamco.cd.kamcoback.postgres.entity.QImageryEntity.imageryEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx5kEntity.mapInkx5kEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataEntity.mapSheetAnalDataEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataGeomEntity.mapSheetAnalDataGeomEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalEntity.mapSheetAnalEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalSttcEntity.mapSheetAnalSttcEntity;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
public class ChangeDetectionRepositoryImpl extends QuerydslRepositorySupport
implements ChangeDetectionRepositoryCustom {
@@ -51,74 +50,77 @@ public class ChangeDetectionRepositoryImpl extends QuerydslRepositorySupport
@Override
public List<ChangeDetectionDto.CountDto> getChangeDetectionClassCount(Long id) {
return queryFactory
.select(Projections.constructor(
ChangeDetectionDto.CountDto.class,
mapSheetAnalSttcEntity.classAfterCd.toUpperCase(),
mapSheetAnalSttcEntity.id.classAfterName,
mapSheetAnalSttcEntity.classAfterCnt.sum()
))
.from(mapSheetAnalEntity)
.innerJoin(mapSheetAnalDataEntity)
.on(mapSheetAnalDataEntity.analUid.eq(mapSheetAnalEntity.id))
.innerJoin(mapSheetAnalSttcEntity)
.on(mapSheetAnalSttcEntity.dataUid.eq(mapSheetAnalDataEntity.id))
.where(mapSheetAnalEntity.id.eq(id))
.groupBy(mapSheetAnalSttcEntity.classAfterCd, mapSheetAnalSttcEntity.id.classAfterName)
.fetch();
.select(
Projections.constructor(
ChangeDetectionDto.CountDto.class,
mapSheetAnalSttcEntity.classAfterCd.toUpperCase(),
mapSheetAnalSttcEntity.id.classAfterName,
mapSheetAnalSttcEntity.classAfterCnt.sum()))
.from(mapSheetAnalEntity)
.innerJoin(mapSheetAnalDataEntity)
.on(mapSheetAnalDataEntity.analUid.eq(mapSheetAnalEntity.id))
.innerJoin(mapSheetAnalSttcEntity)
.on(mapSheetAnalSttcEntity.dataUid.eq(mapSheetAnalDataEntity.id))
.where(mapSheetAnalEntity.id.eq(id))
.groupBy(mapSheetAnalSttcEntity.classAfterCd, mapSheetAnalSttcEntity.id.classAfterName)
.fetch();
}
@Override
public ChangeDetectionDto.CogUrlDto getChangeDetectionCogUrl(ChangeDetectionDto.CogUrlReq req) {
Tuple result = queryFactory
.select(
makeCogUrl(req.getBeforeYear()).max().as("beforeCogUrl"),
makeCogUrl(req.getAfterYear()).max().as("afterCogUrl"),
Expressions.stringTemplate("ST_AsGeoJSON({0})", mapInkx5kEntity.geom).as("bbox")
)
.from(imageryEntity)
.innerJoin(mapInkx5kEntity)
.on(imageryEntity.scene5k.eq(mapInkx5kEntity.mapidcdNo))
.where(
imageryEntity.year.eq(req.getBeforeYear()).or(imageryEntity.year.eq(req.getAfterYear())),
imageryEntity.scene5k.eq(req.getMapSheetNum())
)
.groupBy(mapInkx5kEntity.geom)
.fetchOne();
Tuple result =
queryFactory
.select(
makeCogUrl(req.getBeforeYear()).max().as("beforeCogUrl"),
makeCogUrl(req.getAfterYear()).max().as("afterCogUrl"),
Expressions.stringTemplate("ST_AsGeoJSON({0})", mapInkx5kEntity.geom).as("bbox"))
.from(imageryEntity)
.innerJoin(mapInkx5kEntity)
.on(imageryEntity.scene5k.eq(mapInkx5kEntity.mapidcdNo))
.where(
imageryEntity
.year
.eq(req.getBeforeYear())
.or(imageryEntity.year.eq(req.getAfterYear())),
imageryEntity.scene5k.eq(req.getMapSheetNum()))
.groupBy(mapInkx5kEntity.geom)
.fetchOne();
//Polygon -> JsonNode 로 변환
JsonNode geometryJson = changeGeometryJson(String.valueOf(Objects.requireNonNull(result).get(2, StringExpression.class)));
// Polygon -> JsonNode 로 변환
JsonNode geometryJson =
changeGeometryJson(
String.valueOf(Objects.requireNonNull(result).get(2, StringExpression.class)));
return new ChangeDetectionDto.CogUrlDto(result.get(0, String.class), result.get(1, String.class), geometryJson);
return new ChangeDetectionDto.CogUrlDto(
result.get(0, String.class), result.get(1, String.class), geometryJson);
}
@Override
public List<ChangeDetectionDto.AnalYearList> getChangeDetectionYearList() {
return queryFactory
.select(
Projections.constructor(
ChangeDetectionDto.AnalYearList.class,
mapSheetAnalEntity.id,
mapSheetAnalEntity.analTitle,
mapSheetAnalEntity.compareYyyy.as("beforeYear"),
mapSheetAnalEntity.targetYyyy.as("afterYear"),
mapSheetAnalEntity.baseMapSheetNum
)
)
Projections.constructor(
ChangeDetectionDto.AnalYearList.class,
mapSheetAnalEntity.id,
mapSheetAnalEntity.analTitle,
mapSheetAnalEntity.compareYyyy.as("beforeYear"),
mapSheetAnalEntity.targetYyyy.as("afterYear"),
mapSheetAnalEntity.baseMapSheetNum))
.from(mapSheetAnalEntity)
.orderBy(mapSheetAnalEntity.id.asc())
.fetch()
;
.fetch();
}
private StringExpression makeCogUrl(Integer year) {
return new CaseBuilder()
.when(imageryEntity.year.eq(year))
.then(Expressions.stringTemplate("{0} || {1}",imageryEntity.cogMiddlePath, imageryEntity.cogFilename))
.otherwise("")
;
.when(imageryEntity.year.eq(year))
.then(
Expressions.stringTemplate(
"{0} || {1}", imageryEntity.cogMiddlePath, imageryEntity.cogFilename))
.otherwise("");
}
private JsonNode changeGeometryJson(String geometry){
private JsonNode changeGeometryJson(String geometry) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readTree(geometry);