검수완료 geosjon 생성 스케줄러 수정

This commit is contained in:
2026-02-24 19:52:51 +09:00
parent 135c6b5892
commit 6bec4d017f
282 changed files with 1913 additions and 4824 deletions

View File

@@ -0,0 +1,13 @@
package com.kamcoback.cd.review;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TrainingDataReviewApplication {
public static void main(String[] args) {
SpringApplication.run(TrainingDataReviewApplication.class, args);
}
}

View File

@@ -0,0 +1,15 @@
package com.kamcoback.cd.review.config;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QuerydslConfig {
@Bean
public JPAQueryFactory jpaQueryFactory(EntityManager em) {
return new JPAQueryFactory(em);
}
}

View File

@@ -0,0 +1,22 @@
package com.kamcoback.cd.review.controller;
import com.kamcoback.cd.review.dto.ApiResponseDto;
import com.kamcoback.cd.review.service.TrainingDataReviewJobService;
import java.time.LocalDate;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class TrainingDataReviewController {
private final TrainingDataReviewJobService trainingDataReviewJobService;
@GetMapping("/review-to-geojson")
public ApiResponseDto<Long> runExportGeojsonLabelingGeom(@RequestParam(required = false) LocalDate baseDate) {
trainingDataReviewJobService.exportGeojsonLabelingGeom(baseDate);
return ApiResponseDto.ok(0L);
}
}

View File

@@ -0,0 +1,223 @@
package com.kamcoback.cd.review.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.kamcoback.cd.review.enums.EnumType;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.springframework.http.HttpStatus;
@Getter
@ToString
public class ApiResponseDto<T> {
private T data;
@JsonInclude(JsonInclude.Include.NON_NULL)
private Error error;
@JsonInclude(JsonInclude.Include.NON_NULL)
private T errorData;
@JsonIgnore private HttpStatus httpStatus;
@JsonIgnore private Long errorLogUid;
public ApiResponseDto(T data) {
this.data = data;
}
private ApiResponseDto(T data, HttpStatus httpStatus) {
this.data = data;
this.httpStatus = httpStatus;
}
public ApiResponseDto(ApiResponseCode code) {
this.error = new Error(code.getId(), code.getMessage());
}
public ApiResponseDto(ApiResponseCode code, String message) {
this.error = new Error(code.getId(), message);
}
public ApiResponseDto(ApiResponseCode code, String message, HttpStatus httpStatus) {
this.error = new Error(code.getId(), message);
this.httpStatus = httpStatus;
}
public ApiResponseDto(
ApiResponseCode code, String message, HttpStatus httpStatus, Long errorLogUid) {
this.error = new Error(code.getId(), message);
this.httpStatus = httpStatus;
this.errorLogUid = errorLogUid;
}
public ApiResponseDto(ApiResponseCode code, String message, T errorData) {
this.error = new Error(code.getId(), message);
this.errorData = errorData;
}
// HTTP 상태 코드가 내장된 ApiResponseDto 반환 메서드들
public static <T> ApiResponseDto<T> createOK(T data) {
return new ApiResponseDto<>(data, HttpStatus.CREATED);
}
public static <T> ApiResponseDto<T> ok(T data) {
return new ApiResponseDto<>(data, HttpStatus.OK);
}
public static <T> ApiResponseDto<ResponseObj> okObject(ResponseObj data) {
if (data.getCode().equals(ApiResponseCode.OK)) {
return new ApiResponseDto<>(data, HttpStatus.NO_CONTENT);
} else {
return new ApiResponseDto<>(data.getCode(), data.getMessage(), HttpStatus.CONFLICT);
}
}
public static <T> ApiResponseDto<T> deleteOk(T data) {
return new ApiResponseDto<>(data, HttpStatus.NO_CONTENT);
}
public static ApiResponseDto<String> createException(ApiResponseCode code) {
return new ApiResponseDto<>(code);
}
public static ApiResponseDto<String> createException(ApiResponseCode code, String message) {
return new ApiResponseDto<>(code, message);
}
public static ApiResponseDto<String> createException(
ApiResponseCode code, String message, HttpStatus httpStatus) {
return new ApiResponseDto<>(code, message, httpStatus);
}
public static ApiResponseDto<String> createException(
ApiResponseCode code, String message, HttpStatus httpStatus, Long errorLogUid) {
return new ApiResponseDto<>(code, message, httpStatus, errorLogUid);
}
public static <T> ApiResponseDto<T> createException(
ApiResponseCode code, String message, T data) {
return new ApiResponseDto<>(code, message, data);
}
@Getter
public static class Error {
private final String code;
private final String message;
public Error(String code, String message) {
this.code = code;
this.message = message;
}
}
/** Error가 아닌 Business상 성공이거나 실패인 경우, 메세지 함께 전달하기 위한 object */
@Getter
public static class ResponseObj {
private final ApiResponseCode code;
private final String message;
public ResponseObj(ApiResponseCode code, String message) {
this.code = code;
this.message = message;
}
}
@Getter
@RequiredArgsConstructor
public enum ApiResponseCode implements EnumType {
// @formatter:off
OK("요청이 성공하였습니다."),
BAD_REQUEST("요청 파라미터가 잘못되었습니다."),
BAD_GATEWAY("네트워크 상태가 불안정합니다."),
ALREADY_EXIST_MALL("이미 등록된 쇼핑센터입니다."),
NOT_FOUND_MAP("지도를 찾을 수 없습니다."),
UNAUTHORIZED("권한이 없습니다."),
CONFLICT("이미 등록된 컨텐츠입니다."),
NOT_FOUND("Resource를 찾을 수 없습니다."),
NOT_FOUND_DATA("데이터를 찾을 수 없습니다."),
NOT_FOUND_WEATHER_DATA("날씨 데이터를 찾을 수 없습니다."),
FAIL_SEND_MESSAGE("메시지를 전송하지 못했습니다."),
TOO_MANY_CONNECTED_MACHINES("연결된 기기가 너무 많습니다."),
UNAUTHENTICATED("인증에 실패하였습니다."),
INVALID_TOKEN("잘못된 토큰입니다."),
EXPIRED_TOKEN("만료된 토큰입니다."),
INTERNAL_SERVER_ERROR("서버에 문제가 발생 하였습니다."),
FORBIDDEN("권한을 확인해주세요."),
INVALID_PASSWORD("잘못된 비밀번호 입니다."),
NOT_FOUND_CAR_IN("입차정보가 없습니다."),
WRONG_STATUS("잘못된 상태입니다."),
FAIL_VERIFICATION("인증에 실패하였습니다."),
INVALID_EMAIL("잘못된 형식의 이메일입니다."),
REQUIRED_EMAIL("이메일은 필수 항목입니다."),
WRONG_PASSWORD("잘못된 패스워드입니다."),
DUPLICATE_EMAIL("이미 가입된 이메일입니다."),
DUPLICATE_DATA("이미 등록되어 있습니다."),
DATA_INTEGRITY_ERROR("데이터 무결성이 위반되어 요청을 처리할수 없습니다."),
FOREIGN_KEY_ERROR("참조 중인 데이터가 있어 삭제할 수 없습니다."),
DUPLICATE_EMPLOYEEID("이미 가입된 사번입니다."),
NOT_FOUND_USER_FOR_EMAIL("이메일로 유저를 찾을 수 없습니다."),
NOT_FOUND_USER("사용자를 찾을 수 없습니다."),
UNPROCESSABLE_ENTITY("이 데이터는 삭제할 수 없습니다."),
LOGIN_ID_NOT_FOUND("아이디를 잘못 입력하셨습니다."),
LOGIN_PASSWORD_MISMATCH("비밀번호를 잘못 입력하셨습니다."),
LOGIN_PASSWORD_EXCEEDED("비밀번호 오류 횟수를 초과하여 이용하실 수 없습니다.\n로그인 오류에 대해 관리자에게 문의하시기 바랍니다."),
INACTIVE_ID("사용할 수 없는 계정입니다."),
INVALID_EMAIL_TOKEN(
"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("업로드 용량 제한을 초과했습니다."),
NOT_FOUND_TARGET_YEAR("기준년도 도엽을 찾을 수 없습니다."),
NOT_FOUND_COMPARE_YEAR("비교년도 도엽을 찾을 수 없습니다."),
FAIL_SAVE_MAP_SHEET("도엽 저장 중 오류가 발생했습니다."),
FAIL_CREATE_MAP_SHEET_FILE("도엽 설정파일 생성 중 오류가 발생했습니다."),
;
// @formatter:on
private final String message;
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return message;
}
public static ApiResponseCode getCode(String name) {
return ApiResponseCode.valueOf(name.toUpperCase());
}
public static String getMessage(String name) {
return ApiResponseCode.valueOf(name.toUpperCase()).getText();
}
public static ApiResponseCode from(String codeName, HttpStatus status) {
if (codeName != null && !codeName.isBlank()) {
try {
return ApiResponseCode.valueOf(codeName.toUpperCase());
} catch (IllegalArgumentException ignore) {
// fallback
}
}
if (status != null) {
try {
return ApiResponseCode.valueOf(status.name());
} catch (IllegalArgumentException ignore) {
// fallback
}
}
return INTERNAL_SERVER_ERROR;
}
}
}

