파일생성 추가
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -17,7 +17,6 @@ public class InferenceResultShpApiController {
|
||||
|
||||
private final InferenceResultShpService inferenceResultShpService;
|
||||
|
||||
|
||||
@Operation(summary = "추론결과 데이터 저장", description = "추론결과 데이터 저장")
|
||||
@PostMapping
|
||||
public ApiResponseDto<Void> saveInferenceResultData() {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 생성
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
@@ -5,5 +5,4 @@ import org.hibernate.ScrollableResults;
|
||||
public interface InferenceResultRepositoryCustom {
|
||||
|
||||
ScrollableResults scrollAllOrdered(int fetchSize);
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,4 @@ import org.springframework.stereotype.Repository;
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class MapSheetAnalDataInferenceGeomRepositoryImpl
|
||||
implements MapSheetAnalDataInferenceGeomRepositoryCustom {
|
||||
|
||||
}
|
||||
implements MapSheetAnalDataInferenceGeomRepositoryCustom {}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user