Merge remote-tracking branch 'origin/feat/dev_251201' into feat/dev_251201
# Conflicts: # src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiController.java # src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/MapSheetMngDto.java # src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryImpl.java
This commit is contained in:
@@ -27,7 +27,7 @@ public class CustomAuthenticationProvider implements AuthenticationProvider {
|
||||
// 유저 조회
|
||||
MemberEntity member =
|
||||
membersRepository
|
||||
.findByUserId(username)
|
||||
.findByEmployeeNo(username)
|
||||
.orElseThrow(() -> new CustomApiException(AuthErrorCode.LOGIN_ID_NOT_FOUND));
|
||||
|
||||
// 미사용 상태
|
||||
|
||||
@@ -7,9 +7,9 @@ import lombok.Getter;
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum StatusType implements EnumType {
|
||||
ACTIVE("활성"),
|
||||
ACTIVE("사용"),
|
||||
INACTIVE("미사용"),
|
||||
PENDING("보류");
|
||||
PENDING("계정등록");
|
||||
|
||||
private final String desc;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ public class CommonStringUtils {
|
||||
*/
|
||||
public static boolean isValidPassword(String password) {
|
||||
String passwordPattern =
|
||||
"^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-\\[\\]{};':\"\\\\|,.<>/?]).{8,20}$";
|
||||
"^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-\\[\\]{};':\"\\\\|,.<>/?=]).{8,20}$";
|
||||
return Pattern.matches(passwordPattern, password);
|
||||
}
|
||||
|
||||
|
||||
@@ -152,55 +152,97 @@ public class FIleChecker {
|
||||
File file = new File(filePath);
|
||||
|
||||
if (!file.exists()) {
|
||||
System.err.println("파일이 존재하지 않습니다: " + filePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean hasDriver = false;
|
||||
|
||||
// 운영체제 감지
|
||||
String osName = System.getProperty("os.name").toLowerCase();
|
||||
boolean isWindows = osName.contains("win");
|
||||
boolean isMac = osName.contains("mac");
|
||||
boolean isUnix = osName.contains("nix") || osName.contains("nux") || osName.contains("aix");
|
||||
|
||||
// gdalinfo 경로 찾기 (일반적인 설치 경로 우선 확인)
|
||||
String gdalinfoPath = findGdalinfoPath();
|
||||
if (gdalinfoPath == null) {
|
||||
System.err.println("gdalinfo 명령어를 찾을 수 없습니다. GDAL이 설치되어 있는지 확인하세요.");
|
||||
System.err.println("macOS: brew install gdal");
|
||||
System.err.println("Ubuntu/Debian: sudo apt-get install gdal-bin");
|
||||
System.err.println("CentOS/RHEL: sudo yum install gdal");
|
||||
return false;
|
||||
}
|
||||
|
||||
List<String> command = new ArrayList<>();
|
||||
// 윈도우용
|
||||
|
||||
command.add("cmd.exe"); // 윈도우 명령 프롬프트 실행
|
||||
command.add("/c"); // 명령어를 수행하고 종료한다는 옵션
|
||||
command.add("gdalinfo");
|
||||
command.add(filePath);
|
||||
command.add("|");
|
||||
command.add("findstr");
|
||||
command.add("/i");
|
||||
command.add("Geo");
|
||||
|
||||
/*
|
||||
command.add("sh"); // 리눅스,맥 명령 프롬프트 실행
|
||||
command.add("-c"); // 명령어를 수행하고 종료한다는 옵션
|
||||
command.add("gdalinfo");
|
||||
command.add(filePath);
|
||||
command.add("|");
|
||||
command.add("grep");
|
||||
command.add("-i");
|
||||
command.add("Geo");
|
||||
*/
|
||||
if (isWindows) {
|
||||
// 윈도우용
|
||||
command.add("cmd.exe");
|
||||
command.add("/c");
|
||||
command.add(gdalinfoPath + " \"" + filePath + "\" | findstr /i Geo");
|
||||
} else if (isMac || isUnix) {
|
||||
// 리눅스, 맥용
|
||||
command.add("sh");
|
||||
command.add("-c");
|
||||
command.add(gdalinfoPath + " \"" + filePath + "\" | grep -i Geo");
|
||||
} else {
|
||||
System.err.println("지원하지 않는 운영체제: " + osName);
|
||||
return false;
|
||||
}
|
||||
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||
processBuilder.redirectErrorStream(true);
|
||||
|
||||
Process process = null;
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
Process process = processBuilder.start();
|
||||
System.out.println("gdalinfo 명령어 실행 시작: " + filePath);
|
||||
process = processBuilder.start();
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
System.out.println("line == " + line);
|
||||
System.out.println("gdalinfo 출력: " + line);
|
||||
if (line.contains("Driver: GTiff/GeoTIFF")) {
|
||||
hasDriver = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
process.waitFor();
|
||||
int exitCode = process.waitFor();
|
||||
System.out.println("gdalinfo 종료 코드: " + exitCode);
|
||||
|
||||
} catch (Exception e) {
|
||||
// 프로세스가 정상 종료되지 않았고 Driver를 찾지 못한 경우
|
||||
if (exitCode != 0 && !hasDriver) {
|
||||
System.err.println("gdalinfo 명령 실행 실패. Exit code: " + exitCode);
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
System.err.println("gdalinfo 실행 중 I/O 오류 발생: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} catch (InterruptedException e) {
|
||||
System.err.println("gdalinfo 실행 중 인터럽트 발생: " + e.getMessage());
|
||||
Thread.currentThread().interrupt();
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
System.err.println("gdalinfo 실행 중 예상치 못한 오류 발생: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
// 리소스 정리
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
System.err.println("BufferedReader 종료 중 오류: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
if (process != null) {
|
||||
process.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
return hasDriver;
|
||||
@@ -349,4 +391,54 @@ public class FIleChecker {
|
||||
return nameComparator;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gdalinfo 실행 파일 경로를 찾습니다.
|
||||
*
|
||||
* @return gdalinfo 경로 (찾지 못하면 null)
|
||||
*/
|
||||
private static String findGdalinfoPath() {
|
||||
// 일반적인 설치 경로 확인
|
||||
String[] possiblePaths = {
|
||||
"/usr/local/bin/gdalinfo", // Homebrew (macOS)
|
||||
"/opt/homebrew/bin/gdalinfo", // Homebrew (Apple Silicon macOS)
|
||||
"/usr/bin/gdalinfo", // Linux
|
||||
"gdalinfo" // PATH에 있는 경우
|
||||
};
|
||||
|
||||
for (String path : possiblePaths) {
|
||||
if (isCommandAvailable(path)) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 명령어가 사용 가능한지 확인합니다.
|
||||
*
|
||||
* @param command 명령어 경로
|
||||
* @return 사용 가능 여부
|
||||
*/
|
||||
private static boolean isCommandAvailable(String command) {
|
||||
try {
|
||||
ProcessBuilder pb = new ProcessBuilder(command, "--version");
|
||||
pb.redirectErrorStream(true);
|
||||
Process process = pb.start();
|
||||
|
||||
// 프로세스 완료 대기 (최대 5초)
|
||||
boolean finished = process.waitFor(5, java.util.concurrent.TimeUnit.SECONDS);
|
||||
|
||||
if (!finished) {
|
||||
process.destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 종료 코드가 0이면 정상 (일부 명령어는 --version에서 다른 코드 반환할 수 있음)
|
||||
return process.exitValue() == 0 || process.exitValue() == 1;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||
|
||||
@Slf4j
|
||||
@Order(value = 1)
|
||||
@@ -396,7 +397,8 @@ public class GlobalExceptionHandler {
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ApiResponseDto<String> handlerException(Exception e, HttpServletRequest request) {
|
||||
log.warn("[Exception] resource :{} ", e.getMessage());
|
||||
log.error("[Exception] resource: {}, message: {}", request.getRequestURI(), e.getMessage());
|
||||
log.error("Exception stacktrace: ", e);
|
||||
|
||||
String codeName = "INTERNAL_SERVER_ERROR";
|
||||
ErrorLogEntity errorLog =
|
||||
@@ -504,4 +506,22 @@ public class GlobalExceptionHandler {
|
||||
|
||||
// return new ResponseEntity<>(body, status);
|
||||
}
|
||||
|
||||
@ResponseStatus(HttpStatus.PAYLOAD_TOO_LARGE)
|
||||
@ExceptionHandler(MaxUploadSizeExceededException.class)
|
||||
public ApiResponseDto<String> handleMaxUploadSizeExceeded(
|
||||
MaxUploadSizeExceededException e, HttpServletRequest request) {
|
||||
log.warn("[MaxUploadSizeExceededException] resource :{} ", e.getMessage());
|
||||
ApiResponseCode code = ApiResponseCode.PAYLOAD_TOO_LARGE;
|
||||
ErrorLogEntity errorLog =
|
||||
saveErrorLogData(
|
||||
request,
|
||||
code,
|
||||
HttpStatus.PAYLOAD_TOO_LARGE,
|
||||
ErrorLogDto.LogErrorLevel.WARNING,
|
||||
e.getStackTrace());
|
||||
|
||||
return ApiResponseDto.createException(
|
||||
code, code.getText(), HttpStatus.PAYLOAD_TOO_LARGE, errorLog.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,6 +172,7 @@ public class ApiResponseDto<T> {
|
||||
"You can only reset your password within 24 hours from when the email was sent.\n"
|
||||
+ "To reset your password again, please submit a new request through \"Forgot"
|
||||
+ " Password.\""),
|
||||
PAYLOAD_TOO_LARGE("업로드 용량 제한을 초과했습니다."),
|
||||
;
|
||||
// @formatter:on
|
||||
private final String message;
|
||||
|
||||
@@ -34,11 +34,13 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
@@ -318,11 +320,34 @@ public class MapSheetMngFileCheckerService {
|
||||
@Transactional
|
||||
public String uploadFile(MultipartFile file, String targetPath, boolean overwrite, Long hstUid) {
|
||||
try {
|
||||
// 파일 유효성 검증
|
||||
if (file == null || file.isEmpty()) {
|
||||
throw new ValidationException("업로드 파일이 비어있습니다.");
|
||||
}
|
||||
if (file.getOriginalFilename() == null || file.getOriginalFilename().isEmpty()) {
|
||||
throw new ValidationException("파일명이 유효하지 않습니다.");
|
||||
}
|
||||
|
||||
Path path = Paths.get(targetPath);
|
||||
if (Files.isDirectory(path)) {
|
||||
|
||||
// targetPath가 존재하지 않으면 파일 경로로 가정하고 부모 디렉토리 생성
|
||||
if (!Files.exists(path)) {
|
||||
// 경로가 확장자로 끝나면 파일로 간주
|
||||
if (targetPath.matches(".*\\.[a-zA-Z]{3,4}$")) {
|
||||
if (path.getParent() != null) {
|
||||
Files.createDirectories(path.getParent());
|
||||
}
|
||||
} else {
|
||||
// 확장자가 없으면 디렉토리로 간주
|
||||
Files.createDirectories(path);
|
||||
path = path.resolve(file.getOriginalFilename());
|
||||
}
|
||||
} else if (Files.isDirectory(path)) {
|
||||
path = path.resolve(file.getOriginalFilename());
|
||||
}
|
||||
if (path.getParent() != null) {
|
||||
|
||||
// 최종 파일의 부모 디렉토리 생성
|
||||
if (path.getParent() != null && !Files.exists(path.getParent())) {
|
||||
Files.createDirectories(path.getParent());
|
||||
}
|
||||
|
||||
@@ -403,8 +428,13 @@ public class MapSheetMngFileCheckerService {
|
||||
saveUploadMeta(path, hstUid);
|
||||
|
||||
return "업로드 성공";
|
||||
} catch (ValidationException | DuplicateFileException e) {
|
||||
// 비즈니스 예외는 그대로 던짐
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException("파일 I/O 처리 실패: " + e.getMessage());
|
||||
throw new IllegalArgumentException("파일 I/O 처리 실패: " + e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("파일 업로드 처리 중 오류 발생: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,8 +446,45 @@ public class MapSheetMngFileCheckerService {
|
||||
boolean overwrite,
|
||||
Long hstUid) {
|
||||
try {
|
||||
log.info(
|
||||
"uploadPair 시작 - targetPath: {}, overwrite: {}, hstUid: {}",
|
||||
targetPath,
|
||||
overwrite,
|
||||
hstUid);
|
||||
|
||||
// 파일 유효성 검증
|
||||
if (tfwFile == null || tfwFile.isEmpty()) {
|
||||
throw new ValidationException("TFW 파일이 비어있습니다.");
|
||||
}
|
||||
if (tifFile == null || tifFile.isEmpty()) {
|
||||
throw new ValidationException("TIF 파일이 비어있습니다.");
|
||||
}
|
||||
if (tfwFile.getOriginalFilename() == null || tfwFile.getOriginalFilename().isEmpty()) {
|
||||
throw new ValidationException("TFW 파일명이 유효하지 않습니다.");
|
||||
}
|
||||
if (tifFile.getOriginalFilename() == null || tifFile.getOriginalFilename().isEmpty()) {
|
||||
throw new ValidationException("TIF 파일명이 유효하지 않습니다.");
|
||||
}
|
||||
|
||||
log.info(
|
||||
"파일명 - TFW: {}, TIF: {}", tfwFile.getOriginalFilename(), tifFile.getOriginalFilename());
|
||||
|
||||
Path basePath = Paths.get(targetPath);
|
||||
|
||||
// targetPath가 존재하지 않으면 디렉토리로 생성
|
||||
if (!Files.exists(basePath)) {
|
||||
log.info("대상 경로가 존재하지 않아 디렉토리 생성: {}", basePath);
|
||||
Files.createDirectories(basePath);
|
||||
}
|
||||
|
||||
// 파일인 경우 부모 디렉토리를 basePath로 사용
|
||||
if (Files.isRegularFile(basePath)) {
|
||||
log.info("대상 경로가 파일이므로 부모 디렉토리 사용");
|
||||
basePath = basePath.getParent();
|
||||
}
|
||||
|
||||
if (Files.isDirectory(basePath)) {
|
||||
log.info("디렉토리 확인됨: {}", basePath);
|
||||
// 디렉토리인 경우 파일명 기준으로 경로 생성
|
||||
Path tfwPath = basePath.resolve(tfwFile.getOriginalFilename());
|
||||
Path tifPath = basePath.resolve(tifFile.getOriginalFilename());
|
||||
@@ -427,9 +494,9 @@ public class MapSheetMngFileCheckerService {
|
||||
if (!tfwBase.equalsIgnoreCase(tifBase)) {
|
||||
throw new ValidationException("TFW/TIF 파일명이 동일한 베이스가 아닙니다.");
|
||||
}
|
||||
// 디렉토리 생성
|
||||
if (tfwPath.getParent() != null) Files.createDirectories(tfwPath.getParent());
|
||||
if (tifPath.getParent() != null) Files.createDirectories(tifPath.getParent());
|
||||
// 디렉토리는 이미 생성되었으므로 추가 생성 불필요
|
||||
// if (tfwPath.getParent() != null) Files.createDirectories(tfwPath.getParent());
|
||||
// if (tifPath.getParent() != null) Files.createDirectories(tifPath.getParent());
|
||||
|
||||
// DB 중복 체크 및 overwrite 처리 (각 파일별)
|
||||
String parentPathStr = basePath.toString();
|
||||
@@ -450,32 +517,51 @@ public class MapSheetMngFileCheckerService {
|
||||
}
|
||||
|
||||
// 파일 저장
|
||||
log.info("파일 저장 시작 - TFW: {}, TIF: {}", tfwPath, tifPath);
|
||||
tfwFile.transferTo(tfwPath.toFile());
|
||||
tifFile.transferTo(tifPath.toFile());
|
||||
log.info("파일 저장 완료");
|
||||
|
||||
// 검증
|
||||
log.info("TFW 파일 검증 시작: {}", tfwPath);
|
||||
boolean tfwOk = FIleChecker.checkTfw(tfwPath.toString());
|
||||
if (!tfwOk) {
|
||||
log.warn("TFW 파일 검증 실패: {}", tfwName);
|
||||
Files.deleteIfExists(tfwPath);
|
||||
Files.deleteIfExists(tifPath);
|
||||
throw new ValidationException("유효하지 않은 TFW 파일입니다 (6줄 숫자 형식 검증 실패): " + tfwName);
|
||||
}
|
||||
log.info("TFW 파일 검증 성공");
|
||||
|
||||
log.info("TIF 파일 검증 시작: {}", tifPath);
|
||||
boolean isValidTif = FIleChecker.cmmndGdalInfo(tifPath.toString());
|
||||
if (!isValidTif) {
|
||||
log.warn("TIF 파일 검증 실패: {}", tifName);
|
||||
Files.deleteIfExists(tfwPath);
|
||||
Files.deleteIfExists(tifPath);
|
||||
throw new ValidationException("유효하지 않은 TIF 파일입니다 (GDAL 검증 실패): " + tifName);
|
||||
}
|
||||
log.info("TIF 파일 검증 성공");
|
||||
|
||||
// 메타 저장 (두 파일 각각 저장)
|
||||
log.info("메타 데이터 저장 시작");
|
||||
saveUploadMeta(tfwPath, hstUid);
|
||||
saveUploadMeta(tifPath, hstUid);
|
||||
log.info("메타 데이터 저장 완료");
|
||||
return "TFW/TIF 페어 업로드 성공";
|
||||
} else {
|
||||
throw new ValidationException("targetPath는 디렉토리여야 합니다.");
|
||||
}
|
||||
} catch (ValidationException | DuplicateFileException e) {
|
||||
// 비즈니스 예외는 그대로 던짐
|
||||
log.warn("업로드 비즈니스 예외 발생: {}", e.getMessage());
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException("파일 I/O 처리 실패: " + e.getMessage());
|
||||
log.error("파일 I/O 처리 실패: {}", e.getMessage(), e);
|
||||
throw new IllegalArgumentException("파일 I/O 처리 실패: " + e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
log.error("파일 업로드 처리 중 예상치 못한 오류 발생: {}", e.getMessage(), e);
|
||||
throw new IllegalArgumentException("파일 업로드 처리 중 오류 발생: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,8 @@ public class MembersDto {
|
||||
ZonedDateTime createdDttm,
|
||||
ZonedDateTime firstLoginDttm,
|
||||
ZonedDateTime lastLoginDttm,
|
||||
ZonedDateTime statusChgDttm) {
|
||||
ZonedDateTime statusChgDttm,
|
||||
Boolean pwdResetYn) {
|
||||
this.id = id;
|
||||
this.uuid = uuid;
|
||||
this.userRole = userRole;
|
||||
@@ -54,7 +55,7 @@ public class MembersDto {
|
||||
this.name = name;
|
||||
this.employeeNo = employeeNo;
|
||||
this.status = status;
|
||||
this.statusName = getStatusName(status);
|
||||
this.statusName = getStatusName(status, pwdResetYn);
|
||||
this.createdDttm = createdDttm;
|
||||
this.firstLoginDttm = firstLoginDttm;
|
||||
this.lastLoginDttm = lastLoginDttm;
|
||||
@@ -66,8 +67,12 @@ public class MembersDto {
|
||||
return type.getText();
|
||||
}
|
||||
|
||||
private String getStatusName(String status) {
|
||||
private String getStatusName(String status, Boolean pwdResetYn) {
|
||||
StatusType type = Enums.fromId(StatusType.class, status);
|
||||
pwdResetYn = pwdResetYn != null && pwdResetYn;
|
||||
if (type.equals(StatusType.PENDING) && pwdResetYn) {
|
||||
type = StatusType.ACTIVE;
|
||||
}
|
||||
return type.getText();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import lombok.ToString;
|
||||
@ToString(exclude = "password")
|
||||
public class SignInRequest {
|
||||
|
||||
@Schema(description = "사용자 ID", example = "admin2")
|
||||
@Schema(description = "사용자 ID", example = "1234567")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "비밀번호", example = "Admin2!@#")
|
||||
|
||||
@@ -142,7 +142,7 @@ public class MembersCoreService {
|
||||
public String getUserStatus(SignInRequest request) {
|
||||
MemberEntity memberEntity =
|
||||
membersRepository
|
||||
.findByUserId(request.getUsername())
|
||||
.findByEmployeeNo(request.getUsername())
|
||||
.orElseThrow(MemberNotFoundException::new);
|
||||
return memberEntity.getStatus();
|
||||
}
|
||||
|
||||
@@ -125,7 +125,8 @@ public class MembersRepositoryImpl implements MembersRepositoryCustom {
|
||||
memberEntity.createdDttm,
|
||||
memberEntity.firstLoginDttm,
|
||||
memberEntity.lastLoginDttm,
|
||||
memberEntity.statusChgDttm))
|
||||
memberEntity.statusChgDttm,
|
||||
memberEntity.pwdResetYn))
|
||||
.from(memberEntity)
|
||||
.where(builder)
|
||||
.offset(pageable.getOffset())
|
||||
|
||||
@@ -108,14 +108,19 @@ public class MapSheetMngFileJobRepositoryImpl extends QuerydslRepositorySupport
|
||||
|
||||
public void mngHstDataSyncStateUpdate(MapSheetMngDto.MngHstDto updateReq) {
|
||||
|
||||
ZonedDateTime now = ZonedDateTime.now();
|
||||
|
||||
if (updateReq.getDataState().equals("DONE")) {
|
||||
long updateCount =
|
||||
queryFactory
|
||||
.update(mapSheetMngHstEntity)
|
||||
.set(mapSheetMngHstEntity.dataState, updateReq.getDataState())
|
||||
.set(mapSheetMngHstEntity.dataStateDttm, ZonedDateTime.now())
|
||||
.set(mapSheetMngHstEntity.dataStateDttm, now)
|
||||
.set(mapSheetMngHstEntity.syncState, updateReq.getSyncState())
|
||||
.set(mapSheetMngHstEntity.syncEndDttm, ZonedDateTime.now())
|
||||
.set(mapSheetMngHstEntity.syncEndDttm, now)
|
||||
.set(mapSheetMngHstEntity.syncCheckState, "DONE")
|
||||
.set(mapSheetMngHstEntity.syncCheckStrtDttm, now)
|
||||
.set(mapSheetMngHstEntity.syncCheckEndDttm, now)
|
||||
.where(mapSheetMngHstEntity.hstUid.eq(updateReq.getHstUid()))
|
||||
.execute();
|
||||
} else {
|
||||
@@ -123,10 +128,13 @@ public class MapSheetMngFileJobRepositoryImpl extends QuerydslRepositorySupport
|
||||
queryFactory
|
||||
.update(mapSheetMngHstEntity)
|
||||
.set(mapSheetMngHstEntity.dataState, updateReq.getDataState())
|
||||
.set(mapSheetMngHstEntity.dataStateDttm, ZonedDateTime.now())
|
||||
.set(mapSheetMngHstEntity.dataStateDttm, now)
|
||||
.set(mapSheetMngHstEntity.syncState, updateReq.getSyncState())
|
||||
.set(mapSheetMngHstEntity.syncStrtDttm, ZonedDateTime.now())
|
||||
.set(mapSheetMngHstEntity.syncEndDttm, ZonedDateTime.now())
|
||||
.set(mapSheetMngHstEntity.syncStrtDttm, now)
|
||||
.set(mapSheetMngHstEntity.syncEndDttm, now)
|
||||
.set(mapSheetMngHstEntity.syncCheckState, "PROCESSING")
|
||||
.set(mapSheetMngHstEntity.syncCheckStrtDttm, now)
|
||||
.set(mapSheetMngHstEntity.syncCheckEndDttm, now)
|
||||
.where(mapSheetMngHstEntity.hstUid.eq(updateReq.getHstUid()))
|
||||
.execute();
|
||||
}
|
||||
|
||||
@@ -38,13 +38,14 @@ spring:
|
||||
servlet:
|
||||
multipart:
|
||||
enabled: true
|
||||
max-file-size: 1024MB
|
||||
max-request-size: 2048MB
|
||||
max-file-size: 4GB
|
||||
max-request-size: 4GB
|
||||
file-size-threshold: 10MB
|
||||
|
||||
server:
|
||||
tomcat:
|
||||
max-swallow-size: 2097152000 # 약 2GB
|
||||
max-swallow-size: 4GB
|
||||
max-http-form-post-size: 4GB
|
||||
|
||||
jwt:
|
||||
secret: "kamco_token_9b71e778-19a3-4c1d-97bf-2d687de17d5b"
|
||||
@@ -73,4 +74,3 @@ mapsheet:
|
||||
upload:
|
||||
skipGdalValidation: true
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,18 @@ spring:
|
||||
port: 6379
|
||||
password: 1234
|
||||
|
||||
servlet:
|
||||
multipart:
|
||||
enabled: true
|
||||
max-file-size: 4GB
|
||||
max-request-size: 4GB
|
||||
file-size-threshold: 10MB
|
||||
|
||||
server:
|
||||
tomcat:
|
||||
max-swallow-size: 4GB
|
||||
max-http-form-post-size: 4GB
|
||||
|
||||
jwt:
|
||||
secret: "kamco_token_9b71e778-19a3-4c1d-97bf-2d687de17d5b"
|
||||
access-token-validity-in-ms: 86400000 # 1일
|
||||
@@ -41,7 +53,3 @@ token:
|
||||
springdoc:
|
||||
swagger-ui:
|
||||
persist-authorization: true # 스웨거 새로고침해도 토큰 유지, 로컬스토리지에 저장
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: dev
|
||||
on-profile: prod
|
||||
|
||||
jpa:
|
||||
show-sql: false
|
||||
|
||||
@@ -5,7 +5,7 @@ spring:
|
||||
application:
|
||||
name: kamco-change-detection-api
|
||||
profiles:
|
||||
active: dev # 사용할 프로파일 지정 (ex. dev, prod, test)
|
||||
active: local # 사용할 프로파일 지정 (ex. dev, prod, test)
|
||||
|
||||
datasource:
|
||||
driver-class-name: org.postgresql.Driver
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.kamco.cd.kamcoback.common.utils;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledOnOs;
|
||||
import org.junit.jupiter.api.condition.OS;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
class FIleCheckerTest {
|
||||
|
||||
@Test
|
||||
void testOsDetection() {
|
||||
// 운영체제 감지 테스트
|
||||
String osName = System.getProperty("os.name").toLowerCase();
|
||||
System.out.println("현재 운영체제: " + osName);
|
||||
|
||||
boolean isWindows = osName.contains("win");
|
||||
boolean isMac = osName.contains("mac");
|
||||
boolean isUnix = osName.contains("nix") || osName.contains("nux") || osName.contains("aix");
|
||||
|
||||
// 최소한 하나의 OS는 감지되어야 함
|
||||
assertTrue(isWindows || isMac || isUnix, "지원되는 운영체제를 감지해야 합니다");
|
||||
|
||||
System.out.println("Windows: " + isWindows);
|
||||
System.out.println("Mac: " + isMac);
|
||||
System.out.println("Unix/Linux: " + isUnix);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckTfw_ValidFile(@TempDir File tempDir) throws IOException {
|
||||
// 임시 유효한 TFW 파일 생성
|
||||
File tfwFile = new File(tempDir, "test.tfw");
|
||||
try (FileWriter writer = new FileWriter(tfwFile)) {
|
||||
writer.write("0.25\n"); // pixel size x
|
||||
writer.write("0.0\n"); // rotation x
|
||||
writer.write("0.0\n"); // rotation y
|
||||
writer.write("-0.25\n"); // pixel size y
|
||||
writer.write("127.5\n"); // upper left x
|
||||
writer.write("37.5\n"); // upper left y
|
||||
}
|
||||
|
||||
boolean result = FIleChecker.checkTfw(tfwFile.getAbsolutePath());
|
||||
assertTrue(result, "유효한 TFW 파일은 true를 반환해야 합니다");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckTfw_InvalidFile(@TempDir File tempDir) throws IOException {
|
||||
// 잘못된 TFW 파일 생성 (5줄만)
|
||||
File tfwFile = new File(tempDir, "invalid.tfw");
|
||||
try (FileWriter writer = new FileWriter(tfwFile)) {
|
||||
writer.write("0.25\n");
|
||||
writer.write("0.0\n");
|
||||
writer.write("0.0\n");
|
||||
writer.write("-0.25\n");
|
||||
writer.write("127.5\n");
|
||||
// 6번째 줄 누락
|
||||
}
|
||||
|
||||
boolean result = FIleChecker.checkTfw(tfwFile.getAbsolutePath());
|
||||
assertFalse(result, "잘못된 TFW 파일은 false를 반환해야 합니다");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCheckTfw_NonExistentFile() {
|
||||
boolean result = FIleChecker.checkTfw("/non/existent/path/file.tfw");
|
||||
assertFalse(result, "존재하지 않는 파일은 false를 반환해야 합니다");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCmmndGdalInfo_MethodExists() throws NoSuchMethodException {
|
||||
// cmmndGdalInfo 메서드가 존재하는지 확인
|
||||
assertNotNull(FIleChecker.class.getMethod("cmmndGdalInfo", String.class));
|
||||
System.out.println("cmmndGdalInfo 메서드 존재 확인");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCmmndGdalInfo_NonExistentFile() {
|
||||
// 존재하지 않는 파일은 false를 반환해야 함
|
||||
boolean result = FIleChecker.cmmndGdalInfo("/non/existent/path/file.tif");
|
||||
assertFalse(result, "존재하지 않는 파일은 false를 반환해야 합니다");
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledOnOs(OS.WINDOWS)
|
||||
void testWindowsCommand() {
|
||||
System.out.println("Windows OS 감지됨 - GDAL 명령어 형식 확인");
|
||||
String osName = System.getProperty("os.name").toLowerCase();
|
||||
assertTrue(osName.contains("win"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledOnOs(OS.MAC)
|
||||
void testMacCommand() {
|
||||
System.out.println("Mac OS 감지됨 - GDAL 명령어 형식 확인");
|
||||
String osName = System.getProperty("os.name").toLowerCase();
|
||||
assertTrue(osName.contains("mac"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledOnOs(OS.LINUX)
|
||||
void testLinuxCommand() {
|
||||
System.out.println("Linux OS 감지됨 - GDAL 명령어 형식 확인");
|
||||
String osName = System.getProperty("os.name").toLowerCase();
|
||||
assertTrue(osName.contains("nux") || osName.contains("nix"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user