View File

@@ -0,0 +1,670 @@
package com.kamcoback.cd.review.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.kamcoback.cd.review.enums.EnumType;
import com.kamcoback.cd.review.interfaces.EnumValid;
import com.kamcoback.cd.review.interfaces.JsonFormatDttm;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.time.Duration;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
public class InferenceResultDto {
/** 분석대상 도엽 enum */
@Getter
@AllArgsConstructor
public enum MapSheetScope implements EnumType {
ALL("전체"),
PART("부분"),
;
private final String desc;
public static MapSheetScope fromCode(String code) {
return Arrays.stream(values()).filter(v -> v.name().equals(code)).findFirst().orElse(null);
}
public static String getDescByCode(String code) {
return fromCode(code).getDesc();
}
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
}
/** 탐지 데이터 옵션 dto */
@Getter
@AllArgsConstructor
public enum DetectOption implements EnumType {
EXCL("추론제외"),
PREV("이전 년도 도엽 사용"),
;
private final String desc;
public static DetectOption fromCode(String code) {
return Arrays.stream(values()).filter(v -> v.name().equals(code)).findFirst().orElse(null);
}
public static String getDescByCode(String code) {
return fromCode(code).getDesc();
}
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
}
@Getter
@AllArgsConstructor
public enum Status implements EnumType {
READY("대기"),
IN_PROGRESS("진행중"),
END("완료"),
FORCED_END("강제종료");
private final String desc;
public static Status fromCode(String code) {
return Arrays.stream(values()).filter(v -> v.name().equals(code)).findFirst().orElse(null);
}
public static String getDescByCode(String code) {
return fromCode(code).getDesc();
}
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
}
@Getter
@AllArgsConstructor
public enum ServerStatus implements EnumType {
SAFETY("원활"),
CAUTION("주의"),
FAILUR("장애"),
;
private final String desc;
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
}
/** 목록조회 dto */
// 추론관리 목록
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class ResultList {
private UUID uuid;
// 제목
private String title;
// 회차
private Integer stage;
// 상태
private String status;
// 분석 도엽
private String mapSheetCnt;
// 탐지건수
private Long detectingCnt;
// 시작일시
@JsonFormatDttm
private ZonedDateTime startTime;
// 종료일시
@JsonFormatDttm
private ZonedDateTime endTime;
// 반영여부
private Boolean applyYn;
// 반영일시
@JsonFormatDttm
private ZonedDateTime applyDttm;
// 비교년도
private Integer compareYyyy;
// 기준년도
private Integer targetYyyy;
// uid
private String uid;
// uid 앞 8자리
@JsonProperty("subUid")
public String subUid() {
return this.uid.substring(0, 8).toUpperCase();
}
// 상태명
@JsonProperty("statusName")
public String statusName() {
return Status.getDescByCode(this.status);
}
// 소요시간
@JsonProperty("elapsedTim")
public String getElapsedTime() {
if (this.startTime == null || this.endTime == null) {
return null;
}
ZonedDateTime start = this.startTime;
ZonedDateTime end = this.endTime;
Duration d = Duration.between(start, end);
if (d.isNegative()) {
d = d.negated();
}
long s = d.getSeconds();
long h = s / 3600;
long m = (s % 3600) / 60;
long sec = s % 60;
return String.format("%d시간 %d분 %d초", h, m, sec);
}
}
/** 목록조회 검색 조건 dto */
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class SearchListReq {
// 검색 조건
private String applyYn;
private LocalDate strtDttm;
private LocalDate endDttm;
private String title;
// 페이징 파라미터
private int page = 0;
private int size = 20;
public Pageable toPageable() {
return PageRequest.of(page, size);
}
}
/** 변화탐지 실행 정보 저장 요청 정보 */
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class RegReq {
// 제목
@NotBlank
private String title;
// G1
@NotNull
private UUID model1Uuid;
// G2
@NotNull
private UUID model2Uuid;
// G3
@NotNull
private UUID model3Uuid;
// 비교년도
@NotNull
private Integer compareYyyy;
// 탐지년도
@NotNull
private Integer targetYyyy;
// 분석대상 도엽 - 전체(ALL), 부분(PART)
@NotBlank
@EnumValid(enumClass = MapSheetScope.class, message = "분석대상 도엽 옵션은 '전체', '부분' 만 사용 가능합니다.")
private String mapSheetScope;
// 탐지 데이터 옵션 - 추론제외(EXCL), 이전 년도 도엽 사용(PREV)
@NotBlank
@EnumValid(
enumClass = DetectOption.class,
message = "탐지 데이터 옵션은 '추론제외', '이전 년도 도엽 사용' 만 사용 가능합니다.")
private String detectOption;
// 5k 도협 번호 목록
@NotNull
private List<String> mapSheetNum;
}
@Getter
@Setter
public static class MapSheetNumDto {
private String mapSheetNum;
private String mapSheetName;
}
@Getter
@Setter
@NoArgsConstructor
// 추론(변화탐지) 진행상태
public static class InferenceStatusDetailDto {
// 모델1 사용시간 시작일시
@JsonFormatDttm
ZonedDateTime m1ModelStartDttm;
// 모델2 사용시간 시작일시
@JsonFormatDttm
ZonedDateTime m2ModelStartDttm;
// 모델3 사용시간 시작일시
@JsonFormatDttm
ZonedDateTime m3ModelStartDttm;
// 모델1 사용시간 종료일시
@JsonFormatDttm
ZonedDateTime m1ModelEndDttm;
// 모델2 사용시간 종료일시
@JsonFormatDttm
ZonedDateTime m2ModelEndDttm;
// 모델3 사용시간 종료일시
@JsonFormatDttm
ZonedDateTime m3ModelEndDttm;
// 탐지대상 도엽수
private Long detectingCnt;
// 모델1 분석 대기
private Integer m1PendingJobs;
// 모델2 분석 대기
private Integer m2PendingJobs;
// 모델3 분석 대기
private Integer m3PendingJobs;
// 모델1 분석 진행중
private Integer m1RunningJobs;
// 모델2 분석 진행중
private Integer m2RunningJobs;
// 모델3 분석 진행중
private Integer m3RunningJobs;
// 모델1 분석 완료
private Integer m1CompletedJobs;
// 모델2 분석 완료
private Integer m2CompletedJobs;
// 모델3 분석 완료
private Integer m3CompletedJobs;
// 모델1 분석 실패
private Integer m1FailedJobs;
// 모델2 분석 실패
private Integer m2FailedJobs;
// 모델3 분석 실패
private Integer m3FailedJobs;
// 변화탐지 제목
private String title;
// 비교년도
private Integer compareYyyy;
// 기준년도
private Integer targetYyyy;
// 회차
private Integer stage;
// 변화탐지 시작
@JsonFormatDttm
private ZonedDateTime inferStartDttm;
// 변화탐지 종료
@JsonFormatDttm
private ZonedDateTime inferEndDttm;
// 변화탐지 옵션
private String detectOption;
// 분석도엽
private String mapSheetScope;
// 모델1 버전
private String modelVer1;
// 모델2 버전
private String modelVer2;
// 모델3 버전
private String modelVer3;
// 탑지 도엽 수
@JsonIgnore
private Long totalJobs;
public InferenceStatusDetailDto(
Long detectingCnt,
Integer m1PendingJobs,
Integer m2PendingJobs,
Integer m3PendingJobs,
Integer m1RunningJobs,
Integer m2RunningJobs,
Integer m3RunningJobs,
Integer m1CompletedJobs,
Integer m2CompletedJobs,
Integer m3CompletedJobs,
Integer m1FailedJobs,
Integer m2FailedJobs,
Integer m3FailedJobs,
ZonedDateTime m1ModelStartDttm,
ZonedDateTime m2ModelStartDttm,
ZonedDateTime m3ModelStartDttm,
ZonedDateTime m1ModelEndDttm,
ZonedDateTime m2ModelEndDttm,
ZonedDateTime m3ModelEndDttm,
String title,
Integer compareYyyy,
Integer targetYyyy,
Integer stage,
ZonedDateTime inferStartDttm,
ZonedDateTime inferEndDttm,
String detectOption,
String mapSheetScope,
String modelVer1,
String modelVer2,
String modelVer3,
Long totalJobs) {
this.detectingCnt = detectingCnt;
this.m1PendingJobs = m1PendingJobs;
this.m2PendingJobs = m2PendingJobs;
this.m3PendingJobs = m3PendingJobs;
this.m1RunningJobs = m1RunningJobs;
this.m2RunningJobs = m2RunningJobs;
this.m3RunningJobs = m3RunningJobs;
this.m1CompletedJobs = m1CompletedJobs;
this.m2CompletedJobs = m2CompletedJobs;
this.m3CompletedJobs = m3CompletedJobs;
this.m1FailedJobs = m1FailedJobs;
this.m2FailedJobs = m2FailedJobs;
this.m3FailedJobs = m3FailedJobs;
this.m1ModelStartDttm = m1ModelStartDttm;
this.m2ModelStartDttm = m2ModelStartDttm;
this.m3ModelStartDttm = m3ModelStartDttm;
this.m1ModelEndDttm = m1ModelEndDttm;
this.m2ModelEndDttm = m2ModelEndDttm;
this.m3ModelEndDttm = m3ModelEndDttm;
this.title = title;
this.compareYyyy = compareYyyy;
this.targetYyyy = targetYyyy;
this.stage = stage;
this.inferStartDttm = inferStartDttm;
this.inferEndDttm = inferEndDttm;
this.detectOption = detectOption;
this.mapSheetScope = mapSheetScope;
this.modelVer1 = modelVer1;
this.modelVer2 = modelVer2;
this.modelVer3 = modelVer3;
this.totalJobs = totalJobs;
}
// 진행률
@JsonProperty("progress")
private int getProgress() {
long tiles = this.totalJobs == null ? 0L : this.totalJobs; // 도엽수
int models = 3; // 모델 개수
int completed =
this.m1CompletedJobs
+ this.m2CompletedJobs
+ this.m3CompletedJobs
+ this.m1FailedJobs
+ this.m2FailedJobs
+ this.m3FailedJobs; // 완료수
long total = tiles * models; // 전체 작업량
if (completed >= total) {
return 100;
}
return (int) ((completed * 100L) / total);
}
// 변화탐지 옵션명
@JsonProperty("detectOptionName")
private String getDetectOptionName() {
return DetectOption.getDescByCode(this.detectOption);
}
// 분석도엽 명
@JsonProperty("mapSheetScopeName")
private String getMapSheetScopeName() {
return MapSheetScope.getDescByCode(this.mapSheetScope);
}
// G1 사용시간
@JsonProperty("m1ElapsedTim")
public String getM1ElapsedTime() {
return formatElapsedTime(this.m1ModelStartDttm, this.m1ModelEndDttm);
}
// G2 사용시간
@JsonProperty("m2ElapsedTim")
public String getM2ElapsedTime() {
return formatElapsedTime(this.m2ModelStartDttm, this.m2ModelEndDttm);
}
// G3 사용시간
@JsonProperty("m3ElapsedTim")
public String getM3ElapsedTime() {
return formatElapsedTime(this.m3ModelStartDttm, this.m3ModelEndDttm);
}
private String formatElapsedTime(ZonedDateTime start, ZonedDateTime end) {
if (start == null || end == null) {
return null;
}
Duration d = Duration.between(start, end);
if (d.isNegative()) {
d = d.negated();
}
long s = d.getSeconds();
long h = s / 3600;
long m = (s % 3600) / 60;
long sec = s % 60;
return String.format("%d시간 %d분 %d초", h, m, sec);
}
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class InferenceServerStatusDto {
private String serverName;
@JsonIgnore private float cpu_user;
@JsonIgnore private float cpu_system;
@JsonIgnore private float memused;
private Long kbmemused;
private float gpuUtil;
public float getCpuUseRate() {
return this.cpu_user + this.cpu_system;
}
public String getServerStatus() {
String enumId = "SAFETY";
if (this.cpu_user + this.cpu_system + this.gpuUtil + this.kbmemused == 0) {
enumId = "FAILUR";
}
return enumId;
}
public String getServerStatusName() {
String enumStr = ServerStatus.SAFETY.getText();
if (this.cpu_user + this.cpu_system + this.gpuUtil + this.kbmemused == 0) {
enumStr = ServerStatus.FAILUR.getText();
}
return enumStr;
}
public String getCpuStatus() {
String enumId = "SAFETY";
if (this.cpu_user + this.cpu_system >= 80) {
enumId = "CAUTION";
} else if (this.cpu_user + this.cpu_system + this.memused == 0) {
enumId = "FAILUR";
}
return enumId;
}
public String getGpuStatus() {
String enumId = "SAFETY";
if (this.gpuUtil >= 80) {
enumId = "CAUTION";
} else if (this.cpu_user + this.cpu_system == 0) {
enumId = "FAILUR";
}
return enumId;
}
public String getMemStatus() {
String enumId = "SAFETY";
if (this.memused >= 80) {
enumId = "CAUTION";
} else if (this.cpu_user + this.cpu_system + this.memused == 0) {
enumId = "FAILUR";
}
return enumId;
}
public String getCpuStatusName() {
if (this.cpu_user + this.cpu_system >= 80) {
return ServerStatus.CAUTION.getText();
} else if (this.cpu_user + this.cpu_system + this.memused == 0) {
return ServerStatus.FAILUR.getText();
}
return ServerStatus.SAFETY.getText();
}
public String getGpuStatusName() {
if (this.gpuUtil >= 80) {
return ServerStatus.CAUTION.getText();
} else if (this.cpu_user + this.cpu_system + this.memused == 0) {
return ServerStatus.FAILUR.getText();
}
return ServerStatus.SAFETY.getText();
}
public String getMemStatusName() {
if (this.memused >= 80) {
return ServerStatus.CAUTION.getText();
} else if (this.cpu_user + this.cpu_system + this.memused == 0) {
return ServerStatus.FAILUR.getText();
}
return ServerStatus.SAFETY.getText();
}
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class InferenceStatusDetailDto2 {
InferenceServerStatusDto serverStatus;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class SaveInferenceAiDto {
private UUID uuid;
private Long batchId;
private String status;
private String type;
private ZonedDateTime inferStartDttm;
private ZonedDateTime inferEndDttm;
private Long detectEndCnt;
private String modelComparePath;
private String modelTargetPath;
private String modelModelPath;
private ZonedDateTime modelStartDttm;
private ZonedDateTime modelEndDttm;
private Long updateUid;
private String runningModelType;
private Integer pendingJobs;
private Integer runningJobs;
private Integer completedJobs;
private Integer failedJobs;
}
@Getter
@Setter
public static class InferenceLearnDto {
private String uid;
private Long m1ModelBatchId;
private Long m2ModelBatchId;
private Long m3ModelBatchId;
}
}

View File

@@ -0,0 +1,347 @@
package com.kamcoback.cd.review.dto;
import com.kamcoback.cd.review.enums.EnumType;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
public class LabelAllocateDto {
@Getter
@AllArgsConstructor
public enum LabelMngState implements EnumType {
PENDING("작업대기"),
ASSIGNED("작업할당"),
ING("진행중"),
FINISH("종료");
private String desc;
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
}
@Getter
@AllArgsConstructor
public enum LabelState implements EnumType {
WAIT("대기"),
ASSIGNED("배정"),
SKIP("스킵"),
DONE("완료");
private String desc;
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
}
@Getter
@AllArgsConstructor
public enum InspectState implements EnumType {
UNCONFIRM("미확인"),
EXCEPT("제외"),
COMPLETE("완료");
private String desc;
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
}
@Getter
@Setter
@AllArgsConstructor
public static class AllocateDto {
// 회차 마스터 key
private UUID uuid;
// 비교년도-기준년도
private String yyyy;
// 회차
private Integer stage;
// 라벨러 할당 목록
private List<TargetUser> labelers;
// 검수자 할당 목록
private List<String> inspectors;
}
@Getter
public static class TargetUser {
// 라벨러 사번
private final String userId;
// 할당 건수
private final int demand;
public TargetUser(String userId, int demand) {
this.userId = userId;
this.demand = demand;
}
}
@Getter
@AllArgsConstructor
public static class TargetInspector {
// 검수자 사번
private final String inspectorUid;
// 할당 명수
private int userCount;
}
@Getter
@Setter
@AllArgsConstructor
public static class Basic {
private UUID assignmentUid;
private Long inferenceGeomUid;
private String workerUid;
private String inspectorUid;
private String workState;
private Character stagnationYn;
private String assignGroupId;
private Long learnGeomUid;
private Long analUid;
private ZonedDateTime createdDttm;
private ZonedDateTime updatedDttm;
private String inspectState;
private ZonedDateTime workStatDttm;
private ZonedDateTime inspectStatDttm;
}
@Getter
@Setter
@AllArgsConstructor
public static class UserList {
private String userRole;
private String employeeNo;
private String name;
}
@Getter
@Setter
@AllArgsConstructor
public static class InferenceDetail {
private String analTitle;
private Integer stage;
private ZonedDateTime gukyuinDttm;
private Long count;
}
@Getter
@Setter
@AllArgsConstructor
public static class LabelerDetail {
private String roleType;
private String name;
private String userId; // 사번
private Long count;
private Long completeCnt;
private Long skipCnt;
private Double percent;
private Integer ranking;
private ZonedDateTime createdDttm;
private String ownerName;
private Long remainCnt;
}
@Getter
@Setter
@AllArgsConstructor
public static class AllocateMoveDto {
// 총 잔여 건수
private Integer totalCnt;
// 이관할 라벨러
private List<String> labelers;
// 회차 마스터 key
private String uuid;
// 대상 사번
private String userId;
}
@Getter
@Setter
@AllArgsConstructor
public static class AllocateInfoDto {
private Long geoUid;
private Long mapSheetNum;
private Long pnu;
}
@Getter
@Setter
@AllArgsConstructor
public static class LabelingStatDto {
private String workDate;
private Long dailyTotalCnt;
private Long totalCnt;
private Long assignedCnt;
private Long skipCnt;
private Long completeCnt;
private Long remainCnt;
}
// 일자별 작업 목록 요청
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class searchReq {
// 페이징 파라미터
private int page = 0;
private int size = 20;
private String sort;
public Pageable toPageable() {
if (sort != null && !sort.isEmpty()) {
String[] sortParams = sort.split(",");
String property = sortParams[0];
Sort.Direction direction =
sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC;
return PageRequest.of(page, size, Sort.by(direction, property));
}
return PageRequest.of(page, size);
}
}
@Getter
@Setter
@AllArgsConstructor
public static class MoveUserList {
private String userRole;
private String employeeNo;
private String name;
private Long remainCnt;
private Double percent;
}
@Getter
@Setter
@AllArgsConstructor
public static class MoveInfo {
private Long totalCnt;
private List<MoveUserList> moveUserList;
}
// WorkHistoryDto
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class WorkHistoryDto {
// 행 번호
private Integer rowNum;
// 변화탐지년도
private String changeDetectionYear;
// 국유IN 회차
private Long stage;
// 반영일
private ZonedDateTime gukyuinApplyDttm;
// 할당건수
private Long assignedCnt;
// 완료건수
private Long completeCnt;
// Skip건수
private Long skipCnt;
// 잔여건수
private Long remainCnt;
// 상태 (진행중/완료)
private String status;
// 진행률 (%)
private Double percent;
// 작업기간 시작일
private ZonedDateTime createdDttm;
// 작업기간 종료일
private ZonedDateTime projectCloseDttm;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class InferenceLearnDto {
private UUID analUuid;
private String learnUid;
private String analState;
private Long analId;
}
@Getter
@Setter
@AllArgsConstructor
public static class AllocateAddStbltDto {
// 총 잔여 건수
private Integer totalCnt;
// 추가할당할 라벨러
private List<String> labelers;
// 회차 마스터 key
private UUID uuid;
// 기준일자
private LocalDate baseDate;
}
}

View File

@@ -0,0 +1,22 @@
package com.kamcoback.cd.review.dto;
import java.time.ZonedDateTime;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
public class LabelInspectorDto {
@Getter
@Setter
@AllArgsConstructor
public static class Basic {
private UUID operatorUid;
private Long analUid;
private String inspectorUid;
private ZonedDateTime createdDttm;
private ZonedDateTime updatedDttm;
}
}

View File

@@ -0,0 +1,132 @@
package com.kamcoback.cd.review.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.JsonProcessingException;
import java.util.List;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.node.ObjectNode;
public class TrainingDataReviewJobDto {
@Getter
@Setter
@RequiredArgsConstructor
@AllArgsConstructor
public static class Tasks {
private UUID assignmentUid;
private Long inferenceUid;
private Long analUid;
}
@Getter
@Setter
@RequiredArgsConstructor
@AllArgsConstructor
public static class InspectorPendingDto {
String inspectorUid;
Long pendingCount;
}
@Getter
@Setter
@RequiredArgsConstructor
@AllArgsConstructor
public static class AnalCntInfo {
Long analUid;
String resultUid;
Long allCnt;
Long completeCnt;
Long fileCnt;
}
@Getter
@Setter
@RequiredArgsConstructor
@AllArgsConstructor
public static class AnalMapSheetList {
private Integer compareYyyy;
private Integer targetYyyy;
private String mapSheetNum;
}
@Getter
@Setter
@JsonPropertyOrder({"type", "features"})
public static class FeatureCollection {
private final String type = "FeatureCollection";
private List<CompleteLabelData.GeoJsonFeature> features;
public FeatureCollection(List<CompleteLabelData.GeoJsonFeature> features) {
this.features = features;
}
}
@Getter
@Setter
@JsonPropertyOrder({"type", "geometry", "properties"})
public static class CompleteLabelData {
private Long geoUid;
private String type;
@JsonIgnore private String geomStr;
private JsonNode geometry;
private Properties properties;
public CompleteLabelData(Long geoUid, String type, String geomStr, Properties properties) {
this.geoUid = geoUid;
this.type = type;
this.geomStr = geomStr;
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = null;
if (geomStr != null) {
jsonNode = mapper.readTree(this.geomStr);
}
this.geometry = jsonNode;
if (jsonNode != null && jsonNode.isObject()) {
((ObjectNode) jsonNode).remove("crs");
}
this.properties = properties;
}
@Getter
@Setter
@RequiredArgsConstructor
@AllArgsConstructor
public static class Properties {
private String modelId;
private String before;
private String after;
}
@Getter
@AllArgsConstructor
public static class GeoJsonFeature {
private String type;
private JsonNode geometry;
private Properties properties;
public static GeoJsonFeature from(CompleteLabelData data) {
return new GeoJsonFeature(
data.getType(),
data.getGeometry(), // geoUid 없음
data.getProperties());
}
}
}
}

View File

@@ -0,0 +1,8 @@
package com.kamcoback.cd.review.enums;
public interface EnumType {
String getId();
String getText();
}

View File

@@ -0,0 +1,26 @@
package com.kamcoback.cd.review.enums;
import com.kamcoback.cd.review.interfaces.EnumValid;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
public class EnumValidator implements ConstraintValidator<EnumValid, String> {
private Set<String> acceptedValues;
@Override
public void initialize(EnumValid constraintAnnotation) {
acceptedValues =
Arrays.stream(constraintAnnotation.enumClass().getEnumConstants())
.map(Enum::name)
.collect(Collectors.toSet());
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value != null && acceptedValues.contains(value);
}
}

View File

@@ -0,0 +1,28 @@
package com.kamcoback.cd.review.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum GukYuinStatus implements EnumType {
PENDING("대기"),
IN_PROGRESS("진행중"),
GUK_COMPLETED("국유인 매핑 완료"),
PNU_COMPLETED("PNU 싱크 완료"),
PNU_FAILED("PNU 싱크 중 에러"),
END("종료"),
CANCELED("취소");
private final String desc;
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
}

View File

@@ -0,0 +1,24 @@
package com.kamcoback.cd.review.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum ModelType implements EnumType {
G1("G1"),
G2("G2"),
G3("G3");
private final String desc;
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
}

View File

@@ -0,0 +1,23 @@
package com.kamcoback.cd.review.interfaces;
import com.kamcoback.cd.review.enums.EnumValidator;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EnumValidator.class)
public @interface EnumValid {
String message() default "올바르지 않은 값입니다.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Class<? extends Enum<?>> enumClass();
}

View File

@@ -0,0 +1,19 @@
package com.kamcoback.cd.review.interfaces;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@JacksonAnnotationsInside
@JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "yyyy-MM-dd'T'HH:mm:ssXXX",
timezone = "Asia/Seoul")
public @interface JsonFormatDttm {}

View File

@@ -0,0 +1,35 @@
package com.kamcoback.cd.review.postgres.core;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.AnalCntInfo;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.AnalMapSheetList;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.CompleteLabelData;
import com.kamcoback.cd.review.postgres.repository.TrainingDataReviewJobRepository;
import java.time.LocalDate;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class TrainingDataReviewJobCoreService {
private final TrainingDataReviewJobRepository trainingDataReviewJobRepository;
public List<CompleteLabelData> findCompletedYesterdayLabelingList(
Long analUid, String mapSheetNum, LocalDate baseDate) {
return trainingDataReviewJobRepository.findCompletedYesterdayLabelingList(
analUid, mapSheetNum, baseDate);
}
public List<AnalMapSheetList> findCompletedAnalMapSheetList(Long analUid, LocalDate baseDate) {
return trainingDataReviewJobRepository.findCompletedAnalMapSheetList(analUid, baseDate);
}
public List<AnalCntInfo> findAnalCntInfoList() {
return trainingDataReviewJobRepository.findAnalCntInfoList();
}
public void updateLearnDataGeomFileCreateYn(List<Long> geoUids) {
trainingDataReviewJobRepository.updateLearnDataGeomFileCreateYn(geoUids);
}
}

View File

@@ -0,0 +1,34 @@
package com.kamcoback.cd.review.postgres.entity;
import jakarta.persistence.Column;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import java.time.ZonedDateTime;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
@Getter
@MappedSuperclass
public class CommonDateEntity {
@CreatedDate
@Column(name = "created_dttm", updatable = false, nullable = false)
private ZonedDateTime createdDate;
@LastModifiedDate
@Column(name = "updated_dttm", nullable = false)
private ZonedDateTime modifiedDate;
@PrePersist
protected void onPersist() {
this.createdDate = ZonedDateTime.now();
this.modifiedDate = ZonedDateTime.now();
}
@PreUpdate
protected void onUpdate() {
this.modifiedDate = ZonedDateTime.now();
}
}

View File

@@ -0,0 +1,69 @@
package com.kamcoback.cd.review.postgres.entity;
import com.kamcoback.cd.review.dto.LabelAllocateDto;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.time.ZonedDateTime;
import java.util.UUID;
@Entity
@Table(name = "tb_labeling_assignment")
public class LabelingAssignmentEntity extends CommonDateEntity {
@Id
@Column(name = "assignment_uid")
private UUID assignmentUid;
@Column(name = "inference_geom_uid")
private Long inferenceGeomUid;
@Column(name = "worker_uid")
private String workerUid;
@Column(name = "inspector_uid")
private String inspectorUid;
@Column(name = "work_state")
private String workState;
@Column(name = "stagnation_yn")
private Character stagnationYn;
@Column(name = "assign_group_id")
private String assignGroupId;
@Column(name = "learn_geom_uid")
private Long learnGeomUid;
@Column(name = "anal_uid")
private Long analUid;
@Column(name = "inspect_state")
private String inspectState;
@Column(name = "work_stat_dttm")
private ZonedDateTime workStatDttm;
@Column(name = "inspect_stat_dttm")
private ZonedDateTime inspectStatDttm;
public LabelAllocateDto.Basic toDto() {
return new LabelAllocateDto.Basic(
this.assignmentUid,
this.inferenceGeomUid,
this.workerUid,
this.inspectorUid,
this.workState,
this.stagnationYn,
this.assignGroupId,
this.learnGeomUid,
this.analUid,
super.getCreatedDate(),
super.getModifiedDate(),
this.inspectState,
this.workStatDttm,
this.inspectStatDttm);
}
}

View File

@@ -0,0 +1,32 @@
package com.kamcoback.cd.review.postgres.entity;
import com.kamcoback.cd.review.dto.LabelInspectorDto;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.util.UUID;
@Entity
@Table(name = "tb_labeling_inspector")
public class LabelingInspectorEntity extends CommonDateEntity {
@Id
@Column(name = "operator_uid")
private UUID operatorUid;
@Column(name = "anal_uid")
private Long analUid;
@Column(name = "inspector_uid")
private String inspectorUid;
public LabelInspectorDto.Basic toDto() {
return new LabelInspectorDto.Basic(
this.operatorUid,
this.analUid,
this.inspectorUid,
super.getCreatedDate(),
super.getModifiedDate());
}
}

View File

@@ -0,0 +1,165 @@
package com.kamcoback.cd.review.postgres.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Size;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;
@Getter
@Setter
@Entity
@Table(name = "tb_map_sheet_anal_inference")
public class MapSheetAnalInferenceEntity {
@Id
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "tb_map_sheet_anal_inference_id_gen")
@SequenceGenerator(
name = "tb_map_sheet_anal_inference_id_gen",
sequenceName = "tb_map_sheet_anal_inference_uid",
allocationSize = 1)
@Column(name = "anal_uid", nullable = false)
private Long id;
@Column(name = "compare_yyyy")
private Integer compareYyyy;
@Column(name = "target_yyyy")
private Integer targetYyyy;
@Column(name = "model_uid")
private Long modelUid;
@Size(max = 100)
@Column(name = "server_ids", length = 100)
private String serverIds;
@Column(name = "anal_strt_dttm")
private ZonedDateTime analStrtDttm;
@Column(name = "anal_end_dttm")
private ZonedDateTime analEndDttm;
@Column(name = "anal_sec")
private Long analSec;
@Size(max = 20)
@Column(name = "anal_state", length = 20)
private String analState;
@Size(max = 20)
@Column(name = "gukyuin_used", length = 20)
private String gukyuinUsed;
@Column(name = "accuracy")
private Double accuracy;
@Size(max = 255)
@Column(name = "result_url")
private String resultUrl;
@ColumnDefault("now()")
@Column(name = "created_dttm")
private ZonedDateTime createdDttm;
@Column(name = "created_uid")
private Long createdUid;
@ColumnDefault("now()")
@Column(name = "updated_dttm")
private ZonedDateTime updatedDttm;
@Column(name = "updated_uid")
private Long updatedUid;
@Size(max = 255)
@Column(name = "anal_title")
private String analTitle;
@Column(name = "detecting_cnt")
private Long detectingCnt;
@Column(name = "anal_pred_sec")
private Long analPredSec;
@Column(name = "model_ver_uid")
private Long modelVerUid;
@Column(name = "hyper_params")
@JdbcTypeCode(SqlTypes.JSON)
private Map<String, Object> hyperParams;
@Column(name = "tranning_rate")
private List<Double> tranningRate;
@Column(name = "validation_rate")
private List<Double> validationRate;
@Column(name = "test_rate", length = Integer.MAX_VALUE)
private String testRate;
@Size(max = 128)
@Column(name = "detecting_description", length = 128)
private String detectingDescription;
@Size(max = 12)
@Column(name = "base_map_sheet_num", length = 12)
private String baseMapSheetNum;
@ColumnDefault("gen_random_uuid()")
@Column(name = "uuid")
private UUID uuid;
@Size(max = 50)
@Column(name = "model_m1_ver", length = 50)
private String modelM1Ver;
@Size(max = 50)
@Column(name = "model_m2_ver", length = 50)
private String modelM2Ver;
@Size(max = 50)
@Column(name = "model_m3_ver", length = 50)
private String modelM3Ver;
@Size(max = 20)
@Column(name = "anal_target_type", length = 20)
private String analTargetType;
@Column(name = "gukyuin_apply_dttm")
private ZonedDateTime gukyuinApplyDttm;
@Size(max = 20)
@Column(name = "detection_data_option", length = 20)
private String detectionDataOption;
@Column(name = "stage")
private Integer stage;
@Size(max = 1)
@ColumnDefault("'N'")
@Column(name = "labeling_closed_yn", length = 1)
private String labelingClosedYn = "N";
@Size(max = 1)
@ColumnDefault("'N'")
@Column(name = "inspection_closed_yn", length = 1)
private String inspectionClosedYn = "N";
@Column(name = "learn_id")
private Long learnId;
}

View File

@@ -0,0 +1,45 @@
package com.kamcoback.cd.review.postgres.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
import org.locationtech.jts.geom.Geometry;
/** 라벨링 툴에서 그린 폴리곤 저장 테이블 */
@Getter
@Setter
@Entity
@Table(name = "tb_map_sheet_learn_data_geom")
public class MapSheetLearnDataGeomEntity extends CommonDateEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "geo_uid", nullable = false)
private Long geoUid;
@Column(name = "after_yyyy")
private Integer afterYyyy;
@Column(name = "area")
private Double area;
@Column(name = "before_yyyy")
private Integer beforeYyyy;
@Column(name = "class_after_cd")
private String classAfterCd;
@Column(name = "class_before_cd")
private String classBeforeCd;
@Column(name = "geom")
private Geometry geom;
@Column(name = "file_create_yn")
private Boolean fileCreateYn;
}

