Merge remote-tracking branch 'origin/feat/dev_251201' into feat/dev_251201

# Conflicts:
#	src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/FileDto.java
#	src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java
#	src/main/java/com/kamco/cd/kamcoback/postgres/entity/CommonCodeEntity.java
This commit is contained in:
2025-12-03 18:50:34 +09:00
13 changed files with 366 additions and 95 deletions

View File

@@ -27,6 +27,10 @@ public class CommonCodeDto {
private int order; private int order;
private boolean used; private boolean used;
private Long parentId; private Long parentId;
private String props1;
private String props2;
private String props3;
} }
@Schema(name = "CodeModifyReq", description = "공통코드 수정 정보") @Schema(name = "CodeModifyReq", description = "공통코드 수정 정보")
@@ -35,10 +39,15 @@ public class CommonCodeDto {
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public static class ModifyReq { public static class ModifyReq {
@NotEmpty private String code;
@NotEmpty private String name; @NotEmpty private String name;
private String description; private String description;
private int order; private int order;
private boolean used; private boolean used;
private String props1;
private String props2;
private String props3;
} }
@Schema(name = "CodeOrderReq", description = "공통코드 순서 변경 정보") @Schema(name = "CodeOrderReq", description = "공통코드 순서 변경 정보")
@@ -77,6 +86,10 @@ public class CommonCodeDto {
@JsonFormatDttm private ZonedDateTime updatedDttm; @JsonFormatDttm private ZonedDateTime updatedDttm;
private String props1;
private String props2;
private String props3;
public Basic( public Basic(
Long id, Long id,
String code, String code,
@@ -87,7 +100,11 @@ public class CommonCodeDto {
Boolean deleted, Boolean deleted,
List<CommonCodeDto.Basic> children, List<CommonCodeDto.Basic> children,
ZonedDateTime createdDttm, ZonedDateTime createdDttm,
ZonedDateTime updatedDttm) { ZonedDateTime updatedDttm,
String props1,
String props2,
String props3
) {
this.id = id; this.id = id;
this.code = code; this.code = code;
this.description = description; this.description = description;
@@ -98,6 +115,9 @@ public class CommonCodeDto {
this.children = children; this.children = children;
this.createdDttm = createdDttm; this.createdDttm = createdDttm;
this.updatedDttm = updatedDttm; this.updatedDttm = updatedDttm;
this.props1 = props1;
this.props2 = props2;
this.props3 = props3;
} }
} }
} }

View File

