60 Commits

Author SHA1 Message Date
d240e4349c 영상관리 스케줄러 true로 변경, 영상삭제 시 year도 업데이트 되게 추가 2026-05-18 15:29:44 +09:00
4801ae8b7d 라벨링 툴 영문명칭 수정 추가 2026-05-15 16:41:20 +09:00
8c33439bcd 작업현황 > 작업자목록 RoleType 영문명 추가 2026-05-15 11:13:25 +09:00
ec4fb46cea 적합여부 상태명 영문 추가 2026-05-15 10:57:06 +09:00
63b3b3c09d 변화지도 년도 목록 id desc 로 수정 2026-05-15 09:58:46 +09:00
cfd5963a15 추론 삭제여부 로직 추가 2026-05-15 09:55:31 +09:00
9116bf7b89 선택 모델목록 생성완료일 desc 로 수정 2026-05-12 16:58:29 +09:00
2d7413c8e1 영문버전 변환 누락된 부분 추가 2026-05-12 11:16:19 +09:00
df7a67ed41 추론 목록,class-count, geom-list 에 한글로 나오는 코드 영문버전 로직 추가 2026-05-12 10:49:39 +09:00
176d27c229 로그인 시, 접속 IP 대역 확인 2026-05-12 09:50:26 +09:00
8c70ec345c 추론 상세 geom-list 오래 걸리는 현상 수정 2026-05-11 17:52:37 +09:00
8fd92f5691 lang check 로직 수정 2026-05-11 16:24:11 +09:00
b69d09176e lang check 2026-05-11 16:14:25 +09:00
04af23b814 영문 Enum 항목값 내릴 수 있도록 수정 Accept-Language: en 으로 추가하여 호출해야 함. 2026-05-11 15:58:03 +09:00
a1fc62b3eb 메뉴 목록, 영상관리 목록 API 영문 헤더 추가, 추론 삭제기능 추가 2026-05-11 14:15:45 +09:00
ed3c901143 메뉴 API 영문명 로직 추가 2026-05-11 10:36:45 +09:00
b58b859470 주석 추가 2026-05-11 10:08:18 +09:00
b78fda151a 영상관리 삭제 API 추가, shp 생성 기존로직으로 수정 2026-05-11 10:02:48 +09:00
435a48afb9 test 2026-05-07 12:53:01 +09:00
af0866ff5b Merge branch 'develop' of https://kamco.git.gs.dabeeo.com/MVPTeam/kamco-cd-api into develop 2026-05-06 17:46:56 +09:00
d0132ac697 local 에서도 redis 포트 수정 2026-05-06 17:46:32 +09:00
dean
4272558f32 add log 2026-04-22 09:41:23 +09:00
d83fb01cbe 학습데이터 목록 쿼리 수정 2026-04-20 16:37:22 +09:00
0425a6486d Merge pull request 'shp 테스트' (#160) from feat/infer_dev_260211 into develop
Reviewed-on: #160
2026-03-25 14:07:21 +09:00
241c7222d1 shp 테스트 2026-03-25 14:07:06 +09:00
71e4ab14bd Merge pull request 'shp 테스트' (#159) from feat/infer_dev_260211 into develop
Reviewed-on: #159
2026-03-25 14:01:26 +09:00
52da4dafc3 shp 테스트 2026-03-25 14:01:02 +09:00
24d615174d Merge pull request '토근 정보 변경' (#158) from feat/infer_dev_260211 into develop
Reviewed-on: #158
2026-03-19 13:48:56 +09:00
12b0f0867d 토근 정보 변경 2026-03-19 13:48:14 +09:00
283d906da6 Merge pull request '토큰시간 변경' (#157) from feat/infer_dev_260211 into develop
Reviewed-on: #157
2026-03-19 10:31:05 +09:00
360b451c38 토큰시간 변경 2026-03-19 10:30:42 +09:00
80e281cb99 Merge pull request '개발서버 토큰 시간 변경' (#156) from feat/infer_dev_260211 into develop
Reviewed-on: #156
2026-03-18 14:02:29 +09:00
b07bc38ee8 개발서버 토큰 시간 변경 2026-03-18 14:01:56 +09:00
e4c1c76b2b Merge pull request '재할당 transactional 추가' (#155) from feat/infer_dev_260211 into develop
Reviewed-on: #155
2026-03-17 17:47:43 +09:00
01b64eeca7 재할당 transactional 추가 2026-03-17 17:47:15 +09:00
516f949a37 Merge pull request 'spotless 적용' (#154) from feat/infer_dev_260211 into develop
Reviewed-on: #154
2026-03-17 14:00:22 +09:00
b6ed3b57ef spotless 적용 2026-03-17 14:00:04 +09:00
9eebf23774 Merge pull request 'dev 토큰 유효시간 변경, 인증 Log 추가한거 삭제' (#153) from feat/infer_dev_260211 into develop
Reviewed-on: #153
2026-03-17 13:55:53 +09:00
4f742edf8b dev 토큰 유효시간 변경, 인증 Log 추가한거 삭제 2026-03-17 13:55:30 +09:00
0aa415cf3a Merge pull request '토큰 생성 로그 추가' (#152) from feat/infer_dev_260211 into develop
Reviewed-on: #152
2026-03-17 13:33:34 +09:00
884b635585 토큰 생성 로그 추가 2026-03-17 13:33:17 +09:00
6861f6b8b6 Merge pull request '메뉴 권한 Log 추가' (#151) from feat/infer_dev_260211 into develop
Reviewed-on: #151
2026-03-17 13:22:06 +09:00
a97af0d4dd 메뉴 권한 Log 추가 2026-03-17 13:21:46 +09:00
9297d19e24 Merge pull request 'refresh 토큰 인증 로그 추가' (#150) from feat/infer_dev_260211 into develop
Reviewed-on: #150
2026-03-17 12:46:12 +09:00
65c38b3083 refresh 토큰 인증 로그 추가 2026-03-17 12:45:56 +09:00
24dca652f0 Merge pull request 'refresh 토큰 재발급 로그 추가' (#149) from feat/infer_dev_260211 into develop
Reviewed-on: #149
2026-03-17 12:26:31 +09:00
193cd449a8 refresh 토큰 재발급 로그 추가 2026-03-17 12:23:45 +09:00
dean
0efde4e5bb access-token 2026-03-17 07:49:13 +09:00
dean
548d82da12 access-token 2026-03-17 07:20:08 +09:00
536ff8fc65 추론 종료 async 수정 2026-03-13 15:52:20 +09:00
1dc1ce741e 추론 종료 비동기 호출 2026-03-13 15:38:11 +09:00
d21ed61666 hello 2026-03-12 08:22:39 +09:00
c9a1007c21 hello 2026-03-12 08:08:59 +09:00
413afb0b7c shp파일 바꾸는로직정리 2026-03-12 08:08:11 +09:00
e69eccc82b shp파일 바꾸는로직정리 2026-03-12 07:57:14 +09:00
828a4c5dca shp파일 바꾸는로직정리 2026-03-12 07:31:54 +09:00
5d417d85ff Merge pull request '국유인연동 알럿 문구 변경' (#148) from feat/infer_dev_260211 into develop
Reviewed-on: #148
2026-03-09 10:52:25 +09:00
614d6da695 국유인연동 알럿 문구 변경 2026-03-09 10:51:57 +09:00
8d45e91982 Merge pull request '국유인연동 : 라벨링 진행중 회차 uuid 추가' (#147) from feat/infer_dev_260211 into develop
Reviewed-on: #147
2026-03-09 10:10:52 +09:00
e1febf5863 국유인연동 : 라벨링 진행중 회차 uuid 추가 2026-03-09 10:10:08 +09:00
71 changed files with 1020 additions and 281 deletions

View File

@@ -37,7 +37,6 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
// JWT 토큰을 검증하고, 인증된 사용자로 SecurityContext에 등록
if (token != null && jwtTokenProvider.isValidToken(token)) {
String username = jwtTokenProvider.getSubject(token);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

View File

@@ -8,11 +8,13 @@ import jakarta.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import javax.crypto.SecretKey;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/** 토큰 생성 */
@Component
@Log4j2
public class JwtTokenProvider {
@Value("${jwt.secret}")
@@ -34,11 +36,13 @@ public class JwtTokenProvider {
// Access Token 생성
public String createAccessToken(String subject) {
log.info("TOKEN VALIDITY = {}", accessTokenValidityInMs);
return createToken(subject, accessTokenValidityInMs);
}
// Refresh Token 생성
public String createRefreshToken(String subject) {
log.info("REFRESH TOKEN VALIDITY = {}", refreshTokenValidityInMs);
return createToken(subject, refreshTokenValidityInMs);
}

View File

@@ -58,6 +58,7 @@ public class MenuAuthorizationManager implements AuthorizationManager<RequestAut
for (MenuEntity menu : allowedMenus) {
String baseUri = menu.getMenuUrl();
if (baseUri == null || baseUri.isBlank()) {
continue;
}

View File

@@ -35,6 +35,11 @@ public class ChangeDetectionDto {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return name();
}
}
@CodeExpose
@@ -55,6 +60,11 @@ public class ChangeDetectionDto {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return desc;
}
}
@Schema(name = "TestDto", description = "테스트용")

View File

@@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.code.dto;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import com.kamco.cd.kamcoback.common.utils.html.HtmlEscapeDeserializer;
import com.kamco.cd.kamcoback.common.utils.html.HtmlUnescapeSerializer;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
@@ -119,10 +120,11 @@ public class CommonCodeDto {
String props2,
String props3,
ZonedDateTime deletedDttm) {
boolean english = HeaderUtil.isEnglishRequest();
this.id = id;
this.code = code;
this.description = description;
this.name = name;
this.name = english ? code : name;
this.order = order;
this.used = used;
this.deleted = deleted;

View File

@@ -45,4 +45,9 @@ public enum CommonUseStatus implements EnumType {
public EnumDto<CommonUseStatus> getEnumDto() {
return new EnumDto<>(this, this.id, this.text);
}
@Override
public String getTextEn() {
return id;
}
}

View File

@@ -9,12 +9,13 @@ import lombok.Getter;
@Getter
@AllArgsConstructor
public enum CrsType implements EnumType {
EPSG_3857("Web Mercator, 웹지도 미터(EPSG:900913 동일)"),
EPSG_4326("WGS84 위경도, GeoJSON/OSM 기본"),
EPSG_5186("5186::Korea 2000 중부 TM, 한국 SHP"),
EPSG_5179("5179::Korea 2000 중부 TM, 한국 SHP");
EPSG_3857("Web Mercator, 웹지도 미터(EPSG:900913 동일)", "Web Mercator"),
EPSG_4326("WGS84 위경도, GeoJSON/OSM 기본", "GeoJSON/OSM"),
EPSG_5186("5186::Korea 2000 중부 TM, 한국 SHP", "5186::Korea 2000"),
EPSG_5179("5179::Korea 2000 중부 TM, 한국 SHP", "5179::Korea 2000");
private final String desc;
private final String descEn;
@Override
public String getId() {
@@ -25,4 +26,9 @@ public enum CrsType implements EnumType {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return descEn;
}
}

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.common.enums;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -51,6 +52,6 @@ public enum DetectionClassification {
*/
public static String fromStrDesc(String text) {
DetectionClassification dtf = fromString(text);
return dtf.getDesc();
return HeaderUtil.isEnglishRequest() ? dtf.getId() : dtf.getDesc();
}
}

View File

@@ -9,13 +9,14 @@ import lombok.Getter;
@Getter
@AllArgsConstructor
public enum FileUploadStatus implements EnumType {
INIT("초기화"),
UPLOADING("업로드중"),
DONE("업로드완료"),
MERGED("병합완료"),
MERGE_FAIL("병합 실패");
INIT("초기화", "Init"),
UPLOADING("업로드중", "Uploading"),
DONE("업로드완료", "Upload Done"),
MERGED("병합완료", "Merged Done"),
MERGE_FAIL("병합 실패", "Merge Failed");
private final String desc;
private final String descEn;
@Override
public String getId() {
@@ -26,4 +27,9 @@ public enum FileUploadStatus implements EnumType {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return descEn;
}
}

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.common.enums;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import com.kamco.cd.kamcoback.common.utils.enums.CodeExpose;
import com.kamco.cd.kamcoback.common.utils.enums.EnumType;
import java.util.Arrays;
@@ -25,6 +26,11 @@ public enum ImageryFitStatus implements EnumType {
return desc;
}
@Override
public String getTextEn() {
return name();
}
public static ImageryFitStatus fromCode(String code) {
if (code == null) {
return null;
@@ -38,6 +44,8 @@ public enum ImageryFitStatus implements EnumType {
public static String getDescByCode(String code) {
ImageryFitStatus status = fromCode(code);
return status != null ? status.getDesc() : null;
return status != null
? (HeaderUtil.isEnglishRequest() ? status.getTextEn() : status.getDesc())
: null;
}
}

View File

@@ -10,14 +10,15 @@ import lombok.Getter;
@Getter
@AllArgsConstructor
public enum LayerType implements EnumType {
TILE("배경지도"),
GEOJSON("객체데이터"),
WMTS("타일레이어"),
WMS("지적도"),
KAMCO_WMS("국유인WMS"),
KAMCO_WMTS("국유인WMTS");
TILE("배경지도", "Tile"),
GEOJSON("객체데이터", "GeoJSON"),
WMTS("타일레이어", "WMTS"),
WMS("지적도", "WMS"),
KAMCO_WMS("국유인WMS", "KAMCO_WMS"),
KAMCO_WMTS("국유인WMTS", "KAMCO_WMTS");
private final String desc;
private final String descEn;
@Override
public String getId() {
@@ -29,6 +30,11 @@ public enum LayerType implements EnumType {
return desc;
}
@Override
public String getTextEn() {
return descEn;
}
public static Optional<LayerType> from(String type) {
try {
return Optional.of(LayerType.valueOf(type));

View File

@@ -9,12 +9,13 @@ import lombok.Getter;
@Getter
@AllArgsConstructor
public enum MngStateType implements EnumType {
NOTYET("동기화 시작"),
PROCESSING("데이터 체크"),
DONE("동기화 작업 종료"),
TAKINGERROR("오류 데이터 처리중");
NOTYET("동기화 시작", "Sync Started"),
PROCESSING("데이터 체크", "Data Check"),
DONE("동기화 작업 종료", "Sync Completed"),
TAKINGERROR("오류 데이터 처리중", "Processing Error Data");
private final String desc;
private final String descEn;
@Override
public String getId() {
@@ -25,4 +26,8 @@ public enum MngStateType implements EnumType {
public String getText() {
return desc;
}
public String getTextEn() {
return descEn;
}
}

View File

@@ -24,4 +24,9 @@ public enum RoleType implements EnumType {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return name();
}
}

View File

@@ -24,4 +24,9 @@ public enum StatusType implements EnumType {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return name();
}
}

View File

@@ -23,4 +23,9 @@ public enum SyncCheckStateType implements EnumType {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return name();
}
}

View File

@@ -30,4 +30,9 @@ public enum SyncStateType implements EnumType {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return name();
}
}

View File

@@ -1,23 +1,45 @@
package com.kamco.cd.kamcoback.common.service;
import com.kamco.cd.kamcoback.config.InferenceProperties;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Log4j2
// 0312
@RequiredArgsConstructor
@Component
public class ExternalJarRunner {
@Value("${spring.profiles.active}")
private String profile;
// 0312
private final InferenceProperties inferenceProperties;
private static final long TIMEOUT_MINUTES = TimeUnit.DAYS.toMinutes(3);
// java -jar build/libs/shp-exporter.jar --batch --geoserver.enabled=true
// --converter.inference-id=qq99999 --converter.batch-ids[0]=111
// 0312 shp 파일 배치를 통해 생성
public void run(String inferenceLearningId, List<Long> batchIds) {
// JAR 경로 (shape파일 생성용)
String jarPathV2 = inferenceProperties.getJarPathV2();
List<String> args = new ArrayList<>();
args.add(" --spring.profiles.active=" + profile);
args.add(" --batch");
args.add(" --geoserver.enabled=true");
args.add(" --converter.inference-id=" + inferenceLearningId);
batchIds.forEach(batchId -> args.add(" --converter.batch-ids[" + args.size() + "]=" + batchId));
execJar(jarPathV2, args);
}
/**
* shp 파일 생성
*
@@ -74,7 +96,8 @@ public class ExternalJarRunner {
cmd.add("-jar");
cmd.add(jarPath);
cmd.addAll(args);
// 0312
log.info("exec jar command: {}", cmd);
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true);

View File

@@ -1,6 +1,9 @@
package com.kamco.cd.kamcoback.common.utils;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
public final class HeaderUtil {
@@ -20,4 +23,20 @@ public final class HeaderUtil {
public static String getRequired(HttpServletRequest request, String headerName) {
return get(request, headerName);
}
public static boolean isEnglishRequest() {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
if (!(attrs instanceof ServletRequestAttributes servletAttrs)) {
return false;
}
String acceptLanguage = servletAttrs.getRequest().getHeader("Accept-Language");
if (acceptLanguage == null || acceptLanguage.isBlank()) {
return false;
}
return acceptLanguage.toLowerCase().startsWith("en");
}
}

View File

@@ -5,4 +5,6 @@ public interface EnumType {
String getId();
String getText();
String getTextEn();
}

View File

@@ -1,6 +1,7 @@
package com.kamco.cd.kamcoback.common.utils.enums;
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto.CodeDto;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -32,11 +33,12 @@ public class Enums {
// enum -> CodeDto list
public static List<CodeDto> toList(Class<? extends Enum<?>> enumClass) {
Object[] enums = enumClass.getEnumConstants();
boolean english = HeaderUtil.isEnglishRequest();
return Arrays.stream(enums)
.map(e -> (EnumType) e)
.filter(e -> !isHidden(enumClass, (Enum<?>) e))
.map(e -> new CodeDto(e.getId(), e.getText()))
.map(e -> new CodeDto(e.getId(), english ? e.getTextEn() : e.getText()))
.toList();
}

View File

@@ -16,5 +16,7 @@ public class InferenceProperties {
private String batchUrl;
private String geojsonDir;
private String jarPath;
// 0312
private String jarPathV2;
private String inferenceServerName;
}

View File

@@ -71,6 +71,10 @@ public class SecurityConfig {
.requestMatchers("/api/test/review")
.hasAnyRole("ADMIN", "REVIEWER")
// shapefile 생성 테스트 API - 인증 없이 접근 가능
.requestMatchers("/api/test/make-shapefile")
.permitAll()
// ASYNC/ERROR 재디스패치는 막지 않기 (다운로드/스트리밍에서 필수)
.dispatcherTypeMatchers(DispatcherType.ASYNC, DispatcherType.ERROR)
.permitAll()

View File

@@ -39,10 +39,10 @@ public class ApiLogFunction {
public static String getXFowardedForIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip != null) {
ip = ip.split(",")[0].trim();
if (ip != null && !ip.isBlank()) {
return ip.split(",")[0].trim();
}
return ip;
return request.getRemoteAddr();
}
// 사용자 ID 추출 예시 (Spring Security 기준)

View File

@@ -3,6 +3,7 @@ package com.kamco.cd.kamcoback.config.api;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.kamco.cd.kamcoback.common.utils.enums.EnumType;
import java.util.Arrays;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
@@ -192,6 +193,11 @@ public class ApiResponseDto<T> {
return message;
}
@Override
public String getTextEn() {
return message;
}
public static ApiResponseCode getCode(String name) {
return ApiResponseCode.valueOf(name.toUpperCase());
}
@@ -220,5 +226,12 @@ public class ApiResponseDto<T> {
return INTERNAL_SERVER_ERROR;
}
public static ApiResponseCode fromMessage(String message) {
return Arrays.stream(values())
.filter(code -> code.getMessage().equals(message))
.findFirst()
.orElse(null);
}
}
}

View File

@@ -14,9 +14,9 @@ public class GukYuinDto {
public enum GukYuinLinkFailCode implements EnumType {
OK("연동 가능"),
NOT_FOUND("대상 회차가 없습니다."),
SCOPE_PART_NOT_ALLOWED("부분 도엽은 연동 불가능 합니다."),
HAS_RUNNING_INFERENCE("라벨링 진행 중 회차가 있습니다."),
OTHER_GUKYUIN_IN_PROGRESS("국유in 연동 진행 중 회차가 있습니다.");
SCOPE_PART_NOT_ALLOWED("부분 도엽 추론 결과는 연동 할 수 없습니다."),
HAS_RUNNING_INFERENCE("라벨링 진행중 회차가 있습니다.\n진행중인 라벨링 작업을 종료하신 후 다시 연동해주세요."),
OTHER_GUKYUIN_IN_PROGRESS("국유in 연동 진행중입니다. 선행 연동 작업이 종료된 후 진행할 수 있습니다.");
private final String desc;
@@ -29,6 +29,11 @@ public class GukYuinDto {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return desc;
}
}
@Getter
@@ -36,8 +41,9 @@ public class GukYuinDto {
public static class GukYuinLinkableRes {
private boolean linkable;
// private GukYuinLinkFailCode code;
private GukYuinLinkFailCode code;
private String message;
private UUID inferenceUuid;
}
// Repository가 반환할 Fact(조회 결과)
@@ -45,7 +51,8 @@ public class GukYuinDto {
boolean existsLearn,
boolean isPartScope,
boolean hasRunningInference,
boolean hasOtherUnfinishedGukYuin) {}
boolean hasOtherUnfinishedGukYuin,
UUID inferenceUuid) {}
@Getter
@Setter

View File

@@ -26,4 +26,9 @@ public enum GukYuinStatus implements EnumType {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return desc;
}
}

View File

@@ -237,9 +237,12 @@ public class GukYuinApiService {
GukYuinLinkFailCode code = decideCode(f);
GukYuinLinkableRes res = new GukYuinLinkableRes();
// res.setCode(code);
res.setCode(code);
res.setLinkable(code == GukYuinLinkFailCode.OK);
res.setMessage(code.getDesc());
if (code == GukYuinLinkFailCode.HAS_RUNNING_INFERENCE) {
res.setInferenceUuid(f.inferenceUuid());
}
return res;
}

View File

@@ -8,6 +8,7 @@ import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceServerStatusDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceStatusDetailDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.ResultList;
import com.kamco.cd.kamcoback.inference.service.InferenceAsyncService;
import com.kamco.cd.kamcoback.inference.service.InferenceResultService;
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
import com.kamco.cd.kamcoback.log.dto.AuditLogDto.DownloadReq;
@@ -55,6 +56,7 @@ import org.springframework.web.bind.annotation.RestController;
public class InferenceResultApiController {
private final InferenceResultService inferenceResultService;
private final InferenceAsyncService inferenceAsyncService;
private final MapSheetMngService mapSheetMngService;
private final ModelMngService modelMngService;
private final RangeDownloadResponder rangeDownloadResponder;
@@ -176,7 +178,8 @@ public class InferenceResultApiController {
})
@DeleteMapping("/end")
public ApiResponseDto<UUID> getInferenceGeomList() {
UUID uuid = inferenceResultService.deleteInferenceEnd();
// UUID uuid = inferenceResultService.deleteInferenceEnd();
UUID uuid = inferenceAsyncService.asyncInferenceEnd();
return ApiResponseDto.ok(uuid);
}
@@ -445,4 +448,22 @@ public class InferenceResultApiController {
UUID uuid) {
return ApiResponseDto.ok(inferenceResultService.getInferenceRunMapId(uuid));
}
@Operation(summary = "추론 삭제", description = "추론관리 > 추론목록 > 추론 상세 > 추론 삭제")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "201",
description = "종료 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Page.class))),
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@DeleteMapping("/delete-inference/{uuid}")
public ApiResponseDto<ApiResponseDto.ResponseObj> deleteInference(@PathVariable UUID uuid) {
return ApiResponseDto.ok(inferenceResultService.deleteInference(uuid));
}
}

View File

@@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kamco.cd.kamcoback.common.enums.DetectionClassification;
import com.kamco.cd.kamcoback.common.enums.ImageryFitStatus;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.DetectOption;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheetScope;
@@ -156,9 +157,14 @@ public class InferenceDetailDto {
String classAfterName;
Long classAfterCnt;
boolean english = HeaderUtil.isEnglishRequest();
public Dashboard(String classAfterCd, Long classAfterCnt) {
this.classAfterCd = classAfterCd;
this.classAfterName = DetectionClassification.fromString(classAfterCd).getDesc();
this.classAfterName =
english
? DetectionClassification.fromString(classAfterCd).getId()
: DetectionClassification.fromString(classAfterCd).getDesc();
this.classAfterCnt = classAfterCnt;
}
}
@@ -294,8 +300,10 @@ public class InferenceDetailDto {
}
@Getter
@Setter
public static class Geom {
Long geoUid;
UUID uuid;
String uid;
Integer compareYyyy;
@@ -313,7 +321,10 @@ public class InferenceDetailDto {
String pnu;
String fitState;
boolean english = HeaderUtil.isEnglishRequest();
public Geom(
Long geoUid,
UUID uuid,
String uid,
Integer compareYyyy,
@@ -328,16 +339,23 @@ public class InferenceDetailDto {
String subUid,
String pnu,
String fitState) {
this.geoUid = geoUid;
this.uuid = uuid;
this.uid = uid;
this.compareYyyy = compareYyyy;
this.targetYyyy = targetYyyy;
this.cdProb = cdProb;
this.classBeforeCd = classBeforeCd;
this.classBeforeName = DetectionClassification.fromString(classBeforeCd).getDesc();
this.classBeforeName =
english
? DetectionClassification.fromString(classBeforeCd).getId()
: DetectionClassification.fromString(classBeforeCd).getDesc();
this.classBeforeProb = classBeforeProb;
this.classAfterCd = classAfterCd;
this.classAfterName = DetectionClassification.fromString(classAfterCd).getDesc();
this.classAfterName =
english
? DetectionClassification.fromString(classAfterCd).getId()
: DetectionClassification.fromString(classAfterCd).getDesc();
this.classAfterProb = classAfterProb;
this.mapSheetNum = mapSheetNum;
this.mapSheetName = mapSheetName;

View File

@@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.inference.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import com.kamco.cd.kamcoback.common.utils.enums.EnumType;
import com.kamco.cd.kamcoback.common.utils.interfaces.EnumValid;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
@@ -14,6 +15,8 @@ import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@@ -51,6 +54,11 @@ public class InferenceResultDto {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return desc;
}
}
/** 탐지 데이터 옵션 dto */
@@ -79,6 +87,11 @@ public class InferenceResultDto {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return desc;
}
}
@Getter
@@ -87,6 +100,7 @@ public class InferenceResultDto {
READY("대기"),
IN_PROGRESS("진행중"),
END("완료"),
END_FAIL("종료실패"),
FORCED_END("강제종료");
private final String desc;
@@ -95,7 +109,12 @@ public class InferenceResultDto {
}
public static String getDescByCode(String code) {
return fromCode(code).getDesc();
boolean english = HeaderUtil.isEnglishRequest();
if (english) {
return fromCode(code).getTextEn();
} else {
return fromCode(code).getDesc();
}
}
@Override
@@ -107,6 +126,11 @@ public class InferenceResultDto {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return name();
}
}
@Getter
@@ -128,6 +152,11 @@ public class InferenceResultDto {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return desc;
}
}
/** 목록조회 dto */
@@ -210,7 +239,46 @@ public class InferenceResultDto {
long m = (s % 3600) / 60;
long sec = s % 60;
return String.format("%d시간 %d분 %d초", h, m, sec);
boolean english = HeaderUtil.isEnglishRequest();
if (english) {
return String.format("%dh %dm %ds", h, m, sec);
} else {
return String.format("%d시간 %d분 %d초", h, m, sec);
}
}
@JsonProperty("mapSheetCnt")
public String getMapSheetCnt() {
boolean english = HeaderUtil.isEnglishRequest();
String text = this.mapSheetCnt;
if (!english) {
return text;
}
// "창원 외 34건"
Pattern otherPattern = Pattern.compile("^(.+) 외 (\\d+)건$");
Matcher otherMatcher = otherPattern.matcher(text);
if (otherMatcher.find()) {
String name = otherMatcher.group(1);
int count = Integer.parseInt(otherMatcher.group(2));
return name + " and " + count + (count == 1 ? " other" : " others");
}
// "창원 1건"
Pattern itemPattern = Pattern.compile("^(.+) (\\d+)건$");
Matcher itemMatcher = itemPattern.matcher(text);
if (itemMatcher.find()) {
String name = itemMatcher.group(1);
int count = Integer.parseInt(itemMatcher.group(2));
return name + " (" + count + (count == 1 ? " item" : " items") + ")";
}
return text;
}
}
@@ -683,6 +751,7 @@ public class InferenceResultDto {
@NoArgsConstructor
@AllArgsConstructor
public static class MapSheetFallbackYearDto {
private String mapSheetNum;
private Integer mngYyyy;
}

View File

@@ -0,0 +1,117 @@
package com.kamco.cd.kamcoback.inference.service;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.common.inference.service.InferenceCommonService;
import com.kamco.cd.kamcoback.common.utils.UserUtil;
import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient;
import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient.ExternalCallResult;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.SaveInferenceAiDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.Status;
import com.kamco.cd.kamcoback.postgres.core.AuditLogCoreService;
import com.kamco.cd.kamcoback.postgres.core.InferenceResultCoreService;
import com.kamco.cd.kamcoback.postgres.core.MapSheetMngCoreService;
import com.kamco.cd.kamcoback.postgres.core.ModelMngCoreService;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/** 추론 관리 */
@Service
@Slf4j
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class InferenceAsyncService {
private final InferenceResultCoreService inferenceResultCoreService;
private final MapSheetMngCoreService mapSheetMngCoreService;
private final ModelMngCoreService modelMngCoreService;
private final AuditLogCoreService auditLogCoreService;
private final InferenceCommonService inferenceCommonService;
private final ExternalHttpClient externalHttpClient;
private final UserUtil userUtil;
@Value("${inference.batch-url}")
private String batchUrl;
@Value("${inference.inference-server-name}")
private String inferenceServerName;
@Value("${file.dataset-dir}")
private String datasetDir;
@Value("${spring.profiles.active}")
private String activeEnv;
@Value("${inference.geojson-dir}")
private String inferenceDir;
// 0313
@Transactional
public UUID asyncInferenceEnd() {
SaveInferenceAiDto dto = inferenceResultCoreService.getProcessing();
if (dto == null) {
throw new CustomApiException("NOT_FOUND", HttpStatus.NOT_FOUND);
}
this.deleteInferenceEndAsync(dto); // 비동기 종료 호출
return dto.getUuid();
}
// 0313
@Async("inferenceEndExecutor")
@Transactional
public void deleteInferenceEndAsync(SaveInferenceAiDto dto) {
Long batchId = dto.getBatchId();
String url = batchUrl + "/" + batchId;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
try {
log.info("[추론 종료 비동기 시작] uuid={}, batchId={}", dto.getUuid(), batchId);
ExternalCallResult<String> result =
externalHttpClient.callLong(url, HttpMethod.DELETE, dto, headers, String.class);
if (!result.success()) {
log.error("[추론 종료 실패] 외부 API 호출 실패. uuid={}, batchId={}", dto.getUuid(), batchId);
SaveInferenceAiDto failRequest = new SaveInferenceAiDto();
failRequest.setUuid(dto.getUuid());
failRequest.setStatus(Status.END_FAIL.getId()); // TODO: 종료실패 상태 추가하는 게 맞는지?
failRequest.setUpdateUid(userUtil.getId());
failRequest.setInferEndDttm(ZonedDateTime.now());
inferenceResultCoreService.update(failRequest);
return;
}
SaveInferenceAiDto request = new SaveInferenceAiDto();
request.setStatus(Status.FORCED_END.getId());
request.setUuid(dto.getUuid());
request.setUpdateUid(userUtil.getId());
request.setInferEndDttm(ZonedDateTime.now());
inferenceResultCoreService.update(request);
Long learnId = inferenceResultCoreService.getInferenceLearnIdByUuid(dto.getUuid());
inferenceResultCoreService.upsertGeomData(learnId);
log.info("[추론 종료 비동기 완료] uuid={}, batchId={}", dto.getUuid(), batchId);
} catch (Exception e) {
log.error("[추론 종료 비동기 예외] uuid={}, batchId={}", dto.getUuid(), batchId, e);
}
}
}

View File

@@ -7,24 +7,13 @@ import com.kamco.cd.kamcoback.common.geometry.GeoJsonFileWriter.Scene;
import com.kamco.cd.kamcoback.common.inference.service.InferenceCommonService;
import com.kamco.cd.kamcoback.common.inference.utils.GeoJsonValidator;
import com.kamco.cd.kamcoback.common.utils.UserUtil;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient;
import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient.ExternalCallResult;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.AnalResultInfo;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Dashboard;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Detail;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.Geom;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.MapSheet;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.SearchGeoReq;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto.*;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.DetectOption;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceLearnDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceServerStatusDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceStatusDetailDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheetScope;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.ResultList;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.SaveInferenceAiDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.Status;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.*;
import com.kamco.cd.kamcoback.inference.dto.InferenceSendDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceSendDto.pred_requests_areas;
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
@@ -44,16 +33,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -70,7 +50,7 @@ import org.springframework.transaction.annotation.Transactional;
@Service
@Slf4j
@RequiredArgsConstructor
@Transactional(readOnly = true)
@Transactional
public class InferenceResultService {
private final InferenceResultCoreService inferenceResultCoreService;
@@ -1033,4 +1013,14 @@ public class InferenceResultService {
}
return "";
}
public ApiResponseDto.ResponseObj deleteInference(UUID uuid) {
long result = inferenceResultCoreService.deleteInference(uuid);
if (result > 0) {
return new ApiResponseDto.ResponseObj(ApiResponseDto.ApiResponseCode.OK, "삭제되었습니다.");
} else {
return new ApiResponseDto.ResponseObj(
ApiResponseDto.ApiResponseCode.INTERNAL_SERVER_ERROR, "삭제 실패하였습니다. 관리자에게 문의해주세요.");
}
}
}

View File

@@ -37,6 +37,11 @@ public class LabelAllocateDto {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return name();
}
}
@CodeExpose
@@ -59,6 +64,11 @@ public class LabelAllocateDto {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return name();
}
}
@CodeExpose
@@ -80,6 +90,11 @@ public class LabelAllocateDto {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return name();
}
}
@Getter

View File

@@ -1,6 +1,8 @@
package com.kamco.cd.kamcoback.label.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.kamco.cd.kamcoback.common.enums.RoleType;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import com.kamco.cd.kamcoback.common.utils.enums.Enums;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelMngState;
@@ -34,6 +36,7 @@ public class LabelWorkDto {
@AllArgsConstructor
public static class LabelWorkMng {
private Long analUid;
private UUID uuid;
private Integer compareYyyy;
private Integer targetYyyy;
@@ -108,7 +111,13 @@ public class LabelWorkDto {
if (type == null) {
return enumId;
}
return type.getText();
boolean english = HeaderUtil.isEnglishRequest();
if (!english) {
return type.getText();
}
return type.getTextEn();
}
/**
@@ -222,10 +231,8 @@ public class LabelWorkDto {
}
public String getUserRoleName() {
if (this.userRole.equals("LABELER")) {
return "라벨러";
}
return "검수자";
RoleType type = Enums.fromId(RoleType.class, this.userRole);
return HeaderUtil.isEnglishRequest() ? type.getTextEn() : type.getText();
}
}
@@ -260,4 +267,18 @@ public class LabelWorkDto {
return PageRequest.of(page, size);
}
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class LabelCntInfo {
private Long assignedCnt;
private Long skipCnt;
private Long doneCnt;
private Long unconfirmCnt;
private Long exceptCnt;
private Long completeCnt;
}
}

View File

@@ -157,6 +157,7 @@ public class LabelAllocateService {
return labelAllocateCoreService.findInferenceDetail(uuid);
}
@Transactional
public ApiResponseDto.ResponseObj allocateMove(
Integer totalCnt, String uuid, List<String> targetUsers, String userId) {

View File

@@ -1,7 +1,10 @@
package com.kamco.cd.kamcoback.log.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import com.kamco.cd.kamcoback.common.utils.enums.CodeExpose;
import com.kamco.cd.kamcoback.common.utils.enums.EnumType;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDate;
import lombok.AllArgsConstructor;
@@ -36,6 +39,11 @@ public class ErrorLogDto {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return desc;
}
}
@Schema(name = "ErrorLogBasic", description = "에러로그 기본 정보")
@@ -56,6 +64,26 @@ public class ErrorLogDto {
private final String errorMessage;
private final String errorDetail;
private final String createDate; // to_char해서 가져옴
@JsonProperty("errorMessage")
public String getErrorMessage() {
boolean english = HeaderUtil.isEnglishRequest();
if (!english) {
return this.errorMessage;
}
return ApiResponseDto.ApiResponseCode.fromMessage(this.errorMessage).toString();
}
@JsonProperty("errorName")
public String getErrorName() {
boolean english = HeaderUtil.isEnglishRequest();
if (!english) {
return this.errorName;
}
return ApiResponseDto.ApiResponseCode.fromMessage(this.errorName).toString();
}
}
@Schema(name = "ErrorSearchReq", description = "에러로그 검색 요청")

View File

@@ -21,4 +21,9 @@ public enum EventStatus implements EnumType {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return desc;
}
}

View File

@@ -39,4 +39,9 @@ public enum EventType implements EnumType {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return name();
}
}

View File

@@ -22,14 +22,7 @@ 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;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@Tag(name = "영상 관리", description = "영상 관리 API")
@@ -256,4 +249,11 @@ public class MapSheetMngApiController {
return ApiResponseDto.ok(
mapSheetMngService.uploadChunkMapSheetFile(hstUid, upAddReqDto, chunkFile));
}
@Operation(summary = "영상데이터관리 > 등록된 년도 데이터 전체 삭제", description = "영상데이터관리 > 등록된 년도 데이터 전체 삭제")
@DeleteMapping
public ApiResponseDto<Void> deleteByMngYyyyMngAll(@RequestParam Integer mngYyyy) {
mapSheetMngService.deleteByMngYyyyMngAll(mngYyyy);
return ApiResponseDto.ok(null);
}
}

View File

@@ -3,6 +3,7 @@ package com.kamco.cd.kamcoback.mapsheet.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.kamco.cd.kamcoback.common.enums.MngStateType;
import com.kamco.cd.kamcoback.common.enums.SyncStateType;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import com.kamco.cd.kamcoback.common.utils.enums.EnumType;
import com.kamco.cd.kamcoback.common.utils.enums.Enums;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
@@ -41,6 +42,11 @@ public class MapSheetMngDto {
public String getText() {
return message;
}
@Override
public String getTextEn() {
return message;
}
}
@Schema(name = "MngSearchReq", description = "영상관리 검색 요청")
@@ -217,7 +223,11 @@ public class MapSheetMngDto {
enumId = "NOTYET";
}
boolean english = HeaderUtil.isEnglishRequest();
MngStateType type = Enums.fromId(MngStateType.class, enumId);
if (english) {
return type.getTextEn();
}
return type.getText();
}
}
@@ -341,6 +351,10 @@ public class MapSheetMngDto {
}
SyncStateType type = Enums.fromId(SyncStateType.class, enumId);
boolean english = HeaderUtil.isEnglishRequest();
if (english) {
return type.getTextEn();
}
return type.getText();
}
}

View File

@@ -40,7 +40,7 @@ import org.springframework.web.multipart.MultipartFile;
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
@Transactional
public class MapSheetMngService {
private final MapSheetMngCoreService mapSheetMngCoreService;
@@ -489,4 +489,8 @@ public class MapSheetMngService {
return modelUploadResDto;
}
public void deleteByMngYyyyMngAll(Integer mngYyyy) {
mapSheetMngCoreService.deleteByMngYyyyMngAll(mngYyyy);
}
}

View File

@@ -4,6 +4,7 @@ import com.kamco.cd.kamcoback.auth.CustomUserDetails;
import com.kamco.cd.kamcoback.auth.JwtTokenProvider;
import com.kamco.cd.kamcoback.auth.RefreshTokenService;
import com.kamco.cd.kamcoback.common.enums.StatusType;
import com.kamco.cd.kamcoback.config.api.ApiLogFunction;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.members.dto.MembersDto;
import com.kamco.cd.kamcoback.members.dto.SignInRequest;
@@ -16,11 +17,13 @@ import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.nio.file.AccessDeniedException;
import java.time.Duration;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
@@ -34,6 +37,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@Tag(name = "인증(Auth)", description = "로그인, 토큰 재발급, 로그아웃 API")
@RestController
@RequestMapping("/api/auth")
@@ -103,8 +107,13 @@ public class AuthController {
required = true)
@RequestBody
SignInRequest request,
HttpServletRequest servletRequest,
HttpServletResponse response) {
// TODO: 접속 가능한 IP 대역 조회
String clientIp = ApiLogFunction.getXFowardedForIp(servletRequest);
log.info("####### clientIp: {}", clientIp);
// 사용자 상태 조회
String status = authService.getUserStatus(request);
Authentication authentication = null;
@@ -169,6 +178,7 @@ public class AuthController {
if (refreshToken == null || !jwtTokenProvider.isValidToken(refreshToken)) {
throw new AccessDeniedException("만료되었거나 유효하지 않은 리프레시 토큰 입니다.");
}
String username = jwtTokenProvider.getSubject(refreshToken);
// Redis에 저장된 RefreshToken과 일치하는지 확인

View File

@@ -3,6 +3,7 @@ package com.kamco.cd.kamcoback.members.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.kamco.cd.kamcoback.common.enums.RoleType;
import com.kamco.cd.kamcoback.common.enums.StatusType;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import com.kamco.cd.kamcoback.common.utils.enums.Enums;
import com.kamco.cd.kamcoback.common.utils.interfaces.EnumValid;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
@@ -65,16 +66,18 @@ public class MembersDto {
private String getUserRoleName(String roleId) {
RoleType type = Enums.fromId(RoleType.class, roleId);
return type.getText();
boolean english = HeaderUtil.isEnglishRequest();
return english ? type.getTextEn() : type.getText();
}
private String getStatusName(String status, Boolean pwdResetYn) {
StatusType type = Enums.fromId(StatusType.class, status);
boolean english = HeaderUtil.isEnglishRequest();
pwdResetYn = pwdResetYn != null && pwdResetYn;
if (type.equals(StatusType.PENDING) && pwdResetYn) {
type = StatusType.ACTIVE;
}
return type.getText();
return english ? type.getTextEn() : type.getText();
}
}

View File

@@ -31,7 +31,7 @@ public class MenuDto {
@JsonFormatDttm private ZonedDateTime updatedDttm;
private String menuApiUrl;
private String menuNmEn;
public Basic(
String menuUid,
@@ -45,7 +45,8 @@ public class MenuDto {
Long updatedUid,
List<MenuDto.Basic> children,
ZonedDateTime createdDttm,
ZonedDateTime updatedDttm) {
ZonedDateTime updatedDttm,
String menuNmEn) {
this.menuUid = menuUid;
this.menuNm = menuNm;
this.menuUrl = menuUrl;
@@ -58,6 +59,7 @@ public class MenuDto {
this.children = children;
this.createdDttm = createdDttm;
this.updatedDttm = updatedDttm;
this.menuNmEn = menuNmEn;
}
}

View File

@@ -36,6 +36,11 @@ public class ModelMngDto {
public String getText() {
return desc;
}
@Override
public String getTextEn() {
return desc;
}
}
@Schema(name = "ModelMgmtDto Basic", description = "모델관리 엔티티 기본 정보")

View File

@@ -626,4 +626,8 @@ public class InferenceResultCoreService {
public List<InferenceResultsTestingDto.Basic> getInferenceResultGroupList(List<Long> batchIds) {
return inferenceResultsTestingRepository.getInferenceResultGroupList(batchIds);
}
public long deleteInference(UUID uuid) {
return inferenceResultRepository.deleteInference(uuid);
}
}

View File

@@ -379,4 +379,8 @@ public class MapSheetMngCoreService {
return result;
}
public void deleteByMngYyyyMngAll(Integer mngYyyy) {
mapSheetMngRepository.deleteByMngYyyyMngAll(mngYyyy);
}
}

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
import com.kamco.cd.kamcoback.menu.dto.MyMenuDto;
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
@@ -7,8 +8,10 @@ import com.kamco.cd.kamcoback.postgres.repository.menu.MenuRepository;
import java.util.Comparator;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class MenuCoreService {
@@ -27,6 +30,8 @@ public class MenuCoreService {
*/
public List<MyMenuDto.Basic> getFindByRole(String role) {
List<MenuEntity> entities = menuRepository.getFindByRole(role);
boolean english = HeaderUtil.isEnglishRequest();
log.info("[LANG CHECK] english={}", english);
return entities.stream()
.map(
@@ -34,7 +39,7 @@ public class MenuCoreService {
MyMenuDto.Basic p =
new MyMenuDto.Basic(
parent.getMenuUid(),
parent.getMenuNm(),
english ? parent.getMenuNmEn() : parent.getMenuNm(),
parent.getMenuUrl(),
parent.getMenuOrder());
@@ -48,7 +53,10 @@ public class MenuCoreService {
.map(
c ->
new MyMenuDto.Basic(
c.getMenuUid(), c.getMenuNm(), c.getMenuUrl(), c.getMenuOrder()))
c.getMenuUid(),
english ? c.getMenuNmEn() : c.getMenuNm(),
c.getMenuUrl(),
c.getMenuOrder()))
.forEach(childDto -> p.getChildren().add(childDto));
return p;

View File

@@ -229,6 +229,9 @@ public class MapSheetLearnEntity {
@Column(name = "shp_error_message")
private String shp_error_message;
@Column(name = "is_deleted")
private Boolean isDeleted;
public InferenceResultDto.ResultList toDto() {
return new InferenceResultDto.ResultList(
this.uuid,

View File

@@ -58,6 +58,9 @@ public class MenuEntity extends CommonDateEntity {
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<MenuEntity> children = new ArrayList<>();
@Column(name = "menu_nm_en")
private String menuNmEn; // 영문 메뉴명
public MenuDto.Basic toDto() {
return new MenuDto.Basic(
this.menuUid,
@@ -71,6 +74,7 @@ public class MenuEntity extends CommonDateEntity {
this.updatedUid,
this.children.stream().map(MenuEntity::toDto).toList(),
this.getCreatedDate(),
this.getModifiedDate());
this.getModifiedDate(),
this.menuNmEn);
}
}

View File

@@ -62,4 +62,11 @@ public interface InferenceResultRepositoryCustom {
* @return
*/
Optional<MapSheetAnalInferenceEntity> getAnalInferenceDataByLearnId(Long id);
/**
* 추론 삭제
*
* @param uuid
*/
long deleteInference(UUID uuid);
}

View File

@@ -346,4 +346,13 @@ public class InferenceResultRepositoryImpl implements InferenceResultRepositoryC
.where(mapSheetAnalInferenceEntity.learnId.eq(id))
.fetchOne());
}
@Override
public long deleteInference(UUID uuid) {
return queryFactory
.update(mapSheetLearnEntity)
.set(mapSheetLearnEntity.isDeleted, true)
.where(mapSheetLearnEntity.uuid.eq(uuid))
.execute();
}
}

View File

@@ -30,6 +30,7 @@ import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalInferenceEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnEntity;
import com.kamco.cd.kamcoback.postgres.entity.QModelMngEntity;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
@@ -37,13 +38,10 @@ 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.JPAExpressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
@@ -90,6 +88,9 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto
builder.and(mapSheetLearnEntity.title.containsIgnoreCase(req.getTitle()));
}
// 삭제여부 값 추가
builder.and(mapSheetLearnEntity.isDeleted.eq(false).or(mapSheetLearnEntity.isDeleted.isNull()));
List<MapSheetLearnEntity> content =
queryFactory
.select(mapSheetLearnEntity)
@@ -445,12 +446,14 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto
NumberExpression<Long> inkxNoAsLong =
Expressions.numberTemplate(Long.class, "cast({0} as long)", mapInkx5kEntity.mapidcdNo);
/* 미사용
StringExpression pnu =
Expressions.stringTemplate(
"nullif(({0}), '')",
JPAExpressions.select(Expressions.stringTemplate("string_agg({0}, ',')", pnuEntity.pnu))
.from(pnuEntity)
.where(pnuEntity.geo.geoUid.eq(mapSheetAnalDataInferenceGeomEntity.geoUid)));
*/
// 4) content
List<Geom> content =
@@ -458,6 +461,7 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto
.select(
Projections.constructor(
Geom.class,
mapSheetAnalDataInferenceGeomEntity.geoUid,
mapSheetAnalDataInferenceGeomEntity.uuid,
mapSheetAnalDataInferenceGeomEntity.resultUid,
mapSheetAnalDataInferenceGeomEntity.compareYyyy,
@@ -472,7 +476,7 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto
Expressions.stringTemplate(
"substring({0} from 1 for 8)",
mapSheetAnalDataInferenceGeomEntity.resultUid),
pnu,
Expressions.constant(""),
mapSheetAnalDataInferenceGeomEntity.fitState))
.from(mapSheetAnalInferenceEntity)
.join(mapSheetAnalDataInferenceEntity)
@@ -487,6 +491,33 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto
.limit(pageable.getPageSize())
.fetch();
// 4-1) pnu 를 geoUid 로 검색하기 -> AS-IS 에서는 전체 tb_pnu 를 조회해서 오래 걸렸음
List<Long> geoUids = content.stream().map(Geom::getGeoUid).filter(Objects::nonNull).toList();
Map<Long, String> pnuMap = new HashMap<>();
if (!geoUids.isEmpty()) {
StringExpression pnuAgg = Expressions.stringTemplate("string_agg({0}, ',')", pnuEntity.pnu);
List<Tuple> pnuRows =
queryFactory
.select(
pnuEntity.geo.geoUid,
Expressions.stringTemplate("string_agg({0}, ',')", pnuEntity.pnu))
.from(pnuEntity)
.where(pnuEntity.geo.geoUid.in(geoUids))
.groupBy(pnuEntity.geo.geoUid)
.fetch();
pnuMap =
pnuRows.stream()
.collect(
Collectors.toMap(row -> row.get(pnuEntity.geo.geoUid), row -> row.get(pnuAgg)));
}
for (Geom geom : content) {
geom.setPnu(pnuMap.get(geom.getGeoUid()));
}
// 5) total (조인 최소화 유지)
Long total =
queryFactory
@@ -519,7 +550,7 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto
.fetchOne();
if (learn == null) {
return new GukYuinLinkFacts(false, false, false, false);
return new GukYuinLinkFacts(false, false, false, false, null);
}
// 부분 도엽 실행인지 확인
@@ -529,19 +560,21 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto
QMapSheetLearnEntity learn2 = new QMapSheetLearnEntity("learn2");
QMapSheetLearnEntity learnQ = QMapSheetLearnEntity.mapSheetLearnEntity;
// 실행중인 추론 있는지 확인
boolean hasRunningInference =
// 현재 국유인 연동하려는 추론의 비교년도,기준년도와 같은 회차 중, 할당되거나 진행중인 학습데이터 uuid 조회
// ex. 2022-2023년도 9회차 학습데이터 제작 진행중 -> 10회차 연동하려고 할 시, 먼저 9회차를 종료해야 함
UUID runningInferenceUuid =
queryFactory
.selectOne()
.from(inf)
.join(learn2)
.on(inf.learnId.eq(learn2.id))
.where(
learn2.compareYyyy.eq(learn.getCompareYyyy()),
learn2.targetYyyy.eq(learn.getTargetYyyy()),
inf.analState.in("ASSIGNED", "ING"))
.fetchFirst()
!= null;
.select(inf.uuid)
.from(inf)
.join(learn2)
.on(inf.learnId.eq(learn2.id))
.where(
learn2.compareYyyy.eq(learn.getCompareYyyy()),
learn2.targetYyyy.eq(learn.getTargetYyyy()),
inf.analState.in("ASSIGNED", "ING"))
.fetchFirst();
boolean hasRunningInference = runningInferenceUuid != null;
// 국유인 작업 진행중 있는지 확인
boolean hasOtherUnfinishedGukYuin =
@@ -556,6 +589,7 @@ public class MapSheetLearnRepositoryImpl implements MapSheetLearnRepositoryCusto
.fetchFirst()
!= null;
return new GukYuinLinkFacts(true, isPartScope, hasRunningInference, hasOtherUnfinishedGukYuin);
return new GukYuinLinkFacts(
true, isPartScope, hasRunningInference, hasOtherUnfinishedGukYuin, runningInferenceUuid);
}
}

View File

@@ -211,8 +211,9 @@ public class ChangeDetectionRepositoryImpl extends QuerydslRepositorySupport
.where(
l.status
.eq(Status.END.getId())
.and(JPAExpressions.selectOne().from(d).where(d.analUid.eq(a.id)).exists()))
.orderBy(l.id.asc())
.and(JPAExpressions.selectOne().from(d).where(d.analUid.eq(a.id)).exists()),
l.isDeleted.eq(false).or(l.isDeleted.isNull()))
.orderBy(l.id.desc())
.fetch();
}

View File

@@ -7,6 +7,7 @@ import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InspectState;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelMngState;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelState;
import com.kamco.cd.kamcoback.label.dto.LabelWorkDto;
import com.kamco.cd.kamcoback.label.dto.LabelWorkDto.LabelCntInfo;
import com.kamco.cd.kamcoback.label.dto.LabelWorkDto.LabelWorkMng;
import com.kamco.cd.kamcoback.label.dto.LabelWorkDto.LabelWorkMngDetail;
import com.kamco.cd.kamcoback.label.dto.LabelWorkDto.WorkerState;
@@ -18,7 +19,6 @@ import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceGeomEnti
import com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalInferenceEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMemberEntity;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
@@ -86,7 +86,7 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
}
/**
* 라벨링 작업관리 목록 조회 (복잡한 집계 쿼리로 인해 DTO 직접 반환)
* 라벨링 작업관리 목록 조회 :: 전체 geom 집계 -> inference 먼저 쿼리 하고 count 정보 따로 집계하도록 수정
*
* @param searchReq 검색 조건
* @return 라벨링 작업관리 목록 페이지
@@ -95,9 +95,8 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
public Page<LabelWorkMng> labelWorkMngList(LabelWorkDto.LabelWorkMngSearchReq searchReq) {
Pageable pageable = PageRequest.of(searchReq.getPage(), searchReq.getSize());
BooleanBuilder whereBuilder = new BooleanBuilder();
BooleanBuilder whereSubDataBuilder = new BooleanBuilder();
BooleanBuilder whereSubBuilder = new BooleanBuilder();
BooleanBuilder baseWhereBuilder = new BooleanBuilder();
if (StringUtils.isNotBlank(searchReq.getDetectYear())) {
String[] years = searchReq.getDetectYear().split("-");
@@ -106,67 +105,14 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
Integer compareYear = Integer.valueOf(years[0]);
Integer targetYear = Integer.valueOf(years[1]);
whereBuilder.and(
mapSheetAnalDataInferenceEntity
baseWhereBuilder.and(
mapSheetAnalInferenceEntity
.compareYyyy
.eq(compareYear)
.and(mapSheetAnalDataInferenceEntity.targetYyyy.eq(targetYear)));
.and(mapSheetAnalInferenceEntity.targetYyyy.eq(targetYear)));
}
}
whereSubDataBuilder.and(
mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid));
whereSubBuilder.and(
mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id));
if (searchReq.getStrtDttm() != null && searchReq.getEndDttm() != null) {
ZoneId zoneId = ZoneId.of("Asia/Seoul");
ZonedDateTime start = searchReq.getStrtDttm().atStartOfDay(zoneId);
ZonedDateTime end = searchReq.getEndDttm().plusDays(1).atStartOfDay(zoneId);
whereSubBuilder.and(
mapSheetAnalDataInferenceGeomEntity
.labelStateDttm
.goe(start)
.and(mapSheetAnalDataInferenceGeomEntity.labelStateDttm.lt(end)));
}
// labelTotCnt: pnu가 있고 fitState = UNFIT 인 건수만 라벨링 대상
NumberExpression<Long> labelTotCntExpr =
new CaseBuilder()
.when(
mapSheetAnalDataInferenceGeomEntity
.pnu
.gt(0)
.and(
mapSheetAnalDataInferenceGeomEntity.fitState.eq(
ImageryFitStatus.UNFIT.getId())))
.then(1L)
.otherwise(0L)
.sum();
// stagnation_yn = 'N'인 정상 진행 건수 (서브쿼리로 별도 집계)
Expression<Long> normalProgressCntSubQuery =
JPAExpressions.select(
new CaseBuilder()
.when(labelingAssignmentEntity.stagnationYn.eq('N'))
.then(1L)
.otherwise(0L)
.sum()
.coalesce(0L))
.from(labelingAssignmentEntity)
.where(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id));
// 총 배정 건수 (서브쿼리로 별도 집계)
Expression<Long> totalAssignmentCntSubQuery =
JPAExpressions.select(labelingAssignmentEntity.count().coalesce(0L))
.from(labelingAssignmentEntity)
.where(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id));
/** 순서 ING 진행중 ASSIGNED 작업할당 PENDING 작업대기 FINISH 종료 */
NumberExpression<Integer> stateOrder =
new CaseBuilder()
@@ -180,64 +126,31 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
.then(3)
.otherwise(99);
// 1단계: anal_inference 기준으로 상위 페이지 목록만 조회
List<LabelWorkMng> foundContent =
queryFactory
.select(
Projections.constructor(
LabelWorkMng.class,
mapSheetAnalInferenceEntity.id, // analUid 추가
mapSheetAnalInferenceEntity.uuid,
mapSheetAnalInferenceEntity.compareYyyy,
mapSheetAnalInferenceEntity.targetYyyy,
mapSheetAnalInferenceEntity.stage,
// 국유인 반영 컬럼 gukyuinApplyDttm
mapSheetAnalInferenceEntity.gukyuinApplyDttm,
mapSheetAnalDataInferenceGeomEntity.dataUid.count(),
// labelTotCnt: pnu 있고 pass_yn = false인 건수
labelTotCntExpr,
new CaseBuilder()
.when(
mapSheetAnalDataInferenceGeomEntity.labelState.eq(
LabelState.ASSIGNED.getId()))
.then(1L)
.otherwise(0L)
.sum(),
new CaseBuilder()
.when(
mapSheetAnalDataInferenceGeomEntity.labelState.eq(
LabelState.SKIP.getId())) // "STOP"?
.then(1L)
.otherwise(0L)
.sum(),
new CaseBuilder()
.when(
mapSheetAnalDataInferenceGeomEntity.labelState.eq(
LabelState.DONE.getId()))
.then(1L)
.otherwise(0L)
.sum(),
mapSheetAnalDataInferenceGeomEntity.labelStateDttm.min(),
// analState: tb_map_sheet_anal_inference.anal_state
mapSheetAnalInferenceEntity.detectingCnt,
Expressions.constant(0L),
Expressions.constant(0L),
Expressions.constant(0L),
Expressions.constant(0L),
mapSheetAnalInferenceEntity.createdDttm,
mapSheetAnalInferenceEntity.analState,
// normalProgressCnt: stagnation_yn = 'N'인 건수 (서브쿼리)
normalProgressCntSubQuery,
// totalAssignmentCnt: 총 배정 건수 (서브쿼리)
totalAssignmentCntSubQuery,
Expressions.constant(0L),
Expressions.constant(0L),
mapSheetAnalInferenceEntity.labelingClosedYn,
mapSheetAnalInferenceEntity.inspectionClosedYn,
new CaseBuilder()
.when(
mapSheetAnalDataInferenceGeomEntity.testState.eq(
InspectState.COMPLETE.getId()))
.then(1L)
.otherwise(0L)
.sum(),
new CaseBuilder()
.when(
mapSheetAnalDataInferenceGeomEntity.testState.eq(
InspectState.UNCONFIRM.getId()))
.then(1L)
.otherwise(0L)
.sum(),
Expressions.constant(0L),
Expressions.constant(0L),
new CaseBuilder()
.when(mapSheetAnalInferenceEntity.inspectionClosedYn.eq("Y"))
.then(mapSheetAnalInferenceEntity.updatedDttm)
@@ -247,23 +160,11 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
"substring({0} from 1 for 8)", mapSheetLearnEntity.uid),
mapSheetLearnEntity.uuid))
.from(mapSheetAnalInferenceEntity)
.innerJoin(mapSheetAnalDataInferenceEntity)
.on(whereSubDataBuilder)
.innerJoin(mapSheetAnalDataInferenceGeomEntity)
.on(whereSubBuilder)
.leftJoin(mapSheetLearnEntity)
.on(mapSheetAnalInferenceEntity.learnId.eq(mapSheetLearnEntity.id))
.where(whereBuilder)
.groupBy(
mapSheetAnalInferenceEntity.uuid,
mapSheetAnalInferenceEntity.compareYyyy,
mapSheetAnalInferenceEntity.targetYyyy,
mapSheetAnalInferenceEntity.stage,
mapSheetAnalInferenceEntity.createdDttm,
mapSheetAnalInferenceEntity.analState,
mapSheetAnalInferenceEntity.id,
mapSheetLearnEntity.uid,
mapSheetLearnEntity.uuid)
.innerJoin(mapSheetLearnEntity)
.on(
mapSheetAnalInferenceEntity.learnId.eq(mapSheetLearnEntity.id),
mapSheetLearnEntity.isDeleted.eq(false).or(mapSheetLearnEntity.isDeleted.isNull()))
.where(baseWhereBuilder)
.orderBy(
stateOrder.asc(),
mapSheetAnalInferenceEntity.targetYyyy.desc(),
@@ -273,20 +174,122 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
.limit(pageable.getPageSize())
.fetch();
// Count 쿼리 별도 실행 (null safe handling)
// total count
long total =
Optional.ofNullable(
queryFactory
.select(mapSheetAnalInferenceEntity.uuid.countDistinct())
.select(mapSheetAnalInferenceEntity.count())
.from(mapSheetAnalInferenceEntity)
.innerJoin(mapSheetAnalDataInferenceEntity)
.on(whereSubDataBuilder)
.innerJoin(mapSheetAnalDataInferenceGeomEntity)
.on(whereSubBuilder)
.where(whereBuilder)
.where(baseWhereBuilder)
.fetchOne())
.orElse(0L);
// 2단계: 각 analUid별 count 조회 후 세팅
for (LabelWorkMng item : foundContent) {
Long analUid = item.getAnalUid();
BooleanBuilder geomWhereBuilder = new BooleanBuilder();
geomWhereBuilder.and(mapSheetAnalDataInferenceEntity.analUid.eq(analUid));
geomWhereBuilder.and(
mapSheetAnalDataInferenceGeomEntity.dataUid.eq(mapSheetAnalDataInferenceEntity.id));
if (searchReq.getStrtDttm() != null && searchReq.getEndDttm() != null) {
ZoneId zoneId = ZoneId.of("Asia/Seoul");
ZonedDateTime start = searchReq.getStrtDttm().atStartOfDay(zoneId);
ZonedDateTime end = searchReq.getEndDttm().plusDays(1).atStartOfDay(zoneId);
geomWhereBuilder.and(
mapSheetAnalDataInferenceGeomEntity
.createdDttm
.goe(start)
.and(mapSheetAnalDataInferenceGeomEntity.createdDttm.lt(end)));
}
// labelTotCnt: pnu > 0 and fitState = UNFIT
Long labelTotCnt =
Optional.ofNullable(
queryFactory
.select(mapSheetAnalDataInferenceGeomEntity.count())
.from(mapSheetAnalDataInferenceEntity)
.innerJoin(mapSheetAnalDataInferenceGeomEntity)
.on(
mapSheetAnalDataInferenceGeomEntity.dataUid.eq(
mapSheetAnalDataInferenceEntity.id))
.where(
geomWhereBuilder,
mapSheetAnalDataInferenceGeomEntity.pnu.gt(0),
mapSheetAnalDataInferenceGeomEntity.fitState.eq(
ImageryFitStatus.UNFIT.getId()))
.fetchOne())
.orElse(0L);
LabelCntInfo cntInfo =
queryFactory
.select(
Projections.constructor(
LabelCntInfo.class,
new CaseBuilder()
.when(labelingAssignmentEntity.workState.eq(LabelState.ASSIGNED.getId()))
.then(1L)
.otherwise(0L)
.sum()
.coalesce(0L),
new CaseBuilder()
.when(labelingAssignmentEntity.workState.eq(LabelState.SKIP.getId()))
.then(1L)
.otherwise(0L)
.sum()
.coalesce(0L),
new CaseBuilder()
.when(labelingAssignmentEntity.workState.eq(LabelState.DONE.getId()))
.then(1L)
.otherwise(0L)
.sum()
.coalesce(0L),
new CaseBuilder()
.when(
labelingAssignmentEntity.inspectState.eq(
InspectState.UNCONFIRM.getId()))
.then(1L)
.otherwise(0L)
.sum()
.coalesce(0L),
new CaseBuilder()
.when(
labelingAssignmentEntity.inspectState.eq(InspectState.EXCEPT.getId()))
.then(1L)
.otherwise(0L)
.sum()
.coalesce(0L),
new CaseBuilder()
.when(
labelingAssignmentEntity.inspectState.eq(
InspectState.COMPLETE.getId()))
.then(1L)
.otherwise(0L)
.sum()
.coalesce(0L)))
.from(labelingAssignmentEntity)
.where(labelingAssignmentEntity.analUid.eq(analUid))
.fetchOne();
Long normalProgressCnt = 0L;
Long totalAssignmentCnt = 0L;
if (cntInfo == null) {
cntInfo = new LabelCntInfo(0L, 0L, 0L, 0L, 0L, 0L);
}
item.setLabelTotCnt(labelTotCnt);
item.setLabelAssignCnt(cntInfo.getAssignedCnt());
item.setLabelSkipTotCnt(cntInfo.getSkipCnt());
item.setLabelCompleteTotCnt(cntInfo.getDoneCnt());
item.setNormalProgressCnt(normalProgressCnt);
item.setTotalAssignmentCnt(totalAssignmentCnt);
item.setInspectorCompleteTotCnt(cntInfo.getCompleteCnt());
item.setInspectorRemainCnt(cntInfo.getUnconfirmCnt());
}
return new PageImpl<>(foundContent, pageable, total);
}

View File

@@ -5,6 +5,7 @@ import static com.kamco.cd.kamcoback.postgres.entity.QErrorLogEntity.errorLogEnt
import static com.kamco.cd.kamcoback.postgres.entity.QMemberEntity.memberEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMenuEntity.menuEntity;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
import com.kamco.cd.kamcoback.log.dto.AuditLogDto.DownloadReq;
import com.kamco.cd.kamcoback.log.dto.ErrorLogDto;
@@ -13,6 +14,7 @@ import com.kamco.cd.kamcoback.log.dto.EventType;
import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity;
import com.kamco.cd.kamcoback.postgres.entity.QMenuEntity;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.CaseBuilder;
@@ -83,13 +85,16 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport
public Page<AuditLogDto.MenuAuditList> findLogByMenu(
AuditLogDto.searchReq searchReq, String searchValue) {
Pageable pageable = searchReq.toPageable();
boolean english = HeaderUtil.isEnglishRequest();
Expression<String> menuNameExpr = english ? menuEntity.menuNmEn.max() : menuEntity.menuNm.max();
List<AuditLogDto.MenuAuditList> foundContent =
queryFactory
.select(
Projections.constructor(
AuditLogDto.MenuAuditList.class,
auditLogEntity.menuUid.as("menuId"),
menuEntity.menuNm.max().as("menuName"),
menuNameExpr,
readCount().as("readCount"),
cudCount().as("cudCount"),
printCount().as("printCount"),
@@ -217,21 +222,24 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport
@Override
public Page<AuditLogDto.DailyDetail> findLogByDailyResult(
AuditLogDto.searchReq searchReq, LocalDate logDate) {
boolean english = HeaderUtil.isEnglishRequest();
Pageable pageable = searchReq.toPageable();
QMenuEntity parent = new QMenuEntity("parent");
// 1depth menu name
StringExpression parentMenuName =
new CaseBuilder()
.when(parent.menuUid.isNull())
.then(menuEntity.menuNm)
.otherwise(parent.menuNm);
.then(english ? menuEntity.menuNmEn : menuEntity.menuNm)
.otherwise(english ? parent.menuNmEn : parent.menuNm);
// 2depth menu name
StringExpression menuName =
new CaseBuilder()
.when(parent.menuUid.isNull())
.then(NULL_STRING)
.otherwise(menuEntity.menuNm);
.otherwise(english ? menuEntity.menuNmEn : menuEntity.menuNm);
StringExpression menuNm = (english ? menuEntity.menuNmEn : menuEntity.menuNm);
List<AuditLogDto.DailyDetail> foundContent =
queryFactory
@@ -241,20 +249,20 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport
auditLogEntity.id.as("logId"),
memberEntity.name.as("userName"),
memberEntity.employeeNo.as("loginId"),
menuEntity.menuNm.as("menuName"),
menuNm.as("menuName"),
auditLogEntity.eventType.as("eventType"),
Expressions.stringTemplate(
"to_char({0}, 'YYYY-MM-DD HH24:MI')", auditLogEntity.createdDate)
.as("logDateTime"),
Projections.constructor(
AuditLogDto.LogDetail.class,
Expressions.constant("한국자산관리공사"), // serviceName
Expressions.constant(english ? "Kamco" : "한국자산관리공사"), // serviceName
parentMenuName.as("parentMenuName"),
menuName,
menuEntity.menuUrl.as("menuUrl"),
menuEntity.description.as("menuDescription"),
menuEntity.menuOrder.as("sortOrder"),
menuEntity.isUse.as("used")))) // TODO
menuEntity.isUse.as("used"))))
.from(auditLogEntity)
.leftJoin(menuEntity)
.on(auditLogEntity.menuUid.eq(menuEntity.menuUid))
@@ -285,21 +293,22 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport
@Override
public Page<AuditLogDto.MenuDetail> findLogByMenuResult(
AuditLogDto.searchReq searchReq, String menuUid) {
boolean english = HeaderUtil.isEnglishRequest();
Pageable pageable = searchReq.toPageable();
QMenuEntity parent = new QMenuEntity("parent");
// 1depth menu name
StringExpression parentMenuName =
new CaseBuilder()
.when(parent.menuUid.isNull())
.then(menuEntity.menuNm)
.otherwise(parent.menuNm);
.then(english ? menuEntity.menuNmEn : menuEntity.menuNm)
.otherwise(english ? parent.menuNmEn : parent.menuNm);
// 2depth menu name
StringExpression menuName =
new CaseBuilder()
.when(parent.menuUid.isNull())
.then(NULL_STRING)
.otherwise(menuEntity.menuNm);
.otherwise(english ? menuEntity.menuNmEn : menuEntity.menuNm);
List<AuditLogDto.MenuDetail> foundContent =
queryFactory
@@ -315,7 +324,7 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport
auditLogEntity.eventType.as("eventType"),
Projections.constructor(
AuditLogDto.LogDetail.class,
Expressions.constant("한국자산관리공사"), // serviceName
Expressions.constant(english ? "Kamco" : "한국자산관리공사"), // serviceName
parentMenuName.as("parentMenuName"),
menuName,
menuEntity.menuUrl.as("menuUrl"),
@@ -352,21 +361,24 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport
@Override
public Page<AuditLogDto.UserDetail> findLogByAccountResult(
AuditLogDto.searchReq searchReq, Long userUid) {
boolean english = HeaderUtil.isEnglishRequest();
Pageable pageable = searchReq.toPageable();
QMenuEntity parent = new QMenuEntity("parent");
// 1depth menu name
StringExpression parentMenuName =
new CaseBuilder()
.when(parent.menuUid.isNull())
.then(menuEntity.menuNm)
.otherwise(parent.menuNm);
.then(english ? menuEntity.menuNmEn : menuEntity.menuNm)
.otherwise(english ? parent.menuNmEn : parent.menuNm);
// 2depth menu name
StringExpression menuName =
new CaseBuilder()
.when(parent.menuUid.isNull())
.then(NULL_STRING)
.otherwise(menuEntity.menuNm);
.otherwise(english ? menuEntity.menuNmEn : menuEntity.menuNm);
StringExpression menuNm = (english ? menuEntity.menuNmEn : menuEntity.menuNm);
List<AuditLogDto.UserDetail> foundContent =
queryFactory
@@ -377,11 +389,11 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport
Expressions.stringTemplate(
"to_char({0}, 'YYYY-MM-DD HH24:MI')", auditLogEntity.createdDate)
.as("logDateTime"),
menuEntity.menuNm.as("menuName"),
menuNm.as("menuName"),
auditLogEntity.eventType.as("eventType"),
Projections.constructor(
AuditLogDto.LogDetail.class,
Expressions.constant("한국자산관리공사"), // serviceName
Expressions.constant(english ? "Kamco" : "한국자산관리공사"), // serviceName
parentMenuName.as("parentMenuName"),
menuName,
menuEntity.menuUrl.as("menuUrl"),
@@ -442,7 +454,7 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport
if (StringUtils.isBlank(searchValue)) {
return null;
}
return menuEntity.menuNm.contains(searchValue);
return menuEntity.menuNm.contains(searchValue).or(menuEntity.menuNmEn.contains(searchValue));
}
private BooleanExpression loginIdOrUsernameContains(String searchValue) {

View File

@@ -5,6 +5,7 @@ import static com.kamco.cd.kamcoback.postgres.entity.QErrorLogEntity.errorLogEnt
import static com.kamco.cd.kamcoback.postgres.entity.QMemberEntity.memberEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMenuEntity.menuEntity;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import com.kamco.cd.kamcoback.log.dto.ErrorLogDto;
import com.kamco.cd.kamcoback.log.dto.EventStatus;
import com.kamco.cd.kamcoback.log.dto.EventType;
@@ -38,14 +39,17 @@ public class ErrorLogRepositoryImpl extends QuerydslRepositorySupport
@Override
public Page<ErrorLogDto.Basic> findLogByError(ErrorLogDto.ErrorSearchReq searchReq) {
Pageable pageable = searchReq.toPageable();
boolean english = HeaderUtil.isEnglishRequest();
StringExpression menuNm = (english ? menuEntity.menuNmEn : menuEntity.menuNm);
List<ErrorLogDto.Basic> foundContent =
queryFactory
.select(
Projections.constructor(
ErrorLogDto.Basic.class,
errorLogEntity.id.as("logId"),
Expressions.stringTemplate("{0}", "한국자산관리공사"), // serviceName
menuEntity.menuNm.as("menuName"),
Expressions.constant(english ? "Kamco" : "한국자산관리공사"), // serviceName
menuNm.as("menuName"),
memberEntity.employeeNo.as("loginId"),
memberEntity.name.as("userName"),
errorLogEntity.errorType.as("eventType"),

View File

@@ -748,6 +748,13 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
.delete(mapSheetMngTileEntity)
.where(mapSheetMngTileEntity.mngYyyy.eq(mngYyyy))
.execute();
long updateNotYetCount =
queryFactory
.update(yearEntity)
.set(yearEntity.status, "NOTYET")
.where(yearEntity.yyyy.eq(mngYyyy))
.execute();
}
@Override

View File

@@ -4,7 +4,6 @@ import static com.kamco.cd.kamcoback.postgres.entity.QModelMngEntity.modelMngEnt
import static com.kamco.cd.kamcoback.postgres.entity.QModelResultMetricEntity.modelResultMetricEntity;
import com.kamco.cd.kamcoback.model.dto.ModelMngDto;
import com.kamco.cd.kamcoback.postgres.QuerydslOrderUtil;
import com.kamco.cd.kamcoback.postgres.entity.ModelMngEntity;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Expression;
@@ -101,9 +100,10 @@ public class ModelMngRepositoryImpl extends QuerydslRepositorySupport
modelMngEntity.deleted.isFalse().or(modelMngEntity.deleted.isNull()))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.orderBy(
QuerydslOrderUtil.getOrderSpecifiers(
pageable, ModelMngEntity.class, "modelMngEntity"))
.orderBy(modelMngEntity.createCompleteDttm.desc())
// .orderBy(
// QuerydslOrderUtil.getOrderSpecifiers(
// pageable, ModelMngEntity.class, "modelMngEntity"))
.fetch();
Long countQuery =

View File

@@ -508,7 +508,7 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport
: "")
.classificationName(
DetectionClassification.fromStrDesc(
mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterCd()))
mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeCd()))
.probability(
mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeProb() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeProb()

View File

@@ -534,7 +534,7 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport
: "")
.classificationName(
DetectionClassification.fromStrDesc(
mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterCd()))
mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeCd()))
.probability(
mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeProb() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeProb()

View File

@@ -3,24 +3,30 @@ package com.kamco.cd.kamcoback.scheduler;
import com.kamco.cd.kamcoback.scheduler.service.MapSheetMngFileJobService;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@RequiredArgsConstructor
public class MapSheetMngFileJobController {
private final MapSheetMngFileJobService mapSheetMngFileJobService;
@Value("${spring.profiles.active}")
private String profile;
// 현재 상태 확인용 Getter
@Getter private boolean isSchedulerEnabled = false;
@Getter private boolean isSchedulerEnabled = true;
@Getter private boolean isFileSyncSchedulerEnabled = false;
@Getter private int mngSyncPageSize = 20;
// 파일싱크 진행여부 확인하기
@Scheduled(fixedDelay = 1000 * 10)
public void checkMngFileSync() {
if (!isSchedulerEnabled) {
if ("local".equals(profile) || !isSchedulerEnabled) {
return;
}

View File

@@ -21,6 +21,17 @@ public class AsyncConfig {
return ex;
}
@Bean(name = "makeShapeFile")
public Executor makeShapeFileExecutor() {
ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();
ex.setCorePoolSize(2);
ex.setMaxPoolSize(4);
ex.setQueueCapacity(50);
ex.setThreadNamePrefix("makeShapeFile-");
ex.initialize();
return ex;
}
@Bean(name = "auditLogExecutor")
public Executor auditLogExecutor() {
ThreadPoolTaskExecutor exec = new ThreadPoolTaskExecutor();
@@ -31,4 +42,16 @@ public class AsyncConfig {
exec.initialize();
return exec;
}
// 0313
@Bean(name = "inferenceEndExecutor")
public Executor inferenceEndExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("inference-async-");
executor.initialize();
return executor;
}
}

View File

@@ -255,7 +255,9 @@ public class MapSheetInferenceJobService {
// 추론 종료일때 shp 파일 생성
String batchIdStr = batchIds.stream().map(String::valueOf).collect(Collectors.joining(","));
// shp 파일 비동기 생성
// 0312 shp 파일 비동기 생성 (바꿔주세요)
// shpPipelineService.makeShapeFile(sheet.getUid(), batchIds);
// 0511 shp-exporter-v2.jar 에 에러가 있어 우선 기존 로직으로 변경함
shpPipelineService.runPipeline(jarPath, datasetDir, batchIdStr, sheet.getUid());
}

View File

@@ -3,7 +3,7 @@ package com.kamco.cd.kamcoback.scheduler.service;
import com.kamco.cd.kamcoback.common.service.ExternalJarRunner;
import com.kamco.cd.kamcoback.postgres.core.InferenceResultCoreService;
import com.kamco.cd.kamcoback.scheduler.config.ShpKeyLock;
import java.nio.file.Paths;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.scheduling.annotation.Async;
@@ -18,6 +18,30 @@ public class ShpPipelineService {
private final ExternalJarRunner externalJarRunner;
private final ShpKeyLock shpKeyLock;
// 0312 shp 파일 비동기 생성
@Async("makeShapeFile")
public void makeShapeFile(String inferenceId, List<Long> batchIds) {
if (!shpKeyLock.tryLock(inferenceId)) {
log.info("");
log.info("============================================================");
log.info("SHP pipeline already running. inferenceId={}", inferenceId);
log.info("============================================================");
try {
log.info("SHP pipeline already start. inferenceId={}", inferenceId);
externalJarRunner.run(inferenceId, batchIds);
} catch (Exception e) {
log.error("SHP pipeline failed. inferenceId={}", inferenceId, e);
// TODO 실패 상태 업데이트 로직 추가
} finally {
log.info("============================================================");
log.info("SHP pipeline DONE. inferenceId={}", inferenceId);
log.info("============================================================");
log.info("");
shpKeyLock.unlock(inferenceId);
}
}
}
/**
* shp 파일 생성 1. merge 생성 2. 생성된 merge shp 파일로 geoserver 등록, 3.도엽별로 shp 생성
*
@@ -36,24 +60,33 @@ public class ShpPipelineService {
}
try {
log.info("");
log.info("============================================================");
log.info("SHP pipeline started. inferenceId={}", inferenceId);
log.info("============================================================");
// uid 기준 merge shp, geojson 파일 생성
externalJarRunner.run(jarPath, batchIds, inferenceId, "", "MERGED");
// uid 기준 shp 파일 geoserver 등록
String register =
Paths.get(datasetDir, inferenceId, "merge", inferenceId + ".shp").toString();
log.info("register={}", register);
externalJarRunner.run(jarPath, register, inferenceId);
// uid 기준 도엽별 shp, geojson 파일 생성
externalJarRunner.run(jarPath, batchIds, inferenceId, "", "RESOLVE");
log.info("SHP pipeline finished. inferenceId={}", inferenceId);
// String register =
// Paths.get(datasetDir, inferenceId, "merge", inferenceId + ".shp").toString();
// log.info("register={}", register);
// externalJarRunner.run(jarPath, register, inferenceId);
//
// // uid 기준 도엽별 shp, geojson 파일 생성
// externalJarRunner.run(jarPath, batchIds, inferenceId, "", "RESOLVE");
//
// log.info("SHP pipeline finished. inferenceId={}", inferenceId);
} catch (Exception e) {
log.error("SHP pipeline failed. inferenceId={}", inferenceId, e);
// TODO 실패 상태 업데이트 로직 추가
} finally {
log.info("============================================================");
log.info("SHP pipeline DONE. inferenceId={}", inferenceId);
log.info("============================================================");
shpKeyLock.unlock(inferenceId);
}
}

View File

@@ -0,0 +1,83 @@
package com.kamco.cd.kamcoback.test;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.scheduler.service.ShpPipelineService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.ErrorResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "test shape api", description = "test shape api")
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/test")
public class TestShapeApiController {
private final ShpPipelineService shpPipelineService;
@Value("${inference.jar-path}")
private String jarPath;
@Value("${file.dataset-dir}")
private String datasetDir;
@Operation(
summary = "shapefile 생성 테스트",
description = "지정된 inference ID와 batch ID 목록으로 shapefile을 생성합니다.")
@ApiResponses({
@ApiResponse(
responseCode = "200",
description = "shapefile 생성 요청 성공",
content = @Content(schema = @Schema(implementation = String.class))),
@ApiResponse(
responseCode = "400",
description = "잘못된 요청 데이터",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "500",
description = "서버 오류",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
@GetMapping("/make-shapefile")
public ApiResponseDto<String> makeShapeFile(
@RequestParam String inferenceId, @RequestParam List<Long> batchIds) {
shpPipelineService.makeShapeFile(inferenceId, batchIds);
return ApiResponseDto.ok("Shapefile 생성이 시작되었습니다. inferenceId: " + inferenceId);
}
@Operation(
summary = "기존 run pipeline 테스트",
description = "지정된 inference ID와 batch ID 목록으로 shapefile을 생성합니다.")
@ApiResponses({
@ApiResponse(
responseCode = "200",
description = "shapefile 생성 요청 성공",
content = @Content(schema = @Schema(implementation = String.class))),
@ApiResponse(
responseCode = "400",
description = "잘못된 요청 데이터",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "500",
description = "서버 오류",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
@GetMapping("/run-pipeline")
public ApiResponseDto<String> runPipeline(
@RequestParam String inferenceId, @RequestParam List<Long> batchIds) {
String batchIdStr = batchIds.stream().map(String::valueOf).collect(Collectors.joining(","));
shpPipelineService.runPipeline(jarPath, datasetDir, batchIdStr, inferenceId);
return ApiResponseDto.ok("runPipeline 생성이 시작되었습니다. inferenceId: " + inferenceId);
}
}

View File

@@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.kamco.cd.kamcoback.common.enums.ImageryFitStatus;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import com.kamco.cd.kamcoback.common.utils.geometry.GeometryDeserializer;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
@@ -399,7 +400,10 @@ public class TrainingDataLabelDto {
private String memo;
public InspectionResultInfo(String verificationResult, String inappropriateReason) {
this.verificationResult = ImageryFitStatus.fromCode(verificationResult).getText();
this.verificationResult =
HeaderUtil.isEnglishRequest()
? ImageryFitStatus.fromCode(verificationResult).getTextEn()
: ImageryFitStatus.fromCode(verificationResult).getText();
this.inappropriateReason = inappropriateReason;
}
}

View File

@@ -39,7 +39,7 @@ spring:
data:
redis:
host: 192.168.2.109
host: 192.168.2.126
port: 6379
password: kamco
@@ -59,8 +59,8 @@ jwt:
secret: "kamco_token_9b71e778-19a3-4c1d-97bf-2d687de17d5b"
access-token-validity-in-ms: 86400000 # 1일
refresh-token-validity-in-ms: 604800000 # 7일
#access-token-validity-in-ms: 60000 # 1
#refresh-token-validity-in-ms: 300000 # 5
#access-token-validity-in-ms: 300000 # 5
#refresh-token-validity-in-ms: 600000 # 10
token:
refresh-cookie-name: kamco-dev # 개발용 쿠키 이름
@@ -100,6 +100,7 @@ inference:
url: http://192.168.2.183:8000/jobs
batch-url: http://192.168.2.183:8000/batches
jar-path: ${inference.nfs}/repo/jar/shp-exporter.jar
jar-path-v2: ${inference.nfs}/repo/jar/shp-exporter-v2.jar
inference-server-name: server1,server2,server3,server4
output-dir: ${inference.nfs}/model_output/export

View File

@@ -27,7 +27,7 @@ spring:
data:
redis:
host: 192.168.2.109
host: 192.168.2.126
port: 6379
password: kamco
@@ -78,6 +78,7 @@ inference:
url: http://10.100.0.11:8000/jobs
batch-url: http://10.100.0.11:8000/batches
jar-path: jar/shp-exporter.jar
jar-path-v2: jar/shp-exporter-v2.jar
inference-server-name: server1,server2,server3,server4
output-dir: ${inference.nfs}/model_output/export

View File

@@ -95,6 +95,8 @@ inference:
url: http://172.16.4.56:8000/jobs
batch-url: http://172.16.4.56:8000/batches
jar-path: ${inference.nfs}/repo/jar/shp-exporter.jar
# //0312
jar-path-v2: ${inference.nfs}/repo/jar/shp-exporter-v2.jar
inference-server-name: server1,server2,server3,server4
output-dir: ${inference.nfs}/model_output/export

View File

@@ -88,3 +88,6 @@ inference:
nfs: /kamco-nfs
geojson-dir: ${inference.nfs}/requests/ # 추론실행을 위한 파일생성경로
jar-path: ${inference.nfs}/repo/jar/shp-exporter.jar
# //0312
jar-path-v2: ${inference.nfs}/repo/jar/shp-exporter-v2.jar