View File

@@ -0,0 +1,221 @@
package com.kamcoback.cd.review.postgres.entity;
import com.kamcoback.cd.review.dto.InferenceResultDto;
import com.kamcoback.cd.review.enums.GukYuinStatus;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.time.ZonedDateTime;
import java.util.UUID;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.ColumnDefault;
@Getter
@Setter
@Entity
@Table(name = "tb_map_sheet_learn")
public class MapSheetLearnEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tb_map_sheet_learn_id_gen")
@SequenceGenerator(
name = "tb_map_sheet_learn_id_gen",
sequenceName = "tb_map_sheet_learn_uid",
allocationSize = 1)
@Column(name = "id", nullable = false)
private Long id;
@ColumnDefault("gen_random_uuid()")
@Column(name = "uuid")
private UUID uuid = UUID.randomUUID();
@Size(max = 200)
@NotNull
@Column(name = "title", nullable = false, length = 200)
private String title;
@Size(max = 20)
@Column(name = "status", length = 10)
private String status;
@Column(name = "m1_model_uuid")
private UUID m1ModelUuid;
@Column(name = "m2_model_uuid")
private UUID m2ModelUuid;
@Column(name = "m3_model_uuid")
private UUID m3ModelUuid;
@Column(name = "compare_yyyy")
private Integer compareYyyy;
@Column(name = "target_yyyy")
private Integer targetYyyy;
@Size(max = 20)
@Column(name = "detect_option", length = 20)
private String detectOption;
@Size(max = 100)
@Column(name = "map_sheet_cnt", length = 100)
private String mapSheetCnt;
@Size(max = 20)
@Column(name = "map_sheet_scope", length = 20)
private String mapSheetScope;
@Column(name = "detecting_cnt")
private Long detectingCnt;
@Column(name = "infer_start_dttm")
private ZonedDateTime inferStartDttm;
@Column(name = "infer_end_dttm")
private ZonedDateTime inferEndDttm;
@Column(name = "elapsed_time")
private ZonedDateTime elapsedTime;
@Column(name = "apply_yn")
private Boolean applyYn;
@Column(name = "apply_dttm")
private ZonedDateTime applyDttm;
@org.hibernate.annotations.CreationTimestamp
@Column(name = "created_dttm")
private ZonedDateTime createdDttm;
@Column(name = "created_uid")
private Long createdUid;
@ColumnDefault("now()")
@Column(name = "updated_dttm")
private ZonedDateTime updatedDttm;
@Column(name = "updated_uid")
private Long updatedUid;
@Column(name = "running_model_type")
private String runningModelType;
@Column(name = "detect_end_cnt")
private Long detectEndCnt;
@Column(name = "model_compare_path")
private String modelComparePath;
@Column(name = "model_target_path")
private String modelTargetPath;
@Column(name = "stage")
private Integer stage;
/* ===================== M1 ===================== */
@Column(name = "m1_model_batch_id")
private Long m1ModelBatchId;
@Column(name = "m1_model_start_dttm")
private ZonedDateTime m1ModelStartDttm;
@Column(name = "m1_model_end_dttm")
private ZonedDateTime m1ModelEndDttm;
@Column(name = "m1_pending_jobs", nullable = false)
private int m1PendingJobs = 0;
@Column(name = "m1_running_jobs", nullable = false)
private int m1RunningJobs = 0;
@Column(name = "m1_completed_jobs", nullable = false)
private int m1CompletedJobs = 0;
@Column(name = "m1_failed_jobs", nullable = false)
private int m1FailedJobs = 0;
/* ===================== M2 ===================== */
@Column(name = "m2_model_batch_id")
private Long m2ModelBatchId;
@Column(name = "m2_model_start_dttm")
private ZonedDateTime m2ModelStartDttm;
@Column(name = "m2_model_end_dttm")
private ZonedDateTime m2ModelEndDttm;
@Column(name = "m2_pending_jobs", nullable = false)
private int m2PendingJobs = 0;
@Column(name = "m2_running_jobs", nullable = false)
private int m2RunningJobs = 0;
@Column(name = "m2_completed_jobs", nullable = false)
private int m2CompletedJobs = 0;
@Column(name = "m2_failed_jobs", nullable = false)
private int m2FailedJobs = 0;
/* ===================== M3 ===================== */
@Column(name = "m3_model_batch_id")
private Long m3ModelBatchId;
@Column(name = "m3_model_start_dttm")
private ZonedDateTime m3ModelStartDttm;
@Column(name = "m3_model_end_dttm")
private ZonedDateTime m3ModelEndDttm;
@Column(name = "m3_pending_jobs", nullable = false)
private int m3PendingJobs = 0;
@Column(name = "m3_running_jobs", nullable = false)
private int m3RunningJobs = 0;
@Column(name = "m3_completed_jobs", nullable = false)
private int m3CompletedJobs = 0;
@Column(name = "m3_failed_jobs", nullable = false)
private int m3FailedJobs = 0;
@Column(name = "apply_status")
private String applyStatus = GukYuinStatus.PENDING.getId();
@Column(name = "apply_status_dttm")
private ZonedDateTime applyStatusDttm;
@Column(name = "uid", nullable = false)
private String uid = UUID.randomUUID().toString().replace("-", "").toUpperCase();
@Column(name = "total_jobs")
private Long totalJobs;
@Column(name = "chn_dtct_mst_id")
private String chnDtctMstId;
public InferenceResultDto.ResultList toDto() {
return new InferenceResultDto.ResultList(
this.uuid,
this.title,
this.stage,
this.status,
this.mapSheetCnt,
this.detectingCnt,
this.inferStartDttm,
this.inferEndDttm,
this.applyYn,
this.applyDttm,
this.compareYyyy,
this.targetYyyy,
this.uid);
}
}

