diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java b/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java index 5f4189c4..cfb122c8 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/InferenceResultApiController.java @@ -1,5 +1,6 @@ package com.kamco.cd.kamcoback.inference; +import com.kamco.cd.kamcoback.common.exception.CustomApiException; import com.kamco.cd.kamcoback.config.api.ApiResponseDto; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; @@ -20,11 +21,19 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; import java.time.LocalDate; import java.util.List; import java.util.UUID; import lombok.RequiredArgsConstructor; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; import org.springframework.data.domain.Page; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -33,6 +42,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.util.UriUtils; @Tag(name = "추론관리", description = "추론관리 API") @RequestMapping("/api/inference") @@ -388,4 +398,47 @@ public class InferenceResultApiController { inferenceResultService.getInferenceGeomList(uuid, searchGeoReq); return ApiResponseDto.ok(geomList); } + + @Operation(summary = "shp 파일 다운로드", description = "추론관리 분석결과 shp 파일 다운로드") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "shp zip파일 다운로드", + content = + @Content( + mediaType = "application/octet-stream", + schema = @Schema(type = "string", format = "binary"))), + @ApiResponse(responseCode = "404", description = "파일 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @GetMapping(value = "/download/{uuid}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public ResponseEntity downloadZip(@PathVariable UUID uuid) throws IOException { + + String path; + try { + path = String.valueOf(inferenceResultService.shpDownloadPath(uuid)); + } catch (CustomApiException e) { + // 데이터 없음 등 404 + return ResponseEntity.status(e.getStatus()).build(); + } + + Path zipPath = Path.of(path); + FileSystemResource resource = new FileSystemResource(zipPath); + + if (!resource.exists() || !resource.isReadable()) { + return ResponseEntity.notFound().build(); + } + + String filename = zipPath.getFileName().toString(); + String encodedFilename = UriUtils.encode(filename, StandardCharsets.UTF_8); + + return ResponseEntity.ok() + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .header( + HttpHeaders.CONTENT_DISPOSITION, + "attachment; filename=\"" + filename + "\"; filename*=UTF-8''" + encodedFilename) + .contentLength(resource.contentLength()) + .body((Resource) resource); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceResultDto.java b/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceResultDto.java index 9d579903..2efdbadb 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceResultDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceResultDto.java @@ -622,4 +622,11 @@ public class InferenceResultDto { private Integer completedJobs; private Integer failedJobs; } + + @Getter + @Setter + public static class InferenceLearnDto { + + private String uid; + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceSendDto.java b/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceSendDto.java index bb09413f..ab90238a 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceSendDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/dto/InferenceSendDto.java @@ -5,6 +5,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +/** AI API 추론 실행 DTO */ @Getter @Setter @NoArgsConstructor diff --git a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java index 3586f22b..8634d357 100644 --- a/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java +++ b/src/main/java/com/kamco/cd/kamcoback/inference/service/InferenceResultService.java @@ -16,6 +16,7 @@ import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.MapSheet; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.SearchGeoReq; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.DetectOption; +import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceLearnDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceServerStatusDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceStatusDetailDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheetNumDto; @@ -32,6 +33,7 @@ import com.kamco.cd.kamcoback.postgres.core.InferenceResultCoreService; import com.kamco.cd.kamcoback.postgres.core.MapSheetMngCoreService; import com.kamco.cd.kamcoback.postgres.core.ModelMngCoreService; import jakarta.validation.constraints.NotNull; +import java.nio.file.Path; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; @@ -70,6 +72,9 @@ public class InferenceResultService { @Value("${inference.batch-url}") private String batchUrl; + @Value("${file.dataset-dir}") + private String datasetDir; + @Value("${spring.profiles.active}") private String profile; @@ -536,4 +541,17 @@ public class InferenceResultService { Long learnId = inferenceResultCoreService.getInferenceLearnIdByUuid(dto.getUuid()); inferenceResultCoreService.upsertGeomData(learnId); } + + /** + * 추론결과 shp zip 파일 다운로드 경로 생성 + * + * @param uuid + * @return + */ + public Path shpDownloadPath(UUID uuid) { + InferenceLearnDto dto = inferenceResultCoreService.getInferenceUid(uuid); + String uid = dto.getUid(); + + return Path.of(datasetDir).resolve(uid).resolve("merge").resolve(uid + ".zip"); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java index 75c40180..174ee4eb 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/InferenceResultCoreService.java @@ -11,6 +11,7 @@ import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.MapSheet; import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.SearchGeoReq; import com.kamco.cd.kamcoback.inference.dto.InferenceProgressDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto; +import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceLearnDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceServerStatusDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceStatusDetailDto; import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.ResultList; @@ -461,4 +462,20 @@ public class InferenceResultCoreService { inferenceResultsTetingRepository.getInferenceResultList(batchIds); return list.stream().map(InferenceResultsTestingDto.ShpDto::fromEntity).toList(); } + + /** + * uid 조회 + * + * @param uuid + * @return + */ + public InferenceLearnDto getInferenceUid(UUID uuid) { + MapSheetLearnEntity entity = + inferenceResultRepository + .getInferenceUid(uuid) + .orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND)); + InferenceLearnDto dto = new InferenceLearnDto(); + dto.setUid(entity.getUid()); + return dto; + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryCustom.java index 0d0887c7..c3162853 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryCustom.java @@ -1,7 +1,9 @@ package com.kamco.cd.kamcoback.postgres.repository.Inference; import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataInferenceGeomEntity; +import com.kamco.cd.kamcoback.postgres.entity.MapSheetLearnEntity; import java.util.List; +import java.util.Optional; import java.util.UUID; public interface InferenceResultRepositoryCustom { @@ -27,4 +29,6 @@ public interface InferenceResultRepositoryCustom { List findGeomEntitiesByDataUid(Long dataUid, int limit); Long getInferenceLearnIdByUuid(UUID uuid); + + public Optional getInferenceUid(UUID uuid); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java index f6f02e28..3d51412b 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/InferenceResultRepositoryImpl.java @@ -3,6 +3,7 @@ package com.kamco.cd.kamcoback.postgres.repository.Inference; import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnEntity.mapSheetLearnEntity; import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataInferenceGeomEntity; +import com.kamco.cd.kamcoback.postgres.entity.MapSheetLearnEntity; import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceEntity; import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceGeomEntity; import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalInferenceEntity; @@ -10,6 +11,7 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import java.time.ZonedDateTime; import java.util.List; +import java.util.Optional; import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -468,4 +470,14 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC .where(mapSheetLearnEntity.uuid.eq(uuid)) .fetchOne(); } + + @Override + public Optional getInferenceUid(UUID uuid) { + return Optional.ofNullable( + queryFactory + .select(mapSheetLearnEntity) + .from(mapSheetLearnEntity) + .where(mapSheetLearnEntity.uuid.eq(uuid)) + .fetchOne()); + } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java index a28a2c14..9038d6d5 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/Inference/MapSheetLearnRepositoryImpl.java @@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.postgres.repository.Inference; import static com.kamco.cd.kamcoback.postgres.entity.QGpuMetricEntity.gpuMetricEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx5kEntity.mapInkx5kEntity; +import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceEntity.mapSheetAnalDataInferenceEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalInferenceEntity.mapSheetAnalInferenceEntity; import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalSttcEntity.mapSheetAnalSttcEntity; @@ -419,13 +420,10 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto // mapSheetAnalDataInferenceGeomEntity.geomCenter) )) .from(mapSheetAnalInferenceEntity) + .join(mapSheetAnalDataInferenceEntity) + .on(mapSheetAnalDataInferenceEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) .join(mapSheetAnalDataInferenceGeomEntity) - .on( - mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq( - mapSheetAnalInferenceEntity.compareYyyy), - mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq( - mapSheetAnalInferenceEntity.targetYyyy), - mapSheetAnalDataInferenceGeomEntity.stage.eq(mapSheetAnalInferenceEntity.stage)) + .on(mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id)) .join(mapInkx5kEntity) .on( mapSheetAnalDataInferenceGeomEntity.mapSheetNum.eq( @@ -440,13 +438,10 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto queryFactory .select(mapSheetAnalDataInferenceGeomEntity.geoUid) .from(mapSheetAnalInferenceEntity) + .join(mapSheetAnalDataInferenceEntity) + .on(mapSheetAnalDataInferenceEntity.analUid.eq(mapSheetAnalInferenceEntity.id)) .join(mapSheetAnalDataInferenceGeomEntity) - .on( - mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq( - mapSheetAnalInferenceEntity.compareYyyy), - mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq( - mapSheetAnalInferenceEntity.targetYyyy), - mapSheetAnalDataInferenceGeomEntity.stage.eq(mapSheetAnalInferenceEntity.stage)) + .on(mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id)) .join(mapInkx5kEntity) .on( mapSheetAnalDataInferenceGeomEntity.mapSheetNum.eq(