23 Commits

Author SHA1 Message Date
a2bb1b2442 라벨링툴 count 종료된 회차는 count하지 않게 조건 추가 2026-02-12 18:03:34 +09:00
80b037a9cb 라벨링 다운로드 경로 추가 2026-02-11 09:57:02 +09:00
298b90a289 라벨 다운로드 확인 API 추가 2026-02-10 16:50:02 +09:00
985e1789d2 파일다운로드 변경, 파일다운로드 로그 저장 변경, 라벨 다운로드 이력 추가, 라벨 다운로드 추가 2026-02-10 11:20:16 +09:00
2d86fab030 라벨링툴 > 검수자 상세 라벨러 이름 조건 수정, 이노팸 object DTO 주석 추가 2026-02-09 12:29:35 +09:00
cf6b1323d8 라벨링툴 탐지분류 명칭 추가 2026-02-06 16:46:04 +09:00
5377294e6e 국유인 배치 수정, 라벨링툴 적합여부 수정 2026-02-06 16:32:46 +09:00
4e3e2a0181 레이어명 추가 2026-02-06 15:59:56 +09:00
57a2ec8367 스웨거 로그인 수정 2026-02-06 14:53:54 +09:00
fe6edbb19f 국유인 등록 로직 순서 변경 2026-02-06 14:25:16 +09:00
0e45adc52e 국유인 실태조사 적합여부 업데이트 로직 수정, 라벨링 건수 조건 수정 2026-02-06 11:12:15 +09:00
581b8c968e Merge pull request '국유인 수정, 라벨대상 건수 수정' (#54) from feat/infer_dev_260107 into develop
Reviewed-on: #54
2026-02-06 09:53:01 +09:00
e88ffd1260 국유인 수정, 라벨대상 건수 수정 2026-02-06 09:49:30 +09:00
bdce18119f Merge pull request '학습데이터 라벨링 현황 건수 조건 수정, 라벨러, 검수자 목록 수정' (#53) from feat/infer_dev_260107 into develop
Reviewed-on: #53
2026-02-05 18:01:45 +09:00
533d97a573 학습데이터 라벨링 현황 건수 조건 수정, 라벨러, 검수자 목록 수정 2026-02-05 18:00:52 +09:00
3b5536a57e Merge pull request '국유인 연동 경로 확인 TEST' (#52) from feat/infer_dev_260107 into develop
Reviewed-on: #52
2026-02-05 17:00:37 +09:00
3237863542 국유인 연동 경로 확인 TEST 2026-02-05 16:59:49 +09:00
9dd03f3c52 Merge pull request '국유인 API 수정 추가' (#51) from feat/infer_dev_260107 into develop
Reviewed-on: #51
2026-02-05 15:10:34 +09:00
41b227de3f 국유인 API 수정 추가 2026-02-05 15:09:27 +09:00
796591eca6 Merge pull request '국유인 API 수정 추가' (#50) from feat/infer_dev_260107 into develop
Reviewed-on: #50
2026-02-05 15:03:06 +09:00
83e02c4498 국유인 API 수정 추가 2026-02-05 15:02:00 +09:00
825e393e05 Merge pull request '국유인 API 수정 추가' (#49) from feat/infer_dev_260107 into develop
Reviewed-on: #49
2026-02-05 14:58:50 +09:00
d8804e7c9a 국유인 API 수정 추가 2026-02-05 14:58:30 +09:00
55 changed files with 1143 additions and 285 deletions

View File

@@ -0,0 +1,48 @@
package com.kamco.cd.kamcoback.common.download;
import com.kamco.cd.kamcoback.common.download.dto.DownloadSpec;
import com.kamco.cd.kamcoback.common.utils.UserUtil;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
@Service
@RequiredArgsConstructor
public class DownloadExecutor {
private final UserUtil userUtil;
public ResponseEntity<StreamingResponseBody> stream(DownloadSpec spec) throws IOException {
if (!Files.isReadable(spec.filePath())) {
return ResponseEntity.notFound().build();
}
StreamingResponseBody body =
os -> {
try (InputStream in = Files.newInputStream(spec.filePath())) {
in.transferTo(os);
os.flush();
} catch (Exception e) {
// 고용량은 중간 끊김 흔하니까 throw 금지
}
};
String fileName =
spec.downloadName() != null
? spec.downloadName()
: spec.filePath().getFileName().toString();
return ResponseEntity.ok()
.contentType(
spec.contentType() != null ? spec.contentType() : MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
.body(body);
}
}

View File

@@ -0,0 +1,19 @@
package com.kamco.cd.kamcoback.common.download;
import org.springframework.util.AntPathMatcher;
public final class DownloadPaths {
private DownloadPaths() {}
public static final String[] PATTERNS = {
"/api/inference/download/**", "/api/training-data/stage/download/**"
};
public static boolean matches(String uri) {
AntPathMatcher m = new AntPathMatcher();
for (String p : PATTERNS) {
if (m.match(p, uri)) return true;
}
return false;
}
}

View File

@@ -0,0 +1,12 @@
package com.kamco.cd.kamcoback.common.download.dto;
import java.nio.file.Path;
import java.util.UUID;
import org.springframework.http.MediaType;
public record DownloadSpec(
UUID uuid, // 다운로드 식별(로그/정책용)
Path filePath, // 실제 파일 경로
String downloadName, // 사용자에게 보일 파일명
MediaType contentType // 보통 OCTET_STREAM
) {}

View File

@@ -1,8 +1,8 @@
package com.kamco.cd.kamcoback.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kamco.cd.kamcoback.auth.CustomUserDetails;
import com.kamco.cd.kamcoback.common.utils.HeaderUtil;
import com.kamco.cd.kamcoback.common.utils.UserUtil;
import com.kamco.cd.kamcoback.config.api.ApiLogFunction;
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
import com.kamco.cd.kamcoback.menu.service.MenuService;
@@ -17,7 +17,6 @@ import java.util.Objects;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@@ -27,24 +26,39 @@ public class FileDownloadInteceptor implements HandlerInterceptor {
private final AuditLogRepository auditLogRepository;
private final MenuService menuService;
private final UserUtil userUtil;
@Autowired private ObjectMapper objectMapper;
public FileDownloadInteceptor(AuditLogRepository auditLogRepository, MenuService menuService) {
public FileDownloadInteceptor(
AuditLogRepository auditLogRepository, MenuService menuService, UserUtil userUtil) {
this.auditLogRepository = auditLogRepository;
this.menuService = menuService;
this.userUtil = userUtil;
}
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler) {
if (!request.getRequestURI().contains("/download")) return true;
if (request.getDispatcherType() != jakarta.servlet.DispatcherType.REQUEST) {
return true;
}
saveLog(request, response);
return true;
}
private void saveLog(HttpServletRequest request, HttpServletResponse response) {
// 파일 다운로드 API만 필터링
if (!request.getRequestURI().contains("/download")) {
return;
}
Long userId = extractUserId(request);
Long userId = userUtil.getId();
String ip = ApiLogFunction.getClientIp(request);
List<?> list = menuService.getFindAll();
@@ -81,12 +95,4 @@ public class FileDownloadInteceptor implements HandlerInterceptor {
auditLogRepository.save(log);
}
private Long extractUserId(HttpServletRequest request) {
if (request.getUserPrincipal() instanceof UsernamePasswordAuthenticationToken auth
&& auth.getPrincipal() instanceof CustomUserDetails userDetails) {
return userDetails.getMember().getId();
}
return null;
}
}

View File

@@ -3,6 +3,8 @@ package com.kamco.cd.kamcoback.config;
import com.kamco.cd.kamcoback.auth.CustomAuthenticationProvider;
import com.kamco.cd.kamcoback.auth.JwtAuthenticationFilter;
import com.kamco.cd.kamcoback.auth.MenuAuthorizationManager;
import com.kamco.cd.kamcoback.common.download.DownloadPaths;
import jakarta.servlet.DispatcherType;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
@@ -44,9 +46,11 @@ public class SecurityConfig {
.authorizeHttpRequests(
auth ->
auth
// .requestMatchers("/chunk_upload_test.html").authenticated()
.requestMatchers("/monitor/health", "/monitor/health/**")
.permitAll()
// 맵시트 영역 전체 허용 (우선순위 최상단)
.requestMatchers("/api/mapsheet/**")
.permitAll()
@@ -67,13 +71,25 @@ public class SecurityConfig {
.requestMatchers("/api/test/review")
.hasAnyRole("ADMIN", "REVIEWER")
// ASYNC/ERROR 재디스패치는 막지 않기 (다운로드/스트리밍에서 필수)
.dispatcherTypeMatchers(DispatcherType.ASYNC, DispatcherType.ERROR)
.permitAll()
// 다운로드는 인증 필요
.requestMatchers(HttpMethod.GET, DownloadPaths.PATTERNS)
.authenticated()
// 메뉴 등록 ADMIN만 가능
.requestMatchers(HttpMethod.POST, "/api/menu/auth")
.hasAnyRole("ADMIN")
// 에러 경로는 항상 허용 (이미 있지만 유지)
.requestMatchers("/error")
.permitAll()
// preflight 허용
.requestMatchers(HttpMethod.OPTIONS, "/**")
.permitAll() // preflight 허용
.permitAll()
.requestMatchers(
"/api/auth/signin",
"/api/auth/refresh",
@@ -90,6 +106,7 @@ public class SecurityConfig {
"/api/layer/tile-url",
"/api/layer/tile-url-year")
.permitAll()
// 로그인한 사용자만 가능 IAM
.requestMatchers(
"/api/user/**",
@@ -98,16 +115,11 @@ public class SecurityConfig {
"/api/training-data/label/**",
"/api/training-data/review/**")
.authenticated()
.anyRequest()
.access(menuAuthorizationManager)
// .authenticated()
)
.addFilterBefore(
jwtAuthenticationFilter,
UsernamePasswordAuthenticationFilter
.class) // 요청 들어오면 먼저 JWT 토큰 검사 후 security context 에 사용자 정보 저장.
;
// 나머지는 메뉴권한
.anyRequest()
.access(menuAuthorizationManager))
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@@ -118,23 +130,18 @@ public class SecurityConfig {
return configuration.getAuthenticationManager();
}
/**
* CORS 설정
*
* @return
*/
/** CORS 설정 */
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration(); // CORS 객체 생성
config.setAllowedOriginPatterns(List.of("*")); // 도메인 허용
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOriginPatterns(List.of("*"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
config.setAllowedHeaders(List.of("*")); // 헤더요청 Authorization, Content-Type, X-Custom-Header
config.setAllowCredentials(true); // 쿠키, Authorization 헤더, Bearer Token 등 자격증명 포함 요청을 허용할지 설정
config.setAllowedHeaders(List.of("*"));
config.setAllowCredentials(true);
config.setExposedHeaders(List.of("Content-Disposition"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
/** "/**" → 모든 API 경로에 대해 이 CORS 규칙을 적용 /api/** 같이 특정 경로만 지정 가능. */
source.registerCorsConfiguration("/**", config); // CORS 정책을 등록
source.registerCorsConfiguration("/**", config);
return source;
}

View File

@@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.kamco.cd.kamcoback.common.download.DownloadPaths;
import com.kamco.cd.kamcoback.common.utils.geometry.GeometryDeserializer;
import com.kamco.cd.kamcoback.common.utils.geometry.GeometrySerializer;
import org.locationtech.jts.geom.Geometry;
@@ -39,9 +40,6 @@ public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry
.addInterceptor(fileDownloadInteceptor)
.addPathPatterns("/api/inference/download/**") // 추론 파일 다운로드
.addPathPatterns("/api/training-data/stage/download/**"); // 학습데이터 다운로드
registry.addInterceptor(fileDownloadInteceptor).addPathPatterns(DownloadPaths.PATTERNS);
}
}

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.config.api;
import com.kamco.cd.kamcoback.common.download.DownloadPaths;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
@@ -16,6 +17,14 @@ public class ApiLogFilter extends OncePerRequestFilter {
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String uri = request.getRequestURI();
if (DownloadPaths.matches(uri)) {
filterChain.doFilter(request, response);
return;
}
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);

View File

@@ -1,4 +1,4 @@
package com.kamco.cd.kamcoback.config;
package com.kamco.cd.kamcoback.config.swagger;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.security.SecurityScheme;

View File

@@ -0,0 +1,97 @@
package com.kamco.cd.kamcoback.config.swagger;
import jakarta.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import org.springdoc.core.properties.SwaggerUiConfigProperties;
import org.springdoc.core.properties.SwaggerUiOAuthProperties;
import org.springdoc.core.providers.ObjectMapperProvider;
import org.springdoc.webmvc.ui.SwaggerIndexPageTransformer;
import org.springdoc.webmvc.ui.SwaggerIndexTransformer;
import org.springdoc.webmvc.ui.SwaggerWelcomeCommon;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.core.io.Resource;
import org.springframework.web.servlet.resource.ResourceTransformerChain;
import org.springframework.web.servlet.resource.TransformedResource;
@Profile({"local", "dev"})
@Configuration
public class SwaggerUiAutoAuthConfig {
@Bean
@Primary
public SwaggerIndexTransformer swaggerIndexTransformer(
SwaggerUiConfigProperties swaggerUiConfigProperties,
SwaggerUiOAuthProperties swaggerUiOAuthProperties,
SwaggerWelcomeCommon swaggerWelcomeCommon,
ObjectMapperProvider objectMapperProvider) {
SwaggerIndexPageTransformer delegate =
new SwaggerIndexPageTransformer(
swaggerUiConfigProperties,
swaggerUiOAuthProperties,
swaggerWelcomeCommon,
objectMapperProvider);
return new SwaggerIndexTransformer() {
private static final String TOKEN_KEY = "SWAGGER_ACCESS_TOKEN";
@Override
public Resource transform(
HttpServletRequest request, Resource resource, ResourceTransformerChain chain) {
try {
// 1) springdoc 기본 변환 먼저 적용
Resource transformed = delegate.transform(request, resource, chain);
String html =
new String(transformed.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
String loginPathContains = "/api/auth/signin";
String inject =
"""
tagsSorter: (a, b) => {
const TOP = '인증(Auth)';
if (a === TOP && b !== TOP) return -1;
if (b === TOP && a !== TOP) return 1;
return a.localeCompare(b);
},
requestInterceptor: (req) => {
const token = localStorage.getItem('%s');
if (token) {
req.headers = req.headers || {};
req.headers['Authorization'] = 'Bearer ' + token;
}
return req;
},
responseInterceptor: async (res) => {
try {
const isLogin = (res?.url?.includes('%s') && res?.status === 200);
if (isLogin) {
const text = (typeof res.data === 'string') ? res.data : JSON.stringify(res.data);
const json = JSON.parse(text);
const token = json?.data?.accessToken;
if (token) {
localStorage.setItem('%s', token);
}
}
} catch (e) {}
return res;
},
"""
.formatted(TOKEN_KEY, loginPathContains, TOKEN_KEY);
html = html.replace("SwaggerUIBundle({", "SwaggerUIBundle({\n" + inject);
return new TransformedResource(transformed, html.getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
// 실패 시 원본 반환(문서 깨짐 방지)
return resource;
}
}
};
}
}

View File

@@ -11,6 +11,11 @@ import com.kamco.cd.kamcoback.gukyuin.dto.DetectMastDto.Basic;
import com.kamco.cd.kamcoback.gukyuin.dto.DetectMastDto.DetectMastReq;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkableRes;
import com.kamco.cd.kamcoback.gukyuin.service.GukYuinApiService;
import com.kamco.cd.kamcoback.scheduler.service.GukYuinApiLabelJobService;
import com.kamco.cd.kamcoback.scheduler.service.GukYuinApiPnuJobService;
import com.kamco.cd.kamcoback.scheduler.service.GukYuinApiStatusJobService;
import com.kamco.cd.kamcoback.scheduler.service.GukYuinApiStbltJobService;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
@@ -38,6 +43,10 @@ import org.springframework.web.bind.annotation.RestController;
public class GukYuinApiController {
private final GukYuinApiService gukYuinApiService;
private final GukYuinApiPnuJobService gukYuinApiPnuJobService;
private final GukYuinApiStatusJobService gukYuinApiStatusJobService;
private final GukYuinApiLabelJobService gukYuinApiLabelJobService;
private final GukYuinApiStbltJobService gukYuinApiStbltJobService;
/** 탐지결과 등록 */
@Operation(summary = "탐지결과 등록", description = "탐지결과 등록")
@@ -261,7 +270,7 @@ public class GukYuinApiController {
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/rlb/objt/{chnDtctObjtId}/lbl/{lblYn}")
public ApiResponseDto<ChngDetectContDto.ResultPnuDto> updateChnDtctObjtLabelingYn(
public ApiResponseDto<ChngDetectContDto.ResultLabelDto> updateChnDtctObjtLabelingYn(
@PathVariable String chnDtctObjtId, @PathVariable String lblYn) {
return ApiResponseDto.ok(gukYuinApiService.updateChnDtctObjtLabelingYn(chnDtctObjtId, lblYn));
}
@@ -297,8 +306,10 @@ public class GukYuinApiController {
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ApiResponseDto<ChngDetectMastDto.RlbDtctDto> findRlbDtctList(
@PathVariable String chnDtctId) {
return ApiResponseDto.ok(gukYuinApiService.findRlbDtctList(chnDtctId));
@PathVariable String chnDtctId,
@Parameter(description = "날짜(기본은 어제 날짜)") @RequestParam(defaultValue = "20260205")
String yyyymmdd) {
return ApiResponseDto.ok(gukYuinApiService.findRlbDtctList(chnDtctId, yyyymmdd));
}
@Operation(summary = "탐지객체 적합여부 조회 (객체별 조회)", description = "탐지객체 적합여부 조회 (객체별 조회)")
@@ -319,4 +330,36 @@ public class GukYuinApiController {
@PathVariable String chnDtctObjtId) {
return ApiResponseDto.ok(gukYuinApiService.findRlbDtctObject(chnDtctObjtId));
}
@Hidden
@Operation(summary = "job test pnu", description = "job test pnu")
@GetMapping("/job-test/pnu")
public ApiResponseDto<Void> findGukYuinContListPnuUpdate() {
gukYuinApiPnuJobService.findGukYuinContListPnuUpdate();
return ApiResponseDto.ok(null);
}
@Hidden
@Operation(summary = "job test status", description = "job test status")
@GetMapping("/job-test/status")
public ApiResponseDto<Void> findGukYuinMastCompleteYn() {
gukYuinApiStatusJobService.findGukYuinMastCompleteYn();
return ApiResponseDto.ok(null);
}
@Hidden
@Operation(summary = "job test label", description = "job test label")
@GetMapping("/job-test/label")
public ApiResponseDto<Void> findLabelingCompleteSend() {
gukYuinApiLabelJobService.findLabelingCompleteSend();
return ApiResponseDto.ok(null);
}
@Hidden
@Operation(summary = "job test stblt", description = "job test stblt")
@GetMapping("/job-test/stblt")
public ApiResponseDto<Void> findGukYuinEligibleForSurvey() {
gukYuinApiStbltJobService.findGukYuinEligibleForSurvey();
return ApiResponseDto.ok(null);
}
}

View File

@@ -114,4 +114,38 @@ public class ChngDetectContDto {
private List<DtoPnuDetectMpng> result;
private Boolean success;
}
@Schema(name = "ResultLabelDto", description = "ResultLabelDto list 리턴 형태")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class ResultLabelDto {
private Integer code;
private String message;
private DtoPnuDetectMpng result;
private Boolean success;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class ReqInfo {
private String reqIp;
private String reqEpno;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class StbltResult {
private String stbltYn;
private String incyCd;
private String incyCmnt;
}
}

View File

@@ -247,45 +247,45 @@ public class ChngDetectMastDto {
@AllArgsConstructor
public static class RlbDtctMastDto {
private String pnuDtctId;
private String pnu;
private String lrmSyncYmd;
private String pnuSyncYmd;
private String mpqdNo; // 도번호
private String pnuDtctId; // PNU탐지ID
private String pnu; // PNU코드(19자리)
private String lrmSyncYmd; // 지적도동기화일자(YYYYMMDD)
private String pnuSyncYmd; // PNU동기화일자(YYYYMMDD)
private String mpqdNo; // 도번호
private String cprsYr; // 비교년도
private String crtrYr; // 기준년도
private String chnDtctSno; // 회차
private String chnDtctId;
private String chnDtctSno; // 회차, 변화탐지순번
private String chnDtctId; // 변화탐지ID(UUID)
private String chnDtctMstId;
private String chnDtctObjtId;
private String chnDtctContId;
private String chnCd;
private String chnDtctProb;
private String chnDtctMstId; // 변화탐지마스터ID
private String chnDtctObjtId; // 변화탐지객체ID
private String chnDtctContId; // 변화탐지내용ID
private String chnCd; // 변화코드
private String chnDtctProb; // 변화탐지정확도(0~1)
private String bfClsCd; // 이전분류코드
private String bfClsProb; // 이전분류정확도
private String bfClsProb; // 이전분류정확도(0~1)
private String afClsCd; // 이후분류코드
private String afClsProb; // 이후분류정확도
private String afClsProb; // 이후분류정확도(0~1)
private String pnuSqms;
private String pnuDtctSqms;
private String chnDtctSqms;
private String stbltYn;
private String incyCd;
private String incyRsnCont;
private String lockYn;
private String lblYn;
private String chgYn;
private String rsatctNo;
private String rmk;
private String pnuSqms; // PNU면적(㎡)
private String pnuDtctSqms; // PNU탐지면적(㎡)
private String chnDtctSqms; // 변화탐지면적(㎡)
private String stbltYn; // 적합여부(Y/N) - 안정성 (Y:부적합, N:적합)
private String incyCd; // 부적합코드
private String incyRsnCont; // 부적합사유내용
private String lockYn; // 잠금여부(Y/N)
private String lblYn; // 라벨여부(Y/N)
private String chgYn; // 변경여부(Y/N)
private String rsatctNo; // 부동산등기번호
private String rmk; // 비고
private String crtDt; // 생성일시
private String crtEpno; // 생성사원번호
private String crtIp; // 생성사원아이피
private String chgDt;
private String chgEpno;
private String chgIp;
private String chgDt; // 변경일시
private String chgEpno; // 변경자사번
private String chgIp; // 변경자IP
private String delYn; // 삭제여부
}

View File

@@ -452,6 +452,11 @@ public class GukYuinApiService {
return new ResponseObj(ApiResponseCode.DUPLICATE_DATA, "이미 국유인 연동을 한 회차입니다.");
}
if (!Files.isDirectory(Path.of("/kamco-nfs/dataset/export/" + info.getUid()))) {
return new ResponseObj(
ApiResponseCode.NOT_FOUND_DATA, "파일 경로에 회차 실행 파일이 생성되지 않았습니다. 확인 부탁드립니다.");
}
// 비교년도,기준년도로 전송한 데이터 있는지 확인 후 회차 번호 생성
Integer maxStage =
gukyuinCoreService.findMapSheetLearnYearStage(info.getCompareYyyy(), info.getTargetYyyy());
@@ -464,9 +469,14 @@ public class GukYuinApiService {
reqDto.setChnDtctId(info.getUid());
reqDto.setPathNm("/kamco-nfs/dataset/export/" + info.getUid());
if (Files.isDirectory(Path.of("/kamco-nfs/dataset/export/" + info.getUid()))) {
return new ResponseObj(
ApiResponseCode.NOT_FOUND_DATA, "파일 경로에 회차 실행 파일이 생성되지 않았습니다. 확인 부탁드립니다.");
// 1회차를 종료 상태로 처리하고 2회차를 보내야 함
// 추론(learn), 학습데이터(inference) 둘 다 종료 처리
if (maxStage > 0) {
Long learnId =
gukyuinCoreService.findMapSheetLearnInfoByYyyy(
info.getCompareYyyy(), info.getTargetYyyy(), maxStage);
gukyuinCoreService.updateMapSheetLearnGukyuinEndStatus(learnId);
gukyuinCoreService.updateMapSheetInferenceLabelEndStatus(learnId);
}
// 국유인 /chn/mast/regist 전송
@@ -518,7 +528,7 @@ public class GukYuinApiService {
return result.body();
}
public ChngDetectMastDto.RlbDtctDto findRlbDtctList(String chnDtctId) {
public ChngDetectMastDto.RlbDtctDto findRlbDtctList(String chnDtctId, String yyyymmdd) {
String url =
gukyuinCdiUrl
@@ -527,7 +537,9 @@ public class GukYuinApiService {
+ "?reqIp="
+ myip
+ "&reqEpno="
+ userUtil.getEmployeeNo();
+ userUtil.getEmployeeNo()
+ "&yyyymmdd="
+ yyyymmdd;
ExternalCallResult<ChngDetectMastDto.RlbDtctDto> result =
externalHttpClient.call(

View File

@@ -1,5 +1,7 @@
package com.kamco.cd.kamcoback.inference;
import com.kamco.cd.kamcoback.common.download.DownloadExecutor;
import com.kamco.cd.kamcoback.common.download.dto.DownloadSpec;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceDetailDto;
@@ -17,6 +19,7 @@ import com.kamco.cd.kamcoback.model.dto.ModelMngDto;
import com.kamco.cd.kamcoback.model.service.ModelMngService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -25,17 +28,13 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -46,6 +45,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
@Tag(name = "추론관리", description = "추론관리 API")
@RequestMapping("/api/inference")
@@ -56,6 +56,7 @@ public class InferenceResultApiController {
private final InferenceResultService inferenceResultService;
private final MapSheetMngService mapSheetMngService;
private final ModelMngService modelMngService;
private final DownloadExecutor downloadExecutor;
@Operation(summary = "추론관리 목록", description = "어드민 홈 > 추론관리 > 추론관리 > 추론관리 목록")
@ApiResponses(
@@ -328,7 +329,21 @@ public class InferenceResultApiController {
return ApiResponseDto.ok(geomList);
}
@Operation(summary = "shp 파일 다운로드", description = "추론관리 분석결과 shp 파일 다운로드")
@Operation(
summary = "shp 파일 다운로드",
description = "추론관리 분석결과 shp 파일 다운로드",
parameters = {
@Parameter(
name = "kamco-download-uuid",
in = ParameterIn.HEADER,
required = true,
description = "다운로드 요청 UUID",
schema =
@Schema(
type = "string",
format = "uuid",
example = "69c4e56c-e0bf-4742-9225-bba9aae39052"))
})
@ApiResponses(
value = {
@ApiResponse(
@@ -341,15 +356,14 @@ public class InferenceResultApiController {
@ApiResponse(responseCode = "404", description = "파일 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@GetMapping(value = "/download/{uuid}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<Resource> downloadShp(
@Parameter(description = "uuid", example = "0192efc6-9ec2-43ee-9a90-5b73e763c09f")
@PathVariable
UUID uuid)
@GetMapping(value = "/download/{uuid}")
public ResponseEntity<StreamingResponseBody> download(
@Parameter(example = "69c4e56c-e0bf-4742-9225-bba9aae39052") @PathVariable UUID uuid)
throws IOException {
String path;
String uid;
try {
Map<String, Object> map = inferenceResultService.shpDownloadPath(uuid);
path = String.valueOf(map.get("path"));
@@ -360,24 +374,11 @@ public class InferenceResultApiController {
Path zipPath = Path.of(path);
if (!Files.exists(zipPath) || !Files.isReadable(zipPath)) {
return ResponseEntity.notFound().build();
return downloadExecutor.stream(
new DownloadSpec(uuid, zipPath, uid + ".zip", MediaType.APPLICATION_OCTET_STREAM));
}
FileSystemResource resource = new FileSystemResource(zipPath);
String filename = uid + ".zip";
long fileSize = Files.size(zipPath);
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"")
.contentLength(fileSize)
.body(resource);
}
@Operation(summary = "shp 파일 다운로드 이력", description = "추론관리 분석결과 shp 파일 다운로드 이력")
@Operation(summary = "shp 파일 다운로드 이력 조회", description = "추론관리 분석결과 shp 파일 다운로드 이력 조회")
@GetMapping(value = "/download-audit/{uuid}")
@ApiResponses(
value = {
@@ -392,19 +393,20 @@ public class InferenceResultApiController {
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ApiResponseDto<Page<AuditLogDto.DownloadRes>> downloadAudit(
@Parameter(description = "UUID", example = "0192efc6-9ec2-43ee-9a90-5b73e763c09f")
@Parameter(description = "UUID", example = "69c4e56c-e0bf-4742-9225-bba9aae39052")
@PathVariable
UUID uuid,
@Parameter(description = "다운로드일 시작", example = "2025-01-01") @RequestParam(required = false)
LocalDate strtDttm,
@Parameter(description = "다운로드일 종료", example = "2026-01-01") @RequestParam(required = false)
@Parameter(description = "다운로드일 종료", example = "2026-04-01") @RequestParam(required = false)
LocalDate endDttm,
@Parameter(description = "키워드", example = "관리자") @RequestParam(required = false)
@Parameter(description = "키워드", example = "") @RequestParam(required = false)
String searchValue,
@Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0")
int page,
@Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20")
int size) {
AuditLogDto.searchReq searchReq = new searchReq();
searchReq.setPage(page);
searchReq.setSize(size);
@@ -413,8 +415,7 @@ public class InferenceResultApiController {
downloadReq.setStartDate(strtDttm);
downloadReq.setEndDate(endDttm);
downloadReq.setSearchValue(searchValue);
downloadReq.setMenuId("22");
downloadReq.setRequestUri("/api/inference/download-audit");
downloadReq.setRequestUri("/api/inference/download-audit/download/" + uuid);
return ApiResponseDto.ok(inferenceResultService.getDownloadAudit(searchReq, downloadReq));
}

View File

@@ -1,5 +1,7 @@
package com.kamco.cd.kamcoback.label;
import com.kamco.cd.kamcoback.common.download.DownloadExecutor;
import com.kamco.cd.kamcoback.common.download.dto.DownloadSpec;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail;
@@ -9,25 +11,39 @@ import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.WorkHistoryDto;
import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.UpdateClosedRequest;
import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerListResponse;
import com.kamco.cd.kamcoback.label.service.LabelAllocateService;
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
import com.kamco.cd.kamcoback.log.dto.AuditLogDto.DownloadReq;
import com.kamco.cd.kamcoback.log.dto.AuditLogDto.searchReq;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
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 jakarta.validation.Valid;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.coyote.BadRequestException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
@Slf4j
@Tag(name = "라벨링 작업 관리", description = "라벨링 작업 배정 및 통계 조회 API")
@@ -37,6 +53,10 @@ import org.springframework.web.bind.annotation.RestController;
public class LabelAllocateApiController {
private final LabelAllocateService labelAllocateService;
private final DownloadExecutor downloadExecutor;
@Value("${file.dataset-response}")
private String responsePath;
@Operation(summary = "배정 가능한 사용자 목록 조회", description = "라벨링 작업 배정을 위한 활성 상태의 사용자 목록을 조회합니다.")
@ApiResponses(
@@ -333,4 +353,112 @@ public class LabelAllocateApiController {
public ApiResponseDto<Long> labelingIngProcessCnt() {
return ApiResponseDto.ok(labelAllocateService.findLabelingIngProcessCnt());
}
@Operation(
summary = "라벨 파일 다운로드",
description = "라벨 파일 다운로드",
parameters = {
@Parameter(
name = "kamco-download-uuid",
in = ParameterIn.HEADER,
required = true,
description = "다운로드 요청 UUID",
schema =
@Schema(
type = "string",
format = "uuid",
example = "6d8d49dc-0c9d-4124-adc7-b9ca610cc394"))
})
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "라벨 zip파일 다운로드",
content =
@Content(
mediaType = "application/octet-stream",
schema = @Schema(type = "string", format = "binary"))),
@ApiResponse(responseCode = "404", description = "파일 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@GetMapping("/download/{uuid}")
public ResponseEntity<StreamingResponseBody> download(
@Parameter(example = "6d8d49dc-0c9d-4124-adc7-b9ca610cc394") @PathVariable UUID uuid)
throws IOException {
if (!labelAllocateService.isDownloadable(uuid)) {
throw new BadRequestException();
}
String uid = labelAllocateService.findLearnUid(uuid);
Path zipPath = Paths.get(responsePath).resolve(uid + ".zip");
return downloadExecutor.stream(
new DownloadSpec(uuid, zipPath, uid + ".zip", MediaType.APPLICATION_OCTET_STREAM));
}
@Operation(summary = "라벨 파일 다운로드 이력 조회", description = "라벨 파일 다운로드 이력 조회")
@GetMapping(value = "/download-audit/{uuid}")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "검색 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Page.class))),
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ApiResponseDto<Page<AuditLogDto.DownloadRes>> downloadAudit(
@Parameter(description = "UUID", example = "6d8d49dc-0c9d-4124-adc7-b9ca610cc394")
@PathVariable
UUID uuid,
// @Parameter(description = "다운로드일 시작", example = "2025-01-01") @RequestParam(required =
// false)
// LocalDate strtDttm,
// @Parameter(description = "다운로드일 종료", example = "2026-04-01") @RequestParam(required =
// false)
// LocalDate endDttm,
// @Parameter(description = "키워드", example = "") @RequestParam(required = false)
// String searchValue,
@Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0")
int page,
@Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20")
int size) {
AuditLogDto.searchReq searchReq = new searchReq();
searchReq.setPage(page);
searchReq.setSize(size);
DownloadReq downloadReq = new DownloadReq();
downloadReq.setUuid(uuid);
// downloadReq.setStartDate(strtDttm);
// downloadReq.setEndDate(endDttm);
// downloadReq.setSearchValue(searchValue);
downloadReq.setRequestUri("/api/training-data/stage/download/" + uuid);
return ApiResponseDto.ok(labelAllocateService.getDownloadAudit(searchReq, downloadReq));
}
@Operation(summary = "다운로드 가능여부 조회", description = "다운로드 가능여부 조회 API")
@GetMapping(value = "/download-check/{uuid}")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "검색 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Page.class))),
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ApiResponseDto<Boolean> isDownloadable(
@Parameter(description = "UUID", example = "6d8d49dc-0c9d-4124-adc7-b9ca610cc394")
@PathVariable
UUID uuid) {
return ApiResponseDto.ok(labelAllocateService.isDownloadable(uuid));
}
}

View File

@@ -359,4 +359,15 @@ public class LabelAllocateDto {
@Schema(description = "작업기간 종료일")
private ZonedDateTime projectCloseDttm;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class InferenceLearnDto {
private UUID analUuid;
private String learnUid;
private String analState;
private Long analId;
}
}

View File

@@ -16,10 +16,14 @@ import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.searchReq;
import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.ProjectInfo;
import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkProgressInfo;
import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerListResponse;
import com.kamco.cd.kamcoback.log.dto.AuditLogDto;
import com.kamco.cd.kamcoback.log.dto.AuditLogDto.DownloadReq;
import com.kamco.cd.kamcoback.postgres.core.AuditLogCoreService;
import com.kamco.cd.kamcoback.postgres.core.LabelAllocateCoreService;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
@@ -28,13 +32,11 @@ import org.springframework.transaction.annotation.Transactional;
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class LabelAllocateService {
private final LabelAllocateCoreService labelAllocateCoreService;
public LabelAllocateService(LabelAllocateCoreService labelAllocateCoreService) {
this.labelAllocateCoreService = labelAllocateCoreService;
}
private final AuditLogCoreService auditLogCoreService;
/**
* 도엽 기준 asc sorting 해서 할당 수만큼 배정하는 로직
@@ -273,4 +275,29 @@ public class LabelAllocateService {
public Long findLabelingIngProcessCnt() {
return labelAllocateCoreService.findLabelingIngProcessCnt();
}
public String findLearnUid(UUID uuid) {
return labelAllocateCoreService.findLearnUid(uuid);
}
/**
* 다운로드 이력 조회
*
* @param searchReq 페이징
* @param downloadReq 조회조건
*/
public Page<AuditLogDto.DownloadRes> getDownloadAudit(
AuditLogDto.searchReq searchReq, DownloadReq downloadReq) {
return auditLogCoreService.findLogByAccount(searchReq, downloadReq);
}
/**
* 다운로드 가능 여부 조회
*
* @param uuid
* @return
*/
public boolean isDownloadable(UUID uuid) {
return labelAllocateCoreService.isDownloadable(uuid);
}
}

View File

@@ -31,6 +31,9 @@ public class LayerDto {
@Schema(description = "uuid")
private UUID uuid;
@Schema(description = "레이어명")
private String layerName;
@Schema(example = "WMTS", description = "유형 (TILE/GEOJSON/WMTS/WMS)")
private String layerType;
@@ -63,6 +66,9 @@ public class LayerDto {
@Schema(description = "uuid")
private UUID uuid;
@Schema(description = "레이어명")
private String layerName;
@Schema(description = "유형 (TILE/GEOJSON/WMTS/WMS)")
private String layerType;
@@ -119,6 +125,9 @@ public class LayerDto {
@Schema(name = "LayerAddReq")
public static class AddReq {
@Schema(description = "레이어명")
private String layerName;
@Schema(description = "title WMS, WMTS 선택한 tile")
private String title;
@@ -215,6 +224,9 @@ public class LayerDto {
@Schema(name = "LayerMapDto")
public static class LayerMapDto {
@Schema(description = "레이어명")
private String layerName;
@Schema(example = "WMTS", description = "유형 (TILE/GEOJSON/WMTS/WMS)")
private String layerType;
@@ -268,6 +280,7 @@ public class LayerDto {
private String crs;
public LayerMapDto(
String layerName,
String layerType,
String tag,
Long sortOrder,
@@ -282,6 +295,7 @@ public class LayerDto {
UUID uuid,
String rawJsonString,
String crs) {
this.layerName = layerName;
this.layerType = layerType;
this.tag = tag;
this.sortOrder = sortOrder;

View File

@@ -26,5 +26,6 @@ public class WmsDto {
private String title;
private String description;
private String tag;
private String layerName;
}
}

View File

@@ -26,5 +26,6 @@ public class WmtsDto {
private String title;
private String description;
private String tag;
private String layerName;
}
}

View File

@@ -9,7 +9,6 @@ import com.kamco.cd.kamcoback.layer.dto.LayerDto.LayerMapDto;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.OrderReq;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.TileUrlDto;
import com.kamco.cd.kamcoback.layer.dto.WmsDto.WmsAddDto;
import com.kamco.cd.kamcoback.layer.dto.WmsDto.WmsAddReqDto;
import com.kamco.cd.kamcoback.layer.dto.WmsLayerInfo;
import com.kamco.cd.kamcoback.layer.dto.WmtsDto.WmtsAddDto;
import com.kamco.cd.kamcoback.layer.dto.WmtsLayerInfo;
@@ -79,6 +78,7 @@ public class LayerService {
addDto.setDescription(dto.getDescription());
addDto.setTitle(dto.getTitle());
addDto.setTag(dto.getTag());
addDto.setLayerName(dto.getLayerName());
return mapLayerCoreService.saveWmts(addDto);
}
@@ -89,6 +89,7 @@ public class LayerService {
addDto.setDescription(dto.getDescription());
addDto.setTitle(dto.getTitle());
addDto.setTag(dto.getTag());
addDto.setLayerName(dto.getLayerName());
return mapLayerCoreService.saveWms(addDto);
}
@@ -165,24 +166,6 @@ public class LayerService {
return wmsService.getTile();
}
/**
* wms 저장
*
* @param dto
* @return
*/
@Transactional
public UUID saveWms(WmsAddReqDto dto) {
// 선택한 tile 상세정보 조회
WmsLayerInfo info = wmsService.getDetail(dto.getTitle());
WmsAddDto addDto = new WmsAddDto();
addDto.setWmsLayerInfo(info);
addDto.setDescription(dto.getDescription());
addDto.setTitle(dto.getTitle());
addDto.setTag(dto.getTag());
return mapLayerCoreService.saveWms(addDto);
}
public List<LayerMapDto> findLayerMapList(String type) {
List<LayerMapDto> layerMapDtoList = mapLayerCoreService.findLayerMapList(type);
layerMapDtoList.forEach(

View File

@@ -9,8 +9,10 @@ import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class MenuService {

View File

@@ -64,4 +64,17 @@ public class GukYuinCoreService {
public List<LabelSendDto> findLabelingCompleteSendList(LocalDate yesterday) {
return gukYuinRepository.findLabelingCompleteSendList(yesterday);
}
public Long findMapSheetLearnInfoByYyyy(
Integer compareYyyy, Integer targetYyyy, Integer maxStage) {
return gukYuinRepository.findMapSheetLearnInfoByYyyy(compareYyyy, targetYyyy, maxStage);
}
public void updateMapSheetLearnGukyuinEndStatus(Long learnId) {
gukYuinRepository.updateMapSheetLearnGukyuinEndStatus(learnId);
}
public void updateMapSheetInferenceLabelEndStatus(Long learnId) {
gukYuinRepository.updateMapSheetInferenceLabelEndStatus(learnId);
}
}

View File

@@ -5,6 +5,7 @@ import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus;
import com.kamco.cd.kamcoback.postgres.repository.gukyuin.GukYuinRepository;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class GukYuinJobCoreService {
@@ -15,6 +16,7 @@ public class GukYuinJobCoreService {
this.gukYuinRepository = gukYuinRepository;
}
@Transactional
public void updateGukYuinApplyStateComplete(Long id, GukYuinStatus status) {
gukYuinRepository.updateGukYuinApplyStateComplete(id, status);
}

View File

@@ -4,6 +4,7 @@ import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GeomUidDto;
import com.kamco.cd.kamcoback.postgres.repository.gukyuin.GukYuinLabelJobRepository;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class GukYuinLabelJobCoreService {
@@ -18,6 +19,7 @@ public class GukYuinLabelJobCoreService {
return gukYuinLabelRepository.findYesterdayLabelingCompleteList();
}
@Transactional
public void updateAnalDataInferenceGeomSendDttm(Long geoUid) {
gukYuinLabelRepository.updateAnalDataInferenceGeomSendDttm(geoUid);
}

View File

@@ -5,6 +5,7 @@ import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus;
import com.kamco.cd.kamcoback.postgres.repository.gukyuin.GukYuinPnuJobRepository;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class GukYuinPnuJobCoreService {
@@ -27,6 +28,7 @@ public class GukYuinPnuJobCoreService {
return gukYuinPnuRepository.upsertMapSheetDataAnalGeomPnu(chnDtctObjtId, pnuList);
}
@Transactional
public void updateInferenceGeomDataPnuCnt(String chnDtctObjtId, long pnuCnt) {
gukYuinPnuRepository.updateInferenceGeomDataPnuCnt(chnDtctObjtId, pnuCnt);
}
@@ -35,6 +37,7 @@ public class GukYuinPnuJobCoreService {
return gukYuinPnuRepository.findMapSheetAnalDataInferenceGeomUid(chnDtctObjtId);
}
@Transactional
public void insertGeoUidPnuData(Long geoUid, String[] pnuList, String chnDtctObjtId) {
gukYuinPnuRepository.insertGeoUidPnuData(geoUid, pnuList, chnDtctObjtId);
}

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto.StbltResult;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LearnKeyDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.RlbDtctMastDto;
import com.kamco.cd.kamcoback.postgres.entity.PnuEntity;
@@ -7,6 +8,7 @@ import com.kamco.cd.kamcoback.postgres.repository.gukyuin.GukYuinStbltJobReposit
import java.time.ZonedDateTime;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class GukYuinStbltJobCoreService {
@@ -21,10 +23,12 @@ public class GukYuinStbltJobCoreService {
return gukYuinStbltRepository.findGukYuinEligibleForSurveyList(status);
}
@Transactional
public void updateGukYuinEligibleForSurvey(String resultUid, RlbDtctMastDto stbltDto) {
PnuEntity entity =
gukYuinStbltRepository.findPnuEntityByResultUid(resultUid, stbltDto.getPnu());
if (entity != null) {
entity.setPnuDtctId(stbltDto.getPnuDtctId());
entity.setPnu(stbltDto.getPnu());
entity.setLrmSyncYmd(stbltDto.getLrmSyncYmd());
@@ -57,7 +61,6 @@ public class GukYuinStbltJobCoreService {
entity.setCrtEpno(stbltDto.getCrtEpno());
entity.setCrtIp(stbltDto.getCrtIp());
entity.setChgDt(stbltDto.getChgDt());
entity.setChgEpno(stbltDto.getChgEpno());
entity.setChgIp(stbltDto.getChgIp());
entity.setDelYn(stbltDto.getDelYn().equals("Y"));
@@ -65,3 +68,9 @@ public class GukYuinStbltJobCoreService {
gukYuinStbltRepository.save(entity);
}
}
@Transactional
public void updateGukYuinObjectStbltYn(String resultUid, StbltResult stbResult) {
gukYuinStbltRepository.updateGukYuinObjectStbltYn(resultUid, stbResult);
}
}

View File

@@ -1,8 +1,11 @@
package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.AllocateInfoDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceLearnDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelMngState;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelingStatDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.MoveInfo;
@@ -13,12 +16,18 @@ import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.ProjectInfo;
import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkProgressInfo;
import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerStatistics;
import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity;
import com.kamco.cd.kamcoback.postgres.repository.batch.BatchStepHistoryRepository;
import com.kamco.cd.kamcoback.postgres.repository.label.LabelAllocateRepository;
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.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
@Service
@@ -26,6 +35,10 @@ import org.springframework.stereotype.Service;
public class LabelAllocateCoreService {
private final LabelAllocateRepository labelAllocateRepository;
private final BatchStepHistoryRepository batchStepHistoryRepository;
@Value("${file.dataset-response}")
private String responsePath;
public List<AllocateInfoDto> fetchNextIds(Long lastId, Long batchSize, UUID uuid) {
return labelAllocateRepository.fetchNextIds(lastId, batchSize, uuid);
@@ -234,4 +247,34 @@ public class LabelAllocateCoreService {
public Long findLabelingIngProcessCnt() {
return labelAllocateRepository.findLabelingIngProcessCnt();
}
public boolean isDownloadable(UUID uuid) {
InferenceLearnDto dto = labelAllocateRepository.findLabelingIngProcessId(uuid);
if (dto == null) {
return false;
}
// 파일이 있는지만 확인
Path path = Paths.get(responsePath).resolve(dto.getLearnUid() + ".zip");
if (!Files.exists(path) || !Files.isRegularFile(path)) {
// 실제 파일만 true (디렉터리는 제외)
return false;
}
// 다운로드 확인할 학습데이터가 라벨링중인 경우 파일 생성여부가 정상인지 확인
if (dto.getAnalState().equals(LabelMngState.ASSIGNED.getId())
|| dto.getAnalState().equals(LabelMngState.ING.getId())) {
return batchStepHistoryRepository.isDownloadable(dto.getAnalId());
}
return true;
}
public String findLearnUid(UUID uuid) {
return labelAllocateRepository
.findLearnUid(uuid)
.orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND));
}
}

View File

@@ -87,6 +87,10 @@ public class MapLayerCoreService {
entity.setDescription(dto.getDescription());
}
if (dto.getLayerName() != null) {
entity.setLayerName(dto.getLayerName());
}
if (dto.getUrl() != null) {
entity.setUrl(dto.getUrl());
}
@@ -213,6 +217,7 @@ public class MapLayerCoreService {
Long order = mapLayerRepository.findSortOrderDesc();
MapLayerEntity mapLayerEntity = new MapLayerEntity();
mapLayerEntity.setLayerName(dto.getLayerName());
mapLayerEntity.setDescription(dto.getDescription());
mapLayerEntity.setUrl(dto.getUrl());
mapLayerEntity.setTag(dto.getTag());
@@ -243,6 +248,7 @@ public class MapLayerCoreService {
Long order = mapLayerRepository.findSortOrderDesc();
MapLayerEntity mapLayerEntity = new MapLayerEntity();
mapLayerEntity.setLayerName(addDto.getLayerName());
mapLayerEntity.setDescription(addDto.getDescription());
mapLayerEntity.setUrl(addDto.getUrl());
mapLayerEntity.setTag(addDto.getTag());
@@ -273,6 +279,7 @@ public class MapLayerCoreService {
}
MapLayerEntity mapLayerEntity = new MapLayerEntity();
mapLayerEntity.setLayerName(addDto.getLayerName());
mapLayerEntity.setTitle(addDto.getTitle());
mapLayerEntity.setDescription(addDto.getDescription());
mapLayerEntity.setCreatedUid(userUtil.getId());
@@ -305,6 +312,7 @@ public class MapLayerCoreService {
}
MapLayerEntity mapLayerEntity = new MapLayerEntity();
mapLayerEntity.setLayerName(addDto.getLayerName());
mapLayerEntity.setTitle(addDto.getTitle());
mapLayerEntity.setDescription(addDto.getDescription());
mapLayerEntity.setCreatedUid(userUtil.getId());

View File

@@ -0,0 +1,62 @@
package com.kamco.cd.kamcoback.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 jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity
@Table(name = "batch_step_history")
public class BatchStepHistoryEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
@NotNull
@Column(name = "anal_uid", nullable = false)
private Long analUid;
@Size(max = 255)
@NotNull
@Column(name = "result_uid", nullable = false)
private String resultUid;
@Size(max = 100)
@NotNull
@Column(name = "step_name", nullable = false, length = 100)
private String stepName;
@Size(max = 50)
@NotNull
@Column(name = "status", nullable = false, length = 50)
private String status;
@Column(name = "error_message", length = Integer.MAX_VALUE)
private String errorMessage;
@NotNull
@Column(name = "started_dttm", nullable = false)
private LocalDateTime startedDttm;
@Column(name = "completed_dttm")
private LocalDateTime completedDttm;
@NotNull
@Column(name = "created_dttm", nullable = false)
private LocalDateTime createdDttm;
@NotNull
@Column(name = "updated_dttm", nullable = false)
private LocalDateTime updatedDttm;
}

View File

@@ -43,6 +43,10 @@ public class MapLayerEntity {
@Column(name = "title", length = 200)
private String title;
@Size(max = 255)
@Column(name = "layer_name")
private String layerName;
@Column(name = "description", length = Integer.MAX_VALUE)
private String description;
@@ -109,6 +113,7 @@ public class MapLayerEntity {
public LayerDto.Detail toDto() {
return new LayerDto.Detail(
this.uuid,
this.layerName,
this.layerType,
this.title,
this.description,

View File

@@ -0,0 +1,7 @@
package com.kamco.cd.kamcoback.postgres.repository.batch;
import com.kamco.cd.kamcoback.postgres.entity.BatchStepHistoryEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BatchStepHistoryRepository
extends JpaRepository<BatchStepHistoryEntity, Long>, BatchStepHistoryRepositoryCustom {}

View File

@@ -0,0 +1,5 @@
package com.kamco.cd.kamcoback.postgres.repository.batch;
public interface BatchStepHistoryRepositoryCustom {
boolean isDownloadable(Long analUid);
}

View File

@@ -0,0 +1,37 @@
package com.kamco.cd.kamcoback.postgres.repository.batch;
import com.kamco.cd.kamcoback.postgres.entity.QBatchStepHistoryEntity;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
@Repository
@RequiredArgsConstructor
public class BatchStepHistoryRepositoryImpl implements BatchStepHistoryRepositoryCustom {
private final JPAQueryFactory queryFactory;
@Override
public boolean isDownloadable(Long analUid) {
QBatchStepHistoryEntity h = QBatchStepHistoryEntity.batchStepHistoryEntity;
boolean startedExists =
queryFactory
.selectOne()
.from(h)
.where(
h.analUid.eq(analUid), h.stepName.eq("zipResponseStep"), h.status.eq("STARTED"))
.fetchFirst()
!= null;
boolean successExists =
queryFactory
.selectOne()
.from(h)
.where(
h.analUid.eq(analUid), h.stepName.eq("zipResponseStep"), h.status.eq("SUCCESS"))
.fetchFirst()
!= null;
return successExists && !startedExists;
}
}

View File

@@ -30,13 +30,19 @@ public class GukYuinLabelJobRepositoryImpl implements GukYuinLabelJobRepositoryC
public List<GeomUidDto> findYesterdayLabelingCompleteList() {
ZoneId zone = ZoneId.of("Asia/Seoul");
ZonedDateTime todayStart = ZonedDateTime.now(zone).toLocalDate().atStartOfDay(zone);
ZonedDateTime tomorrowStart = todayStart.plusDays(1);
ZonedDateTime yesterdayStart = todayStart.minusDays(1);
// BooleanExpression isYesterday =
// labelingAssignmentEntity
// .inspectStatDttm
// .goe(yesterdayStart)
// .and(labelingAssignmentEntity.inspectStatDttm.lt(todayStart));
BooleanExpression isYesterday =
labelingAssignmentEntity
.inspectStatDttm
.goe(yesterdayStart)
.and(labelingAssignmentEntity.inspectStatDttm.lt(todayStart));
.goe(todayStart)
.and(labelingAssignmentEntity.inspectStatDttm.lt(tomorrowStart));
return queryFactory
.select(

View File

@@ -53,8 +53,9 @@ public class GukYuinPnuJobRepositoryImpl implements GukYuinPnuJobRepositoryCusto
if (entity == null) {
queryFactory
.insert(pnuEntity)
.columns(pnuEntity.geo.geoUid, pnuEntity.pnu, pnuEntity.createdDttm)
.values(geoUid, pnu, ZonedDateTime.now())
.columns(
pnuEntity.geo.geoUid, pnuEntity.pnu, pnuEntity.createdDttm, pnuEntity.chnDtctObjtId)
.values(geoUid, pnu, ZonedDateTime.now(), chnDtctObjtId)
.execute();
}
}

View File

@@ -39,4 +39,10 @@ public interface GukYuinRepositoryCustom {
void updateAnalDataInferenceGeomSendDttm(Long geoUid);
List<LabelSendDto> findLabelingCompleteSendList(LocalDate yesterday);
Long findMapSheetLearnInfoByYyyy(Integer compareYyyy, Integer targetYyyy, Integer maxStage);
void updateMapSheetLearnGukyuinEndStatus(Long learnId);
void updateMapSheetInferenceLabelEndStatus(Long learnId);
}

View File

@@ -13,6 +13,7 @@ import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GeomUidDto;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.LearnInfo;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InspectState;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelMngState;
import com.kamco.cd.kamcoback.postgres.entity.PnuEntity;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
@@ -204,6 +205,7 @@ public class GukYuinRepositoryImpl implements GukYuinRepositoryCustom {
.update(mapSheetAnalInferenceEntity)
.set(mapSheetAnalInferenceEntity.gukyuinUsed, "Y")
.set(mapSheetAnalInferenceEntity.gukyuinApplyDttm, ZonedDateTime.now())
.set(mapSheetAnalInferenceEntity.stage, Integer.parseInt(registRes.getChnDtctSno()))
.where(mapSheetAnalInferenceEntity.learnId.eq(learnId))
.execute();
}
@@ -283,6 +285,39 @@ public class GukYuinRepositoryImpl implements GukYuinRepositoryCustom {
.fetch();
}
@Override
public Long findMapSheetLearnInfoByYyyy(
Integer compareYyyy, Integer targetYyyy, Integer maxStage) {
return queryFactory
.select(mapSheetLearnEntity.id)
.from(mapSheetLearnEntity)
.where(
mapSheetLearnEntity.compareYyyy.eq(compareYyyy),
mapSheetLearnEntity.targetYyyy.eq(targetYyyy),
mapSheetLearnEntity.stage.eq(maxStage))
.fetchOne();
}
@Override
public void updateMapSheetLearnGukyuinEndStatus(Long learnId) {
queryFactory
.update(mapSheetLearnEntity)
.set(mapSheetLearnEntity.applyStatus, GukYuinStatus.END.getId())
.set(mapSheetLearnEntity.applyStatusDttm, ZonedDateTime.now())
.where(mapSheetLearnEntity.id.eq(learnId))
.execute();
}
@Override
public void updateMapSheetInferenceLabelEndStatus(Long learnId) {
queryFactory
.update(mapSheetAnalInferenceEntity)
.set(mapSheetAnalInferenceEntity.analState, LabelMngState.FINISH.getId())
.set(mapSheetAnalInferenceEntity.updatedDttm, ZonedDateTime.now())
.where(mapSheetAnalInferenceEntity.learnId.eq(learnId))
.execute();
}
@Override
@Transactional
public void updateGukYuinApplyStateComplete(Long id, GukYuinStatus status) {

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.postgres.repository.gukyuin;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto.StbltResult;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LearnKeyDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.RlbDtctMastDto;
import com.kamco.cd.kamcoback.postgres.entity.PnuEntity;
@@ -12,4 +13,6 @@ public interface GukYuinStbltJobRepositoryCustom {
void updateGukYuinEligibleForSurvey(String resultUid, RlbDtctMastDto stbltDto);
PnuEntity findPnuEntityByResultUid(String resultUid, String pnu);
void updateGukYuinObjectStbltYn(String resultUid, StbltResult stbResult);
}

View File

@@ -6,6 +6,8 @@ import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalInferenceEntit
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnEntity.mapSheetLearnEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QPnuEntity.pnuEntity;
import com.kamco.cd.kamcoback.common.enums.ImageryFitStatus;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto.StbltResult;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LearnKeyDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.RlbDtctMastDto;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus;
@@ -15,6 +17,7 @@ import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import java.time.ZonedDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
@@ -44,7 +47,7 @@ public class GukYuinStbltJobRepositoryImpl implements GukYuinStbltJobRepositoryC
.on(mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid))
.where(
mapSheetLearnEntity.applyStatus.eq(GukYuinStatus.PNU_COMPLETED.getId()),
mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(),
mapSheetAnalDataInferenceGeomEntity.pnu.gt(0),
mapSheetAnalDataInferenceGeomEntity.fitState.isNull())
.groupBy(mapSheetLearnEntity.id, mapSheetLearnEntity.uid, mapSheetLearnEntity.chnDtctMstId)
.having(mapSheetAnalDataInferenceGeomEntity.geoUid.count().gt(1L))
@@ -64,54 +67,21 @@ public class GukYuinStbltJobRepositoryImpl implements GukYuinStbltJobRepositoryC
PnuEntity pnuEt =
queryFactory
.selectFrom(pnuEntity)
.where(pnuEntity.pnu.eq(stbltDto.getPnu()), pnuEntity.chnDtctObjtId.eq(resultUid))
.fetchOne();
if (pnuEt != null) {
// update
queryFactory
.update(pnuEntity)
.set(pnuEntity.pnuDtctId, stbltDto.getPnuDtctId())
.set(pnuEntity.lrmSyncYmd, stbltDto.getLrmSyncYmd())
.set(pnuEntity.pnuSyncYmd, stbltDto.getPnuSyncYmd())
.set(pnuEntity.mpqdNo, stbltDto.getMpqdNo())
.set(pnuEntity.cprsYr, stbltDto.getCprsYr())
.set(pnuEntity.crtrYr, stbltDto.getCrtrYr())
.set(pnuEntity.chnDtctId, stbltDto.getChnDtctId())
.set(pnuEntity.chnDtctMstId, stbltDto.getChnDtctMstId())
.set(pnuEntity.chnDtctObjtId, stbltDto.getChnDtctObjtId())
.set(pnuEntity.chnDtctContId, stbltDto.getChnDtctContId())
.set(pnuEntity.chnCd, stbltDto.getChnCd())
.set(pnuEntity.chnDtctProb, stbltDto.getChnDtctProb())
.set(pnuEntity.bfClsCd, stbltDto.getBfClsCd())
.set(pnuEntity.bfClsProb, stbltDto.getBfClsProb())
.set(pnuEntity.afClsCd, stbltDto.getAfClsCd())
.set(pnuEntity.afClsProb, stbltDto.getAfClsProb())
.set(pnuEntity.pnuSqms, stbltDto.getPnuSqms())
.set(pnuEntity.pnuDtctSqms, stbltDto.getPnuDtctSqms())
.set(pnuEntity.chnDtctSqms, stbltDto.getChnDtctSqms())
.set(pnuEntity.stbltYn, stbltDto.getStbltYn())
.set(pnuEntity.incyCd, stbltDto.getIncyCd())
.set(pnuEntity.incyRsnCont, stbltDto.getIncyRsnCont())
.where(
pnuEntity.geo.geoUid.eq(geomEntity.getGeoUid()),
pnuEntity.chnDtctObjtId.eq(resultUid))
.execute();
} else {
// insert
}
}
// queryFactory
// .update(mapSheetAnalDataInferenceGeomEntity)
// .set(
// mapSheetAnalDataInferenceGeomEntity.fitState,
// stbltDto.getStbltYn().equals("Y") ? ImageryFitStatus.FIT.getId() :
// ImageryFitStatus.UNFIT.getId())
// .set(mapSheetAnalDataInferenceGeomEntity.fitStateDttm, ZonedDateTime.now())
// .set(mapSheetAnalDataInferenceGeomEntity.lockYn, stbltDto.getLockYn())
// .where(mapSheetAnalDataInferenceGeomEntity.resultUid.eq(resultUid))
// .execute();
.where(pnuEntity.chnDtctObjtId.eq(resultUid))
.fetchFirst();
// TODO
queryFactory
.update(mapSheetAnalDataInferenceGeomEntity)
.set(
mapSheetAnalDataInferenceGeomEntity.fitState,
pnuEt.getStbltYn().equals("Y")
? ImageryFitStatus.UNFIT.getId()
: ImageryFitStatus.FIT.getId()) // 적합여부가 Y 이면 부적합인 것, N 이면 적합한 것이라고 함
.set(mapSheetAnalDataInferenceGeomEntity.fitStateDttm, ZonedDateTime.now())
.set(mapSheetAnalDataInferenceGeomEntity.lockYn, stbltDto.getLockYn())
.where(mapSheetAnalDataInferenceGeomEntity.resultUid.eq(resultUid))
.execute();
}
}
@Override
@@ -121,4 +91,19 @@ public class GukYuinStbltJobRepositoryImpl implements GukYuinStbltJobRepositoryC
.where(pnuEntity.pnu.eq(pnu), pnuEntity.chnDtctObjtId.eq(resultUid))
.fetchOne();
}
@Override
public void updateGukYuinObjectStbltYn(String resultUid, StbltResult stbResult) {
queryFactory
.update(mapSheetAnalDataInferenceGeomEntity)
.set(
mapSheetAnalDataInferenceGeomEntity.fitState,
stbResult.getStbltYn().equals("Y")
? ImageryFitStatus.UNFIT.getId()
: ImageryFitStatus.FIT.getId()) // 적합여부가 Y 이면 부적합인 것, N 이면 적합한 것이라고 함
.set(mapSheetAnalDataInferenceGeomEntity.fitStateDttm, ZonedDateTime.now())
.set(mapSheetAnalDataInferenceGeomEntity.fitStateCmmnt, stbResult.getIncyCmnt())
.where(mapSheetAnalDataInferenceGeomEntity.resultUid.eq(resultUid))
.execute();
}
}

View File

@@ -3,6 +3,7 @@ package com.kamco.cd.kamcoback.postgres.repository.label;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.AllocateInfoDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceLearnDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelerDetail;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelingStatDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.MoveInfo;
@@ -15,6 +16,7 @@ import com.kamco.cd.kamcoback.label.dto.WorkerStatsDto.WorkerStatistics;
import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.springframework.data.domain.Page;
@@ -104,4 +106,8 @@ public interface LabelAllocateRepositoryCustom {
void updateAnalInferenceMngState(UUID uuid, String status);
Long findLabelingIngProcessCnt();
InferenceLearnDto findLabelingIngProcessId(UUID uuid);
Optional<String> findLearnUid(UUID uuid);
}

View File

@@ -6,12 +6,15 @@ import static com.kamco.cd.kamcoback.postgres.entity.QLabelingLabelerEntity.labe
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceEntity.mapSheetAnalDataInferenceEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalInferenceEntity.mapSheetAnalInferenceEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnEntity.mapSheetLearnEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMemberEntity.memberEntity;
import com.kamco.cd.kamcoback.common.enums.ImageryFitStatus;
import com.kamco.cd.kamcoback.common.enums.StatusType;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.AllocateInfoDto;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceDetail;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InferenceLearnDto;
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;
@@ -48,6 +51,7 @@ import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -82,7 +86,9 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
.innerJoin(mapSheetAnalDataInferenceGeomEntity)
.on(
mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid),
mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(),
// mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(),
mapSheetAnalDataInferenceGeomEntity.pnu.gt(0),
mapSheetAnalDataInferenceGeomEntity.fitState.eq(ImageryFitStatus.UNFIT.getId()),
mapSheetAnalDataInferenceGeomEntity.labelState.isNull())
.where(
mapSheetAnalInferenceEntity.uuid.eq(uuid),
@@ -189,7 +195,9 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
.innerJoin(mapSheetAnalDataInferenceGeomEntity)
.on(
mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid),
mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(),
// mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull(),
mapSheetAnalDataInferenceGeomEntity.pnu.gt(0),
mapSheetAnalDataInferenceGeomEntity.fitState.eq(ImageryFitStatus.UNFIT.getId()),
mapSheetAnalDataInferenceGeomEntity.labelState.isNull())
.where(mapSheetAnalInferenceEntity.uuid.eq(uuid))
.fetchOne();
@@ -380,9 +388,10 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
mapSheetAnalDataInferenceGeomEntity.compareYyyy.eq(analEntity.getCompareYyyy()),
mapSheetAnalDataInferenceGeomEntity.targetYyyy.eq(analEntity.getTargetYyyy()),
mapSheetAnalDataInferenceGeomEntity.stage.eq(analEntity.getStage()),
mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull()
// mapSheetAnalDataInferenceGeomEntity.pnu.gt(0L)
// mapSheetAnalDataInferenceGeomEntity.passYn.isFalse() //TODO:
// mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull()
mapSheetAnalDataInferenceGeomEntity.pnu.gt(0L),
mapSheetAnalDataInferenceGeomEntity.fitState.eq(
ImageryFitStatus.UNFIT.getId()) // TODO:
// 추후 라벨링 대상 조건 수정하기
)
.fetchOne();
@@ -554,11 +563,9 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
mapSheetAnalDataInferenceGeomEntity.dataUid))
.where(
mapSheetAnalInferenceEntity.uuid.eq(targetUuid),
mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull()
// mapSheetAnalDataInferenceGeomEntity.pnu.gt(0L),
// mapSheetAnalDataInferenceGeomEntity.passYn.isFalse() //TODO: 추후 라벨링
// 대상 조건 수정하기
)
// mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull()
mapSheetAnalDataInferenceGeomEntity.pnu.gt(0L),
mapSheetAnalDataInferenceGeomEntity.fitState.eq(ImageryFitStatus.UNFIT.getId()))
.fetchOne();
}
@@ -575,8 +582,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
queryFactory
.select(labelingAssignmentEntity.count())
.from(labelingAssignmentEntity)
.where(
analUidCondition, labelingAssignmentEntity.workState.in("ASSIGNED", "SKIP", "DONE"))
.where(analUidCondition, labelingAssignmentEntity.workState.in("SKIP", "DONE"))
.fetchOne();
Long skipCount =
@@ -601,6 +607,13 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
.where(analUidCondition, labelingAssignmentEntity.inspectState.eq("COMPLETE"))
.fetchOne();
Long inspectionExcept =
queryFactory
.select(labelingAssignmentEntity.count())
.from(labelingAssignmentEntity)
.where(analUidCondition, labelingAssignmentEntity.inspectState.eq("EXCEPT"))
.fetchOne();
Long inspectorCount =
queryFactory
.select(labelingAssignmentEntity.inspectorUid.countDistinct())
@@ -613,6 +626,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
long labelCompleted = labelingCompleted != null ? labelingCompleted : 0L;
long inspectCompleted = inspectionCompleted != null ? inspectionCompleted : 0L;
long skipped = skipCount != null ? skipCount : 0L;
long inspectExcepted = inspectionExcept != null ? inspectionExcept : 0L;
long labelingRemaining = labelingTotal - labelCompleted - skipped;
if (labelingRemaining < 0) {
@@ -620,7 +634,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
}
long inspectionTotal = labelingTotal;
long inspectionRemaining = inspectionTotal - inspectCompleted - skipped;
long inspectionRemaining = inspectionTotal - inspectCompleted - inspectExcepted;
if (inspectionRemaining < 0) {
inspectionRemaining = 0;
}
@@ -657,7 +671,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
.inspectionStatus(inspectionStatus)
.inspectionTotalCount(inspectionTotal)
.inspectionCompletedCount(inspectCompleted)
.inspectionSkipCount(skipped) // TODO
.inspectionSkipCount(inspectExcepted)
.inspectionRemainingCount(inspectionRemaining)
.inspectorCount(inspectorCount != null ? inspectorCount : 0L)
.progressRate(labelingRate)
@@ -739,11 +753,9 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
mapSheetAnalInferenceEntity.targetYyyy.eq(
mapSheetAnalDataInferenceGeomEntity.targetYyyy),
mapSheetAnalInferenceEntity.stage.eq(mapSheetAnalDataInferenceGeomEntity.stage),
mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull()
// mapSheetAnalDataInferenceGeomEntity.pnu.gt(0),
// mapSheetAnalDataInferenceGeomEntity.passYn.isFalse() //TODO: 추후 라벨링 대상 조건
// 수정하기
)
// mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull()
mapSheetAnalDataInferenceGeomEntity.pnu.gt(0),
mapSheetAnalDataInferenceGeomEntity.fitState.eq(ImageryFitStatus.UNFIT.getId()))
.where(mapSheetAnalInferenceEntity.id.eq(analEntity.getId()))
.groupBy(
mapSheetAnalInferenceEntity.analTitle,
@@ -1815,4 +1827,33 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
LabelMngState.ASSIGNED.getId(), LabelMngState.ING.getId()))
.fetchOne();
}
@Override
public InferenceLearnDto findLabelingIngProcessId(UUID uuid) {
return queryFactory
.select(
Projections.constructor(
InferenceLearnDto.class,
mapSheetAnalInferenceEntity.uuid,
mapSheetLearnEntity.uid,
mapSheetAnalInferenceEntity.analState,
mapSheetAnalInferenceEntity.id))
.from(mapSheetLearnEntity)
.join(mapSheetAnalInferenceEntity)
.on(mapSheetAnalInferenceEntity.learnId.eq(mapSheetLearnEntity.id))
.where(mapSheetAnalInferenceEntity.uuid.eq(uuid))
.fetchOne();
}
@Override
public Optional<String> findLearnUid(UUID uuid) {
return Optional.ofNullable(
queryFactory
.select(mapSheetLearnEntity.uid)
.from(mapSheetLearnEntity)
.innerJoin(mapSheetAnalInferenceEntity)
.on(mapSheetAnalInferenceEntity.learnId.eq(mapSheetLearnEntity.id))
.where(mapSheetAnalInferenceEntity.uuid.eq(uuid))
.fetchOne());
}
}

View File

@@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.postgres.repository.label;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnEntity.mapSheetLearnEntity;
import com.kamco.cd.kamcoback.common.enums.ImageryFitStatus;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InspectState;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelState;
import com.kamco.cd.kamcoback.label.dto.LabelWorkDto;
@@ -133,20 +134,16 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
.and(mapSheetAnalDataInferenceGeomEntity.labelStateDttm.lt(end)));
}
// labelTotCnt: pnu가 있고 pass_yn = false (부적합)인 건수만 라벨링 대상
// labelTotCnt: pnu가 있고 fitState = UNFIT 인 건수만 라벨링 대상
NumberExpression<Long> labelTotCntExpr =
new CaseBuilder()
.when(
mapSheetAnalDataInferenceGeomEntity
.pnu
.isNotNull()
.gt(0)
.and(
mapSheetAnalDataInferenceGeomEntity.pnu
.isNotNull()) // TODO: 이노팸 연동 후 0 이상이라고 해야할 듯
//
// .and(mapSheetAnalDataInferenceGeomEntity.passYn.eq(Boolean.FALSE)) //TODO: 추후
// 라벨링 대상 조건 수정하기
)
mapSheetAnalDataInferenceGeomEntity.fitState.eq(
ImageryFitStatus.UNFIT.getId())))
.then(1L)
.otherwise(0L)
.sum();
@@ -200,7 +197,7 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
new CaseBuilder()
.when(
mapSheetAnalDataInferenceGeomEntity.labelState.eq(
LabelState.DONE.getId())) // "LABEL_COMPLETE"?
LabelState.DONE.getId()))
.then(1L)
.otherwise(0L)
.sum(),
@@ -294,14 +291,14 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
if (searchReq.getSearchVal() != null && !searchReq.getSearchVal().isEmpty()) {
whereSubBuilder.and(
Expressions.stringTemplate("{0}", memberEntity.userId)
Expressions.stringTemplate("{0}", memberEntity.employeeNo)
.likeIgnoreCase("%" + searchReq.getSearchVal() + "%")
.or(
Expressions.stringTemplate("{0}", memberEntity.name)
.likeIgnoreCase("%" + searchReq.getSearchVal() + "%")));
}
whereSubBuilder.and(labelingAssignmentEntity.workerUid.eq(memberEntity.userId));
whereSubBuilder.and(labelingAssignmentEntity.workerUid.eq(memberEntity.employeeNo));
// 공통 조건 추출
BooleanExpression doneStateCondition =
@@ -344,7 +341,7 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
WorkerState.class,
memberEntity.userRole,
memberEntity.name,
memberEntity.userId,
memberEntity.employeeNo,
assignedCnt.as("assignedCnt"),
doneCnt.as("doneCnt"),
skipCnt.as("skipCnt"),
@@ -363,7 +360,10 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
.on(whereSubBuilder)
.where(whereBuilder)
.groupBy(
memberEntity.userRole, memberEntity.name, memberEntity.userId, memberEntity.status)
memberEntity.userRole,
memberEntity.name,
memberEntity.employeeNo,
memberEntity.status)
.orderBy(orderSpecifiers.toArray(new OrderSpecifier[0]))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
@@ -441,14 +441,14 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
if (searchReq.getSearchVal() != null && !searchReq.getSearchVal().isEmpty()) {
whereSubBuilder.and(
Expressions.stringTemplate("{0}", memberEntity.userId)
Expressions.stringTemplate("{0}", memberEntity.employeeNo)
.likeIgnoreCase("%" + searchReq.getSearchVal() + "%")
.or(
Expressions.stringTemplate("{0}", memberEntity.name)
.likeIgnoreCase("%" + searchReq.getSearchVal() + "%")));
}
whereSubBuilder.and(labelingAssignmentEntity.inspectorUid.eq(memberEntity.userId));
whereSubBuilder.and(labelingAssignmentEntity.inspectorUid.eq(memberEntity.employeeNo));
// 공통 조건 추출
BooleanExpression doneStateCondition =
@@ -492,7 +492,7 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
WorkerState.class,
memberEntity.userRole,
memberEntity.name,
memberEntity.userId,
memberEntity.employeeNo,
assignedCnt.as("assignedCnt"),
doneCnt.as("doneCnt"),
skipCnt.as("skipCnt"),
@@ -511,7 +511,10 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
.on(whereSubBuilder)
.where(whereBuilder)
.groupBy(
memberEntity.userRole, memberEntity.name, memberEntity.userId, memberEntity.status)
memberEntity.userRole,
memberEntity.name,
memberEntity.employeeNo,
memberEntity.status)
.orderBy(orderSpecifiers.toArray(new OrderSpecifier[0]))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
@@ -551,7 +554,14 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
NumberExpression<Long> labelTotCnt =
new CaseBuilder()
.when(mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull())
// .when(mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull())
.when(
mapSheetAnalDataInferenceGeomEntity
.pnu
.gt(0)
.and(
mapSheetAnalDataInferenceGeomEntity.fitState.eq(
ImageryFitStatus.UNFIT.getId())))
.then(1L)
.otherwise(0L)
.sum();

View File

@@ -46,6 +46,7 @@ public class MapLayerRepositoryImpl implements MapLayerRepositoryCustom {
if (searchReq.getTag() != null) {
whereBuilder.and(mapLayerEntity.tag.toLowerCase().eq(searchReq.getTag().toLowerCase()));
}
if (searchReq.getLayerType() != null) {
whereBuilder.and(
mapLayerEntity.layerType.toLowerCase().eq(searchReq.getLayerType().toLowerCase()));
@@ -57,6 +58,7 @@ public class MapLayerRepositoryImpl implements MapLayerRepositoryCustom {
Projections.constructor(
LayerDto.Basic.class,
mapLayerEntity.uuid,
mapLayerEntity.layerName,
mapLayerEntity.layerType,
mapLayerEntity.description,
mapLayerEntity.tag,
@@ -101,6 +103,7 @@ public class MapLayerRepositoryImpl implements MapLayerRepositoryCustom {
.select(
Projections.constructor(
LayerMapDto.class,
mapLayerEntity.layerName,
mapLayerEntity.layerType,
mapLayerEntity.tag,
mapLayerEntity.order,

View File

@@ -168,13 +168,13 @@ public class AuditLogRepositoryImpl extends QuerydslRepositorySupport
whereBuilder.and(auditLogEntity.eventStatus.ne(EventStatus.valueOf("FAILED")));
whereBuilder.and(auditLogEntity.eventType.eq(EventType.valueOf("DOWNLOAD")));
if (req.getMenuId() != null && !req.getMenuId().isEmpty()) {
whereBuilder.and(auditLogEntity.menuUid.eq(req.getMenuId()));
}
// if (req.getMenuId() != null && !req.getMenuId().isEmpty()) {
// whereBuilder.and(auditLogEntity.menuUid.eq(req.getMenuId()));
// }
if (req.getUuid() != null) {
whereBuilder.and(auditLogEntity.requestUri.contains("/api/inference/download/"));
whereBuilder.and(auditLogEntity.requestUri.endsWith(String.valueOf(req.getUuid())));
whereBuilder.and(auditLogEntity.requestUri.contains(req.getRequestUri()));
whereBuilder.and(auditLogEntity.downloadUuid.eq(req.getUuid()));
}
if (req.getSearchValue() != null && !req.getSearchValue().isEmpty()) {

View File

@@ -10,6 +10,7 @@ import static com.kamco.cd.kamcoback.postgres.entity.QPnuEntity.pnuEntity;
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.label.dto.LabelAllocateDto.LabelMngState;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelState;
import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity;
@@ -305,6 +306,10 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport
queryFactory
.select(labelingAssignmentEntity.count())
.from(labelingAssignmentEntity)
.innerJoin(mapSheetAnalInferenceEntity)
.on(
labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id),
mapSheetAnalInferenceEntity.analState.ne(LabelMngState.FINISH.getId()))
.where(labelingAssignmentEntity.workerUid.eq(userId))
.fetchOne();
@@ -325,6 +330,10 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport
queryFactory
.select(labelingAssignmentEntity.count())
.from(labelingAssignmentEntity)
.innerJoin(mapSheetAnalInferenceEntity)
.on(
labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id),
mapSheetAnalInferenceEntity.analState.ne(LabelMngState.FINISH.getId()))
.where(
labelingAssignmentEntity.workerUid.eq(userId),
labelingAssignmentEntity.workState.eq("ASSIGNED"))
@@ -353,6 +362,10 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport
queryFactory
.select(labelingAssignmentEntity.count())
.from(labelingAssignmentEntity)
.innerJoin(mapSheetAnalInferenceEntity)
.on(
labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id),
mapSheetAnalInferenceEntity.analState.ne(LabelMngState.FINISH.getId()))
.where(
labelingAssignmentEntity.workerUid.eq(userId),
labelingAssignmentEntity.workState.in(
@@ -492,6 +505,9 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport
mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeCd() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeCd()
: "")
.classificationName(
DetectionClassification.fromStrDesc(
mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterCd()))
.probability(
mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeProb() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeProb()
@@ -503,6 +519,9 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport
mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterCd() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterCd()
: "")
.classificationName(
DetectionClassification.fromStrDesc(
mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterCd()))
.probability(
mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterProb() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterProb()
@@ -524,12 +543,17 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport
.build();
var inspectionResultInfo =
InspectionResultInfo.builder()
.verificationResult(convertInspectState(assignment.toDto().getInspectState()))
.inappropriateReason("")
// .memo(assignment.toDto().getInspectMemo() != null ?
// assignment.toDto().getInspectMemo() : "")
.build();
queryFactory
.select(
Projections.constructor(
InspectionResultInfo.class,
mapSheetAnalDataInferenceGeomEntity.fitState,
mapSheetAnalDataInferenceGeomEntity.fitStateCmmnt))
.from(mapSheetAnalDataInferenceGeomEntity)
.where(
mapSheetAnalDataInferenceGeomEntity.geoUid.eq(
mapSheetAnalDataInferenceGeomEntityEntity.getGeoUid()))
.fetchOne();
// 6. Geometry를 GeoJSON으로 변환
InferenceDataGeometry inferData =

View File

@@ -11,6 +11,7 @@ import static com.kamco.cd.kamcoback.postgres.entity.QPnuEntity.pnuEntity;
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.label.dto.LabelAllocateDto.InspectState;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelMngState;
import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity;
@@ -24,7 +25,6 @@ import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.DetailRes;
import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.GeoFeatureRequest.Properties;
import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.InferenceDataGeometry;
import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.InferenceDataGeometry.InferenceProperties;
import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.InspectionResultInfo;
import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.LearnDataGeometry;
import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.LearnDataGeometry.LearnProperties;
import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.ReviewGeometryInfo;
@@ -314,6 +314,10 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport
queryFactory
.select(labelingAssignmentEntity.count())
.from(labelingAssignmentEntity)
.innerJoin(mapSheetAnalInferenceEntity)
.on(
labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id),
mapSheetAnalInferenceEntity.analState.ne(LabelMngState.FINISH.getId()))
.where(labelingAssignmentEntity.inspectorUid.eq(userId))
.fetchOne();
@@ -334,6 +338,10 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport
queryFactory
.select(labelingAssignmentEntity.count())
.from(labelingAssignmentEntity)
.innerJoin(mapSheetAnalInferenceEntity)
.on(
labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id),
mapSheetAnalInferenceEntity.analState.ne(LabelMngState.FINISH.getId()))
.where(
labelingAssignmentEntity.inspectorUid.eq(userId),
labelingAssignmentEntity.inspectState.eq("UNCONFIRM"))
@@ -362,6 +370,10 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport
queryFactory
.select(labelingAssignmentEntity.count())
.from(labelingAssignmentEntity)
.innerJoin(mapSheetAnalInferenceEntity)
.on(
labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id),
mapSheetAnalInferenceEntity.analState.ne(LabelMngState.FINISH.getId()))
.where(
labelingAssignmentEntity.inspectorUid.eq(userId),
labelingAssignmentEntity.inspectState.in("COMPLETE", "EXCEPT"),
@@ -483,7 +495,7 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport
queryFactory
.select(memberEntity.name)
.from(memberEntity)
.where(memberEntity.userId.eq(assignment.toDto().getWorkerUid()))
.where(memberEntity.employeeNo.eq(assignment.toDto().getWorkerUid()))
.fetchFirst();
if (workerName == null) {
workerName = "";
@@ -520,6 +532,9 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport
mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeCd() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeCd()
: "")
.classificationName(
DetectionClassification.fromStrDesc(
mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterCd()))
.probability(
mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeProb() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getClassBeforeProb()
@@ -531,6 +546,9 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport
mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterCd() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterCd()
: "")
.classificationName(
DetectionClassification.fromStrDesc(
mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterCd()))
.probability(
mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterProb() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getClassAfterProb()
@@ -553,11 +571,17 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport
.build();
var inspectionResultInfo =
InspectionResultInfo.builder()
.verificationResult(convertInspectState(assignment.toDto().getInspectState()))
.inappropriateReason("")
.memo("")
.build();
queryFactory
.select(
Projections.constructor(
TrainingDataReviewDto.InspectionResultInfo.class,
mapSheetAnalDataInferenceGeomEntity.fitState,
mapSheetAnalDataInferenceGeomEntity.fitStateCmmnt))
.from(mapSheetAnalDataInferenceGeomEntity)
.where(
mapSheetAnalDataInferenceGeomEntity.geoUid.eq(
mapSheetAnalDataInferenceGeomEntityEntity.getGeoUid()))
.fetchOne();
// 6. Geometry를 GeoJSON으로 변환
InferenceDataGeometry inferData =

View File

@@ -44,7 +44,7 @@ public class GukYuinApiLabelJobService {
}
for (GeomUidDto gto : list) {
ChngDetectContDto.ResultPnuDto dto =
ChngDetectContDto.ResultLabelDto dto =
gukYuinApiService.updateChnDtctObjtLabelingYn(gto.getResultUid(), "Y");
if (dto.getSuccess()) {
// inference_geom 에 label_send_dttm 업데이트 하기

View File

@@ -36,7 +36,7 @@ public class GukYuinApiPnuJobService {
}
/** 국유인 등록 완료 후, 탐지객체 조회해서 PNU 업데이트 하는 스케줄링 하루 1번 새벽 1시에 실행 */
@Scheduled(cron = "0 * * * * *") // 0 0 1 * * *
@Scheduled(cron = "0 0 1 * * *")
public void findGukYuinContListPnuUpdate() {
if (isLocalProfile()) {
return;

View File

@@ -33,7 +33,7 @@ public class GukYuinApiStatusJobService {
}
/** 국유인 연동 후, 100% 되었는지 확인하는 스케줄링 매 10분마다 호출 */
@Scheduled(cron = "0 0/10 * * * *") // 0 0/10 * * * *
@Scheduled(cron = "0 0/10 * * * *")
public void findGukYuinMastCompleteYn() {
if (isLocalProfile()) {
return;

View File

@@ -1,12 +1,18 @@
package com.kamco.cd.kamcoback.scheduler.service;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto.StbltResult;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LearnKeyDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.RlbDtctDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.RlbDtctMastDto;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus;
import com.kamco.cd.kamcoback.gukyuin.service.GukYuinApiService;
import com.kamco.cd.kamcoback.postgres.core.GukYuinStbltJobCoreService;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
@@ -34,7 +40,7 @@ public class GukYuinApiStbltJobService {
}
/** 국유인 연동 후, 실태조사 적합여부 확인하여 update */
@Scheduled(cron = "0 * * * * *") // 0 0 3 * * *
@Scheduled(cron = "0 0 3 * * *")
public void findGukYuinEligibleForSurvey() {
if (isLocalProfile()) {
return;
@@ -49,7 +55,11 @@ public class GukYuinApiStbltJobService {
for (LearnKeyDto dto : list) {
try {
RlbDtctDto result = gukYuinApiService.findRlbDtctList(dto.getUid());
String yesterday =
LocalDate.now(ZoneId.of("Asia/Seoul"))
.minusDays(1)
.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
RlbDtctDto result = gukYuinApiService.findRlbDtctList(dto.getUid(), yesterday);
if (result == null || result.getResult() == null || result.getResult().isEmpty()) {
log.warn("[GUKYUIN] empty result chnDtctMstId={}", dto.getChnDtctMstId());
@@ -60,6 +70,43 @@ public class GukYuinApiStbltJobService {
String resultUid = stbltDto.getChnDtctObjtId();
gukYuinStbltJobCoreService.updateGukYuinEligibleForSurvey(resultUid, stbltDto);
}
Map<String, StbltResult> resultMap =
result.getResult().stream()
.collect(Collectors.groupingBy(RlbDtctMastDto::getChnDtctObjtId))
.entrySet()
.stream()
.collect(
Collectors.toMap(
Map.Entry::getKey,
e -> {
List<RlbDtctMastDto> pnuList = e.getValue();
boolean hasY = pnuList.stream().anyMatch(v -> "Y".equals(v.getStbltYn()));
String fitYn = hasY ? "Y" : "N";
RlbDtctMastDto selected =
hasY
? pnuList.stream()
.filter(v -> "Y".equals(v.getStbltYn()))
.findFirst()
.orElse(null)
: pnuList.stream()
.filter(v -> "N".equals(v.getStbltYn()))
.findFirst()
.orElse(null);
if (selected == null) {
return null; // 방어 코드
}
return new StbltResult(
fitYn, selected.getIncyCd(), selected.getIncyRsnCont());
}));
resultMap.forEach(gukYuinStbltJobCoreService::updateGukYuinObjectStbltYn);
} catch (Exception e) {
log.error("[GUKYUIN] failed uid={}", dto.getChnDtctMstId(), e);
}

View File

@@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.JsonNode;
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.geometry.GeometryDeserializer;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
@@ -372,9 +373,12 @@ public class TrainingDataLabelDto {
@AllArgsConstructor
public static class ClassificationInfo {
@Schema(description = "분류", example = "일반토지")
@Schema(description = "분류", example = "land")
private String classification;
@Schema(description = "분류 한글명", example = "일반토지")
private String classificationName;
@Schema(description = "확률", example = "80.0")
private Double probability;
}
@@ -382,9 +386,7 @@ public class TrainingDataLabelDto {
@Schema(name = "InspectionResultInfo", description = "실태조사결과정보")
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class InspectionResultInfo {
@Schema(description = "검증결과 (미확인/제외/완료)", example = "미확인")
@@ -395,6 +397,11 @@ public class TrainingDataLabelDto {
@Schema(description = "메모")
private String memo;
public InspectionResultInfo(String verificationResult, String inappropriateReason) {
this.verificationResult = ImageryFitStatus.fromCode(verificationResult).getText();
this.inappropriateReason = inappropriateReason;
}
}
@Schema(name = "SummaryRes", description = "작업 통계 응답")

View File

@@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.JsonNode;
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.geometry.GeometryDeserializer;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
@@ -368,9 +369,12 @@ public class TrainingDataReviewDto {
@AllArgsConstructor
public static class ClassificationInfo {
@Schema(description = "분류", example = "일반토지")
@Schema(description = "분류", example = "land")
private String classification;
@Schema(description = "분류한글명", example = "일반토지")
private String classificationName;
@Schema(description = "확률", example = "80.0")
private Double probability;
}
@@ -378,9 +382,7 @@ public class TrainingDataReviewDto {
@Schema(name = "InspectionResultInfo", description = "실태조사결과정보")
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class InspectionResultInfo {
@Schema(description = "검증결과 (미확인/제외/완료)", example = "미확인")
@@ -391,6 +393,11 @@ public class TrainingDataReviewDto {
@Schema(description = "메모")
private String memo;
public InspectionResultInfo(String verificationResult, String inappropriateReason) {
this.verificationResult = ImageryFitStatus.fromCode(verificationResult).getText();
this.inappropriateReason = inappropriateReason;
}
}
@Schema(name = "SummaryRes", description = "작업 통계 응답")

View File

@@ -107,6 +107,8 @@ file:
pt-path: /kamco-nfs/ckpt/model/v6-cls-checkpoints/
pt-FileName: yolov8_6th-6m.pt
dataset-response: /kamco-nfs/dataset/response/
inference:
url: http://192.168.2.183:8000/jobs
batch-url: http://192.168.2.183:8000/batches

View File

@@ -62,6 +62,8 @@ file:
pt-path: /kamco-nfs/ckpt/model/v6-cls-checkpoints/
pt-FileName: yolov8_6th-6m.pt
dataset-response: /kamco-nfs/dataset/response/
inference:
url: http://192.168.2.183:8000/jobs
batch-url: http://192.168.2.183:8000/batches