View File

@@ -0,0 +1,23 @@
package com.kamcoback.cd.review.postgres.repository;
import com.kamcoback.cd.review.postgres.entity.LabelingInspectorEntity;
import jakarta.persistence.LockModeType;
import java.util.List;
import java.util.UUID;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;
public interface TrainingDataReviewJobRepository
extends JpaRepository<LabelingInspectorEntity, UUID>, TrainingDataReviewJobRepositoryCustom {
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query(
"""
select r
from LabelingInspectorEntity r
where r.analUid = :analUid
and r.inspectorUid in :inspectorUids
""")
List<LabelingInspectorEntity> lockInspectors(Long analUid, List<String> inspectorUids);
}

View File

@@ -0,0 +1,19 @@
package com.kamcoback.cd.review.postgres.repository;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.AnalCntInfo;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.AnalMapSheetList;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.CompleteLabelData;
import java.time.LocalDate;
import java.util.List;
public interface TrainingDataReviewJobRepositoryCustom {
List<CompleteLabelData> findCompletedYesterdayLabelingList(
Long analUid, String mapSheetNum, LocalDate baseDate);
List<AnalMapSheetList> findCompletedAnalMapSheetList(Long analUid, LocalDate baseDate);
List<AnalCntInfo> findAnalCntInfoList();
void updateLearnDataGeomFileCreateYn(List<Long> geoUids);
}