@@ -19,6 +19,7 @@ import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotReadableException;
@@ -287,6 +288,29 @@ public class GlobalExceptionHandler {
errorLog.getId()); errorLog.getId());
} }
@ResponseStatus(HttpStatus.CONFLICT)
@ExceptionHandler(DuplicateKeyException.class)
public ApiResponseDto<String> 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) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(RuntimeException.class) @ExceptionHandler(RuntimeException.class)
public ApiResponseDto<String> handlerRuntimeException( public ApiResponseDto<String> handlerRuntimeException(

View File

@@ -22,8 +22,8 @@ public class GeoJsonMonitorConfig {
/** 처리 실패 파일을 이동할 폴더 경로 */ /** 처리 실패 파일을 이동할 폴더 경로 */
private String errorDirectory = "~/geojson/error"; private String errorDirectory = "~/geojson/error";
/** 파일 모니터링 스케줄 (cron 표현식) 기본값: 매 30초마다 실행 */ /** 파일 모니터링 스케줄 (cron 표현식) 기본값: 매 1분마다 실행 */
private String cronExpression = "0/30 * * * * *"; private String cronExpression = "0 * * * * *";
/** 지원하는 압축파일 확장자 */ /** 지원하는 압축파일 확장자 */
private String[] supportedExtensions = {"zip", "tar", "tar.gz", "tgz"}; private String[] supportedExtensions = {"zip", "tar", "tar.gz", "tgz"};

View File

@@ -27,43 +27,57 @@ public class GeoJsonDataService {
private final GeoJsonReader geoJsonReader = new GeoJsonReader(); private final GeoJsonReader geoJsonReader = new GeoJsonReader();
/** GeoJSON 파일들을 데이터베이스에 저장 */ /** GeoJSON 파일들을 데이터베이스에 저장 */
@Transactional
public List<Long> processGeoJsonFiles( public List<Long> processGeoJsonFiles(
Map<String, String> geoJsonContents, String archiveFileName) { Map<String, String> geoJsonContents, String archiveFileName) {
List<Long> savedIds = new ArrayList<>(); List<Long> savedIds = new ArrayList<>();
log.info("GeoJSON 파일 처리 시작: {} ({}개 파일)", archiveFileName, geoJsonContents.size()); log.info("GeoJSON 파일 처리 시작: {} ({}개 파일)", archiveFileName, geoJsonContents.size());
// 개별 파일별로 독립적인 트랜잭션으로 처리
for (Map.Entry<String, String> entry : geoJsonContents.entrySet()) { for (Map.Entry<String, String> entry : geoJsonContents.entrySet()) {
String fileName = entry.getKey(); String fileName = entry.getKey();
String geoJsonContent = entry.getValue(); String geoJsonContent = entry.getValue();
try { try {
Long savedId = processGeoJsonFile(fileName, geoJsonContent, archiveFileName); Long savedId = processGeoJsonFileWithTransaction(fileName, geoJsonContent, archiveFileName);
if (savedId != null) { if (savedId != null) {
savedIds.add(savedId); savedIds.add(savedId);
log.debug("GeoJSON 파일 저장 성공: {} (ID: {})", fileName, savedId); log.debug("GeoJSON 파일 저장 성공: {} (ID: {})", fileName, savedId);
// 학습 모델 결과 파일인지 확인하여 geometry 데이터 처리
if (isLearningModelResult(fileName, geoJsonContent)) {
processLearningModelGeometry(savedId, geoJsonContent, fileName);
}
} }
} catch (Exception e) { } catch (Exception e) {
log.error("GeoJSON 파일 처리 실패: {}", fileName, e); log.error("GeoJSON 파일 처리 실패: {}", fileName, e);
// 개별 파일 처리 실패는 전체 처리를 중단시키지 않음 // 개별 파일 처리 실패는 전체 처리를 중단시키지 않음
} }
// 메모리 정리
System.gc();
} }
log.info( log.info(
"GeoJSON 파일 처리 완료: {} (성공: {}개, 전체: {}개)", "GeoJSON 파일 처리 완료: {} (성공: {}개, 전체: {}개)",
archiveFileName, archiveFileName,
savedIds.size(), savedIds.size(),
geoJsonContents.size()); geoJsonContents.size());
return savedIds; 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로 변환하여 저장 */ /** 개별 GeoJSON 파일을 MapSheetLearnDataEntity로 변환하여 저장 */
private Long processGeoJsonFile(String fileName, String geoJsonContent, String archiveFileName) { private Long processGeoJsonFile(String fileName, String geoJsonContent, String archiveFileName) {
try { try {
@@ -74,7 +88,7 @@ public class GeoJsonDataService {
// 파일이 이미 처리되었는지 확인 // 파일이 이미 처리되었는지 확인
String dataPath = generateDataPath(archiveFileName, fileName); String dataPath = generateDataPath(archiveFileName, fileName);
Optional<MapSheetLearnDataEntity> existingData = Optional<MapSheetLearnDataEntity> existingData =
mapSheetLearnDataRepository.findByDataPath(dataPath); mapSheetLearnDataRepository.findByDataPath(dataPath);
if (existingData.isPresent()) { if (existingData.isPresent()) {
log.warn("이미 처리된 파일입니다: {}", dataPath); log.warn("이미 처리된 파일입니다: {}", dataPath);
@@ -83,7 +97,7 @@ public class GeoJsonDataService {
// 새 엔티티 생성 및 저장 // 새 엔티티 생성 및 저장
MapSheetLearnDataEntity entity = MapSheetLearnDataEntity entity =
createMapSheetLearnDataEntity(fileName, geoJsonContent, archiveFileName, geoJsonNode); createMapSheetLearnDataEntity(fileName, geoJsonContent, archiveFileName, geoJsonNode);
MapSheetLearnDataEntity savedEntity = mapSheetLearnDataRepository.save(entity); MapSheetLearnDataEntity savedEntity = mapSheetLearnDataRepository.save(entity);
return savedEntity.getId(); return savedEntity.getId();
@@ -108,7 +122,7 @@ public class GeoJsonDataService {
/** MapSheetLearnDataEntity 생성 */ /** MapSheetLearnDataEntity 생성 */
private MapSheetLearnDataEntity createMapSheetLearnDataEntity( private MapSheetLearnDataEntity createMapSheetLearnDataEntity(
String fileName, String geoJsonContent, String archiveFileName, JsonNode geoJsonNode) { String fileName, String geoJsonContent, String archiveFileName, JsonNode geoJsonNode) {
MapSheetLearnDataEntity entity = new MapSheetLearnDataEntity(); MapSheetLearnDataEntity entity = new MapSheetLearnDataEntity();
@@ -273,8 +287,8 @@ public class GeoJsonDataService {
JsonNode properties = firstFeature.get("properties"); JsonNode properties = firstFeature.get("properties");
// 학습 모델 특화 필드 확인 // 학습 모델 특화 필드 확인
return properties.has("cd_prob") return properties.has("cd_prob")
|| properties.has("class") || properties.has("class")
|| (properties.has("before") && properties.has("after")); || (properties.has("before") && properties.has("after"));
} }
} }
} }
@@ -285,9 +299,9 @@ public class GeoJsonDataService {
return false; return false;
} }
/** 학습 모델 결과의 geometry 데이터 처리 */ /** 학습 모델 결과의 geometry 데이터 처리 - 최적화된 배치 처리 */
@Transactional public void processLearningModelGeometryOptimized(
public void processLearningModelGeometry(Long dataUid, String geoJsonContent, String fileName) { Long dataUid, String geoJsonContent, String fileName) {
try { try {
log.info("학습 모델 geometry 데이터 처리 시작: {} (dataUid: {})", fileName, dataUid); log.info("학습 모델 geometry 데이터 처리 시작: {} (dataUid: {})", fileName, dataUid);
@@ -295,7 +309,7 @@ public class GeoJsonDataService {
// 메타데이터 추출 // 메타데이터 추출
String mapSheetName = 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) // 파일명에서 연도 및 지도번호 추출 (캠코_2021_2022_35813023)
String[] parts = mapSheetName.split("_"); String[] parts = mapSheetName.split("_");
@@ -318,36 +332,75 @@ public class GeoJsonDataService {
return; return;
} }
List<MapSheetLearnDataGeomEntity> geomEntities = new ArrayList<>(); // 소규모 배치로 나누어 처리
int totalFeatures = features.size();
int batchSize = 10; // 작은 배치 크기
int processedCount = 0; int processedCount = 0;
for (JsonNode feature : features) { log.info("총 {}개 feature를 {}개씩 배치로 나누어 처리", totalFeatures, batchSize);
try {
MapSheetLearnDataGeomEntity geomEntity = for (int i = 0; i < totalFeatures; i += batchSize) {
int endIndex = Math.min(i + batchSize, totalFeatures);
List<MapSheetLearnDataGeomEntity> batch = new ArrayList<>();
for (int j = i; j < endIndex; j++) {
try {
JsonNode feature = features.get(j);
MapSheetLearnDataGeomEntity geomEntity =
createGeometryEntity(feature, dataUid, beforeYear, afterYear, mapSheetNum); createGeometryEntity(feature, dataUid, beforeYear, afterYear, mapSheetNum);
if (geomEntity != null) { if (geomEntity != null) {
geomEntities.add(geomEntity); batch.add(geomEntity);
processedCount++; }
} 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();
} }
// 배치 저장 log.info("학습 모델 geometry 데이터 저장 완료: {} ({}개 feature)", fileName, processedCount);
if (!geomEntities.isEmpty()) {
mapSheetLearnDataGeomRepository.saveAll(geomEntities);
log.info("학습 모델 geometry 데이터 저장 완료: {} ({}개 feature)", fileName, geomEntities.size());
}
} catch (Exception e) { } catch (Exception e) {
log.error("학습 모델 geometry 데이터 처리 실패: {}", fileName, 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<MapSheetLearnDataGeomEntity> 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 생성 */ /** 개별 feature에서 geometry entity 생성 */
private MapSheetLearnDataGeomEntity createGeometryEntity( 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 properties = feature.get("properties");
JsonNode geometry = feature.get("geometry"); JsonNode geometry = feature.get("geometry");

View File

@@ -67,6 +67,27 @@ public class MapSheetMngApiController {
return ApiResponseDto.createOK(mapSheetMngService.getFilesAll(srchDto)); 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<FilesDto> getAllFiles(@RequestBody SrchFilesDto srchDto) {
return ApiResponseDto.createOK(mapSheetMngService.getFilesDepthAll(srchDto));
}
/** /**
* 오류데이터 목록 조회 * 오류데이터 목록 조회
* *

View File

@@ -23,10 +23,15 @@ public class FileDto {
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public static class SrchFilesDto { public static class SrchFilesDto {
@Schema(description = "디렉토리경로", example = "/data")
@NotNull private String dirPath; @NotNull private String dirPath;
@Schema(description = "전체(*), cpg,dbf,geojson등", example = "*")
@NotNull private String extension; @NotNull private String extension;
@Schema(description = "파일명(name), 최종수정일(date)", example = "name")
@NotNull private String sortType; @NotNull private String sortType;
@Schema(description = "파일시작위치", example = "1")
@NotNull private Integer startPos; @NotNull private Integer startPos;
@Schema(description = "파일종료위치", example = "100")
@NotNull private Integer endPos; @NotNull private Integer endPos;
} }
@@ -43,14 +48,14 @@ public class FileDto {
private final Boolean isValid; private final Boolean isValid;
public FolderDto( public FolderDto(
String folderNm, String folderNm,
String parentFolderNm, String parentFolderNm,
String parentPath, String parentPath,
String fullPath, String fullPath,
int depth, int depth,
long childCnt, long childCnt,
String lastModified, String lastModified,
Boolean isValid) { Boolean isValid) {
this.folderNm = folderNm; this.folderNm = folderNm;
this.parentFolderNm = parentFolderNm; this.parentFolderNm = parentFolderNm;
this.parentPath = parentPath; this.parentPath = parentPath;
@@ -70,8 +75,7 @@ public class FileDto {
private final int folderErrTotCnt; private final int folderErrTotCnt;
private final List<FolderDto> folders; private final List<FolderDto> folders;
public FoldersDto( public FoldersDto(String dirPath, int folderTotCnt, int folderErrTotCnt, List<FolderDto> folders) {
String dirPath, int folderTotCnt, int folderErrTotCnt, List<FolderDto> folders) {
this.dirPath = dirPath; this.dirPath = dirPath;
this.folderTotCnt = folderTotCnt; this.folderTotCnt = folderTotCnt;
@@ -80,20 +84,26 @@ public class FileDto {
} }
} }
@Schema(name = "File Basic", description = "파일 기본 정보") @Schema(name = "File Basic", description = "파일 기본 정보")
@Getter @Getter
public static class Basic { public static class Basic {
private final String fileNm; 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 String extension;
private final long fileSize; private final long fileSize;
private final String lastModified; private final String lastModified;
public Basic( 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.fileNm = fileNm;
this.filePath = filePath; this.parentFolderNm = parentFolderNm;
this.parentPath = parentPath;
this.fullPath = fullPath;
this.extension = extension; this.extension = extension;
this.fileSize = fileSize; this.fileSize = fileSize;
this.lastModified = lastModified; this.lastModified = lastModified;

View File

@@ -37,6 +37,7 @@ public class MapSheetMngService {
private final MapSheetMngCoreService mapSheetMngCoreService; private final MapSheetMngCoreService mapSheetMngCoreService;
public FoldersDto getFolderAll(SrchFoldersDto srchDto) { public FoldersDto getFolderAll(SrchFoldersDto srchDto) {
Path startPath = Paths.get(srchDto.getDirPath()); Path startPath = Paths.get(srchDto.getDirPath());
@@ -66,11 +67,8 @@ public class MapSheetMngService {
String parentPath = path.getParent().toString(); String parentPath = path.getParent().toString();
String fullPath = path.toAbsolutePath().toString(); String fullPath = path.toAbsolutePath().toString();
boolean isValid = true; boolean isValid = !NameValidator.containsKorean(folderNm) &&
if (NameValidator.containsKorean(folderNm) !NameValidator.containsWhitespaceRegex(folderNm);
|| NameValidator.containsWhitespaceRegex(folderNm)) {
isValid = false;
}
File directory = new File(fullPath); File directory = new File(fullPath);
File[] childFolders = directory.listFiles(File::isDirectory); File[] childFolders = directory.listFiles(File::isDirectory);
@@ -81,26 +79,24 @@ public class MapSheetMngService {
} }
FileTime time = null; FileTime time = null;
String lastModified = "";
try { try {
time = Files.getLastModifiedTime(path); time = Files.getLastModifiedTime(path);
lastModified = dttmFormat.format(new Date(time.toMillis()));
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
String lastModified = dttmFormat.format(new Date(time.toMillis())); return new FolderDto(
folderNm,
FolderDto folderDto = parentFolderNm,
new FolderDto( parentPath,
folderNm, fullPath,
parentFolderNm, depth,
parentPath, childCnt,
fullPath, lastModified,
depth, isValid
childCnt, );
lastModified,
isValid);
return folderDto;
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
@@ -112,19 +108,17 @@ public class MapSheetMngService {
folderTotCnt = folderDtoList.size(); folderTotCnt = folderDtoList.size();
folderErrTotCnt = folderErrTotCnt = (int)folderDtoList.stream()
(int) .filter(dto -> dto.getIsValid().toString().equals("false") )
folderDtoList.stream() .count();
.filter(dto -> dto.getIsValid().toString().equals("false"))
.count();
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); 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) { public FilesDto getFilesAll(SrchFilesDto srchDto) {
@@ -161,12 +155,17 @@ public class MapSheetMngService {
// 생성자를 통해 객체를 만들고 리스트에 추가 // 생성자를 통해 객체를 만들고 리스트에 추가
String fileName = file.getName(); String fileName = file.getName();
String filePath = file.getAbsolutePath(); String parentPath = file.getParent();
String fullPath = file.getAbsolutePath();
String ext = FilenameUtils.getExtension(fileName); String ext = FilenameUtils.getExtension(fileName);
Path path = Paths.get(parentPath);
String parentFolderNm = path.getFileName().toString();
long fileSize = file.length(); long fileSize = file.length();
String lastModified = dttmFormat.format(new Date(file.lastModified())); 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; fileTotCnt = fileTotCnt + 1;
fileTotSize = fileTotSize + fileSize; fileTotSize = fileTotSize + fileSize;
@@ -181,6 +180,61 @@ public class MapSheetMngService {
return filesDto; 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<FileDto.Basic> fileDtoList = new ArrayList<>();
SimpleDateFormat dttmFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
int fileTotCnt = 0;
long fileTotSize = 0;
try (Stream<Path> 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<MapSheetMngDto.ErrorDataDto> findMapSheetErrorList( public Page<MapSheetMngDto.ErrorDataDto> findMapSheetErrorList(
MapSheetMngDto.@Valid searchReq searchReq) { MapSheetMngDto.@Valid searchReq searchReq) {
return mapSheetMngCoreService.findMapSheetErrorList(searchReq); return mapSheetMngCoreService.findMapSheetErrorList(searchReq);

View File

@@ -10,6 +10,7 @@ import jakarta.persistence.EntityNotFoundException;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -34,16 +35,21 @@ public class CommonCodeCoreService
new EntityNotFoundException( new EntityNotFoundException(
"parent id 를 찾을 수 없습니다. id : " + req.getParentId())); "parent id 를 찾을 수 없습니다. id : " + req.getParentId()));
Long existsCount = commonCodeRepository.findByParentIdCodeExists(req.getParentId(), req.getCode());
if (existsCount > 0) {
throw new DuplicateKeyException("이미 등록되어 있습니다.");
}
CommonCodeEntity entity = CommonCodeEntity entity =
new CommonCodeEntity( 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); entity.addParent(parentCommonCodeEntity);
return commonCodeRepository.save(entity).toDto(); return commonCodeRepository.save(entity).toDto();
} }
CommonCodeEntity entity = CommonCodeEntity entity =
new CommonCodeEntity( 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(); return commonCodeRepository.save(entity).toDto();
} }
@@ -53,14 +59,25 @@ public class CommonCodeCoreService
.findByCodeId(id) .findByCodeId(id)
.orElseThrow(() -> new EntityNotFoundException("common code 를 찾을 수 없습니다. id : " + 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 = CommonCodeEntity entity =
new CommonCodeEntity( new CommonCodeEntity(
id, id,
req.getCode(),
req.getName(), req.getName(),
req.getDescription(), req.getDescription(),
req.getOrder(), req.getOrder(),
req.isUsed(), req.isUsed(),
found.getDeleted()); found.getDeleted(),
req.getProps1(),
req.getProps2(),
req.getProps3()
);
return commonCodeRepository.save(entity).toDto(); return commonCodeRepository.save(entity).toDto();
} }

View File

@@ -61,37 +61,60 @@ public class CommonCodeEntity extends CommonDateEntity {
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL) @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<CommonCodeEntity> children = new ArrayList<>(); private List<CommonCodeEntity> 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( 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.code = code;
this.name = name; this.name = name;
this.description = description; this.description = description;
this.order = order; this.order = order;
this.used = used; this.used = used;
this.props1 = props1;
this.props2 = props2;
this.props3 = props3;
} }
public CommonCodeEntity( 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.id = id;
this.code = code;
this.name = name; this.name = name;
this.description = description; this.description = description;
this.order = order; this.order = order;
this.used = used; this.used = used;
this.deleted = deleted; this.deleted = deleted;
this.props1 = props1;
this.props2 = props2;
this.props3 = props3;
} }
public CommonCodeDto.Basic toDto() { public CommonCodeDto.Basic toDto() {
return new CommonCodeDto.Basic( return new CommonCodeDto.Basic(
this.id, this.id,
this.code, this.code,
this.description, this.description,
this.name, this.name,
this.order, this.order,
this.used, this.used,
this.deleted, this.deleted,
this.children.stream().map(CommonCodeEntity::toDto).toList(), this.children.stream().map(CommonCodeEntity::toDto).toList(),
super.getCreatedDate(), super.getCreatedDate(),
super.getModifiedDate()); super.getModifiedDate(),
this.props1,
this.props2,
this.props3
);
} }
public void addParent(CommonCodeEntity parent) { public void addParent(CommonCodeEntity parent) {

View File

@@ -2,7 +2,10 @@ package com.kamco.cd.kamcoback.postgres.entity;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
@@ -20,6 +23,11 @@ import org.hibernate.type.SqlTypes;
public class MapSheetLearnDataEntity { public class MapSheetLearnDataEntity {
@Id @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) @Column(name = "data_uid", nullable = false)
private Long id; private Long id;

View File

@@ -2,7 +2,10 @@ package com.kamco.cd.kamcoback.postgres.entity;
import jakarta.persistence.Column; import jakarta.persistence.Column;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
@@ -17,6 +20,13 @@ import org.locationtech.jts.geom.Geometry;
public class MapSheetLearnDataGeomEntity { public class MapSheetLearnDataGeomEntity {
@Id @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) @Column(name = "geo_uid", nullable = false)
private Long id; private Long id;

View File

@@ -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.code.dto.CommonCodeDto;
import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity; import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity;
import jakarta.validation.constraints.NotEmpty;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@@ -15,4 +17,8 @@ public interface CommonCodeRepositoryCustom {
void updateOrder(CommonCodeDto.OrderReq req); void updateOrder(CommonCodeDto.OrderReq req);
Optional<String> getCode(String parentCodeCd, String childCodeCd); Optional<String> getCode(String parentCodeCd, String childCodeCd);
Long findByParentIdCodeExists(Long parentId, @NotEmpty String code);
Long findByParentIdCodeExiststoUpdate(Long id, Long parentId, @NotEmpty String code);
} }

View File

@@ -96,6 +96,31 @@ public class CommonCodeRepositoryImpl implements CommonCodeRepositoryCustom {
return Optional.ofNullable(result); 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<CommonCodeEntity> findAllByIds(Set<Long> ids) { private List<CommonCodeEntity> findAllByIds(Set<Long> ids) {
return queryFactory return queryFactory
.selectFrom(commonCodeEntity) .selectFrom(commonCodeEntity)