파일생성 추가

This commit is contained in:
2025-12-26 10:23:03 +09:00
parent 8e6b41c9ad
commit baffb147d9
15 changed files with 183 additions and 248 deletions

View File

@@ -2,7 +2,6 @@ package com.kamco.cd.kamcoback.common.utils;
import static java.lang.String.CASE_INSENSITIVE_ORDER;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.DmlReturn;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.BufferedReader;
import java.io.File;
@@ -457,15 +456,13 @@ public class FIleChecker {
return FIleChecker.getFilesFromAllDepth(dir, targetFileNm, extension, 100, "name", 0, 100);
}
public static int getFileCountFromAllDepth(
String dir, String targetFileNm, String extension) {
public static int getFileCountFromAllDepth(String dir, String targetFileNm, String extension) {
List<FIleChecker.Basic> basicList =
FIleChecker.getFilesFromAllDepth(dir, targetFileNm, extension);
FIleChecker.getFilesFromAllDepth(dir, targetFileNm, extension);
return (int) basicList.stream()
.filter(dto -> dto.getExtension().toString().equals(extension))
.count();
return (int)
basicList.stream().filter(dto -> dto.getExtension().toString().equals(extension)).count();
}
public static Long getFileTotSize(List<FIleChecker.Basic> files) {
@@ -478,8 +475,7 @@ public class FIleChecker {
return fileTotSize;
}
public static boolean multipartSaveTo(MultipartFile mfile, String targetPath)
{
public static boolean multipartSaveTo(MultipartFile mfile, String targetPath) {
Path tmpSavePath = Paths.get(targetPath);
boolean fileUpload = true;
@@ -493,8 +489,7 @@ public class FIleChecker {
return true;
}
public static boolean validationMultipart(MultipartFile mfile)
{
public static boolean validationMultipart(MultipartFile mfile) {
// 파일 유효성 검증
if (mfile == null || mfile.isEmpty() || mfile.getSize() == 0) {
return false;

View File

@@ -17,7 +17,6 @@ public class InferenceResultShpApiController {
private final InferenceResultShpService inferenceResultShpService;
@Operation(summary = "추론결과 데이터 저장", description = "추론결과 데이터 저장")
@PostMapping
public ApiResponseDto<Void> saveInferenceResultData() {

View File

@@ -30,22 +30,21 @@ public class InferenceResultShpDto {
private Geometry geometry;
public Basic(
Long id,
UUID uuid,
Integer stage,
Float cdProb,
Integer input1,
Integer input2,
Long mapId,
String beforeClass,
Float beforeProbability,
String afterClass,
Float afterProbability,
Float area,
ZonedDateTime createdDttm,
ZonedDateTime updatedDttm,
Geometry geometry
) {
Long id,
UUID uuid,
Integer stage,
Float cdProb,
Integer input1,
Integer input2,
Long mapId,
String beforeClass,
Float beforeProbability,
String afterClass,
Float afterProbability,
Float area,
ZonedDateTime createdDttm,
ZonedDateTime updatedDttm,
Geometry geometry) {
this.id = id;
this.uuid = uuid;
this.stage = stage;
@@ -65,22 +64,21 @@ public class InferenceResultShpDto {
public static Basic from(InferenceResultEntity e) {
return new Basic(
e.getId(),
e.getUuid(),
e.getStage(),
e.getCdProb(),
e.getInput1(),
e.getInput2(),
e.getMapId(),
e.getBeforeClass(),
e.getBeforeProbability(),
e.getAfterClass(),
e.getAfterProbability(),
e.getArea(),
e.getCreatedDttm(),
e.getUpdatedDttm(),
e.getGeometry()
);
e.getId(),
e.getUuid(),
e.getStage(),
e.getCdProb(),
e.getInput1(),
e.getInput2(),
e.getMapId(),
e.getBeforeClass(),
e.getBeforeProbability(),
e.getAfterClass(),
e.getAfterProbability(),
e.getArea(),
e.getCreatedDttm(),
e.getUpdatedDttm(),
e.getGeometry());
}
}
}

View File

@@ -48,13 +48,14 @@ public class GeoToolsShpWriter implements ShpWriter {
/**
* SHP 파일(.shp/.shx/.dbf/.prj)을 생성한다.
* <p>
* - shpBasePath를 기준으로 파일을 생성한다. 예) /Users/kim/export/shp/1_map_2021_2022 → 1_map_2021_2022.shp → 1_map_2021_2022.shx → 1_map_2021_2022.dbf → 1_map_2021_2022.prj
* <p>
* - geometry 타입은 첫 번째 유효 geometry 기준으로 스키마를 생성한다. - 좌표계는 EPSG:5186으로 설정하며, .prj 파일을 직접 생성한다.
*
* <p>- shpBasePath를 기준으로 파일을 생성한다. 예) /Users/kim/export/shp/1_map_2021_2022 → 1_map_2021_2022.shp
* → 1_map_2021_2022.shx → 1_map_2021_2022.dbf → 1_map_2021_2022.prj
*
* <p>- geometry 타입은 첫 번째 유효 geometry 기준으로 스키마를 생성한다. - 좌표계는 EPSG:5186으로 설정하며, .prj 파일을 직접 생성한다.
*
* @param shpBasePath 확장자를 제외한 SHP 파일 기본 경로
* @param rows 동일 그룹(stage, mapId, input1, input2)의 데이터 목록
* @param rows 동일 그룹(stage, mapId, input1, input2)의 데이터 목록
*/
@Override
public void writeShp(String shpBasePath, List<InferenceResultShpDto.Basic> rows) {
@@ -67,13 +68,11 @@ public class GeoToolsShpWriter implements ShpWriter {
// 첫 번째 유효 geometry의 "구체 타입"을 기준으로 스키마를 생성한다.
Geometry firstGeom = firstNonNullGeometry(rows);
if (firstGeom == null) {
throw new IllegalArgumentException(
"SHP 생성 실패: geometry가 전부 null 입니다. path=" + shpBasePath);
throw new IllegalArgumentException("SHP 생성 실패: geometry가 전부 null 입니다. path=" + shpBasePath);
}
@SuppressWarnings("unchecked")
Class<? extends Geometry> geomType =
(Class<? extends Geometry>) firstGeom.getClass();
Class<? extends Geometry> geomType = (Class<? extends Geometry>) firstGeom.getClass();
ShapefileDataStore dataStore = null;
@@ -91,8 +90,7 @@ public class GeoToolsShpWriter implements ShpWriter {
dataStore = createDataStore(shpFile, schema);
// FeatureCollection 생성
DefaultFeatureCollection collection =
buildFeatureCollection(schema, rows);
DefaultFeatureCollection collection = buildFeatureCollection(schema, rows);
// 실제 SHP 파일에 feature 쓰기
writeFeatures(dataStore, collection);
@@ -100,11 +98,7 @@ public class GeoToolsShpWriter implements ShpWriter {
// .prj 파일 직접 생성 (EPSG:5186)
writePrjFile(shpBasePath, crs);
log.info(
"SHP 생성 완료: {} ({} features)",
shpFile.getAbsolutePath(),
collection.size()
);
log.info("SHP 생성 완료: {} ({} features)", shpFile.getAbsolutePath(), collection.size());
} catch (Exception e) {
throw new RuntimeException("SHP 생성 실패: " + shpBasePath, e);
@@ -120,14 +114,16 @@ public class GeoToolsShpWriter implements ShpWriter {
/**
* GeoJSON 파일(.geojson)을 생성한다.
* <p>
* - FeatureCollection 형태로 출력한다. - 최상단에 name / crs / properties를 포함한다. - 각 Feature는 polygon 단위로 생성된다. - geometry는 GeoTools GeometryJSON을 사용하여 직렬화한다.
* <p>
* GeoJSON 구조 예: { "type": "FeatureCollection", "name": "stage_input1_input2_mapId", "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::5186" } },
* "properties": { ... }, "features": [ ... ] }
*
* <p>- FeatureCollection 형태로 출력한다. - 최상단에 name / crs / properties를 포함한다. - 각 Feature는 polygon 단위로
* 생성된다. - geometry는 GeoTools GeometryJSON을 사용하여 직렬화한다.
*
* <p>GeoJSON 구조 예: { "type": "FeatureCollection", "name": "stage_input1_input2_mapId", "crs": {
* "type": "name", "properties": { "name": "urn:ogc:def:crs:EPSG::5186" } }, "properties": { ...
* }, "features": [ ... ] }
*
* @param geoJsonPath 생성할 GeoJSON 파일의 전체 경로 (.geojson 포함)
* @param rows 동일 그룹(stage, mapId, input1, input2)의 데이터 목록
* @param rows 동일 그룹(stage, mapId, input1, input2)의 데이터 목록
*/
@Override
public void writeGeoJson(String geoJsonPath, List<InferenceResultShpDto.Basic> rows) {
@@ -151,13 +147,10 @@ public class GeoToolsShpWriter implements ShpWriter {
root.put("type", "FeatureCollection");
// name: stage_input1_input2_mapId
String name = String.format(
"%d_%d_%d_%d",
first.getStage(),
first.getInput1(),
first.getInput2(),
first.getMapId()
);
String name =
String.format(
"%d_%d_%d_%d",
first.getStage(), first.getInput1(), first.getInput2(), first.getMapId());
root.put("name", name);
// CRS (EPSG:5186)
@@ -175,9 +168,9 @@ public class GeoToolsShpWriter implements ShpWriter {
groupProps.put("input2", first.getInput2());
groupProps.put("map_id", first.getMapId());
// 학습서버 버전은 추후 추가
// groupProps.put("m1", "v1.2222.251223121212");
// groupProps.put("m2", "v2.211.251223121213");
// groupProps.put("m3", "v3.233.251223121214");
// groupProps.put("m1", "v1.2222.251223121212");
// groupProps.put("m2", "v2.211.251223121213");
// groupProps.put("m3", "v3.233.251223121214");
root.set("properties", groupProps);
// features 배열
@@ -193,8 +186,7 @@ public class GeoToolsShpWriter implements ShpWriter {
// feature properties
ObjectNode p = om.createObjectNode();
p.put("polygon_id",
dto.getUuid() != null ? dto.getUuid().toString() : null);
p.put("polygon_id", dto.getUuid() != null ? dto.getUuid().toString() : null);
if (dto.getCdProb() != null) {
p.put("cd_prob", dto.getCdProb());
}
@@ -233,18 +225,11 @@ public class GeoToolsShpWriter implements ShpWriter {
// 파일 쓰기
try (OutputStreamWriter w =
new OutputStreamWriter(
new FileOutputStream(geoJsonFile),
GEOJSON_CHARSET
)) {
new OutputStreamWriter(new FileOutputStream(geoJsonFile), GEOJSON_CHARSET)) {
om.writerWithDefaultPrettyPrinter().writeValue(w, root);
}
log.info(
"GeoJSON 생성 완료: {} ({} features)",
geoJsonFile.getAbsolutePath(),
features.size()
);
log.info("GeoJSON 생성 완료: {} ({} features)", geoJsonFile.getAbsolutePath(), features.size());
} catch (Exception e) {
throw new RuntimeException("GeoJSON 생성 실패: " + geoJsonPath, e);
@@ -253,8 +238,8 @@ public class GeoToolsShpWriter implements ShpWriter {
/**
* rows 목록에서 첫 번째로 발견되는 non-null Geometry를 반환한다.
* <p>
* - SHP 스키마 생성 시 geometry 타입 결정을 위해 사용된다.
*
* <p>- SHP 스키마 생성 시 geometry 타입 결정을 위해 사용된다.
*
* @param rows DTO 목록
* @return 첫 번째 non-null Geometry, 없으면 null
@@ -270,17 +255,15 @@ public class GeoToolsShpWriter implements ShpWriter {
/**
* SHP 파일에 사용할 SimpleFeatureType(schema)를 생성한다.
* <p>
* - geometry 컬럼은 반드시 첫 번째 컬럼이어야 한다. - DBF 컬럼은 SHP 제약(컬럼명 10자, 길이 제한)을 고려한다.
*
* <p>- geometry 컬럼은 반드시 첫 번째 컬럼이어야 한다. - DBF 컬럼은 SHP 제약(컬럼명 10자, 길이 제한)을 고려한다.
*
* @param geomType geometry의 구체 타입 (Polygon, MultiPolygon 등)
* @param crs 좌표계(EPSG:5186)
* @param crs 좌표계(EPSG:5186)
* @return SimpleFeatureType
*/
private SimpleFeatureType createSchema(
Class<? extends Geometry> geomType,
CoordinateReferenceSystem crs
) {
Class<? extends Geometry> geomType, CoordinateReferenceSystem crs) {
SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
b.setName("inference_result");
b.setCRS(crs);
@@ -305,25 +288,22 @@ public class GeoToolsShpWriter implements ShpWriter {
/**
* ShapefileDataStore를 생성하고 스키마를 등록한다.
* <p>
* - DBF 파일 인코딩은 EUC-KR로 설정한다. - spatial index(.qix)를 생성한다.
*
* <p>- DBF 파일 인코딩은 EUC-KR로 설정한다. - spatial index(.qix)를 생성한다.
*
* @param shpFile SHP 파일 객체
* @param schema SimpleFeatureType
* @param schema SimpleFeatureType
* @return 생성된 ShapefileDataStore
*/
private ShapefileDataStore createDataStore(
File shpFile,
SimpleFeatureType schema
) throws Exception {
private ShapefileDataStore createDataStore(File shpFile, SimpleFeatureType schema)
throws Exception {
Map<String, Serializable> params = new HashMap<>();
params.put("url", shpFile.toURI().toURL());
params.put("create spatial index", Boolean.TRUE);
ShapefileDataStoreFactory factory = new ShapefileDataStoreFactory();
ShapefileDataStore dataStore =
(ShapefileDataStore) factory.createNewDataStore(params);
ShapefileDataStore dataStore = (ShapefileDataStore) factory.createNewDataStore(params);
dataStore.setCharset(DBF_CHARSET);
dataStore.createSchema(schema);
@@ -333,17 +313,15 @@ public class GeoToolsShpWriter implements ShpWriter {
/**
* DTO 목록을 SimpleFeatureCollection으로 변환한다.
* <p>
* - DTO 1건당 Feature 1개 생성 - geometry가 null인 데이터는 제외한다.
*
* <p>- DTO 1건당 Feature 1개 생성 - geometry가 null인 데이터는 제외한다.
*
* @param schema FeatureType
* @param rows DTO 목록
* @param rows DTO 목록
* @return DefaultFeatureCollection
*/
private DefaultFeatureCollection buildFeatureCollection(
SimpleFeatureType schema,
List<InferenceResultShpDto.Basic> rows
) {
SimpleFeatureType schema, List<InferenceResultShpDto.Basic> rows) {
DefaultFeatureCollection collection = new DefaultFeatureCollection();
SimpleFeatureBuilder builder = new SimpleFeatureBuilder(schema);
@@ -360,13 +338,11 @@ public class GeoToolsShpWriter implements ShpWriter {
builder.add(dto.getMapId());
builder.add(dto.getArea() != null ? dto.getArea().doubleValue() : null);
builder.add(dto.getBeforeClass());
builder.add(dto.getBeforeProbability() != null
? dto.getBeforeProbability().doubleValue()
: null);
builder.add(
dto.getBeforeProbability() != null ? dto.getBeforeProbability().doubleValue() : null);
builder.add(dto.getAfterClass());
builder.add(dto.getAfterProbability() != null
? dto.getAfterProbability().doubleValue()
: null);
builder.add(
dto.getAfterProbability() != null ? dto.getAfterProbability().doubleValue() : null);
SimpleFeature feature = builder.buildFeature(null);
collection.add(feature);
@@ -379,17 +355,14 @@ public class GeoToolsShpWriter implements ShpWriter {
/**
* FeatureCollection을 SHP 파일에 실제로 기록한다.
*
* @param dataStore ShapefileDataStore
* @param dataStore ShapefileDataStore
* @param collection FeatureCollection
*/
private void writeFeatures(
ShapefileDataStore dataStore,
DefaultFeatureCollection collection
) throws Exception {
private void writeFeatures(ShapefileDataStore dataStore, DefaultFeatureCollection collection)
throws Exception {
String typeName = dataStore.getTypeNames()[0];
SimpleFeatureSource featureSource =
dataStore.getFeatureSource(typeName);
SimpleFeatureSource featureSource = dataStore.getFeatureSource(typeName);
if (!(featureSource instanceof SimpleFeatureStore store)) {
throw new IllegalStateException("FeatureStore 생성 실패");
@@ -404,21 +377,14 @@ public class GeoToolsShpWriter implements ShpWriter {
* SHP 좌표계 정보를 담은 .prj 파일을 생성한다.
*
* @param shpBasePath SHP 기본 경로 (확장자 제외)
* @param crs 좌표계(EPSG:5186)
* @param crs 좌표계(EPSG:5186)
*/
private void writePrjFile(
String shpBasePath,
CoordinateReferenceSystem crs
) throws Exception {
private void writePrjFile(String shpBasePath, CoordinateReferenceSystem crs) throws Exception {
File prjFile = new File(shpBasePath + ".prj");
createDirectories(prjFile);
Files.writeString(
prjFile.toPath(),
crs.toWKT(),
StandardCharsets.UTF_8
);
Files.writeString(prjFile.toPath(), crs.toWKT(), StandardCharsets.UTF_8);
}
/**

View File

@@ -19,14 +19,16 @@ public class InferenceResultShpService {
public void saveInferenceResultData() {
coreService.streamGrouped(1000, (key, entities) -> {
coreService.streamGrouped(
1000,
(key, entities) -> {
// Entity -> DTO
List<InferenceResultShpDto.Basic> dtoList =
entities.stream().map(InferenceResultShpDto.Basic::from).toList();
// Entity -> DTO
List<InferenceResultShpDto.Basic> dtoList =
entities.stream().map(InferenceResultShpDto.Basic::from).toList();
flushGroup(key, dtoList);
});
flushGroup(key, dtoList);
});
}
/**
@@ -41,12 +43,10 @@ public class InferenceResultShpService {
String baseDir = System.getProperty("user.home") + "/export";
// 파일명 stage_input1_input2_mapId
String baseName = String.format(
"%d_%d_%d_%d",
key.stage(), key.mapId(), key.input1(), key.input2()
);
String baseName =
String.format("%d_%d_%d_%d", key.stage(), key.mapId(), key.input1(), key.input2());
String shpBasePath = baseDir + "/shp/" + baseName; // 확장자 없이
String shpBasePath = baseDir + "/shp/" + baseName; // 확장자 없이
String geoJsonPath = baseDir + "/geojson/" + baseName + ".geojson";
// shp: .shp/.shx/.dbf 생성

View File

@@ -226,21 +226,19 @@ public class MapSheetMngApiController {
return ApiResponseDto.ok(mapSheetMngService.deleteByFileUidMngFile(fileUids));
}
@Operation(summary = "폴더 조회", description = "폴더 조회 (ROOT:/app/original-images 이하로 경로입력)")
@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)
})
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("/folder-list")
public ApiResponseDto<FoldersDto> getDir(@RequestBody SrchFoldersDto srchDto) {
@@ -249,22 +247,20 @@ public class MapSheetMngApiController {
@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)
})
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-list")
public ApiResponseDto<FilesDto> getFiles(@RequestBody SrchFilesDto srchDto) {
return ApiResponseDto.createOK(mapSheetMngService.getFilesAll(srchDto));
}
}

View File

@@ -14,7 +14,6 @@ import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngFilesDto;
import com.kamco.cd.kamcoback.postgres.core.MapSheetMngCoreService;
import jakarta.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -86,7 +85,8 @@ public class MapSheetMngService {
}
@Transactional
public DmlReturn uploadPair(MultipartFile tfwFile, MultipartFile tifFile, Long hstUid, Boolean overwrite) {
public DmlReturn uploadPair(
MultipartFile tfwFile, MultipartFile tifFile, Long hstUid, Boolean overwrite) {
String rootPath = syncRootDir;
String tmpPath = syncTmpDir;
@@ -104,26 +104,29 @@ public class MapSheetMngService {
return new DmlReturn("fail", "CREATE TEMP FOLDER ERROR");
}
//업로드 파일 사이즈,확장자명 체크
// 업로드 파일 사이즈,확장자명 체크
dmlReturn = this.validationFile(tfwFile, tifFile);
if( dmlReturn.getFlag().equals("fail") )return dmlReturn;
if (dmlReturn.getFlag().equals("fail")) return dmlReturn;
MngDto mngDto = mapSheetMngCoreService.findMapSheetMng(errDto.getMngYyyy());
String targetYearDir = mngDto.getMngPath();
// 중복체크
if( !overwrite ) {
dmlReturn = this.duplicateFile(errDto.getMngYyyy(), tfwFile.getOriginalFilename(), tifFile.getOriginalFilename());
if( dmlReturn.getFlag().equals("duplicate") )return dmlReturn;
if (!overwrite) {
dmlReturn =
this.duplicateFile(
errDto.getMngYyyy(), tfwFile.getOriginalFilename(), tifFile.getOriginalFilename());
if (dmlReturn.getFlag().equals("duplicate")) return dmlReturn;
}
//멀티파트 파일 tmp폴더 저장(파일형식 체크를 위해)
// 멀티파트 파일 tmp폴더 저장(파일형식 체크를 위해)
String tfwTmpPath = tmpPath + tfwFile.getOriginalFilename();
String tifTmpPath = tmpPath + tifFile.getOriginalFilename();
if(!FIleChecker.multipartSaveTo(tfwFile, tfwTmpPath))return new DmlReturn("fail", "UPLOAD ERROR");
if(!FIleChecker.multipartSaveTo(tifFile, tifTmpPath))return new DmlReturn("fail", "UPLOAD ERROR");
if (!FIleChecker.multipartSaveTo(tfwFile, tfwTmpPath))
return new DmlReturn("fail", "UPLOAD ERROR");
if (!FIleChecker.multipartSaveTo(tifFile, tifTmpPath))
return new DmlReturn("fail", "UPLOAD ERROR");
if (!FIleChecker.cmmndGdalInfo(tifTmpPath)) return new DmlReturn("fail", "TIF TYPE ERROR");
if (!FIleChecker.checkTfw(tfwTmpPath)) return new DmlReturn("fail", "TFW TYPE ERROR");
@@ -136,7 +139,6 @@ public class MapSheetMngService {
break;
}
Path tfwTmpSavePath = Paths.get(tfwTmpPath);
Path tifTmpSavePath = Paths.get(tifTmpPath);
Path tfwTargetPath = null;
@@ -232,20 +234,18 @@ public class MapSheetMngService {
return new DmlReturn("success", fileUids.size() + "개 파일이 삭제되었습니다.");
}
public DmlReturn validationFile(MultipartFile tfwFile, MultipartFile tifFile)
{
if( !FIleChecker.validationMultipart(tfwFile) )return new DmlReturn("fail", "TFW SIZE 오류");
else if( !FIleChecker.validationMultipart(tifFile) )return new DmlReturn("fail", "TFW SIZE 오류");
else if (!FIleChecker.checkExtensions(tfwFile.getOriginalFilename(), "tfw"))return new DmlReturn("fail", "TFW FILENAME ERROR");
else if (!FIleChecker.checkExtensions(tifFile.getOriginalFilename(), "tif"))return new DmlReturn("fail", "TIF FILENAME ERROR");
public DmlReturn validationFile(MultipartFile tfwFile, MultipartFile tifFile) {
if (!FIleChecker.validationMultipart(tfwFile)) return new DmlReturn("fail", "TFW SIZE 오류");
else if (!FIleChecker.validationMultipart(tifFile)) return new DmlReturn("fail", "TFW SIZE 오류");
else if (!FIleChecker.checkExtensions(tfwFile.getOriginalFilename(), "tfw"))
return new DmlReturn("fail", "TFW FILENAME ERROR");
else if (!FIleChecker.checkExtensions(tifFile.getOriginalFilename(), "tif"))
return new DmlReturn("fail", "TIF FILENAME ERROR");
return new DmlReturn("success", "파일체크");
}
public DmlReturn duplicateFile(int mngYyyy, String tfwFileName, String tifFileName)
{
public DmlReturn duplicateFile(int mngYyyy, String tfwFileName, String tifFileName) {
int tfwCnt = mapSheetMngCoreService.findByYearFileNameFileCount(mngYyyy, tfwFileName);
int tifCnt = mapSheetMngCoreService.findByYearFileNameFileCount(mngYyyy, tifFileName);
@@ -254,14 +254,11 @@ public class MapSheetMngService {
if (tfwCnt > 0 || tifCnt > 0) {
String resMsg = "";
if (tfwCnt > 0)
resMsg = tfwFileName;
if (tfwCnt > 0) resMsg = tfwFileName;
if (tifCnt > 0) {
if (tfwCnt > 0)
resMsg = resMsg + "," + tifFileName;
else
resMsg = tifFileName;
if (tfwCnt > 0) resMsg = resMsg + "," + tifFileName;
else resMsg = tifFileName;
}
return new DmlReturn("duplicate", resMsg);
}
@@ -279,8 +276,8 @@ public class MapSheetMngService {
int folderTotCnt = folderList.size();
int folderErrTotCnt =
(int)
folderList.stream().filter(dto -> dto.getIsValid().toString().equals("false")).count();
(int)
folderList.stream().filter(dto -> dto.getIsValid().toString().equals("false")).count();
return new FoldersDto(dirPath, folderTotCnt, folderErrTotCnt, folderList);
}
@@ -292,14 +289,14 @@ public class MapSheetMngService {
int endPos = srchDto.getEndPos();
List<FIleChecker.Basic> files =
FIleChecker.getFilesFromAllDepth(
srchDto.getDirPath(),
"*",
srchDto.getExtension(),
1,
srchDto.getSortType(),
startPos,
endPos);
FIleChecker.getFilesFromAllDepth(
srchDto.getDirPath(),
"*",
srchDto.getExtension(),
1,
srchDto.getSortType(),
startPos,
endPos);
int fileListPos = 0;
int fileTotCnt = files.size();

View File

@@ -16,15 +16,12 @@ public class InferenceResultShpCoreService {
private final InferenceResultRepository inferenceResultRepository;
public record ShpKey(Integer stage, Long mapId, Integer input1, Integer input2) {
public record ShpKey(Integer stage, Long mapId, Integer input1, Integer input2) {}
}
/**
* DB를 스트리밍하면서 그룹이 완성될 때마다 handler로 넘김 handler: (key, groupRows)
*/
/** DB를 스트리밍하면서 그룹이 완성될 때마다 handler로 넘김 handler: (key, groupRows) */
@Transactional(readOnly = true)
public void streamGrouped(int fetchSize, BiConsumer<ShpKey, List<InferenceResultEntity>> handler) {
public void streamGrouped(
int fetchSize, BiConsumer<ShpKey, List<InferenceResultEntity>> handler) {
ScrollableResults cursor = inferenceResultRepository.scrollAllOrdered(fetchSize);

View File

@@ -135,16 +135,12 @@ public class MapSheetAnalDataInferenceGeomEntity {
@Column(name = "file_created_yn")
private Boolean fileCreatedYn;
@Column(name = "geom", columnDefinition = "geometry")
private Geometry geom;
@Column(name = "geom_center", columnDefinition = "geometry")
private Geometry geomCenter;
@Column(name = "before_geom", columnDefinition = "geometry")
private Geometry beforeGeom;
}

View File

@@ -5,5 +5,4 @@ import org.hibernate.ScrollableResults;
public interface InferenceResultRepositoryCustom {
ScrollableResults scrollAllOrdered(int fetchSize);
}

View File

@@ -20,22 +20,16 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC
QInferenceResultEntity e = QInferenceResultEntity.inferenceResultEntity;
JPAQuery<InferenceResultEntity> q =
queryFactory
.selectFrom(e)
.orderBy(
e.stage.asc(),
e.mapId.asc(),
e.input1.asc(),
e.input2.asc(),
e.id.asc()
);
queryFactory
.selectFrom(e)
.orderBy(e.stage.asc(), e.mapId.asc(), e.input1.asc(), e.input2.asc(), e.id.asc());
// QueryDSL -> Hibernate Query로 unwrap 해서 커서 스트리밍
Query<?> hQuery = q.createQuery().unwrap(Query.class);
return hQuery
.setReadOnly(true)
.setFetchSize(fetchSize) // PostgreSQL 커서/스트리밍에 영향
.scroll(ScrollMode.FORWARD_ONLY);
.setReadOnly(true)
.setFetchSize(fetchSize) // PostgreSQL 커서/스트리밍에 영향
.scroll(ScrollMode.FORWARD_ONLY);
}
}

View File

@@ -6,6 +6,4 @@ import org.springframework.stereotype.Repository;
@Repository
@RequiredArgsConstructor
public class MapSheetAnalDataInferenceGeomRepositoryImpl
implements MapSheetAnalDataInferenceGeomRepositoryCustom {
}
implements MapSheetAnalDataInferenceGeomRepositoryCustom {}

View File

@@ -4,7 +4,5 @@ import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataInferenceEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MapSheetAnalDataInferenceRepository
extends JpaRepository<MapSheetAnalDataInferenceEntity, Long>,
MapSheetAnalDataInferenceRepositoryCustom {
}
extends JpaRepository<MapSheetAnalDataInferenceEntity, Long>,
MapSheetAnalDataInferenceRepositoryCustom {}

View File

@@ -661,13 +661,17 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
}
@Override
public int findByYearFileNameFileCount(int mngYyyy, String fileName){
Long execCount = queryFactory
.select(mapSheetMngFileEntity.count())
.from(mapSheetMngFileEntity)
.where(mapSheetMngFileEntity.mngYyyy.eq(mngYyyy)
.and(mapSheetMngFileEntity.fileName.eq(fileName)))
.fetchOne();
public int findByYearFileNameFileCount(int mngYyyy, String fileName) {
Long execCount =
queryFactory
.select(mapSheetMngFileEntity.count())
.from(mapSheetMngFileEntity)
.where(
mapSheetMngFileEntity
.mngYyyy
.eq(mngYyyy)
.and(mapSheetMngFileEntity.fileName.eq(fileName)))
.fetchOne();
return Math.toIntExact(execCount);
}

View File

@@ -25,7 +25,6 @@ public class MapSheetMngFileJobController {
mapSheetMngFileJobService.checkMapSheetFileProcess(0, mngSyncPageSize);
}
@Scheduled(fixedDelay = 5000)
public void mngFileSyncJob01() {
if (!isSchedulerEnabled) return;
@@ -98,7 +97,6 @@ public class MapSheetMngFileJobController {
mapSheetMngFileJobService.checkMapSheetFileProcess(9, mngSyncPageSize);
}
// 3. 외부에서 플래그를 변경할 수 있는 Setter 메서드
public void setSchedulerEnabled(boolean enabled) {
this.isSchedulerEnabled = enabled;