View File

@@ -0,0 +1,173 @@
package com.kamcoback.cd.review.postgres.repository;
import static com.kamcoback.cd.review.postgres.entity.QLabelingAssignmentEntity.labelingAssignmentEntity;
import static com.kamcoback.cd.review.postgres.entity.QMapSheetLearnDataGeomEntity.mapSheetLearnDataGeomEntity;
import static com.kamcoback.cd.review.postgres.entity.QMapSheetAnalInferenceEntity.mapSheetAnalInferenceEntity;
import static com.kamcoback.cd.review.postgres.entity.QMapSheetLearnEntity.mapSheetLearnEntity;
import com.kamcoback.cd.review.dto.LabelAllocateDto.InspectState;
import com.kamcoback.cd.review.dto.LabelAllocateDto.LabelMngState;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.AnalCntInfo;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.AnalMapSheetList;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.CompleteLabelData;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.CompleteLabelData.Properties;
import com.kamcoback.cd.review.enums.ModelType;
import com.kamcoback.cd.review.postgres.entity.LabelingAssignmentEntity;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.CaseBuilder;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.NumberExpression;
import com.querydsl.core.types.dsl.StringExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.transaction.Transactional;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.List;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;
@Repository
public class TrainingDataReviewJobRepositoryImpl extends QuerydslRepositorySupport
implements TrainingDataReviewJobRepositoryCustom {
private final JPAQueryFactory queryFactory;
private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)");
public TrainingDataReviewJobRepositoryImpl(JPAQueryFactory queryFactory) {
super(LabelingAssignmentEntity.class);
this.queryFactory = queryFactory;
}
@Override
public List<CompleteLabelData> findCompletedYesterdayLabelingList(
Long analUid, String mapSheetNum, LocalDate baseDate) {
ZoneId zoneId = ZoneId.of("Asia/Seoul");
// baseDate가 null이면 기존처럼 오늘 기준
LocalDate targetDate = (baseDate != null) ? baseDate : LocalDate.now(zoneId);
ZonedDateTime end = targetDate.plusDays(1).atStartOfDay(zoneId);
return queryFactory
.select(
Projections.constructor(
CompleteLabelData.class,
mapSheetLearnDataGeomEntity.geoUid,
Expressions.stringTemplate("{0}", "Feature").as("type"),
Expressions.stringTemplate("ST_AsGeoJSON({0})", mapSheetLearnDataGeomEntity.geom),
Projections.constructor(
Properties.class,
new CaseBuilder()
.when(mapSheetLearnDataGeomEntity.classAfterCd.in("building", "container"))
.then(ModelType.G1.getId())
.when(mapSheetLearnDataGeomEntity.classAfterCd.eq("waste"))
.then(ModelType.G2.getId())
.otherwise(ModelType.G3.getId()),
mapSheetLearnDataGeomEntity.classBeforeCd,
mapSheetLearnDataGeomEntity.classAfterCd)))
.from(labelingAssignmentEntity)
.leftJoin(mapSheetLearnDataGeomEntity)
.on(labelingAssignmentEntity.inferenceGeomUid.eq(mapSheetLearnDataGeomEntity.geoUid))
.where(
labelingAssignmentEntity.analUid.eq(analUid),
labelingAssignmentEntity.assignGroupId.eq(mapSheetNum),
labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId()),
labelingAssignmentEntity.inspectStatDttm.lt(end))
.fetch();
}
@Override
public List<AnalMapSheetList> findCompletedAnalMapSheetList(Long analUid, LocalDate baseDate) {
ZoneId zoneId = ZoneId.of("Asia/Seoul");
// baseDate가 null이면 기존처럼 오늘 기준
LocalDate targetDate = (baseDate != null) ? baseDate : LocalDate.now(zoneId);
ZonedDateTime end = targetDate.plusDays(1).atStartOfDay(zoneId);
return queryFactory
.select(
Projections.constructor(
AnalMapSheetList.class,
mapSheetAnalInferenceEntity.compareYyyy,
mapSheetAnalInferenceEntity.targetYyyy,
labelingAssignmentEntity.assignGroupId))
.from(labelingAssignmentEntity)
.innerJoin(mapSheetAnalInferenceEntity)
.on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id))
.where(
labelingAssignmentEntity.analUid.eq(analUid),
labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId()),
labelingAssignmentEntity.inspectStatDttm.lt(end))
.groupBy(
mapSheetAnalInferenceEntity.compareYyyy,
mapSheetAnalInferenceEntity.targetYyyy,
labelingAssignmentEntity.assignGroupId)
.fetch();
}
@Override
public List<AnalCntInfo> findAnalCntInfoList() {
// 검수 제외(EXCEPT)를 뺀 나머지 cnt
NumberExpression<Long> allCnt =
new CaseBuilder()
.when(
labelingAssignmentEntity
.inspectState
.eq(InspectState.UNCONFIRM.getId())
.or(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId()))
.or(labelingAssignmentEntity.inspectState.isNull()))
.then(1L)
.otherwise(0L)
.sum();
// file_cnt
NumberExpression<Long> fileCnt =
new CaseBuilder()
.when(mapSheetLearnDataGeomEntity.fileCreateYn.isTrue())
.then(1L)
.otherwise(0L)
.sum();
NumberExpression<Long> completeCnt =
new CaseBuilder()
.when(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId()))
.then(1L)
.otherwise(0L)
.sum();
return queryFactory
.select(
Projections.constructor(
AnalCntInfo.class,
labelingAssignmentEntity.analUid,
mapSheetLearnEntity.uid,
allCnt,
completeCnt,
fileCnt))
.from(labelingAssignmentEntity)
.innerJoin(mapSheetAnalInferenceEntity)
.on(
labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id),
mapSheetAnalInferenceEntity.analState.eq(LabelMngState.ING.getId()))
.leftJoin(mapSheetLearnEntity)
.on(mapSheetAnalInferenceEntity.learnId.eq(mapSheetLearnEntity.id))
.leftJoin(mapSheetLearnDataGeomEntity)
.on(labelingAssignmentEntity.inferenceGeomUid.eq(mapSheetLearnDataGeomEntity.geoUid))
.groupBy(labelingAssignmentEntity.analUid, mapSheetLearnEntity.uid)
.having(completeCnt.gt(0L))
.fetch();
}
@Override
@Transactional
public void updateLearnDataGeomFileCreateYn(List<Long> geoUids) {
queryFactory
.update(mapSheetLearnDataGeomEntity)
.set(mapSheetLearnDataGeomEntity.fileCreateYn, true)
.set(mapSheetLearnDataGeomEntity.modifiedDate, ZonedDateTime.now())
.where(mapSheetLearnDataGeomEntity.geoUid.in(geoUids))
.execute();
}
}

