From 46de8c223a4260f36c647227411d0a2968afa734 Mon Sep 17 00:00:00 2001 From: "gayoun.park" Date: Wed, 3 Dec 2025 16:36:31 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=EA=B3=B5=ED=86=B5=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=BB=AC=EB=9F=BC=20=EC=B6=94=EA=B0=80,=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=EB=8F=84=20=EC=A0=80=EC=9E=A5,=EC=88=98=EC=A0=95=ED=95=A0=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=88=EA=B2=8C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cd/kamcoback/code/dto/CommonCodeDto.java | 22 +++++++++++++- .../config/GlobalExceptionHandler.java | 24 +++++++++++++++ .../postgres/core/CommonCodeCoreService.java | 23 +++++++++++++-- .../postgres/entity/CommonCodeEntity.java | 29 +++++++++++++++++-- .../code/CommonCodeRepositoryCustom.java | 6 ++++ .../code/CommonCodeRepositoryImpl.java | 25 ++++++++++++++++ 6 files changed, 122 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/code/dto/CommonCodeDto.java b/src/main/java/com/kamco/cd/kamcoback/code/dto/CommonCodeDto.java index 0c8c5c48..46c35eb5 100644 --- a/src/main/java/com/kamco/cd/kamcoback/code/dto/CommonCodeDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/code/dto/CommonCodeDto.java @@ -27,6 +27,10 @@ public class CommonCodeDto { private int order; private boolean used; private Long parentId; + + private String props1; + private String props2; + private String props3; } @Schema(name = "CodeModifyReq", description = "공통코드 수정 정보") @@ -35,10 +39,15 @@ public class CommonCodeDto { @NoArgsConstructor @AllArgsConstructor public static class ModifyReq { + @NotEmpty private String code; @NotEmpty private String name; private String description; private int order; private boolean used; + + private String props1; + private String props2; + private String props3; } @Schema(name = "CodeOrderReq", description = "공통코드 순서 변경 정보") @@ -77,6 +86,10 @@ public class CommonCodeDto { @JsonFormatDttm private ZonedDateTime updatedDttm; + private String props1; + private String props2; + private String props3; + public Basic( Long id, String code, @@ -87,7 +100,11 @@ public class CommonCodeDto { Boolean deleted, List children, ZonedDateTime createdDttm, - ZonedDateTime updatedDttm) { + ZonedDateTime updatedDttm, + String props1, + String props2, + String props3 + ) { this.id = id; this.code = code; this.description = description; @@ -98,6 +115,9 @@ public class CommonCodeDto { this.children = children; this.createdDttm = createdDttm; this.updatedDttm = updatedDttm; + this.props1 = props1; + this.props2 = props2; + this.props3 = props3; } } } diff --git a/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java b/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java index 76e349c1..eab9775e 100644 --- a/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java +++ b/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java @@ -18,6 +18,7 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.DuplicateKeyException; import org.springframework.http.HttpStatus; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.bind.MethodArgumentNotValidException; @@ -285,6 +286,29 @@ public class GlobalExceptionHandler { errorLog.getId()); } + @ResponseStatus(HttpStatus.CONFLICT) + @ExceptionHandler(DuplicateKeyException.class) + public ApiResponseDto handlerDuplicateKeyException( + DuplicateKeyException e, HttpServletRequest request) { + log.warn("[DuplicateKeyException] resource :{} ", e.getMessage()); + + String codeName = "DUPLICATE_DATA"; + + ErrorLogEntity errorLog = + saveErrerLogData( + request, + ApiResponseCode.getCode(codeName), + HttpStatus.valueOf("CONFLICT"), + ErrorLogDto.LogErrorLevel.WARNING, + e.getStackTrace()); + + return ApiResponseDto.createException( + ApiResponseCode.getCode(codeName), + ApiResponseCode.getMessage(codeName), + HttpStatus.valueOf("CONFLICT"), + errorLog.getId()); + } + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(RuntimeException.class) public ApiResponseDto handlerRuntimeException( diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/CommonCodeCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/CommonCodeCoreService.java index 156a1bad..a2b14051 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/CommonCodeCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/CommonCodeCoreService.java @@ -10,6 +10,7 @@ import jakarta.persistence.EntityNotFoundException; import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; +import org.springframework.dao.DuplicateKeyException; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; @@ -34,16 +35,21 @@ public class CommonCodeCoreService new EntityNotFoundException( "parent id 를 찾을 수 없습니다. id : " + req.getParentId())); + Long existsCount = commonCodeRepository.findByParentIdCodeExists(req.getParentId(), req.getCode()); + if (existsCount > 0) { + throw new DuplicateKeyException("이미 등록되어 있습니다."); + } + CommonCodeEntity entity = new CommonCodeEntity( - req.getCode(), req.getName(), req.getDescription(), req.getOrder(), req.isUsed()); + req.getCode(), req.getName(), req.getDescription(), req.getOrder(), req.isUsed(), req.getProps1(), req.getProps2(), req.getProps3()); entity.addParent(parentCommonCodeEntity); return commonCodeRepository.save(entity).toDto(); } CommonCodeEntity entity = new CommonCodeEntity( - req.getCode(), req.getName(), req.getDescription(), req.getOrder(), req.isUsed()); + req.getCode(), req.getName(), req.getDescription(), req.getOrder(), req.isUsed(), req.getProps1(), req.getProps2(), req.getProps3()); return commonCodeRepository.save(entity).toDto(); } @@ -53,14 +59,25 @@ public class CommonCodeCoreService .findByCodeId(id) .orElseThrow(() -> new EntityNotFoundException("common code 를 찾을 수 없습니다. id : " + id)); + Long parentId = found.getParent() == null ? null : found.getParent().getId(); + Long existsCount = commonCodeRepository.findByParentIdCodeExiststoUpdate(id, parentId, req.getCode()); + if (existsCount > 0) { + throw new DuplicateKeyException("이미 등록되어 있습니다."); + } + CommonCodeEntity entity = new CommonCodeEntity( id, + req.getCode(), req.getName(), req.getDescription(), req.getOrder(), req.isUsed(), - found.getDeleted()); + found.getDeleted(), + req.getProps1(), + req.getProps2(), + req.getProps3() + ); return commonCodeRepository.save(entity).toDto(); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/CommonCodeEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/CommonCodeEntity.java index 3971d8fd..9344ccbd 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/CommonCodeEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/CommonCodeEntity.java @@ -61,23 +61,42 @@ public class CommonCodeEntity extends CommonDateEntity { @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL) private List children = new ArrayList<>(); + @Size(max = 255) + @Column(name = "props1") + private String props1; + + @Size(max = 255) + @Column(name = "props2") + private String props2; + + @Size(max = 255) + @Column(name = "props3") + private String props3; + public CommonCodeEntity( - String code, String name, String description, Integer order, Boolean used) { + String code, String name, String description, Integer order, Boolean used, String props1, String props2, String props3) { this.code = code; this.name = name; this.description = description; this.order = order; this.used = used; + this.props1 = props1; + this.props2 = props2; + this.props3 = props3; } public CommonCodeEntity( - Long id, String name, String description, Integer order, Boolean used, Boolean deleted) { + Long id, String code, String name, String description, Integer order, Boolean used, Boolean deleted, String props1, String props2, String props3) { this.id = id; + this.code = code; this.name = name; this.description = description; this.order = order; this.used = used; this.deleted = deleted; + this.props1 = props1; + this.props2 = props2; + this.props3 = props3; } public CommonCodeDto.Basic toDto() { @@ -91,7 +110,11 @@ public class CommonCodeEntity extends CommonDateEntity { this.deleted, this.children.stream().map(CommonCodeEntity::toDto).toList(), super.getCreatedDate(), - super.getModifiedDate()); + super.getModifiedDate(), + this.props1, + this.props2, + this.props3 + ); } public void addParent(CommonCodeEntity parent) { diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/code/CommonCodeRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/code/CommonCodeRepositoryCustom.java index 974b2073..232d8866 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/code/CommonCodeRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/code/CommonCodeRepositoryCustom.java @@ -2,6 +2,8 @@ package com.kamco.cd.kamcoback.postgres.repository.code; import com.kamco.cd.kamcoback.code.dto.CommonCodeDto; import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity; +import jakarta.validation.constraints.NotEmpty; + import java.util.List; import java.util.Optional; @@ -15,4 +17,8 @@ public interface CommonCodeRepositoryCustom { void updateOrder(CommonCodeDto.OrderReq req); Optional getCode(String parentCodeCd, String childCodeCd); + + Long findByParentIdCodeExists(Long parentId, @NotEmpty String code); + + Long findByParentIdCodeExiststoUpdate(Long id, Long parentId, @NotEmpty String code); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/code/CommonCodeRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/code/CommonCodeRepositoryImpl.java index 560f64c4..90d97d3d 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/code/CommonCodeRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/code/CommonCodeRepositoryImpl.java @@ -96,6 +96,31 @@ public class CommonCodeRepositoryImpl implements CommonCodeRepositoryCustom { return Optional.ofNullable(result); } + @Override + public Long findByParentIdCodeExists(Long parentId, String code) { + return queryFactory + .select(commonCodeEntity.code.count()) + .from(commonCodeEntity) + .where( + commonCodeEntity.parent.id.eq(parentId), + commonCodeEntity.code.eq(code) + ) + .fetchOne(); + } + + @Override + public Long findByParentIdCodeExiststoUpdate(Long id, Long parentId, String code) { + return queryFactory + .select(commonCodeEntity.code.count()) + .from(commonCodeEntity) + .where( + commonCodeEntity.parent.id.eq(parentId), + commonCodeEntity.code.eq(code), + commonCodeEntity.id.ne(id) + ) + .fetchOne(); + } + private List findAllByIds(Set ids) { return queryFactory .selectFrom(commonCodeEntity) From 527167611b1d39faf5eff908e249fafa6f1c71ff Mon Sep 17 00:00:00 2001 From: DanielLee <198891672+sanghyeonhd@users.noreply.github.com> Date: Wed, 3 Dec 2025 17:11:09 +0900 Subject: [PATCH 2/3] Geojson File Data Type Change to Apply - Daniel C No.11 --- .../geojson/config/GeoJsonMonitorConfig.java | 4 +- .../geojson/service/GeoJsonDataService.java | 125 +++++++++++++----- .../entity/MapSheetLearnDataEntity.java | 8 ++ .../entity/MapSheetLearnDataGeomEntity.java | 10 ++ 4 files changed, 109 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/geojson/config/GeoJsonMonitorConfig.java b/src/main/java/com/kamco/cd/kamcoback/geojson/config/GeoJsonMonitorConfig.java index cf99cd49..93c55425 100644 --- a/src/main/java/com/kamco/cd/kamcoback/geojson/config/GeoJsonMonitorConfig.java +++ b/src/main/java/com/kamco/cd/kamcoback/geojson/config/GeoJsonMonitorConfig.java @@ -22,8 +22,8 @@ public class GeoJsonMonitorConfig { /** 처리 실패 파일을 이동할 폴더 경로 */ private String errorDirectory = "~/geojson/error"; - /** 파일 모니터링 스케줄 (cron 표현식) 기본값: 매 30초마다 실행 */ - private String cronExpression = "0/30 * * * * *"; + /** 파일 모니터링 스케줄 (cron 표현식) 기본값: 매 1분마다 실행 */ + private String cronExpression = "0 * * * * *"; /** 지원하는 압축파일 확장자 */ private String[] supportedExtensions = {"zip", "tar", "tar.gz", "tgz"}; diff --git a/src/main/java/com/kamco/cd/kamcoback/geojson/service/GeoJsonDataService.java b/src/main/java/com/kamco/cd/kamcoback/geojson/service/GeoJsonDataService.java index 5659a3ac..273db83c 100644 --- a/src/main/java/com/kamco/cd/kamcoback/geojson/service/GeoJsonDataService.java +++ b/src/main/java/com/kamco/cd/kamcoback/geojson/service/GeoJsonDataService.java @@ -27,43 +27,57 @@ public class GeoJsonDataService { private final GeoJsonReader geoJsonReader = new GeoJsonReader(); /** GeoJSON 파일들을 데이터베이스에 저장 */ - @Transactional public List processGeoJsonFiles( - Map geoJsonContents, String archiveFileName) { + Map geoJsonContents, String archiveFileName) { List savedIds = new ArrayList<>(); log.info("GeoJSON 파일 처리 시작: {} ({}개 파일)", archiveFileName, geoJsonContents.size()); + // 개별 파일별로 독립적인 트랜잭션으로 처리 for (Map.Entry entry : geoJsonContents.entrySet()) { String fileName = entry.getKey(); String geoJsonContent = entry.getValue(); try { - Long savedId = processGeoJsonFile(fileName, geoJsonContent, archiveFileName); + Long savedId = processGeoJsonFileWithTransaction(fileName, geoJsonContent, archiveFileName); if (savedId != null) { savedIds.add(savedId); log.debug("GeoJSON 파일 저장 성공: {} (ID: {})", fileName, savedId); - - // 학습 모델 결과 파일인지 확인하여 geometry 데이터 처리 - if (isLearningModelResult(fileName, geoJsonContent)) { - processLearningModelGeometry(savedId, geoJsonContent, fileName); - } } } catch (Exception e) { log.error("GeoJSON 파일 처리 실패: {}", fileName, e); // 개별 파일 처리 실패는 전체 처리를 중단시키지 않음 } + + // 메모리 정리 + System.gc(); } log.info( - "GeoJSON 파일 처리 완료: {} (성공: {}개, 전체: {}개)", - archiveFileName, - savedIds.size(), - geoJsonContents.size()); + "GeoJSON 파일 처리 완료: {} (성공: {}개, 전체: {}개)", + archiveFileName, + savedIds.size(), + geoJsonContents.size()); return savedIds; } + /** 개별 파일을 별도 트랜잭션으로 처리 */ + @Transactional + public Long processGeoJsonFileWithTransaction( + String fileName, String geoJsonContent, String archiveFileName) { + try { + Long savedId = processGeoJsonFile(fileName, geoJsonContent, archiveFileName); + if (savedId != null && isLearningModelResult(fileName, geoJsonContent)) { + processLearningModelGeometryOptimized(savedId, geoJsonContent, fileName); + } + return savedId; + } catch (Exception e) { + log.error("파일 처리 중 트랜잭션 에러: {}", fileName, e); + throw e; // 트랜잭션 롤백을 위해 재throw + } + } + /** 개별 GeoJSON 파일을 MapSheetLearnDataEntity로 변환하여 저장 */ private Long processGeoJsonFile(String fileName, String geoJsonContent, String archiveFileName) { try { @@ -74,7 +88,7 @@ public class GeoJsonDataService { // 파일이 이미 처리되었는지 확인 String dataPath = generateDataPath(archiveFileName, fileName); Optional existingData = - mapSheetLearnDataRepository.findByDataPath(dataPath); + mapSheetLearnDataRepository.findByDataPath(dataPath); if (existingData.isPresent()) { log.warn("이미 처리된 파일입니다: {}", dataPath); @@ -83,7 +97,7 @@ public class GeoJsonDataService { // 새 엔티티 생성 및 저장 MapSheetLearnDataEntity entity = - createMapSheetLearnDataEntity(fileName, geoJsonContent, archiveFileName, geoJsonNode); + createMapSheetLearnDataEntity(fileName, geoJsonContent, archiveFileName, geoJsonNode); MapSheetLearnDataEntity savedEntity = mapSheetLearnDataRepository.save(entity); return savedEntity.getId(); @@ -108,7 +122,7 @@ public class GeoJsonDataService { /** MapSheetLearnDataEntity 생성 */ private MapSheetLearnDataEntity createMapSheetLearnDataEntity( - String fileName, String geoJsonContent, String archiveFileName, JsonNode geoJsonNode) { + String fileName, String geoJsonContent, String archiveFileName, JsonNode geoJsonNode) { MapSheetLearnDataEntity entity = new MapSheetLearnDataEntity(); @@ -273,8 +287,8 @@ public class GeoJsonDataService { JsonNode properties = firstFeature.get("properties"); // 학습 모델 특화 필드 확인 return properties.has("cd_prob") - || properties.has("class") - || (properties.has("before") && properties.has("after")); + || properties.has("class") + || (properties.has("before") && properties.has("after")); } } } @@ -285,9 +299,9 @@ public class GeoJsonDataService { return false; } - /** 학습 모델 결과의 geometry 데이터 처리 */ - @Transactional - public void processLearningModelGeometry(Long dataUid, String geoJsonContent, String fileName) { + /** 학습 모델 결과의 geometry 데이터 처리 - 최적화된 배치 처리 */ + public void processLearningModelGeometryOptimized( + Long dataUid, String geoJsonContent, String fileName) { try { log.info("학습 모델 geometry 데이터 처리 시작: {} (dataUid: {})", fileName, dataUid); @@ -295,7 +309,7 @@ public class GeoJsonDataService { // 메타데이터 추출 String mapSheetName = - rootNode.has("name") ? rootNode.get("name").asText() : fileName.replace(".geojson", ""); + rootNode.has("name") ? rootNode.get("name").asText() : fileName.replace(".geojson", ""); // 파일명에서 연도 및 지도번호 추출 (캠코_2021_2022_35813023) String[] parts = mapSheetName.split("_"); @@ -318,36 +332,75 @@ public class GeoJsonDataService { return; } - List geomEntities = new ArrayList<>(); + // 소규모 배치로 나누어 처리 + int totalFeatures = features.size(); + int batchSize = 10; // 작은 배치 크기 int processedCount = 0; - for (JsonNode feature : features) { - try { - MapSheetLearnDataGeomEntity geomEntity = + log.info("총 {}개 feature를 {}개씩 배치로 나누어 처리", totalFeatures, batchSize); + + for (int i = 0; i < totalFeatures; i += batchSize) { + int endIndex = Math.min(i + batchSize, totalFeatures); + List batch = new ArrayList<>(); + + for (int j = i; j < endIndex; j++) { + try { + JsonNode feature = features.get(j); + MapSheetLearnDataGeomEntity geomEntity = createGeometryEntity(feature, dataUid, beforeYear, afterYear, mapSheetNum); - if (geomEntity != null) { - geomEntities.add(geomEntity); - processedCount++; + if (geomEntity != null) { + batch.add(geomEntity); + } + } catch (Exception e) { + log.warn("Feature geometry 처리 실패 (feature {}): {}", j + 1, e.getMessage()); } - } catch (Exception e) { - log.warn("Feature geometry 처리 실패 (feature {}): {}", processedCount, e.getMessage()); } + + // 배치별 저장 + if (!batch.isEmpty()) { + saveBatchGeometry(batch); + processedCount += batch.size(); + log.debug("배치 {}-{} 처리 완료 ({}개)", i + 1, endIndex, batch.size()); + } + + // 메모리 정리 + batch.clear(); } - // 배치 저장 - if (!geomEntities.isEmpty()) { - mapSheetLearnDataGeomRepository.saveAll(geomEntities); - log.info("학습 모델 geometry 데이터 저장 완료: {} ({}개 feature)", fileName, geomEntities.size()); - } + log.info("학습 모델 geometry 데이터 저장 완료: {} ({}개 feature)", fileName, processedCount); } catch (Exception e) { log.error("학습 모델 geometry 데이터 처리 실패: {}", fileName, e); + throw new RuntimeException("Geometry 처리 실패: " + fileName, e); + } + } + + /** 배치별 geometry 저장 - 별도 트랜잭션 */ + @Transactional(propagation = org.springframework.transaction.annotation.Propagation.REQUIRES_NEW) + public void saveBatchGeometry(List batch) { + try { + if (batch == null || batch.isEmpty()) { + return; + } + mapSheetLearnDataGeomRepository.saveAll(batch); + } catch (Exception e) { + log.error("배치 geometry 저장 실패: {}", e.getMessage()); + // 개별 저장 시도 + for (MapSheetLearnDataGeomEntity entity : batch) { + try { + if (entity != null) { + mapSheetLearnDataGeomRepository.save(entity); + } + } catch (Exception individualError) { + log.warn("개별 geometry 저장 실패: {}", individualError.getMessage()); + } + } } } /** 개별 feature에서 geometry entity 생성 */ private MapSheetLearnDataGeomEntity createGeometryEntity( - JsonNode feature, Long dataUid, String beforeYear, String afterYear, String mapSheetNum) { + JsonNode feature, Long dataUid, String beforeYear, String afterYear, String mapSheetNum) { JsonNode properties = feature.get("properties"); JsonNode geometry = feature.get("geometry"); diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnDataEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnDataEntity.java index e49a1833..0224dd26 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnDataEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnDataEntity.java @@ -2,7 +2,10 @@ package com.kamco.cd.kamcoback.postgres.entity; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.SequenceGenerator; import jakarta.persistence.Table; import jakarta.validation.constraints.Size; import java.time.ZonedDateTime; @@ -20,6 +23,11 @@ import org.hibernate.type.SqlTypes; public class MapSheetLearnDataEntity { @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tb_map_sheet_learn_data_id_gen") + @SequenceGenerator( + name = "tb_map_sheet_learn_data_id_gen", + sequenceName = "tb_map_sheet_learn_data_data_uid", + allocationSize = 1) @Column(name = "data_uid", nullable = false) private Long id; diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnDataGeomEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnDataGeomEntity.java index 72ef0304..6d7cebcb 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnDataGeomEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetLearnDataGeomEntity.java @@ -2,7 +2,10 @@ package com.kamco.cd.kamcoback.postgres.entity; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.SequenceGenerator; import jakarta.persistence.Table; import jakarta.validation.constraints.Size; import java.time.ZonedDateTime; @@ -17,6 +20,13 @@ import org.locationtech.jts.geom.Geometry; public class MapSheetLearnDataGeomEntity { @Id + @GeneratedValue( + strategy = GenerationType.SEQUENCE, + generator = "tb_map_sheet_learn_data_geom_id_gen") + @SequenceGenerator( + name = "tb_map_sheet_learn_data_geom_id_gen", + sequenceName = "tb_map_sheet_learn_data_geom_geom_uid", + allocationSize = 1) @Column(name = "geo_uid", nullable = false) private Long id; From dd975f48d2cd5ab873d80b38bd755e441ba6e443 Mon Sep 17 00:00:00 2001 From: "Harry M. You" Date: Wed, 3 Dec 2025 17:45:53 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=ED=8F=B4=EB=8D=94=20validation=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 --- .../mapsheet/MapSheetMngApiController.java | 21 ++++ .../cd/kamcoback/mapsheet/dto/FileDto.java | 15 ++- .../mapsheet/service/MapSheetMngService.java | 102 +++++++++++++----- 3 files changed, 111 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiController.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiController.java index 9f860352..a5667ad5 100644 --- a/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiController.java @@ -68,6 +68,27 @@ public class MapSheetMngApiController { return ApiResponseDto.createOK(mapSheetMngService.getFilesAll(srchDto)); } + @Operation(summary = "파일목록 조회", description = "파일목록 조회") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = CommonCodeDto.Basic.class))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @PostMapping("/file-all-list") + public ApiResponseDto getAllFiles(@RequestBody SrchFilesDto srchDto) { + + return ApiResponseDto.createOK(mapSheetMngService.getFilesDepthAll(srchDto)); + } + + + /** * 오류데이터 목록 조회 * diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/FileDto.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/FileDto.java index e62f41d3..6ba902f3 100644 --- a/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/FileDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/FileDto.java @@ -23,10 +23,15 @@ public class FileDto { @NoArgsConstructor @AllArgsConstructor public static class SrchFilesDto { + @Schema(description = "디렉토리경로", example = "/data") @NotNull private String dirPath; + @Schema(description = "전체(*), cpg,dbf,geojson등", example = "*") @NotNull private String extension; + @Schema(description = "파일명(name), 최종수정일(date)", example = "name") @NotNull private String sortType; + @Schema(description = "파일시작위치", example = "1") @NotNull private Integer startPos; + @Schema(description = "파일종료위치", example = "100") @NotNull private Integer endPos; } @@ -86,15 +91,19 @@ public class FileDto { public static class Basic { private final String fileNm; - private final String filePath; + private final String parentFolderNm; + private final String parentPath; + private final String fullPath; private final String extension; private final long fileSize; private final String lastModified; public Basic( - String fileNm, String filePath, String extension, long fileSize, String lastModified) { + String fileNm, String parentFolderNm, String parentPath, String fullPath, String extension, long fileSize, String lastModified) { this.fileNm = fileNm; - this.filePath = filePath; + this.parentFolderNm = parentFolderNm; + this.parentPath = parentPath; + this.fullPath = fullPath; this.extension = extension; this.fileSize = fileSize; this.lastModified = lastModified; diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java index 764e21fa..a4785ef3 100644 --- a/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java @@ -67,11 +67,8 @@ public class MapSheetMngService { String parentPath = path.getParent().toString(); String fullPath = path.toAbsolutePath().toString(); - boolean isValid = true; - if( NameValidator.containsKorean(folderNm) || - NameValidator.containsWhitespaceRegex(folderNm) ){ - isValid = false; - } + boolean isValid = !NameValidator.containsKorean(folderNm) && + !NameValidator.containsWhitespaceRegex(folderNm); File directory = new File(fullPath); File[] childFolders = directory.listFiles(File::isDirectory); @@ -82,27 +79,24 @@ public class MapSheetMngService { } FileTime time = null; + String lastModified = ""; try { time = Files.getLastModifiedTime(path); + lastModified = dttmFormat.format(new Date(time.toMillis())); } catch (IOException e) { throw new RuntimeException(e); } - String lastModified = dttmFormat.format(new Date(time.toMillis())); - - FolderDto folderDto = - new FolderDto( - folderNm, - parentFolderNm, - parentPath, - fullPath, - depth, - childCnt, - lastModified, - isValid - ); - - return folderDto; + return new FolderDto( + folderNm, + parentFolderNm, + parentPath, + fullPath, + depth, + childCnt, + lastModified, + isValid + ); }) .collect(Collectors.toList()); @@ -122,9 +116,9 @@ public class MapSheetMngService { throw new RuntimeException(e); } - FoldersDto foldersDto = new FoldersDto(dirPath, folderTotCnt, folderErrTotCnt, folderDtoList); + // FoldersDto foldersDto = new FoldersDto(dirPath, folderTotCnt, folderErrTotCnt, folderDtoList); - return foldersDto; + return new FoldersDto(dirPath, folderTotCnt, folderErrTotCnt, folderDtoList); } public FilesDto getFilesAll(SrchFilesDto srchDto) { @@ -161,12 +155,17 @@ public class MapSheetMngService { // 생성자를 통해 객체를 만들고 리스트에 추가 String fileName = file.getName(); - String filePath = file.getAbsolutePath(); + String parentPath = file.getParent(); + String fullPath = file.getAbsolutePath(); String ext = FilenameUtils.getExtension(fileName); + + Path path = Paths.get(parentPath); + String parentFolderNm = path.getFileName().toString(); + long fileSize = file.length(); String lastModified = dttmFormat.format(new Date(file.lastModified())); - files.add(new FileDto.Basic(fileName, filePath, ext, fileSize, lastModified)); + files.add(new FileDto.Basic(fileName, parentFolderNm, parentPath, fullPath, ext, fileSize, lastModified)); fileTotCnt = fileTotCnt + 1; fileTotSize = fileTotSize + fileSize; @@ -181,6 +180,61 @@ public class MapSheetMngService { return filesDto; } + + + public FilesDto getFilesDepthAll(SrchFilesDto srchDto) { + + int maxDepth = 20; + Path startPath = Paths.get(srchDto.getDirPath()); + String dirPath = srchDto.getDirPath(); + String extension = srchDto.getExtension(); + + List fileDtoList = new ArrayList<>(); + SimpleDateFormat dttmFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + int fileTotCnt = 0; + long fileTotSize = 0; + + try (Stream stream = Files.walk(startPath, maxDepth)) { + + fileDtoList = + stream + .filter(Files::isRegularFile) + .map( + path -> { + + int depth = path.getNameCount(); + + String fileNm = path.getFileName().toString(); + String ext = FilenameUtils.getExtension(fileNm); + String parentFolderNm = path.getParent().getFileName().toString(); + String parentPath = path.getParent().toString(); + String fullPath = path.toAbsolutePath().toString(); + + File file = new File(fullPath); + long fileSize = file.length(); + String lastModified = dttmFormat.format(new Date(file.lastModified())); + + return new FileDto.Basic(fileNm, parentFolderNm, parentPath, fullPath, ext, fileSize, lastModified); + }) + .collect(Collectors.toList()); + + fileTotCnt = fileDtoList.size(); + fileTotSize = fileDtoList.stream() + .mapToLong(FileDto.Basic::getFileSize) + .sum(); + + } catch (IOException e) { + System.err.println("파일 I/O 오류 발생: " + e.getMessage()); + } + + + FilesDto filesDto = new FilesDto(dirPath, fileTotCnt, fileTotSize, fileDtoList); + + return filesDto; + } + + public Page findMapSheetErrorList( MapSheetMngDto.@Valid searchReq searchReq) { return mapSheetMngCoreService.findMapSheetErrorList(searchReq);