영상데이터관리 > tif 대용량 분할전송 추가

This commit is contained in:
2026-01-26 18:20:39 +09:00
parent 8a0c6d124b
commit bbc87071fb
5 changed files with 112 additions and 16 deletions

View File

@@ -10,6 +10,8 @@ import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.SrchFoldersDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngYyyyDto;
import com.kamco.cd.kamcoback.mapsheet.service.MapSheetMngService;
import com.kamco.cd.kamcoback.model.dto.ModelMngDto.ModelUploadResDto;
import com.kamco.cd.kamcoback.upload.dto.UploadDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -19,6 +21,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
@@ -40,6 +43,12 @@ public class MapSheetMngApiController {
private final CommonCodeService commonCodeService;
private final MapSheetMngService mapSheetMngService;
@Value("${file.sync-root-dir}")
private String syncRootDir;
@Value("${file.sync-tmp-dir}")
private String syncRootTmpDir;
@Operation(summary = "영상 데이터 관리 목록 조회", description = "영상 데이터 관리 목록 조회")
@ApiResponses(
value = {
@@ -300,4 +309,37 @@ public class MapSheetMngApiController {
return ApiResponseDto.ok(mapSheetMngService.findMapSheetMngDoneYyyyList());
}
@Operation(summary = "영상 tif 대용량 파일 분할 전송", description = "영상 tif 파일 대용량 파일을 청크 단위로 전송합니다.")
@ApiResponses(
value = {
@ApiResponse(responseCode = "200", description = "청크 업로드 성공", content = @Content),
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
@ApiResponse(responseCode = "404", description = "업로드 세션을 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping(value = "/file-chunk-upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ApiResponseDto<ModelUploadResDto> fileChunkUpload(
@RequestParam("hstUid") Long hstUid,
@RequestParam("fileName") String fileName,
@RequestParam("fileSize") long fileSize,
@RequestParam("chunkIndex") Integer chunkIndex,
@RequestParam("chunkTotalIndex") Integer chunkTotalIndex,
@RequestPart("chunkFile") MultipartFile chunkFile) {
String uploadDivi = "mapsheet";
UploadDto.UploadAddReq upAddReqDto = new UploadDto.UploadAddReq();
upAddReqDto.setDatasetId(0L);
upAddReqDto.setFileName(fileName);
upAddReqDto.setFileSize(fileSize);
upAddReqDto.setChunkIndex(chunkIndex);
upAddReqDto.setChunkTotalIndex(chunkTotalIndex);
upAddReqDto.setUploadDivi(uploadDivi);
upAddReqDto.setFinalPath(syncRootDir);
upAddReqDto.setTempPath(syncRootTmpDir);
return ApiResponseDto.ok(
mapSheetMngService.uploadChunkMapSheetFile(hstUid, upAddReqDto, chunkFile));
}
}

View File

@@ -9,6 +9,7 @@ import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
@@ -256,6 +257,8 @@ public class MapSheetMngDto {
private String errorCheckTifFileName;
private String mapSheetPath;
private UUID uuid;
// private List<MngFIleDto> fileArray;
public ErrorDataDto(
@@ -274,7 +277,8 @@ public class MapSheetMngDto {
String errorCheckState,
String errorCheckTfwFileName,
String errorCheckTifFileName,
String mapSheetPath) {
String mapSheetPath,
UUID uuid) {
this.hstUid = hstUid;
this.mngYyyy = mngYyyy;
this.mapSheetNum = mapSheetNum;
@@ -293,6 +297,7 @@ public class MapSheetMngDto {
this.errorCheckTfwFileName = errorCheckTfwFileName;
this.errorCheckTifFileName = errorCheckTifFileName;
this.mapSheetPath = mapSheetPath;
this.uuid = uuid;
}
private String getSyncStateName(String enumId) {

View File

@@ -15,8 +15,12 @@ import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngFilesDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngYyyyDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.YearSearchReq;
import com.kamco.cd.kamcoback.model.dto.ModelMngDto.ModelUploadResDto;
import com.kamco.cd.kamcoback.postgres.core.MapSheetMngCoreService;
import com.kamco.cd.kamcoback.postgres.entity.YearEntity;
import com.kamco.cd.kamcoback.upload.dto.UploadDto;
import com.kamco.cd.kamcoback.upload.dto.UploadDto.UploadAddReq;
import com.kamco.cd.kamcoback.upload.service.UploadService;
import jakarta.validation.Valid;
import java.io.IOException;
import java.nio.file.Files;
@@ -38,6 +42,7 @@ import org.springframework.web.multipart.MultipartFile;
public class MapSheetMngService {
private final MapSheetMngCoreService mapSheetMngCoreService;
private final UploadService uploadService;
private final UserUtil userUtil = new UserUtil();
@Value("${file.sync-root-dir}")
@@ -129,15 +134,15 @@ public class MapSheetMngService {
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;
}
}
// 중복체크 -> 도엽/uuid_yyyyMMddhhmmss 경로에 업로드 할 거라 overwrite 되지 않음
// if (!overwrite) {
// dmlReturn =
// this.duplicateFile(
// errDto.getMngYyyy(), tfwFile.getOriginalFilename(), tifFile.getOriginalFilename());
// if (dmlReturn.getFlag().equals("duplicate")) {
// return dmlReturn;
// }
// }
// 멀티파트 파일 tmp폴더 저장(파일형식 체크를 위해)
String tfwTmpPath = tmpPath + tfwFile.getOriginalFilename();
@@ -357,4 +362,44 @@ public class MapSheetMngService {
return yearList;
}
@Transactional
public ModelUploadResDto uploadChunkMapSheetFile(
Long hstUid, UploadAddReq upAddReqDto, MultipartFile chunkFile) {
// String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
ErrorDataDto errDto = mapSheetMngCoreService.findMapSheetError(hstUid);
// 싱크파일목록으로 업로드 경로 확인
List<MngFilesDto> mngFiles = mapSheetMngCoreService.findByHstUidMapSheetFileList(hstUid);
String uploadPath = "";
for (MngFilesDto dto : mngFiles) {
uploadPath = dto.getFilePath();
break;
}
if (uploadPath.isEmpty()) {
MngFilesDto filesDto =
mapSheetMngCoreService.findYyyyToMapSheetFilePathRefer(errDto.getMngYyyy());
String referPath = filesDto.getFilePath();
uploadPath = Paths.get(referPath).getParent().toString() + "/" + errDto.getRefMapSheetNum();
}
upAddReqDto.setUuid(errDto.getUuid());
upAddReqDto.setFinalPath(uploadPath + "/");
upAddReqDto.setTempPath(upAddReqDto.getTempPath() + "/");
UploadDto.UploadRes upRes = uploadService.uploadChunk(upAddReqDto, chunkFile);
ModelUploadResDto modelUploadResDto = new ModelUploadResDto();
modelUploadResDto.setRes(upRes.getRes());
modelUploadResDto.setResMsg(upRes.getResMsg());
modelUploadResDto.setUuid(upRes.getUuid());
modelUploadResDto.setFilePath(upRes.getFilePath());
modelUploadResDto.setFileName(upRes.getFileName());
modelUploadResDto.setChunkIndex(upRes.getChunkIndex());
modelUploadResDto.setChunkTotalIndex(upRes.getChunkTotalIndex());
return modelUploadResDto;
}
}

View File

@@ -12,6 +12,7 @@ import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Size;
import java.time.ZonedDateTime;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
@@ -159,6 +160,9 @@ public class MapSheetMngHstEntity extends CommonDateEntity {
@Column(name = "sync_check_tfw_file_name", length = 100)
private String syncCheckTfwFileName;
@Column(name = "uuid")
private UUID uuid;
// 파일정보 업데이트
public void updateFileInfos(Long tifSizeBytes, Long tfwSizeBytes) {
tifSizeBytes = tifSizeBytes == null ? 0L : tifSizeBytes;

View File

@@ -387,7 +387,8 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
mapSheetMngHstEntity.syncCheckState,
mapSheetMngHstEntity.syncCheckTfwFileName,
mapSheetMngHstEntity.syncCheckTifFileName,
mapSheetMngHstEntity.mapSheetPath))
mapSheetMngHstEntity.mapSheetPath,
mapSheetMngHstEntity.uuid))
.from(mapSheetMngHstEntity)
.innerJoin(mapInkx5kEntity)
.on(
@@ -435,7 +436,6 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
Expressions.stringTemplate(
"concat({0}, substring({1}, 1, 5))",
mapInkx5kEntity.mapidNm, mapSheetMngHstEntity.mapSheetNum),
// 튜플 방지: concat으로 문자열 생성
Expressions.stringTemplate(
"concat('(', {0}, ',', {1}, ')')",
@@ -443,18 +443,18 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
Expressions.stringTemplate(
"concat({0}, substring({1}, 6, 3))",
mapInkx5kEntity.mapidNm, mapSheetMngHstEntity.mapSheetNum),
// fid 타입 주의 (Long이면 DTO도 Long으로 맞추는 걸 추천)
mapInkx5kEntity.fid, // 또는 mapInkx5kEntity.fid.intValue()
// createdDate 말고 ZonedDateTime으로 매핑된 필드로
mapSheetMngHstEntity.createdDate, // (예시)
mapSheetMngHstEntity.createdDate, // (예시) //createdDttm
mapSheetMngHstEntity.syncState,
mapSheetMngHstEntity.syncTfwFileName,
mapSheetMngHstEntity.syncTifFileName,
mapSheetMngHstEntity.syncCheckState,
mapSheetMngHstEntity.syncCheckTfwFileName,
mapSheetMngHstEntity.syncCheckTifFileName))
mapSheetMngHstEntity.syncCheckTifFileName,
mapSheetMngHstEntity.mapSheetPath,
mapSheetMngHstEntity.uuid))
.from(mapSheetMngHstEntity)
.innerJoin(mapInkx5kEntity)
.on(mapSheetMngHstEntity.mapSheetNum.eq(mapInkx5kEntity.mapidcdNo))