View File

@@ -0,0 +1,117 @@
package com.kamcoback.cd.review.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.AnalCntInfo;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.AnalMapSheetList;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.CompleteLabelData;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.CompleteLabelData.GeoJsonFeature;
import com.kamcoback.cd.review.dto.TrainingDataReviewJobDto.FeatureCollection;
import com.kamcoback.cd.review.postgres.core.TrainingDataReviewJobCoreService;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Log4j2
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class TrainingDataReviewJobService {
private final TrainingDataReviewJobCoreService trainingDataReviewJobCoreService;
@Value("${spring.profiles.active}")
private String profile;
@Value("${training-data.geojson-dir}")
private String trainingDataDir;
private boolean isLocalProfile() {
return "local".equalsIgnoreCase(profile);
}
@Scheduled(cron = "0 0 2 * * *")
public void runTask() {
exportGeojsonLabelingGeom(null);
}
@Transactional
public void exportGeojsonLabelingGeom(LocalDate baseDate) {
//
// if (isLocalProfile()) {
// return;
// }
// 1) 경로/파일명 결정
String targetDir = "local".equals(profile) ? System.getProperty("user.home") + "/geojson" : trainingDataDir;
// 2) 진행중인 회차 중, complete_cnt 가 존재하는 회차 목록 가져오기
List<AnalCntInfo> analList = trainingDataReviewJobCoreService.findAnalCntInfoList();
for (AnalCntInfo info : analList) {
if (Objects.equals(info.getAllCnt(), info.getFileCnt())) {
continue;
}
String resultUid = info.getResultUid(); // 회차의 대문자 uid (폴더명으로 사용)
// 3) 회차 + 어제까지 검수 완료된 총 데이터의 도엽별 목록 가져오기
List<AnalMapSheetList> analMapList =
trainingDataReviewJobCoreService.findCompletedAnalMapSheetList(
info.getAnalUid(), baseDate);
if (analMapList.isEmpty()) {
continue;
}
for (AnalMapSheetList mapSheet : analMapList) {
// 4) 도엽별 geom 데이터 가지고 와서 geojson 만들기
List<CompleteLabelData> completeList =
trainingDataReviewJobCoreService.findCompletedYesterdayLabelingList(
info.getAnalUid(), mapSheet.getMapSheetNum(), baseDate);
if (!completeList.isEmpty()) {
List<Long> geoUids = completeList.stream().map(CompleteLabelData::getGeoUid).toList();
List<GeoJsonFeature> features = completeList.stream().map(GeoJsonFeature::from).toList();
// 5) 파일서버에 uid 폴더 생성 후 업로드 하기
FeatureCollection collection = new FeatureCollection(features);
String filename =
String.format(
"%s_%s_%s_%s_D15.geojson",
resultUid.substring(0, 8),
mapSheet.getCompareYyyy(),
mapSheet.getTargetYyyy(),
mapSheet.getMapSheetNum());
Path outputPath = Paths.get(targetDir + "/" + resultUid, filename);
try {
Files.createDirectories(outputPath.getParent());
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.writeValue(outputPath.toFile(), collection);
// geoUids : file_create_yn = true 로 업데이트
trainingDataReviewJobCoreService.updateLearnDataGeomFileCreateYn(geoUids);
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
}
}
}

View File

@@ -0,0 +1,66 @@
spring:
config:
activate:
on-profile: dev
jpa:
show-sql: false
hibernate:
ddl-auto: validate
properties:
hibernate:
default_batch_fetch_size: 100 # ✅ 성능 - N+1 쿼리 방지
order_updates: true # ✅ 성능 - 업데이트 순서 정렬로 데드락 방지
order_inserts: true
use_sql_comments: true # ⚠️ 선택 - SQL에 주석 추가 (디버깅용)
format_sql: true # ⚠️ 선택 - SQL 포맷팅 (가독성)
jdbc:
batch_size: 1000 # ✅ 추가 (JDBC batch)
open-in-view: false
mvc:
async:
request-timeout: 300s # 5분 (예: 30s, 120s, 10m 등도 가능)
datasource:
url: jdbc:postgresql://192.168.2.127:15432/kamco_cds
#url: jdbc:postgresql://localhost:15432/kamco_cds
username: kamco_cds
password: kamco_cds_Q!W@E#R$
hikari:
minimum-idle: 10
maximum-pool-size: 20
connection-timeout: 60000 # 60초 연결 타임아웃
idle-timeout: 300000 # 5분 유휴 타임아웃
max-lifetime: 1800000 # 30분 최대 수명
leak-detection-threshold: 60000 # 연결 누수 감지
transaction:
default-timeout: 300 # 5분 트랜잭션 타임아웃
data:
redis:
host: 192.168.2.109
port: 6379
password: kamco
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
logging:
level:
root: INFO
org.springframework.web: DEBUG
training-data:
geojson-dir: /kamco-nfs/dataset/request/

View File

@@ -0,0 +1,51 @@
spring:
config:
activate:
on-profile: local
jpa:
show-sql: false
hibernate:
ddl-auto: update # 로컬만 완화(시킬려면 update으로 변경)
properties:
hibernate:
default_batch_fetch_size: 100 # ✅ 성능 - N+1 쿼리 방지
order_updates: true # ✅ 성능 - 업데이트 순서 정렬로 데드락 방지
use_sql_comments: true # ⚠️ 선택 - SQL에 주석 추가 (디버깅용)
format_sql: true # ⚠️ 선택 - SQL 포맷팅 (가독성)
open-in-view: false
datasource:
url: jdbc:postgresql://192.168.2.127:15432/kamco_cds
#url: jdbc:postgresql://localhost:5432/kamco_cds # 로컬호스트
username: kamco_cds
password: kamco_cds_Q!W@E#R$
hikari:
minimum-idle: 1
maximum-pool-size: 5
data:
redis:
host: 192.168.2.109
port: 6379
password: kamco
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
logging:
level:
org.hibernate.SQL: debug
org.hibernate.orm.jdbc.bind: trace
training-data:
geojson-dir: /Users/bokmin/kamco-nfs/model_output/labeling/

View File

@@ -0,0 +1,64 @@
spring:
config:
activate:
on-profile: prod
jpa:
show-sql: true
hibernate:
ddl-auto: validate
properties:
hibernate:
default_batch_fetch_size: 100 # ✅ 성능 - N+1 쿼리 방지
order_updates: true # ✅ 성능 - 업데이트 순서 정렬로 데드락 방지
order_inserts: true
use_sql_comments: true # ⚠️ 선택 - SQL에 주석 추가 (디버깅용)
format_sql: true # ⚠️ 선택 - SQL 포맷팅 (가독성)
jdbc:
batch_size: 1000 # ✅ 추가 (JDBC batch)
open-in-view: false
mvc:
async:
request-timeout: 300s # 5분 (예: 30s, 120s, 10m 등도 가능)
datasource:
url: jdbc:postgresql://127.0.0.1:15432/kamco_cds
#url: jdbc:postgresql://localhost:15432/kamco_cds
username: kamco_cds
password: kamco_cds_Q!W@E#R$
hikari:
minimum-idle: 10
maximum-pool-size: 20
connection-timeout: 60000 # 60초 연결 타임아웃
idle-timeout: 300000 # 5분 유휴 타임아웃
max-lifetime: 1800000 # 30분 최대 수명
leak-detection-threshold: 60000 # 연결 누수 감지
transaction:
default-timeout: 300 # 5분 트랜잭션 타임아웃
data:
redis:
host: 127.0.0.1
port: 16379
password: kamco
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
logging:
level:
root: INFO
org.springframework.web: DEBUG
training-data:
geojson-dir: /kamco-nfs/dataset/request/

View File

@@ -0,0 +1,40 @@
server:
port: 8080
spring:
application:
name: kamco-change-detection-api
profiles:
active: local # 사용할 프로파일 지정 (ex. dev, prod, test)
datasource:
driver-class-name: org.postgresql.Driver
hikari:
jdbc:
time_zone: UTC
batch_size: 50
# 권장 설정
minimum-idle: 2
maximum-pool-size: 2
connection-timeout: 20000
idle-timeout: 300000
max-lifetime: 1800000
leak-detection-threshold: 60000
data:
redis:
host: localhost
port: 6379
password:
jpa:
hibernate:
ddl-auto: update # 테이블이 없으면 생성, 있으면 업데이트
properties:
hibernate:
jdbc:
batch_size: 50
default_batch_fetch_size: 100
logging:
level:
root: INFO
org.springframework.web: DEBUG