285 Commits

Author SHA1 Message Date
e88ffd1260 국유인 수정, 라벨대상 건수 수정 2026-02-06 09:49:30 +09:00
533d97a573 학습데이터 라벨링 현황 건수 조건 수정, 라벨러, 검수자 목록 수정 2026-02-05 18:00:52 +09:00
3237863542 국유인 연동 경로 확인 TEST 2026-02-05 16:59:49 +09:00
41b227de3f 국유인 API 수정 추가 2026-02-05 15:09:27 +09:00
83e02c4498 국유인 API 수정 추가 2026-02-05 15:02:00 +09:00
d8804e7c9a 국유인 API 수정 추가 2026-02-05 14:58:30 +09:00
f326b5f651 국유인 API 수정 2026-02-05 14:55:16 +09:00
c1b6061e3e 라벨링 할당 수정 2026-02-05 13:55:42 +09:00
71a8f27afc 라벨링 가능 건수 조건 수정 2026-02-05 13:49:18 +09:00
299d1b09a0 국유인 API reqIp, reqEpno 추가, 스케줄러 수정 2026-02-04 17:55:39 +09:00
3461376b35 국유in 등록 로그 추가 2026-02-04 11:13:49 +09:00
17bd89fafa 국유in 등록 로그 추가 2026-02-04 11:10:16 +09:00
e5fa99daef 국유인, 라벨링 job 각각 분리 작업 2026-02-02 19:16:26 +09:00
d563f47abd spotless 적용 2026-02-02 17:17:29 +09:00
cf4f79f7ca 추론결과 국유In 등록 벨리데이션 체크 수정 2026-02-02 17:15:57 +09:00
6e9b4196b8 영상관리 count 조건 수정 2026-02-02 17:08:38 +09:00
a4f66f511e 국유인 연동 리턴 타입 수정 okObject 2026-02-02 15:59:05 +09:00
9734a5acb2 국유인 스케줄러 분리 2026-02-02 15:40:17 +09:00
9fb4a25955 국유인 연동 API 실태조사 적합여부 추가 2026-02-02 14:56:04 +09:00
3af05bbeef 인증 예시 아이디 수정 2026-02-02 14:00:30 +09:00
1c2e41ced6 사번 자리수 6자리 벨리데이션 수정 2026-02-02 13:36:53 +09:00
c52c2ab9bd 변화지도 레이어 조회 url 수정 2026-02-02 12:22:32 +09:00
eb8d798714 Merge remote-tracking branch 'origin/feat/infer_dev_260107' into feat/infer_dev_260107 2026-02-02 12:17:46 +09:00
7e95b53881 변화지도 레이어 조회 url 수정 2026-02-02 12:17:39 +09:00
74b244981b 국유인 연동 API 응답 로직 수정 2026-02-02 12:17:18 +09:00
699d39d402 타일 url 시큐리티 추가 2026-02-02 10:31:11 +09:00
e3ae889152 Merge remote-tracking branch 'origin/feat/infer_dev_260107' into feat/infer_dev_260107 2026-02-02 10:28:07 +09:00
20a835cf45 레이어관리 삭제 수정 2026-02-02 10:27:57 +09:00
c0b5dd99ef spotless 2026-02-02 10:13:58 +09:00
5015a2a437 국유인 연동 API validation 체크 주석 해제 2026-02-02 10:10:52 +09:00
d8d35c3462 crs 타입 수정하기 2026-01-30 21:42:47 +09:00
b77de057f0 영상관리 년도별 타일 crs 추가하기 2026-01-30 21:26:52 +09:00
2559b225d5 레이어관리 수정 2026-01-30 21:09:35 +09:00
9a00c38cc7 Merge remote-tracking branch 'origin/feat/infer_dev_260107' into feat/infer_dev_260107 2026-01-30 21:03:56 +09:00
e8fa7411d5 레이어관리 수정 2026-01-30 21:03:50 +09:00
71f1f03b89 영상관리 년도별 타일 crs 추가하기 2026-01-30 21:00:15 +09:00
96d7ea205c properties 커밋 2026-01-30 19:42:37 +09:00
0993ce646a wmts, wms url 추가 2026-01-30 19:40:41 +09:00
302e1ad957 geoserver url 변경 2026-01-30 19:13:02 +09:00
e11f365bf8 bbox 5186 transform 2026-01-30 18:19:47 +09:00
9dd439b920 bbox 5186 으로 변환 2026-01-30 18:09:13 +09:00
a42729a475 wmts 수정 2026-01-30 17:56:20 +09:00
bc5c5b3dd7 추론실행 퍼센트 수정 2026-01-30 17:49:16 +09:00
60ff43cd3c Merge branch 'feat/infer_dev_260107' of https://kamco.git.gs.dabeeo.com/MVPTeam/kamco-cd-api into feat/infer_dev_260107 2026-01-30 17:43:43 +09:00
ff7654baa7 RestTemplateConfig 수정 2026-01-30 17:43:27 +09:00
21f922a5f4 국유인 어제완료된 라벨전송, 전송완료된 리스트 기능 추가 2026-01-30 17:32:39 +09:00
5ff72f927c RestTemplateConfig 수정 2026-01-30 17:20:53 +09:00
e6ef4c2525 RestTemplateConfig 수정, wmts 수정 2026-01-30 17:13:08 +09:00
86e8408f27 RestTemplateConfig 수정 2026-01-30 16:51:27 +09:00
d4fb11deb2 RestTemplateConfig 수정 2026-01-30 16:44:21 +09:00
c2b87ca12a RestTemplateConfig 수정, 추론실행 수정 2026-01-30 16:18:40 +09:00
37b7877083 RestTemplateConfig 수정 2026-01-30 14:43:33 +09:00
3b636a85e6 wmts 수정 2026-01-30 14:18:57 +09:00
d95dc364aa wmts 수정 2026-01-30 14:10:22 +09:00
29556b6a05 등록 post로 수정 2026-01-30 13:33:00 +09:00
df8bac950b 국유인 API 진행중 2026-01-30 13:30:13 +09:00
f3453ab499 레이어관리 수정 2026-01-30 12:04:11 +09:00
2865b075a2 레이어관리 수정 2026-01-30 11:54:11 +09:00
10ab050a1c 년도 1개만 조회하는 타일 API 2026-01-30 11:17:13 +09:00
babf35142a 년도별 타일 API 2026-01-30 11:04:14 +09:00
ceebbdfa50 변화지도, 라벨링 맵 리스트 uuid, rawjson 추가 2026-01-30 10:51:22 +09:00
af19ca905b geoserver 등록 수정 2026-01-30 10:22:39 +09:00
3686f1d248 geoserver 등록 수정 2026-01-30 10:21:06 +09:00
565e76a4e2 Merge remote-tracking branch 'origin/feat/infer_dev_260107' into feat/infer_dev_260107 2026-01-30 09:50:38 +09:00
e379c49453 geoserver 등록 수정 2026-01-30 09:50:32 +09:00
9bec466d7c 레이어관리 - 변화지도,라벨링툴 맵 리스트 2026-01-29 20:56:14 +09:00
cea1d82bd9 ai 주소 변경 2026-01-29 20:12:00 +09:00
e4550d1e71 영상관리 등록 년도 tile 추가 2026-01-29 19:03:08 +09:00
38ad63172a ai 주소 변경 2026-01-29 17:34:15 +09:00
586c0f7e9a Merge remote-tracking branch 'origin/feat/infer_dev_260107' into feat/infer_dev_260107 2026-01-29 16:23:50 +09:00
32cb47cfc2 geojson 파일생성 api 추가 2026-01-29 16:23:44 +09:00
23a096a600 라벨링 툴 pnu 정보 list string으로 수정 2026-01-29 16:23:13 +09:00
480b016f33 geoserver url 변경 2026-01-29 14:42:21 +09:00
8563204e59 영상관리 folder-list 수정 2026-01-29 12:49:16 +09:00
e31913ff9a cls model 적용 2026-01-29 12:31:52 +09:00
f87a714892 헬스체크 시큐리티 설정 추가 2026-01-29 12:30:12 +09:00
d83f8befa9 Merge branch 'feat/infer_dev_260107' of https://kamco.git.gs.dabeeo.com/MVPTeam/kamco-cd-api into feat/infer_dev_260107 2026-01-29 12:15:45 +09:00
7f60a63a0f false 2026-01-29 12:14:27 +09:00
87374c8f6f 모델등록 pt 수정 2026-01-29 12:08:01 +09:00
0c3aaaa8f5 모델등록 pt 수정 2026-01-29 11:18:33 +09:00
43ed8b5409 국유인 API 연동 작업중 2026-01-29 10:41:08 +09:00
614f0dccf0 추론실행 수정 2026-01-29 10:34:51 +09:00
50c9efedd1 Merge branch 'develop' of https://kamco.git.gs.dabeeo.com/MVPTeam/kamco-cd-api into feat/infer_dev_260107 2026-01-29 10:29:26 +09:00
f793042927 추론실행 수정 2026-01-29 10:27:08 +09:00
0f8261b20b Merge remote-tracking branch 'origin/feat/infer_dev_260107' into feat/infer_dev_260107 2026-01-28 11:46:58 +09:00
c8c8816981 추론실행 수정 2026-01-28 11:46:51 +09:00
2cce3bd18b 에러로그 날짜 전체 나오게 수정 2026-01-28 10:21:05 +09:00
2e43ec76f2 영상관리 업로드 경로 수정 2026-01-27 21:41:45 +09:00
4e3789b5ce Merge remote-tracking branch 'origin/feat/infer_dev_260107' into feat/infer_dev_260107 2026-01-27 21:32:03 +09:00
56adcc8181 레이어 관리 api 추가 2026-01-27 21:31:56 +09:00
3445329d48 영상관리 업로드 경로 수정 2026-01-27 21:31:38 +09:00
bcf44a6f4a 레이어 관리 api 추가 2026-01-27 21:18:43 +09:00
20e06f9e28 Merge pull request '학습데이터관리 목록 진행중 상태 수정' (#353) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/353
2026-01-27 09:33:24 +09:00
b203412560 Merge pull request '영상데이터관리 > uploadPair 로직 수정 test' (#352) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/352
2026-01-26 19:35:06 +09:00
7eadc49b78 Merge pull request '영상데이터관리 > tif 대용량 분할전송 추가' (#351) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/351
2026-01-26 18:21:15 +09:00
73862e95bd Merge pull request '추론실행 모델경로 path 수정' (#350) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/350
2026-01-26 17:21:55 +09:00
fba1e5f4e3 Merge pull request 'feat/infer_dev_260107' (#349) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/349
2026-01-26 15:33:46 +09:00
43651289ec Merge pull request '추론결과 목록조회 수정' (#348) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/348
2026-01-26 15:17:50 +09:00
8d38ca24d2 Merge pull request '추론결과 목록조회 수정' (#347) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/347
2026-01-26 15:06:02 +09:00
5dfd31e5bf Merge pull request '로그관리 - 일자별 상세에도 시,분까지 표기 추가' (#346) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/346
2026-01-26 14:32:31 +09:00
4027621379 Merge pull request 'feat/infer_dev_260107' (#345) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/345
2026-01-26 14:19:06 +09:00
12cc37e41d Merge pull request 'feat/infer_dev_260107' (#344) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/344
2026-01-26 14:14:18 +09:00
0b88fc058d Merge pull request '리스트의 탐지건수와 상세의 탐지건수 불일치 오류 수정' (#343) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/343
2026-01-26 13:56:09 +09:00
c94bcbd49e Merge pull request '추론도엽관리 - 자동추론 제외 상태 추가' (#342) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/342
2026-01-26 12:06:56 +09:00
f44717531b Merge pull request '영상관리 수정 - 확장자 대문자 ignore, 파일경로 추가, 오류목록 등록일 기준 수정' (#341) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/341
2026-01-26 11:48:57 +09:00
78b9645607 Merge pull request 'feat/infer_dev_260107' (#340) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/340
2026-01-26 11:21:28 +09:00
4040ac950a 스케줄러 2026-01-25 13:32:42 +09:00
20432c8f8a Merge pull request '추론결과 상세 목록 조회조건 수정' (#339) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/339
2026-01-23 20:57:35 +09:00
2772b41dcf Merge pull request 'feat/infer_dev_260107' (#338) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/338
2026-01-23 20:46:58 +09:00
600bdce4ac Merge pull request '로그관리 목록 API 수정 + spotless' (#337) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/337
2026-01-23 20:44:48 +09:00
6d6f22b9da Merge pull request 'feat/infer_dev_260107' (#336) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/336
2026-01-23 20:35:14 +09:00
f9caf1fa73 Merge pull request 'feat/infer_dev_260107' (#335) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/335
2026-01-23 18:41:43 +09:00
361edc58da Merge pull request 'feat/infer_dev_260107' (#334) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/334
2026-01-23 18:39:56 +09:00
91ac7be53a Merge pull request '변화탐지 cog-url bbox 5186 으로 변환' (#333) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/333
2026-01-23 18:13:22 +09:00
a71e8698ca Merge pull request 'feat/infer_dev_260107' (#332) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/332
2026-01-23 17:51:32 +09:00
6782788429 Merge pull request '변화탐지 API 로그인 인증 제외처리' (#331) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/331
2026-01-23 15:57:20 +09:00
4be0362bfa Merge pull request 'feat/infer_dev_260107' (#330) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/330
2026-01-23 15:29:27 +09:00
983505d443 Merge pull request 'tb_map_sheet_learn_5k 엔티티수정' (#329) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/329
2026-01-23 15:04:50 +09:00
832fc0f499 Merge pull request 'shp파일 생성 수정' (#328) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/328
2026-01-23 14:08:26 +09:00
ea373909b4 Merge pull request 'shp파일 생성 수정, 미사용 소스 제거' (#327) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/327
2026-01-23 11:47:18 +09:00
67a8500bc3 Merge pull request 'shp파일 생성 수정, 미사용 소스 제거' (#326) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/326
2026-01-23 11:41:49 +09:00
95b020de55 Merge pull request '로그 eventType 에 CodeExpose 추가' (#325) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/325
2026-01-23 11:22:37 +09:00
a67425c074 Merge pull request '로그 ip 확인 로직 수정' (#324) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/324
2026-01-23 11:03:58 +09:00
5bfcb9e771 Merge pull request '로그 날짜 검색 조회, 상세 조회 로직 수정' (#323) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/323
2026-01-23 10:42:19 +09:00
86b2dbd721 Merge pull request 'feat/infer_dev_260107' (#322) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/322
2026-01-23 10:14:26 +09:00
76e06d17bd Merge pull request '자동 추론제외, spotless 적용' (#321) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/321
2026-01-23 10:00:11 +09:00
d02e3d9728 Merge pull request 'jsonNode 변환 로직 수정' (#320) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/320
2026-01-23 09:52:11 +09:00
9a9dad76f7 Merge pull request 'feat/infer_dev_260107' (#319) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/319
2026-01-22 21:12:35 +09:00
0ffcf0b616 Merge pull request 'feat/infer_dev_260107' (#318) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/318
2026-01-22 21:03:50 +09:00
2f388701e1 Merge pull request 'feat/infer_dev_260107' (#317) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/317
2026-01-22 21:00:35 +09:00
7dc3a1e83b Merge pull request '로그 적재 방식 변경' (#316) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/316
2026-01-22 20:58:19 +09:00
c7a50900dc Merge pull request '국유인in 연동 가능여부 api' (#315) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/315
2026-01-22 20:42:03 +09:00
c142234e47 Merge pull request 'ip 확인' (#314) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/314
2026-01-22 20:33:23 +09:00
8a72a8f7c9 Merge pull request '에러 이벤트 타입 추가' (#313) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/313
2026-01-22 20:23:22 +09:00
8f92ff89e3 Merge pull request 'feat/infer_dev_260107' (#312) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/312
2026-01-22 20:18:54 +09:00
d11d6551ef Merge pull request 'feat/infer_dev_260107' (#311) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/311
2026-01-22 19:37:19 +09:00
704ed303aa Merge pull request 'feat/infer_dev_260107' (#310) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/310
2026-01-22 14:10:14 +09:00
60ac3a1349 Merge pull request '추론 결과 조회 수정' (#308) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/308
2026-01-22 12:27:04 +09:00
3975babe91 Merge pull request 'feat/infer_dev_260107' (#307) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/307
2026-01-22 12:16:38 +09:00
becce0e397 Merge pull request '학습데이터 목록에 추론 uuid 컬럼도 추가' (#306) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/306
2026-01-22 12:04:22 +09:00
baef53850c Merge pull request 'feat/infer_dev_260107' (#305) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/305
2026-01-22 11:27:41 +09:00
6db92082ca Merge pull request 'feat/infer_dev_260107' (#304) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/304
2026-01-22 09:40:51 +09:00
88ca806d2f Merge pull request 'feat/infer_dev_260107' (#303) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/303
2026-01-21 14:38:45 +09:00
f1aaef2efe Merge pull request 'feat/infer_dev_260107' (#302) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/302
2026-01-21 14:23:22 +09:00
9fee939f59 Merge pull request 'shp jar실행 소스 수정' (#301) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/301
2026-01-21 11:56:42 +09:00
dde18431e8 Merge pull request 'feat/infer_dev_260107' (#300) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/300
2026-01-21 11:15:29 +09:00
02486ff8ee Merge pull request 'feat/infer_dev_260107' (#299) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/299
2026-01-21 09:54:09 +09:00
713db18323 Merge pull request '실패 메시지 저장 추가' (#298) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/298
2026-01-20 20:53:33 +09:00
1b13a9225d Merge pull request '실패 메시지 저장 추가' (#297) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/297
2026-01-20 20:48:31 +09:00
bee37e716c Merge pull request '라벨링툴 목록 기준년도 asc,비교년도 asc 기준으로 sorting, 변화탐지 cog API 수정' (#296) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/296
2026-01-20 18:36:16 +09:00
a8f398f0a6 Merge pull request 'feat/infer_dev_260107' (#295) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/295
2026-01-20 17:13:08 +09:00
839164c743 Merge pull request 'spotless 적용' (#294) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/294
2026-01-20 16:37:07 +09:00
0f8b59a173 Merge pull request 'feat/infer_dev_260107' (#293) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/293
2026-01-20 16:28:36 +09:00
6248c9b1ee Merge pull request '상태 추가 쿼리 오류 수정' (#292) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/292
2026-01-20 16:13:34 +09:00
612d8829cb Merge pull request 'feat/infer_dev_260107' (#291) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/291
2026-01-20 16:11:19 +09:00
1514534248 Merge pull request 'shp 파일 geosjon 등록추가, 파일다운로드 파일명 오류 수정' (#290) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/290
2026-01-20 15:58:52 +09:00
762a674e0e Merge pull request 'feat/infer_dev_260107' (#289) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/289
2026-01-20 15:39:09 +09:00
aca8098e80 Merge pull request '상태값 수정' (#288) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/288
2026-01-20 15:28:59 +09:00
d653865cee Merge pull request '학습데이터 목록 analState 적용' (#287) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/287
2026-01-20 15:19:44 +09:00
6c2b7fe8ec Merge pull request 'feat/infer_dev_260107' (#286) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/286
2026-01-20 15:10:09 +09:00
67566cffc4 Merge pull request 'feat/infer_dev_260107' (#285) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/285
2026-01-20 14:24:02 +09:00
69eabfdc2f Merge pull request 'feat/infer_dev_260107' (#284) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/284
2026-01-20 10:22:34 +09:00
1400a9c30b Merge pull request 'feat/infer_dev_260107' (#283) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/283
2026-01-19 21:47:10 +09:00
bb56dce623 Merge pull request '추론결과 파일 다운로드 이력 조회 수정' (#282) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/282
2026-01-19 21:42:09 +09:00
42a8d59b5e Merge pull request 'spring security 파일 다운로드 설정 추가' (#281) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/281
2026-01-19 20:42:42 +09:00
a73bfea11b Merge pull request 'feat/infer_dev_260107' (#280) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/280
2026-01-19 19:48:48 +09:00
9c9c87b5be Merge pull request '추론 전체 실행 파일생성 수정' (#279) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/279
2026-01-19 18:02:23 +09:00
a4f94d460e Merge pull request '전체일 때 기본으로 라벨러 목록 조회' (#278) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/278
2026-01-19 18:01:22 +09:00
8ef9de6a81 Merge pull request 'feat/infer_dev_260107' (#277) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/277
2026-01-19 17:56:16 +09:00
e5164c3fbc Merge pull request '[KC-116] shp 파일 다운로드 이력 추가' (#276) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/276
2026-01-19 17:42:31 +09:00
22c20389f4 Merge pull request 'feat/infer_dev_260107' (#275) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/275
2026-01-19 17:29:37 +09:00
e8cdce2bab Merge pull request '다운로드 호출 로그관리 작업' (#274) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/274
2026-01-19 17:12:09 +09:00
dea620afeb Merge pull request 'feat/infer_dev_260107' (#273) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/273
2026-01-19 16:27:18 +09:00
721f386f2e Merge pull request 'feat/infer_dev_260107' (#272) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/272
2026-01-19 15:19:36 +09:00
398831a855 Merge pull request '라벨링 어제 완료된 건 검수할당 스케줄링 + 라벨 저장 시 실시간 할당 추가' (#271) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/271
2026-01-19 14:41:50 +09:00
b88733daf8 Merge pull request '[KC-116] shp 파일 생성 기능 수정' (#270) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/270
2026-01-19 12:17:11 +09:00
1eb6cffd3e Merge pull request 'feat/infer_dev_260107' (#269) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/269
2026-01-19 12:09:28 +09:00
42c1c728bb Merge pull request '[KC-116] shp 파일 생성 기능 수정' (#268) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/268
2026-01-19 11:36:29 +09:00
7b18cf1912 Merge pull request '라벨링 툴 라벨러,검수자 저장 후 status 리턴하기' (#267) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/267
2026-01-19 11:32:48 +09:00
4786d59111 Merge pull request '[KC-116] shp 파일 생성 기능 수정' (#266) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/266
2026-01-19 10:49:18 +09:00
1ad2a4dc03 Merge pull request 'shp 파일 경로 수정' (#265) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/265
2026-01-19 10:20:38 +09:00
5b3d56112e Merge pull request 'shp 파일 생성 수정' (#264) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/264
2026-01-19 09:54:30 +09:00
937c3d0972 Merge pull request 'shp 파일 생성 수정' (#263) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/263
2026-01-16 18:24:17 +09:00
8d217e3fdf Merge pull request 'learn 테이블 uid 추가' (#262) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/262
2026-01-16 17:51:22 +09:00
af3b6968b2 Merge pull request 'feat/infer_dev_260107' (#261) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/261
2026-01-16 17:39:09 +09:00
1cbc698081 Merge pull request '라벨링 툴 상태 조건 수정, 검수 저장 로직 수정' (#260) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/260
2026-01-16 17:23:57 +09:00
1c7a72cbd1 Merge pull request 'feat/infer_dev_260107' (#259) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/259
2026-01-16 17:03:47 +09:00
4f52bd84bf Merge pull request '추론실행할때 회차 저장 제거' (#258) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/258
2026-01-16 17:00:04 +09:00
6286e2f9b6 Merge pull request '추론실행 shp파일 생성 jar' (#257) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/257
2026-01-16 16:56:40 +09:00
4a234fa6ce Merge pull request 'feat/infer_dev_260107' (#256) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/256
2026-01-16 15:56:51 +09:00
3fe5375e9d Merge pull request 'feat/infer_dev_260107' (#255) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/255
2026-01-16 15:43:57 +09:00
ac446bc3fc Merge pull request '추론종료 시 geom 데이터 넣기, geom-list 쿼리 수정' (#254) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/254
2026-01-16 15:08:29 +09:00
2ae333bb35 Merge pull request 'feat/infer_dev_260107' (#253) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/253
2026-01-16 14:33:42 +09:00
82107387a6 Merge pull request 'feat/infer_dev_260107' (#252) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/252
2026-01-16 11:46:57 +09:00
b9951bf741 Merge pull request 'spotless 적용' (#251) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/251
2026-01-16 09:57:20 +09:00
a7a226ff45 Merge pull request 'feat/infer_dev_260107' (#250) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/250
2026-01-16 09:56:09 +09:00
771cf01803 Merge pull request 'feat/infer_dev_260107' (#249) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/249
2026-01-16 09:53:42 +09:00
f8bb5d34f7 Merge pull request '[KC-99] 추론관리 분석결과 상세목록 uuid없을때 오류 메시지 변경' (#248) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/248
2026-01-16 09:49:51 +09:00
486657a6ab Merge pull request '[KC-103] 추론 실패 도엽별저장' (#247) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/247
2026-01-15 19:54:48 +09:00
1a87ea87d0 Merge pull request 'feat/infer_dev_260107' (#246) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/246
2026-01-15 18:56:52 +09:00
74a10de243 Merge pull request '[KC-99] 추론 완료 상세목록 수정' (#245) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/245
2026-01-15 18:41:14 +09:00
fc1849ed9c Merge pull request 'feat/infer_dev_260107' (#244) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/244
2026-01-15 17:53:53 +09:00
cd150220f5 Merge pull request 'feat/infer_dev_260107' (#243) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/243
2026-01-15 15:12:54 +09:00
4b5303bedf Merge pull request '[KC-99] 추론상세 stage 추가' (#242) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/242
2026-01-15 13:37:44 +09:00
a27d2834ce Merge pull request 'feat/infer_dev_260107' (#241) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/241
2026-01-15 12:39:11 +09:00
698c81a260 Merge pull request '[KC-99] 분석도엽 코드 추가' (#240) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/240
2026-01-15 11:32:14 +09:00
2733a866e9 Merge pull request '[KC-103] 결과 테이블 적용' (#239) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/239
2026-01-15 11:27:16 +09:00
a5b047abb0 Merge pull request '[KC-103] 결과 테이블 적용' (#238) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/238
2026-01-15 09:58:03 +09:00
5a229c965e Merge pull request '추론 실행 수정' (#237) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/237
2026-01-14 20:14:10 +09:00
b9e1c32c69 Merge pull request '추론 실행 수정' (#236) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/236
2026-01-14 19:50:02 +09:00
e926cec6d1 Merge pull request 'feat/infer_dev_260107' (#235) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/235
2026-01-14 19:40:35 +09:00
0e0fc0afef Merge pull request 'feat/infer_dev_260107' (#234) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/234
2026-01-14 18:16:57 +09:00
5c6231a6b4 Merge pull request 'feat/infer_dev_260107' (#233) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/233
2026-01-14 17:41:24 +09:00
494b3df0ca Merge pull request 'feat/infer_dev_260107' (#232) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/232
2026-01-14 17:26:02 +09:00
fd6507ce41 Merge pull request 'feat/infer_dev_260107' (#231) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/231
2026-01-14 17:03:22 +09:00
7b026a7376 Merge pull request 'feat/infer_dev_260107' (#230) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/230
2026-01-14 16:04:02 +09:00
3daf150d82 Merge pull request '[KC-103] 추론 실행 배치 수정' (#229) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/229
2026-01-14 15:26:23 +09:00
9eb06d2c2e Merge pull request 'feat/infer_dev_260107' (#228) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/228
2026-01-14 15:16:04 +09:00
b8258ec8f6 Merge pull request '[KC-103] 추론 실행 배치 수정' (#227) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/227
2026-01-13 15:58:27 +09:00
74cfe2edd0 Merge pull request 'feat/infer_dev_260107' (#226) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/226
2026-01-13 15:53:21 +09:00
fe2f4f5187 Merge pull request '[KC-103] 추론 실행 배치 수정' (#225) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/225
2026-01-13 15:12:49 +09:00
b4407037a5 Merge pull request 'feat/infer_dev_260107' (#224) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/224
2026-01-13 14:56:06 +09:00
4a3a156bdb Merge pull request '[KC-103] 추론 실행 배치 오류 수정' (#223) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/223
2026-01-13 14:41:52 +09:00
8d385a2fc7 Merge pull request 'feat/infer_dev_260107' (#222) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/222
2026-01-13 14:13:02 +09:00
503ce52623 Merge pull request '[KC-168] 라벨링 툴 > 목록, 기본 페이징 API 지정uuid 페이징 계산 추가' (#221) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/221
2026-01-13 14:08:39 +09:00
db077fd512 Merge pull request '[KC-99] 추론 진행여부 api 추가, spotless 적용' (#220) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/220
2026-01-13 13:58:27 +09:00
b36ccb48fa Merge pull request '[KC-168] 라벨링 툴 > 목록 - 기본 페이징 API 사이즈 수정' (#219) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/219
2026-01-13 13:34:49 +09:00
b6a8763d05 Merge pull request '[KC-168] 라벨링 툴 > 목록 - 기본 페이징 API' (#218) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/218
2026-01-13 13:30:20 +09:00
0c56b45684 Merge pull request 'feat/infer_dev_260107' (#217) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/217
2026-01-13 10:27:59 +09:00
683a645863 Merge pull request '[KC-108] 추론실행 파라미터 변경' (#216) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/216
2026-01-13 09:48:12 +09:00
e95131d75e Merge pull request '[KC-108] 추론실행 배치 오류 수정' (#215) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/215
2026-01-13 09:42:15 +09:00
4225923150 Merge pull request '[KC-108] 추론실행 파라미터 변경' (#214) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/214
2026-01-13 09:17:01 +09:00
054b13f95c Merge pull request '[KC-108] 추론실행 파라미터 변경' (#213) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/213
2026-01-12 23:17:55 +09:00
4de39adb93 Merge pull request '[KC-108] 추론실행 파라미터 변경' (#212) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/212
2026-01-12 23:12:15 +09:00
b03331a5a6 Merge pull request '[KC-108] ai api batch 작업중' (#211) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/211
2026-01-12 22:57:24 +09:00
d8ccf261ac Merge pull request '추론수정' (#210) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/210
2026-01-12 22:56:03 +09:00
b0217494bd Merge pull request 'feat/infer_dev_260107' (#209) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/209
2026-01-12 22:54:06 +09:00
d4e27de8e7 Merge pull request '[KC-108] ai api batch 작업중' (#208) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/208
2026-01-12 22:50:43 +09:00
6f7ca3001a Merge pull request 'feat/infer_dev_260107' (#207) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/207
2026-01-12 22:47:25 +09:00
e08d15c435 Merge pull request '라벨러 일자별 건수 쿼리 수정' (#206) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/206
2026-01-12 21:44:46 +09:00
f60872f3cf Merge pull request 'feat/infer_dev_260107' (#205) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/205
2026-01-12 21:27:58 +09:00
b1e136ac40 Merge pull request 'feat/infer_dev_260107' (#204) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/204
2026-01-12 21:09:55 +09:00
0af192d4fe Merge pull request 'feat/infer_dev_260107' (#203) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/203
2026-01-12 21:08:58 +09:00
749958314d Merge pull request 'spotless' (#202) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/202
2026-01-12 19:40:45 +09:00
4e7f5ffb94 Merge pull request 'feat/infer_dev_260107' (#201) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/201
2026-01-12 19:30:33 +09:00
b425fc1b77 Merge pull request '[KC-108] ai api 실행' (#200) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/200
2026-01-12 18:49:18 +09:00
1768cdccf0 Merge pull request '[KC-108] resttemplate 설정 변경' (#199) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/199
2026-01-12 18:21:41 +09:00
0a001ab827 Merge pull request '[KC-108] 분석도엽 ai api호출 테스트중' (#198) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/198
2026-01-12 18:11:54 +09:00
ceb29dcbc5 Merge pull request '[KC-108] 분석도엽 ai api호출 테스트중' (#197) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/197
2026-01-12 18:04:37 +09:00
13417887fe Merge pull request '[KC-108] 분석도엽 ai api호출 테스트중' (#196) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/196
2026-01-12 17:57:46 +09:00
51024d2ed8 Merge pull request '라벨링툴 상세 geom 리턴 형식 수정' (#195) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/195
2026-01-12 17:30:29 +09:00
5988cffe76 Merge pull request '[KC-108] 분석도엽 ai api호출 테스트중, 모델타입 조회 컬럼 추가' (#194) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/194
2026-01-12 16:59:49 +09:00
4c01c6803a Merge pull request '라벨링 저장 테이블 learn data 로 수정' (#193) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/193
2026-01-12 16:40:19 +09:00
d47f5ec5d4 Merge pull request '공통코드 url prefix 수정' (#192) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/192
2026-01-12 15:49:03 +09:00
ae43f2a9fa Merge pull request '라벨링 툴 API security 추가' (#191) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/191
2026-01-12 15:43:56 +09:00
88935675bb Merge pull request '기본 비밀번호 example 적용' (#190) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/190
2026-01-12 15:39:08 +09:00
e5f8636eb2 Merge pull request 'count 쿼리 workStatDttm 으로 수정' (#189) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/189
2026-01-12 14:47:41 +09:00
d67660f954 Merge pull request 'feat/infer_dev_260107' (#188) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/188
2026-01-12 14:43:25 +09:00
5b78b8380b Merge pull request '라벨링 툴 상세정보, 요약정보, 저장' (#187) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/187
2026-01-12 14:40:27 +09:00
870b46f62c Merge pull request '[KC-108] 분석도엽 ai api호출 테스트' (#186) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/186
2026-01-12 14:23:47 +09:00
5bdd7f4bb0 Merge pull request '[KC-108] 분석도엽 ai api호출 테스트' (#185) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/185
2026-01-12 14:09:35 +09:00
d57c2c2bcd Merge pull request '[KC-108] 분석도엽 ai api호출 테스트' (#184) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/184
2026-01-12 14:00:00 +09:00
3c1f6f2b61 Merge pull request '[KC-108] 분석도엽 ai api호출 테스트' (#183) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/183
2026-01-12 13:42:49 +09:00
6f5d8f5d77 Merge pull request '[KC-108] 분석도엽 추론제외 조건 수정, 모델관리수정' (#182) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/182
2026-01-12 12:21:01 +09:00
0de3d70697 Merge pull request '[KC-108] 상태 코드명 추가' (#181) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/181
2026-01-12 12:08:48 +09:00
ae985172b5 Merge pull request '[KC-168] 라벨링 툴 - 목록, 상세 API 나누기' (#180) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/180
2026-01-12 10:56:10 +09:00
52e2f6166b Merge pull request '[KC-108] 모델 조회 수정 id->uuid 변경' (#179) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/179
2026-01-12 09:52:37 +09:00
3cb32da912 Merge pull request '[KC-148] 라벨링 목록 - 진행율 퍼센트 2째자리까지만 + spotless' (#178) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/178
2026-01-12 09:49:48 +09:00
b97f734d96 Merge pull request 'feat/infer_dev_260107' (#177) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/177
2026-01-12 09:43:48 +09:00
b3e9a49297 Merge pull request '[KC-99] 추론관리 등록 수정, 모델 조회 추가' (#176) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/176
2026-01-09 17:52:17 +09:00
c64eddb7ed Merge pull request '라벨링 툴 라벨러 목록 상태 필터 추가' (#175) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/175
2026-01-09 17:51:14 +09:00
756b09d7ba Merge pull request '라벨링 툴 라벨러 목록에 polygon, cog 추가' (#174) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/174
2026-01-09 16:58:29 +09:00
fcc7c11125 Merge pull request '라벨러 detail 쿼리 수정' (#173) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/173
2026-01-09 16:31:07 +09:00
76752923de Merge pull request '[KC-99] 추론관리 등록 ai api 추가중, spotless 적용' (#172) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/172
2026-01-09 16:14:10 +09:00
85251c3172 Merge pull request 'api url 수정' (#171) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/171
2026-01-09 16:07:21 +09:00
3f5f5eb5e0 Merge pull request 'feat/infer_dev_260107' (#170) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/170
2026-01-09 16:04:09 +09:00
f14db3ea6b Merge pull request 'feat/infer_dev_260107' (#169) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/169
2026-01-09 12:07:16 +09:00
b8add0001e Merge pull request '[KC-148] 학습데이터 목록 API 항목 수정, 현황관리 상세 사용자 목록 API 수정' (#168) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/168
2026-01-09 11:49:35 +09:00
cbf23462f3 Merge pull request '[KC-99] 추론관리 등록 dto 변경' (#167) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/167
2026-01-09 11:34:53 +09:00
52c26bbae1 Merge pull request '[KC-99] 추론관리 등록 leran, 5k 테이블 저장 기능 추가' (#166) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/166
2026-01-09 11:29:36 +09:00
ab6d2f50e3 Merge pull request '[KC-99] 추론관리 등록 dto 수정' (#165) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/165
2026-01-09 11:24:12 +09:00
2ace4c7f55 Merge pull request 'feat/infer_dev_260107' (#164) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/164
2026-01-09 11:22:13 +09:00
6897f4a5de Merge pull request 'feat/infer_dev_260107' (#163) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/163
2026-01-09 09:51:07 +09:00
b52d5283c7 Merge pull request 'feat/infer_dev_260107' (#162) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/162
2026-01-09 09:41:19 +09:00
8ba4efcfce Merge pull request 'feat/infer_dev_260107' (#161) from feat/infer_dev_260107 into develop
Reviewed-on: https://kamco.gitea.gs.dabeeo.com/dabeeo/kamco-dabeeo-backoffice/pulls/161
2026-01-08 18:32:24 +09:00
96 changed files with 5875 additions and 1052 deletions

View File

@@ -0,0 +1,27 @@
package com.kamco.cd.kamcoback.common.enums;
import com.kamco.cd.kamcoback.common.utils.enums.CodeExpose;
import com.kamco.cd.kamcoback.common.utils.enums.EnumType;
import lombok.AllArgsConstructor;
import lombok.Getter;
@CodeExpose
@Getter
@AllArgsConstructor
public enum CrsType implements EnumType {
EPSG_3857("Web Mercator, 웹지도 미터(EPSG:900913 동일)"),
EPSG_4326("WGS84 위경도, GeoJSON/OSM 기본"),
EPSG_5186("Korea 2000 중부 TM, 한국 SHP");
private final String desc;
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
}

View File

@@ -0,0 +1,37 @@
package com.kamco.cd.kamcoback.common.enums;
import com.kamco.cd.kamcoback.common.utils.enums.CodeExpose;
import com.kamco.cd.kamcoback.common.utils.enums.EnumType;
import java.util.Optional;
import lombok.AllArgsConstructor;
import lombok.Getter;
@CodeExpose
@Getter
@AllArgsConstructor
public enum LayerType implements EnumType {
TILE("배경지도"),
GEOJSON("객체데이터"),
WMTS("타일레이어"),
WMS("지적도");
private final String desc;
@Override
public String getId() {
return name();
}
@Override
public String getText() {
return desc;
}
public static Optional<LayerType> from(String type) {
try {
return Optional.of(LayerType.valueOf(type));
} catch (Exception e) {
return Optional.empty();
}
}
}

View File

@@ -54,8 +54,8 @@ public class ExternalJarRunner {
public void run(String jarPath, String register, String layer) {
List<String> args = new ArrayList<>();
addArg(args, "register", register);
addArg(args, "layer", layer);
addArg(args, "upload-shp", register);
// addArg(args, "layer", layer);
execJar(jarPath, args);
}

View File

@@ -30,12 +30,14 @@ import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.gce.geotiff.GeoTiffReader;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.multipart.MultipartFile;
@Slf4j
public class FIleChecker {
static SimpleDateFormat dttmFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@@ -138,7 +140,9 @@ public class FIleChecker {
// null을 넣으면 전체 영역을 읽지 않고 메타데이터 위주로 체크하여 빠름
GridCoverage2D coverage = reader.read(null);
if (coverage == null) return false;
if (coverage == null) {
return false;
}
// 3. GIS 필수 정보(좌표계)가 있는지 확인
// if (coverage.getCoordinateReferenceSystem() == null) {
@@ -152,7 +156,9 @@ public class FIleChecker {
return false;
} finally {
// 리소스 해제 (필수)
if (reader != null) reader.dispose();
if (reader != null) {
reader.dispose();
}
}
}
@@ -296,7 +302,8 @@ public class FIleChecker {
boolean isValid =
!NameValidator.containsKorean(folderNm)
&& !NameValidator.containsWhitespaceRegex(folderNm);
&& !NameValidator.containsWhitespaceRegex(folderNm)
&& !parentFolderNm.equals("kamco-nfs");
File file = new File(fullPath);
int childCnt = getChildFolderCount(file);
@@ -586,7 +593,9 @@ public class FIleChecker {
}
public static boolean checkExtensions(String fileName, String ext) {
if (fileName == null) return false;
if (fileName == null) {
return false;
}
if (!fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase().equals(ext)) {
return false;
@@ -690,6 +699,7 @@ public class FIleChecker {
@Schema(name = "Folder", description = "폴더 정보")
@Getter
public static class Folder {
private final String folderNm;
private final String parentFolderNm;
private final String parentPath;

View File

@@ -5,11 +5,9 @@ import java.net.InetAddress;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
public class NetUtils {
@@ -56,9 +54,8 @@ public class NetUtils {
public HttpHeaders jsonHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(List.of(MediaType.APPLICATION_JSON));
headers.set(HttpHeaders.ACCEPT, "application/json;charset=UTF-8");
headers.set(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
return headers;
}
}

View File

@@ -465,8 +465,7 @@ public class GlobalExceptionHandler {
String stackTraceStr =
Arrays.stream(stackTrace)
.map(StackTraceElement::toString)
.collect(Collectors.joining("\n"))
.substring(0, 255);
.collect(Collectors.joining("\n"));
String actionType = HeaderUtil.get(request, "kamco-action-type");

View File

@@ -45,7 +45,8 @@ public class SecurityConfig {
auth ->
auth
// .requestMatchers("/chunk_upload_test.html").authenticated()
.requestMatchers("/monitor/health", "/monitor/health/**")
.permitAll()
// 맵시트 영역 전체 허용 (우선순위 최상단)
.requestMatchers("/api/mapsheet/**")
.permitAll()
@@ -84,7 +85,10 @@ public class SecurityConfig {
"/api/model/file-chunk-upload",
"/api/upload/file-chunk-upload",
"/api/upload/chunk-upload-complete",
"/api/change-detection/**")
"/api/change-detection/**",
"/api/layer/map/**",
"/api/layer/tile-url",
"/api/layer/tile-url-year")
.permitAll()
// 로그인한 사용자만 가능 IAM
.requestMatchers(

View File

@@ -1,72 +1,120 @@
package com.kamco.cd.kamcoback.config.resttemplate;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.charset.StandardCharsets;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestTemplate;
@RequiredArgsConstructor
@Component
@Log4j2
@RequiredArgsConstructor
public class ExternalHttpClient {
private final RestTemplate restTemplate;
private final ObjectMapper objectMapper;
public <T> ExternalCallResult<T> call(
String url, HttpMethod method, Object body, HttpHeaders headers, Class<T> responseType) {
HttpEntity<Object> entity = new HttpEntity<>(body, headers);
// responseType 기반으로 Accept 동적 세팅
HttpHeaders resolvedHeaders = resolveHeaders(headers, responseType);
logRequestBody(body);
// 요청 로그
log.info("[HTTP-REQ] {} {}", method, url);
if (body != null) {
log.debug("[HTTP-REQ-BODY] {}", body);
}
HttpEntity<Object> entity = new HttpEntity<>(body, resolvedHeaders);
try {
// String: raw bytes -> UTF-8 string
if (responseType == String.class) {
ResponseEntity<byte[]> res = restTemplate.exchange(url, method, entity, byte[].class);
String raw =
(res.getBody() == null) ? null : new String(res.getBody(), StandardCharsets.UTF_8);
@SuppressWarnings("unchecked")
T casted = (T) raw;
return new ExternalCallResult<>(res.getStatusCodeValue(), true, casted, null);
}
// byte[]: raw bytes로 받고, JSON이면 에러로 처리
if (responseType == byte[].class) {
ResponseEntity<byte[]> res = restTemplate.exchange(url, method, entity, byte[].class);
MediaType ct = res.getHeaders().getContentType();
byte[] bytes = res.getBody();
if (isJsonLike(ct)) {
String err = (bytes == null) ? null : new String(bytes, StandardCharsets.UTF_8);
return new ExternalCallResult<>(res.getStatusCodeValue(), false, null, err);
}
@SuppressWarnings("unchecked")
T casted = (T) bytes;
return new ExternalCallResult<>(res.getStatusCodeValue(), true, casted, null);
}
// DTO 등: 일반 역직렬화
ResponseEntity<T> res = restTemplate.exchange(url, method, entity, responseType);
return new ExternalCallResult<>(res.getStatusCodeValue(), true, res.getBody(), null);
int code = res.getStatusCodeValue();
// 응답 로그
log.info("[HTTP-RES] {} {} -> {}", method, url, code);
log.debug("[HTTP-RES-BODY] {}", res.getBody());
return new ExternalCallResult<>(code, code >= 200 && code < 300, res.getBody());
} catch (HttpClientErrorException.NotFound e) {
log.info("[HTTP-RES] {} {} -> 404 (Not Found)", method, url);
log.debug("[HTTP-RES-BODY] {}", e.getResponseBodyAsString());
return new ExternalCallResult<>(404, false, null);
} catch (HttpClientErrorException e) {
// 기타 4xx
log.warn(
"[HTTP-ERR] {} {} -> {} body={}",
method,
url,
e.getStatusCode().value(),
e.getResponseBodyAsString());
throw e;
} catch (HttpServerErrorException e) {
// 5xx
log.error(
"[HTTP-ERR] {} {} -> {} body={}",
method,
url,
e.getStatusCode().value(),
e.getResponseBodyAsString());
throw e;
} catch (HttpStatusCodeException e) {
return new ExternalCallResult<>(
e.getStatusCode().value(), false, null, e.getResponseBodyAsString());
}
}
public record ExternalCallResult<T>(int statusCode, boolean success, T body) {}
// 기존 resolveJsonHeaders를 "동적"으로 교체
private HttpHeaders resolveHeaders(HttpHeaders headers, Class<?> responseType) {
// 원본 headers를 그대로 쓰면 외부에서 재사용할 때 사이드이펙트 날 수 있어서 복사 권장
HttpHeaders h = (headers == null) ? new HttpHeaders() : new HttpHeaders(headers);
// 요청 바디 기본은 JSON이라고 가정 (필요하면 호출부에서 덮어쓰기)
if (h.getContentType() == null) {
h.setContentType(MediaType.APPLICATION_JSON);
}
// 호출부에서 Accept를 명시했으면 존중
if (h.getAccept() != null && !h.getAccept().isEmpty()) {
return h;
}
// responseType 기반 Accept 자동 지정
if (responseType == byte[].class) {
h.setAccept(
List.of(
MediaType.APPLICATION_OCTET_STREAM,
MediaType.valueOf("application/zip"),
MediaType.APPLICATION_JSON // 실패(JSON 에러 바디) 대비
));
} else {
h.setAccept(List.of(MediaType.APPLICATION_JSON));
}
return h;
}
private boolean isJsonLike(MediaType ct) {
if (ct == null) return false;
return ct.includes(MediaType.APPLICATION_JSON)
|| "application/problem+json".equalsIgnoreCase(ct.toString());
}
private void logRequestBody(Object body) {
try {
if (body != null) {
log.info("[HTTP-REQ-BODY-JSON] {}", objectMapper.writeValueAsString(body));
}
} catch (Exception e) {
log.warn("[HTTP-REQ-BODY-JSON] serialize failed: {}", e.getMessage());
}
}
public record ExternalCallResult<T>(int statusCode, boolean success, T body, String errBody) {}
}

View File

@@ -4,6 +4,7 @@ import lombok.extern.log4j.Log4j2;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@@ -13,10 +14,20 @@ public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
SimpleClientHttpRequestFactory f = new SimpleClientHttpRequestFactory();
f.setConnectTimeout(2000);
f.setReadTimeout(3000);
SimpleClientHttpRequestFactory baseFactory = new SimpleClientHttpRequestFactory();
baseFactory.setConnectTimeout(2000);
baseFactory.setReadTimeout(3000);
return builder.requestFactory(() -> f).additionalInterceptors(new RetryInterceptor()).build();
RestTemplate rt =
builder
.requestFactory(() -> new BufferingClientHttpRequestFactory(baseFactory))
.additionalInterceptors(new RetryInterceptor())
.build();
// byte[] 응답은 무조건 raw로 읽게 강제 (Jackson이 끼어들 여지 제거)
rt.getMessageConverters()
.add(0, new org.springframework.http.converter.ByteArrayHttpMessageConverter());
return rt;
}
}

View File

@@ -1,12 +1,15 @@
package com.kamco.cd.kamcoback.config.resttemplate;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
@Log4j2
public class RetryInterceptor implements ClientHttpRequestInterceptor {
private static final int MAX_RETRY = 3;
@@ -20,21 +23,25 @@ public class RetryInterceptor implements ClientHttpRequestInterceptor {
for (int attempt = 1; attempt <= MAX_RETRY; attempt++) {
try {
// HTTP 응답을 받으면(2xx/4xx/5xx 포함) 그대로 반환
return execution.execute(request, body);
log.info("[WIRE-REQ] {} {}", request.getMethod(), request.getURI());
log.info("[WIRE-REQ-HEADERS] {}", request.getHeaders());
log.info("[WIRE-REQ-BODY] {}", new String(body, StandardCharsets.UTF_8));
ClientHttpResponse response = execution.execute(request, body);
log.info("[WIRE-RES-STATUS] {}", response.getStatusCode());
return response;
} catch (IOException e) {
// 네트워크/타임아웃 등 I/O 예외만 재시도
lastException = e;
log.error("[WIRE-IO-ERR] attempt={} msg={}", attempt, e.getMessage(), e);
}
// 마지막 시도가 아니면 대기
if (attempt < MAX_RETRY) {
sleep();
}
}
// 마지막 예외를 그대로 던져서 원인이 로그에 남게 함
throw lastException;
}

View File

@@ -1,14 +1,21 @@
package com.kamco.cd.kamcoback.gukyuin;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ResponseObj;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.ChnDetectMastReqDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.ChngDetectMastSearchDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.ResReturn;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LabelSendDto;
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;
@@ -17,6 +24,7 @@ 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.time.LocalDate;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
@@ -35,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 = "탐지결과 등록")
@@ -50,10 +62,10 @@ public class GukYuinApiController {
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/mast/regist")
public ChngDetectMastDto.Basic regist(
@PostMapping("/chn/mast/regist")
public ApiResponseDto<ChngDetectMastDto.RegistResDto> regist(
@RequestBody @Valid ChngDetectMastDto.ChnDetectMastReqDto chnDetectMastReq) {
return gukYuinApiService.regist(chnDetectMastReq);
return ApiResponseDto.ok(gukYuinApiService.regist(chnDetectMastReq));
}
@Operation(summary = "탐지결과 삭제", description = "탐지결과 삭제")
@@ -69,14 +81,14 @@ public class GukYuinApiController {
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/mast/remove")
public ResReturn remove(
@PostMapping("/chn/mast/remove")
public ApiResponseDto<ChngDetectMastDto.RemoveResDto> remove(
@RequestBody @Valid ChngDetectMastDto.ChnDetectMastReqDto chnDetectMastReq) {
return gukYuinApiService.remove(chnDetectMastReq);
return ApiResponseDto.ok(gukYuinApiService.remove(chnDetectMastReq));
}
@Operation(summary = "탐지결과 등록목록 조회", description = "탐지결과 등록목록 조회")
@GetMapping("/mast/list")
@Operation(summary = "탐지결과 등록목록 조회(년도,차수 조회)", description = "탐지결과 등록목록 조회")
@GetMapping("/chn/mast")
@ApiResponses(
value = {
@ApiResponse(
@@ -89,17 +101,53 @@ public class GukYuinApiController {
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public List<ChngDetectMastDto.Basic> selectChangeDetectionList(
@RequestParam(required = false) String chnDtctId,
public ApiResponseDto<ChngDetectMastDto.ResultDto> selectChangeDetectionList(
@RequestParam(required = false) String cprsYr,
@RequestParam(required = false) String crtrYr,
@RequestParam(required = false) String chnDtctSno) {
ChngDetectMastSearchDto searchDto = new ChngDetectMastSearchDto();
searchDto.setChnDtctId(chnDtctId);
searchDto.setCprsYr(cprsYr);
searchDto.setCrtrYr(crtrYr);
searchDto.setChnDtctSno(chnDtctSno);
return gukYuinApiService.list(searchDto);
return ApiResponseDto.ok(gukYuinApiService.listYearStage(searchDto));
}
@Operation(summary = "탐지결과 등록목록 조회(회차uid)", description = "탐지결과 등록목록 조회")
@GetMapping("/chn/mast/{chnDtctId}")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "목록 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ApiResponseDto<ChngDetectMastDto.ResultDto> selectChangeDetectionDtctIdList(
@RequestParam(required = false) String chnDtctId) {
return ApiResponseDto.ok(gukYuinApiService.listChnDtctId(chnDtctId));
}
@Operation(summary = "탐지결과 등록목록 조회(1건 조회)", description = "탐지결과 등록목록 조회")
@GetMapping("/chn/mast/list/{chnDtctMstId}")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "목록 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ApiResponseDto<ChngDetectMastDto.ResultDto> selectChangeDetectionDetail(
@PathVariable String chnDtctMstId) {
return ApiResponseDto.ok(gukYuinApiService.detail(chnDtctMstId));
}
@Operation(summary = "국유in연동 가능여부 확인", description = "국유in연동 가능여부 확인")
@@ -125,4 +173,193 @@ public class GukYuinApiController {
UUID uuid) {
return ApiResponseDto.ok(gukYuinApiService.getIsLinkGukYuin(uuid));
}
@Operation(summary = "탐지객체 조회 (탐지객체)", description = "탐지객체 조회 (탐지객체)")
@GetMapping("/chn/cont/{chnDtctId}")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "목록 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ApiResponseDto<ChngDetectContDto.ResultContDto> findChnContList(
@PathVariable String chnDtctId,
@RequestParam(defaultValue = "0") Integer pageIndex,
@RequestParam(defaultValue = "10") Integer pageSize) {
return ApiResponseDto.ok(gukYuinApiService.findChnContList(chnDtctId, pageIndex, pageSize));
}
@Operation(summary = "탐지객체 조회 (탐지객체 1건 조회)", description = "탐지객체 조회 (탐지객체 1건 조회)")
@GetMapping("/chn/cont/{chnDtctId}/objt/{chnDtctObjtId}")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "목록 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ApiResponseDto<ChngDetectContDto.ResultContDto> findChnPnuToContObject(
@PathVariable String chnDtctId,
@PathVariable String chnDtctObjtId,
@RequestParam(defaultValue = "0") Integer pageIndex,
@RequestParam(defaultValue = "10") Integer pageSize) {
return ApiResponseDto.ok(
gukYuinApiService.findChnPnuToContObject(chnDtctId, chnDtctObjtId, pageIndex, pageSize));
}
@Operation(summary = "탐지객체 조회 (PNU에 해당하는 탐지객체)", description = "탐지객체 조회 (PNU에 해당하는 탐지객체)")
@GetMapping("/chn/cont/{chnDtctId}/pnu/{pnu}")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "목록 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ApiResponseDto<ChngDetectContDto.ResultContDto> findChnPnuToContList(
@PathVariable String chnDtctId, @PathVariable String pnu) {
return ApiResponseDto.ok(gukYuinApiService.findChnPnuToContList(chnDtctId, pnu));
}
@Operation(summary = "탐지객체 조회 (탐지객체와 교차하는 PNU)", description = "탐지객체 조회 (탐지객체와 교차하는 PNU)")
@GetMapping("/chn/pnu/{chnDtctId}/objt/{chnDtctObjtId}")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "목록 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ApiResponseDto<ChngDetectContDto.ResultPnuDto> findPnuObjMgmtList(
@PathVariable String chnDtctId, @PathVariable String chnDtctObjtId) {
return ApiResponseDto.ok(gukYuinApiService.findPnuObjMgmtList(chnDtctId, chnDtctObjtId));
}
@Operation(summary = "라벨여부 수정", description = "라벨여부 수정")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "201",
description = "등록 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = DetectMastReq.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/rlb/objt/{chnDtctObjtId}/lbl/{lblYn}")
public ApiResponseDto<ChngDetectContDto.ResultLabelDto> updateChnDtctObjtLabelingYn(
@PathVariable String chnDtctObjtId, @PathVariable String lblYn) {
return ApiResponseDto.ok(gukYuinApiService.updateChnDtctObjtLabelingYn(chnDtctObjtId, lblYn));
}
@Operation(summary = "국유in연동 등록", description = "국유in연동 등록")
@PostMapping("/mast/reg/{uuid}")
public ApiResponseDto<ResponseObj> connectChnMastRegist(
@Parameter(description = "uuid", example = "7a593d0e-76a8-4b50-8978-9af1fbe871af")
@PathVariable
UUID uuid) {
return ApiResponseDto.okObject(gukYuinApiService.connectChnMastRegist(uuid));
}
@Operation(summary = "라벨 전송 완료 리스트", description = "라벨 전송 완료 리스트")
@GetMapping("/label/send-list")
public ApiResponseDto<List<LabelSendDto>> findLabelingCompleteSendList(
@Parameter(description = "어제 날짜", example = "2026-01-29") LocalDate yesterday) {
return ApiResponseDto.ok(gukYuinApiService.findLabelingCompleteSendList(yesterday));
}
@Operation(summary = "탐지객체 적합여부 조회 (리스트조회)", description = "탐지객체 적합여부 조회 (리스트조회)")
@GetMapping("/rlb/dtct/{chnDtctId}")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "목록 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ApiResponseDto<ChngDetectMastDto.RlbDtctDto> findRlbDtctList(
@PathVariable String chnDtctId,
@Parameter(description = "날짜(기본은 어제 날짜)") @RequestParam(defaultValue = "20260205")
String yyyymmdd) {
return ApiResponseDto.ok(gukYuinApiService.findRlbDtctList(chnDtctId, yyyymmdd));
}
@Operation(summary = "탐지객체 적합여부 조회 (객체별 조회)", description = "탐지객체 적합여부 조회 (객체별 조회)")
@GetMapping("/rlb/objt/{chnDtctObjtId}")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "목록 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
public ApiResponseDto<ChngDetectMastDto.RlbDtctDto> findRlbDtctObject(
@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

@@ -0,0 +1,140 @@
package com.kamco.cd.kamcoback.gukyuin.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
public class ChngDetectContDto {
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class ContBasic {
private String chnDtctMstId; // 탐지콘텐츠아이디
private String chnDtctContId; // 탐지마스타아이디
private String cprsYr; // 비교년도 2023
private String crtrYr; // 기준년도 2024
private String chnDtctSno; // 차수 (1 | 2 | ...)
private String mpqdNo; // 도엽번호
private String chnDtctId; // 탐지아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성
private String chnDtctObjtId; // 탐지객체아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성
private String chnDtctPolygon; // 탐지객체폴리곤
private String chnDtctSqms; // 탐지객체면적
private String chnCd; // 변화코드
private String chnDtctJson; // 변화탐지JSON
private String chnDtctProb; // 변화탐지정확도
private String bfClsCd; // 이전부류코드
private String bfClsProb; // 이전분류정확도
private String afClsCd; // 이후분류코드
private String afClsProb; // 이후분류정확도
private String crtDt; // 생성일시
private String crtEpno; // 생성사원번호
private String crtIp; // 생성사원아이피
private String delYn; // 삭제여부
private String[] pnuList; // pnuList
private String reqEpno; // 요청사원번호
private String reqIp; // 요청사원아이피
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class ChnDetectContReqDto {
private String cprsYr; // 비교년도 2023
private String crtrYr; // 기준년도 2024
private String chnDtctSno; // 차수 (1 | 2 | ...)
private String mpqdNo; // 도엽번호
private String chnDtctId; // 탐지아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성
private String chnDtctObjtId; // 탐지객체아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성
private String reqEpno; // 사원번호
private String reqIp;
}
@Schema(name = "ResReturn", description = "수행 후 리턴")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class ResReturn {
private String flag;
private String message;
}
@Schema(name = "ResultContDto", description = "cont list 리턴 형태")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class ResultContDto {
private Integer code;
private String message;
private List<ContBasic> result;
private Boolean success;
}
@Schema(name = "DtoPnuDetectMpng", description = "PNU 결과 형태")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class DtoPnuDetectMpng {
private String pnuDtctId;
private String lrmYmd;
private String pnu;
private String pnuSqms;
private String pnuDtctSqms;
private String chnDtctSqms;
private String chnDtctMstId;
private String chnDtctContId;
private String chnDtctId;
private String chnDtctObjtId;
private String crtDt;
}
@Schema(name = "ResultPnuDto", description = "pnu list 리턴 형태")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class ResultPnuDto {
private Integer code;
private String message;
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;
}
}

View File

@@ -1,6 +1,7 @@
package com.kamco.cd.kamcoback.gukyuin.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.ZonedDateTime;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -66,13 +67,30 @@ public class ChngDetectMastDto {
@AllArgsConstructor
public static class ChnDetectMastReqDto {
private String cprsYr; // 비교년도 2023
private String crtrYr; // 기준년도 2024
private String chnDtctSno; // 차수 (1 | 2 | ...)
private String chnDtctId; // 탐지아이디. UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성
private String pathNm; // 탐지결과 절대경로명 /kamco_nas/export/{chnDtctId}
private String reqEpno; // 사원번호
private String reqIp; // 사원아이피
@Schema(description = "비교년도", example = "2023")
private String cprsYr;
@Schema(description = "기준년도", example = "2024")
private String crtrYr;
@Schema(description = "차수", example = "1")
private String chnDtctSno;
@Schema(
description = "탐지아이디, UUID를 기반으로 '-'를 제거하고 대문자/숫자로 구성",
example = "D5F192EC76D34F6592035BE63A84F591")
private String chnDtctId;
@Schema(
description = "탐지결과 절대경로명 /kamco_nas/export/{chnDtctId}",
example = "/kamco-nfs/dataset/export/D5F192EC76D34F6592035BE63A84F591")
private String pathNm;
@Schema(description = "사원번호", example = "123456")
private String reqEpno;
@Schema(description = "사원아이피", example = "127.0.0.1")
private String reqIp;
}
@Getter
@@ -129,7 +147,7 @@ public class ChngDetectMastDto {
@AllArgsConstructor
public static class ChngDetectMastSearchDto {
private String chnDtctId;
// private String chnDtctId;
private String cprsYr;
private String crtrYr;
private String chnDtctSno;
@@ -145,4 +163,142 @@ public class ChngDetectMastDto {
private String flag;
private String message;
}
@Schema(name = "ResultDto", description = "mast list 리턴 형태")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class ResultDto {
private Integer code;
private String message;
private List<Basic> result;
private Boolean success;
}
@Schema(name = "RegistResDto", description = "reg 등록 후 리턴 형태")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class RegistResDto {
private Integer code;
private String message;
private Basic result;
private Boolean success;
}
@Schema(name = "LearnKeyDto", description = "learn 엔티티 key 정보")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class LearnKeyDto {
private Long id;
private String uid;
private String chnDtctMstId;
}
@Schema(name = "LabelSendDto", description = "라벨링 전송한 목록")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class LabelSendDto {
private String chnDtctObjtId;
private String labelerId;
private ZonedDateTime labelerWorkDttm;
private String reviewerId;
private ZonedDateTime reviewerWorkDttm;
private ZonedDateTime labelSendDttm;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class ErrorResDto {
private String timestamp;
private Integer status;
private String error;
private String path;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class RlbDtctDto {
private Integer code;
private String message;
private List<RlbDtctMastDto> result;
private Boolean success;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class RlbDtctMastDto {
private String pnuDtctId;
private String pnu;
private String lrmSyncYmd;
private String pnuSyncYmd;
private String mpqdNo; // 도엽번호
private String cprsYr; // 비교년도
private String crtrYr; // 기준년도
private String chnDtctSno; // 회차
private String chnDtctId;
private String chnDtctMstId;
private String chnDtctObjtId;
private String chnDtctContId;
private String chnCd;
private String chnDtctProb;
private String bfClsCd; // 이전분류코드
private String bfClsProb; // 이전분류정확도
private String afClsCd; // 이후분류코드
private String afClsProb; // 이후분류정확도
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 crtDt; // 생성일시
private String crtEpno; // 생성사원번호
private String crtIp; // 생성사원아이피
private String chgDt;
private String chgEpno;
private String chgIp;
private String delYn; // 삭제여부
}
@Schema(name = "RemoveResDto", description = "remove 후 리턴 형태")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class RemoveResDto {
private Integer code;
private String message;
private Boolean result;
private Boolean success;
}
}

View File

@@ -1,21 +1,13 @@
package com.kamco.cd.kamcoback.gukyuin.dto;
import com.kamco.cd.kamcoback.common.utils.enums.EnumType;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
public class GukYuinDto {
@Getter
@Setter
public static class GukYuinLinkableRes {
private boolean linkable;
// private GukYuinLinkFailCode code;
private String message;
}
/** 실패 코드 enum */
@Getter
@AllArgsConstructor
@@ -39,10 +31,47 @@ public class GukYuinDto {
}
}
@Getter
@Setter
public static class GukYuinLinkableRes {
private boolean linkable;
// private GukYuinLinkFailCode code;
private String message;
}
// Repository가 반환할 Fact(조회 결과)
public record GukYuinLinkFacts(
boolean existsLearn,
boolean isPartScope,
boolean hasRunningInference,
boolean hasOtherUnfinishedGukYuin) {}
@Getter
@Setter
@AllArgsConstructor
public static class LearnInfo {
private Long id;
private UUID uuid;
private Integer compareYyyy;
private Integer targetYyyy;
private Integer stage;
private String uid;
private String applyStatus;
private Boolean applyYn;
public Boolean getApplyYn() {
return this.applyYn != null && this.applyYn;
}
}
@Getter
@Setter
@AllArgsConstructor
public static class GeomUidDto {
private Long geoUid;
private String resultUid;
}
}

View File

@@ -8,8 +8,12 @@ import lombok.Getter;
@AllArgsConstructor
public enum GukYuinStatus implements EnumType {
PENDING("대기"),
IN_PROGRESS("사용"),
COMPLETED("완료");
IN_PROGRESS("진행중"),
GUK_COMPLETED("국유인 매핑 완료"),
PNU_COMPLETED("PNU 싱크 완료"),
PNU_FAILED("PNU 싱크 중 에러"),
END("종료"),
CANCELED("취소");
private final String desc;

View File

@@ -1,99 +1,223 @@
package com.kamco.cd.kamcoback.gukyuin.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kamco.cd.kamcoback.common.utils.NetUtils;
import com.kamco.cd.kamcoback.common.utils.UserUtil;
import com.kamco.cd.kamcoback.config.api.ApiLogFunction;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ResponseObj;
import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient;
import com.kamco.cd.kamcoback.config.resttemplate.ExternalHttpClient.ExternalCallResult;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto.ContBasic;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto.ReqInfo;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto.ResultContDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto.ResultPnuDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.ResReturn;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.ChnDetectMastReqDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.ErrorResDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LabelSendDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.ResultDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.RlbDtctDto;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkFacts;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkFailCode;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkableRes;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.LearnInfo;
import com.kamco.cd.kamcoback.log.dto.EventStatus;
import com.kamco.cd.kamcoback.log.dto.EventType;
import com.kamco.cd.kamcoback.postgres.core.GukYuinCoreService;
import java.util.ArrayList;
import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity;
import com.kamco.cd.kamcoback.postgres.repository.log.AuditLogRepository;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Slf4j
@Service
@Transactional(readOnly = true)
@Transactional
@RequiredArgsConstructor
public class GukYuinApiService {
private final GukYuinCoreService gukyuinCoreService;
private final ExternalHttpClient externalHttpClient;
private final NetUtils netUtils = new NetUtils();
private final UserUtil userUtil;
private final AuditLogRepository auditLogRepository;
private final ObjectMapper objectMapper;
private final String myip = netUtils.getLocalIP();
@Value("${spring.profiles.active:local}")
private String profile;
@Value("${gukyuin.url}")
private String gukyuinUrl;
@Value("${gukyuin.mast}")
private String gukyuinMastUrl;
@Value("${gukyuin.cdi}")
private String gukyuinCdiUrl;
private final GukYuinCoreService gukyuinCoreService;
private final ExternalHttpClient externalHttpClient;
private final NetUtils netUtils = new NetUtils();
@Value("${file.dataset-dir}")
private String datasetDir;
@Transactional
public ChngDetectMastDto.Basic regist(ChngDetectMastDto.ChnDetectMastReqDto chnDetectMastReq) {
public ChngDetectMastDto.RegistResDto regist(
ChngDetectMastDto.ChnDetectMastReqDto chnDetectMastReq) {
ChngDetectMastDto.Basic basic = new ChngDetectMastDto.Basic();
String url = gukyuinCdiUrl + "/chn/mast/regist";
String url = gukyuinMastUrl + "/regist";
// url = "http://localhost:8080/api/kcd/cdi/detect/mast/regist";
String myip = netUtils.getLocalIP();
chnDetectMastReq.setReqIp(myip);
chnDetectMastReq.setReqEpno(userUtil.getEmployeeNo());
System.out.println("url == " + url);
System.out.println("url == " + myip);
ExternalCallResult<String> result =
ExternalCallResult<ChngDetectMastDto.RegistResDto> result =
externalHttpClient.call(
url, HttpMethod.POST, chnDetectMastReq, netUtils.jsonHeaders(), String.class);
url,
HttpMethod.POST,
chnDetectMastReq,
netUtils.jsonHeaders(),
ChngDetectMastDto.RegistResDto.class);
System.out.println("result == " + result);
ChngDetectMastDto.RegistResDto resultBody = result.body();
boolean success = false;
if (resultBody != null && resultBody.getSuccess() != null) {
ChngDetectMastDto.Basic registRes = resultBody.getResult();
return basic;
success = resultBody.getSuccess();
// 이미 등록한 경우에는 result가 없음
if (resultBody.getResult() == null) {
return resultBody;
}
// 추론 회차에 applyStatus, applyStatusDttm 업데이트
gukyuinCoreService.updateGukYuinMastRegResult(registRes);
// anal_inference 에도 국유인 반영여부, applyDttm 업데이트
gukyuinCoreService.updateAnalInferenceApplyDttm(registRes);
} else {
String errBody = result.errBody();
ErrorResDto error = null;
try {
error = objectMapper.readValue(errBody, ErrorResDto.class);
return new ChngDetectMastDto.RegistResDto(error.getStatus(), error.getError(), null, false);
} catch (JsonProcessingException e) {
log.error("에러 응답 파싱 실패. rawBody={}", errBody, e);
return new ChngDetectMastDto.RegistResDto(
result.statusCode(), // HTTP status
errBody, // 원문 그대로
null,
false);
}
}
this.insertGukyuinAuditLog(
EventType.ADDED.getId(),
myip,
userUtil.getId(),
url.replace(gukyuinUrl, ""),
chnDetectMastReq,
success);
return resultBody;
}
@Transactional
public ResReturn remove(ChngDetectMastDto.ChnDetectMastReqDto chnDetectMastReq) {
ChngDetectMastDto.Basic basic = new ChngDetectMastDto.Basic();
public ChngDetectMastDto.RemoveResDto remove(
ChngDetectMastDto.ChnDetectMastReqDto chnDetectMastReq) {
String url = gukyuinCdiUrl + "/chn/mast/remove";
String url = gukyuinMastUrl + "/remove";
// url = "http://localhost:8080/api/kcd/cdi/detect/mast/remove";
String myip = netUtils.getLocalIP();
chnDetectMastReq.setReqIp(myip);
chnDetectMastReq.setReqEpno(userUtil.getEmployeeNo());
System.out.println("url == " + url);
System.out.println("url == " + myip);
ExternalCallResult<String> result =
boolean success = false;
ExternalCallResult<ChngDetectMastDto.RemoveResDto> result =
externalHttpClient.call(
url, HttpMethod.POST, chnDetectMastReq, netUtils.jsonHeaders(), String.class);
url,
HttpMethod.POST,
chnDetectMastReq,
netUtils.jsonHeaders(),
ChngDetectMastDto.RemoveResDto.class);
System.out.println("result == " + result);
ChngDetectMastDto.RemoveResDto resultBody = result.body();
if (resultBody != null && resultBody.getSuccess() != null) {
return new ResReturn("success", "탐지결과 삭제 되었습니다.");
success = resultBody.getSuccess();
if (resultBody.getSuccess()) {
gukyuinCoreService.updateGukYuinMastRegRemove(chnDetectMastReq.getChnDtctId());
}
}
@Transactional
public List<ChngDetectMastDto.Basic> list(ChngDetectMastDto.ChngDetectMastSearchDto searchDto) {
List<ChngDetectMastDto.Basic> masterList = new ArrayList<>();
this.insertGukyuinAuditLog(
EventType.REMOVE.getId(),
myip,
userUtil.getId(),
url.replace(gukyuinUrl, ""),
chnDetectMastReq,
success);
return resultBody;
}
// 등록목록 1개 확인
public ChngDetectMastDto.ResultDto detail(String chnDtctMstId) {
String url =
gukyuinCdiUrl
+ "/chn/mast/list/"
+ chnDtctMstId
+ "?reqIp="
+ myip
+ "&reqEpno="
+ userUtil.getEmployeeNo();
ExternalCallResult<ChngDetectMastDto.ResultDto> result =
externalHttpClient.call(
url, HttpMethod.GET, null, netUtils.jsonHeaders(), ChngDetectMastDto.ResultDto.class);
this.insertGukyuinAuditLog(
EventType.DETAIL.getId(),
netUtils.getLocalIP(),
userUtil.getId(),
url.replace(gukyuinUrl, ""),
null,
result.body().getSuccess());
return result.body();
}
// 등록목록 비교년도,기준년도,차수 조합해서 n개 확인
public ChngDetectMastDto.ResultDto listYearStage(
ChngDetectMastDto.ChngDetectMastSearchDto searchDto) {
String queryString = netUtils.dtoToQueryString(searchDto, null);
String url = gukyuinMastUrl + queryString;
String url =
gukyuinCdiUrl
+ "/chn/mast"
+ queryString
+ "&reqIp="
+ myip
+ "&reqEpno="
+ userUtil.getEmployeeNo();
ExternalCallResult<String> result =
externalHttpClient.call(url, HttpMethod.GET, null, netUtils.jsonHeaders(), String.class);
ExternalCallResult<ChngDetectMastDto.ResultDto> result =
externalHttpClient.call(
url, HttpMethod.GET, null, netUtils.jsonHeaders(), ChngDetectMastDto.ResultDto.class);
System.out.println("list result == " + result);
return masterList;
this.insertGukyuinAuditLog(
EventType.LIST.getId(),
netUtils.getLocalIP(),
userUtil.getId(),
url.replace(gukyuinUrl, ""),
null,
result.body().getSuccess());
return result.body();
}
/**
@@ -133,4 +257,325 @@ public class GukYuinApiService {
return GukYuinLinkFailCode.OK;
}
// 탐지객체 리스트 조회
public ResultContDto findChnContList(String chnDtctId, Integer pageIndex, Integer pageSize) {
String url =
gukyuinCdiUrl
+ "/chn/cont/"
+ chnDtctId
+ "?pageIndex="
+ pageIndex
+ "&pageSize="
+ pageSize
+ "&reqIp="
+ myip
+ "&reqEpno="
+ userUtil.getEmployeeNo();
ExternalCallResult<ChngDetectContDto.ResultContDto> result =
externalHttpClient.call(
url,
HttpMethod.GET,
null,
netUtils.jsonHeaders(),
ChngDetectContDto.ResultContDto.class);
List<ContBasic> contList = result.body().getResult();
if (contList == null || contList.isEmpty()) {
return new ResultContDto(
result.body().getCode(),
result.body().getMessage(),
result.body().getResult(),
result.body().getSuccess());
}
this.insertGukyuinAuditLog(
EventType.LIST.getId(),
netUtils.getLocalIP(),
userUtil.getId(),
url.replace(gukyuinUrl, ""),
null,
result.body().getSuccess());
return result.body();
}
public ResultPnuDto findPnuObjMgmtList(String chnDtctId, String chnDtctObjtId) {
String url =
gukyuinCdiUrl
+ "/chn/pnu/"
+ chnDtctId
+ "/objt/"
+ chnDtctObjtId
+ "?reqIp="
+ myip
+ "&reqEpno="
+ userUtil.getEmployeeNo();
ExternalCallResult<ChngDetectContDto.ResultPnuDto> result =
externalHttpClient.call(
url,
HttpMethod.GET,
null,
netUtils.jsonHeaders(),
ChngDetectContDto.ResultPnuDto.class);
this.insertGukyuinAuditLog(
EventType.DETAIL.getId(),
netUtils.getLocalIP(),
userUtil.getId(),
url.replace(gukyuinUrl, ""),
null,
result.body().getSuccess());
return result.body();
}
public ChngDetectContDto.ResultLabelDto updateChnDtctObjtLabelingYn(
String chnDtctObjtId, String lblYn) {
String url = gukyuinCdiUrl + "/rlb/objt/" + chnDtctObjtId + "/lbl/" + lblYn;
ReqInfo info = new ReqInfo();
info.setReqIp(myip);
info.setReqEpno(userUtil.getEmployeeNo());
ExternalCallResult<ChngDetectContDto.ResultLabelDto> result =
externalHttpClient.call(
url,
HttpMethod.POST,
info,
netUtils.jsonHeaders(),
ChngDetectContDto.ResultLabelDto.class);
this.insertGukyuinAuditLog(
EventType.MODIFIED.getId(),
netUtils.getLocalIP(),
userUtil.getId(),
url.replace(gukyuinUrl, ""),
null,
result.body().getSuccess());
return result.body();
}
public ResultContDto findChnPnuToContList(String chnDtctId, String pnu) {
String url =
gukyuinCdiUrl
+ "/chn/cont/"
+ chnDtctId
+ "/pnu/"
+ pnu
+ "?reqIp="
+ myip
+ "&reqEpno="
+ userUtil.getEmployeeNo();
ExternalCallResult<ChngDetectContDto.ResultContDto> result =
externalHttpClient.call(
url,
HttpMethod.GET,
null,
netUtils.jsonHeaders(),
ChngDetectContDto.ResultContDto.class);
this.insertGukyuinAuditLog(
EventType.LIST.getId(),
netUtils.getLocalIP(),
userUtil.getId(),
url.replace(gukyuinUrl, ""),
null,
result.body().getSuccess());
return result.body();
}
public ResultDto listChnDtctId(String chnDtctId) {
String url =
gukyuinCdiUrl
+ "/chn/mast/"
+ chnDtctId
+ "?reqIp="
+ myip
+ "&reqEpno="
+ userUtil.getEmployeeNo();
ExternalCallResult<ChngDetectMastDto.ResultDto> result =
externalHttpClient.call(
url, HttpMethod.GET, null, netUtils.jsonHeaders(), ChngDetectMastDto.ResultDto.class);
this.insertGukyuinAuditLog(
EventType.DETAIL.getId(),
netUtils.getLocalIP(),
userUtil.getId(),
url.replace(gukyuinUrl, ""),
null,
result.body().getSuccess());
return result.body();
}
@Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = false)
public void insertGukyuinAuditLog(
String actionType,
String myIp,
Long userUid,
String requestUri,
Object requestBody,
boolean successFail) {
try {
AuditLogEntity log =
new AuditLogEntity(
userUid,
EventType.fromName(actionType),
successFail ? EventStatus.SUCCESS : EventStatus.FAILED,
"GUKYUIN", // 메뉴도 국유인으로 하나 따기
myIp,
requestUri,
requestBody == null ? null : ApiLogFunction.cutRequestBody(requestBody.toString()),
null,
null,
null);
auditLogRepository.save(log);
} catch (Exception e) {
log.error(e.getMessage());
throw e;
}
}
public ResponseObj connectChnMastRegist(UUID uuid) {
// uuid로 추론 회차 조회
LearnInfo info = gukyuinCoreService.findMapSheetLearnInfo(uuid);
if (info.getApplyYn() != null && info.getApplyYn()) {
return new ResponseObj(ApiResponseCode.DUPLICATE_DATA, "이미 국유인 연동을 한 회차입니다.");
}
// 비교년도,기준년도로 전송한 데이터 있는지 확인 후 회차 번호 생성
Integer maxStage =
gukyuinCoreService.findMapSheetLearnYearStage(info.getCompareYyyy(), info.getTargetYyyy());
// 1회차를 종료 상태로 처리하고 2회차를 보내야 함
// 추론(learn), 학습데이터(inference) 둘 다 종료 처리
if (maxStage > 0) {
Long learnId =
gukyuinCoreService.findMapSheetLearnInfoByYyyy(
info.getCompareYyyy(), info.getTargetYyyy(), maxStage);
gukyuinCoreService.updateMapSheetLearnGukyuinEndStatus(learnId);
gukyuinCoreService.updateMapSheetInferenceLabelEndStatus(learnId);
}
// reqDto 셋팅
ChnDetectMastReqDto reqDto = new ChnDetectMastReqDto();
reqDto.setCprsYr(String.valueOf(info.getCompareYyyy()));
reqDto.setCrtrYr(String.valueOf(info.getTargetYyyy()));
reqDto.setChnDtctSno(String.valueOf(maxStage + 1));
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, "파일 경로에 회차 실행 파일이 생성되지 않았습니다. 확인 부탁드립니다.");
}
// 국유인 /chn/mast/regist 전송
ChngDetectMastDto.RegistResDto result = this.regist(reqDto);
if (result.getSuccess()) {
return new ResponseObj(ApiResponseCode.OK, "연동되었습니다.");
} else {
return new ResponseObj(ApiResponseCode.INTERNAL_SERVER_ERROR, result.getMessage());
}
}
public List<LabelSendDto> findLabelingCompleteSendList(LocalDate yesterday) {
return gukyuinCoreService.findLabelingCompleteSendList(yesterday);
}
public ResultContDto findChnPnuToContObject(
String chnDtctId, String chnDtctObjtId, Integer pageIndex, Integer pageSize) {
String url =
gukyuinCdiUrl
+ "/chn/cont/"
+ chnDtctId
+ "/chnDtctObjtId/"
+ chnDtctObjtId
+ "?pageIndex="
+ pageIndex
+ "&pageSize="
+ pageSize
+ "&reqIp="
+ myip
+ "&reqEpno="
+ userUtil.getEmployeeNo();
ExternalCallResult<ChngDetectContDto.ResultContDto> result =
externalHttpClient.call(
url,
HttpMethod.GET,
null,
netUtils.jsonHeaders(),
ChngDetectContDto.ResultContDto.class);
this.insertGukyuinAuditLog(
EventType.DETAIL.getId(),
netUtils.getLocalIP(),
userUtil.getId(),
url.replace(gukyuinUrl, ""),
null,
result.body() != null && result.body().getSuccess());
return result.body();
}
public ChngDetectMastDto.RlbDtctDto findRlbDtctList(String chnDtctId, String yyyymmdd) {
String url =
gukyuinCdiUrl
+ "/rlb/dtct/"
+ chnDtctId
+ "?reqIp="
+ myip
+ "&reqEpno="
+ userUtil.getEmployeeNo()
+ "&yyyymmdd="
+ yyyymmdd;
ExternalCallResult<ChngDetectMastDto.RlbDtctDto> result =
externalHttpClient.call(
url, HttpMethod.GET, null, netUtils.jsonHeaders(), ChngDetectMastDto.RlbDtctDto.class);
this.insertGukyuinAuditLog(
EventType.LIST.getId(),
netUtils.getLocalIP(),
userUtil.getId(),
url.replace(gukyuinUrl, ""),
null,
result.body() != null && result.body().getSuccess());
return result.body();
}
public RlbDtctDto findRlbDtctObject(String chnDtctObjtId) {
String url =
gukyuinCdiUrl
+ "/rlb/objt/"
+ chnDtctObjtId
+ "?reqIp="
+ myip
+ "&reqEpno="
+ userUtil.getEmployeeNo();
ExternalCallResult<ChngDetectMastDto.RlbDtctDto> result =
externalHttpClient.call(
url, HttpMethod.GET, null, netUtils.jsonHeaders(), ChngDetectMastDto.RlbDtctDto.class);
this.insertGukyuinAuditLog(
EventType.DETAIL.getId(),
netUtils.getLocalIP(),
userUtil.getId(),
url.replace(gukyuinUrl, ""),
null,
result.body() != null && result.body().getSuccess());
return result.body();
}
}

View File

@@ -1,5 +1,7 @@
package com.kamco.cd.kamcoback.inference;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.common.geometry.GeoJsonFileWriter.Scene;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultShpDto;
import com.kamco.cd.kamcoback.inference.service.InferenceResultShpService;
@@ -10,20 +12,28 @@ import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpStatus;
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.RestController;
@Tag(name = "추론결과 데이터 생성", description = "추론결과 데이터 생성 API")
@Log4j2
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/inference/shp")
public class InferenceResultShpApiController {
private final InferenceResultShpService inferenceResultShpService;
public static final String MAP_ID =
"{ \"mapIds\": [\"37716096\",\"37716095\",\"37716094\",\"37716091\",\"37716086\",\"37716085\",\"37716084\",\"37716083\",\"37716076\",\"37716066\",\"37716065\",\"37716064\",\"37716063\",\"37716061\",\"37716051\",\"37716011\"] }";
@Operation(summary = "추론결과 데이터 저장", description = "추론결과 데이터 저장")
@ApiResponses(
@@ -52,4 +62,29 @@ public class InferenceResultShpApiController {
inferenceResultShpService.createShp(uuid);
return ApiResponseDto.createOK(null);
}
@Operation(summary = "추론실행에 필요한 geojson 파일 생성", description = "추론실행에 필요한 geojson 파일 생성")
@PostMapping("/geojson/{yyyy}/{mapSheetScope}/{detectOption}")
public ApiResponseDto<Scene> createGeojson(
@Schema(description = "년도") @PathVariable String yyyy,
@Schema(description = "전체(ALL),부분(PART)", example = "PART") @PathVariable
String mapSheetScope,
@Schema(description = "추론제외(EXCL),이전 년도 도엽 사용(PREV)", example = "EXCL") @PathVariable
String detectOption,
@Schema(description = "5k도엽번호", example = MAP_ID) @RequestBody Map<String, Object> body) {
Object raw = body.get("mapIds");
if (raw == null) {
throw new CustomApiException("BAD_REQUEST", HttpStatus.BAD_REQUEST);
}
@SuppressWarnings("unchecked")
List<String> mapIds = (List<String>) raw;
Scene scene =
inferenceResultShpService.createGeojson(yyyy, mapSheetScope, detectOption, mapIds);
return ApiResponseDto.createOK(scene);
}
}

View File

@@ -534,6 +534,10 @@ public class InferenceDetailDto {
throw new RuntimeException(e);
}
}
public Boolean getApplyYn() {
return this.applyYn != null && this.applyYn;
}
}
@Getter

View File

@@ -1,15 +1,20 @@
package com.kamco.cd.kamcoback.inference.service;
import com.kamco.cd.kamcoback.common.geometry.GeoJsonFileWriter.Scene;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.InferenceLearnDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultShpDto;
import com.kamco.cd.kamcoback.postgres.core.InferenceResultCoreService;
import com.kamco.cd.kamcoback.postgres.core.InferenceResultShpCoreService;
import com.kamco.cd.kamcoback.postgres.core.MapSheetMngCoreService;
import com.kamco.cd.kamcoback.scheduler.service.ShpPipelineService;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -19,9 +24,11 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional(readOnly = true)
public class InferenceResultShpService {
private static final Logger log = LogManager.getLogger(InferenceResultShpService.class);
private final InferenceResultShpCoreService coreService;
private final InferenceResultCoreService inferenceResultCoreService;
private final ShpPipelineService shpPipelineService;
private final MapSheetMngCoreService mapSheetMngCoreService;
@Value("${mapsheet.shp.baseurl}")
private String baseDir;
@@ -59,4 +66,21 @@ public class InferenceResultShpService {
// shp 파일 비동기 생성
shpPipelineService.runPipeline(jarPath, datasetDir, batchId, dto.getUid());
}
/**
* 추론 실행전 geojson 파일 생성
*
* @param yyyy
* @param mapSheetScope
* @param detectOption
* @param mapIds
* @return
*/
public Scene createGeojson(
String yyyy, String mapSheetScope, String detectOption, List<String> mapIds) {
Scene getSceneInference =
mapSheetMngCoreService.getSceneInference(yyyy, mapIds, mapSheetScope, detectOption);
log.info("getSceneInference: {}", getSceneInference);
return getSceneInference;
}
}

View File

@@ -1,9 +1,12 @@
package com.kamco.cd.kamcoback.layer;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.layer.dto.WmtsDto.WmtsAddReqDto;
import com.kamco.cd.kamcoback.layer.dto.WmtsLayerInfo;
import com.kamco.cd.kamcoback.layer.service.WmtsService;
import com.kamco.cd.kamcoback.layer.dto.LayerDto;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.IsMapYn;
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.SearchReq;
import com.kamco.cd.kamcoback.layer.service.LayerService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
@@ -13,11 +16,16 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "레이어 관리", description = "레이어 관리 API")
@@ -26,7 +34,158 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/api/layer")
public class LayerApiController {
private final WmtsService wmtsService;
private final LayerService layerService;
@Operation(summary = "지도 레이어 관리 목록", description = "지도 레이어 관리 목록 api")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "검색 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = LayerDto.Basic.class))),
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@GetMapping("/list")
public ApiResponseDto<List<LayerDto.Basic>> getLayers(
@RequestParam(required = false) String tag) {
LayerDto.SearchReq searchReq = new SearchReq();
searchReq.setTag(tag);
List<LayerDto.Basic> layers = layerService.getLayers(searchReq);
return ApiResponseDto.ok(layers);
}
/**
* 레이어 등록
*
* @param layerType
* @param dto
* @return
*/
@Operation(summary = "레이어 등록", description = "레이어 등록 api")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "201",
description = "등록 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = UUID.class))),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/save/{layerType}")
public ApiResponseDto<UUID> save(
@Schema(description = "TILE,GEOJSON,WMS,WMTS", example = "GEOJSON") @PathVariable
String layerType,
@RequestBody LayerDto.AddReq dto) {
return ApiResponseDto.ok(layerService.saveLayers(layerType, dto));
}
@Operation(summary = "순서 변경", description = "순서 변경 api")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "201",
description = "등록 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Void.class))),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PutMapping("/order")
public ApiResponseDto<Void> updateOrder(@RequestBody List<OrderReq> dto) {
layerService.orderUpdate(dto);
return ApiResponseDto.ok(null);
}
@Operation(summary = "상세 조회", description = "상세 조회 api")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "검색 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = LayerDto.Detail.class))),
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@GetMapping("/detail/{uuid}")
public ApiResponseDto<LayerDto.Detail> getDetail(@PathVariable UUID uuid) {
return ApiResponseDto.ok(layerService.getDetail(uuid));
}
/**
* 레이어 삭제
*
* @param uuid
* @return
*/
@Operation(summary = "레이어 삭제", description = "레이어 삭제 api")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "201",
description = "삭제 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Void.class))),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@DeleteMapping("/delete/{uuid}")
public ApiResponseDto<Void> delete(@PathVariable UUID uuid) {
layerService.delete(uuid);
return ApiResponseDto.ok(null);
}
/**
* 레이어 수정
*
* @param uuid
* @return
*/
@Operation(summary = "레이어 수정", description = "레이어 수정 api")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "201",
description = "수정 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Void.class))),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PutMapping("/update/{uuid}")
public ApiResponseDto<Void> update(@PathVariable UUID uuid, @RequestBody LayerDto.Detail dto) {
layerService.update(uuid, dto);
return ApiResponseDto.ok(null);
}
@Operation(summary = "맵 노출여부 수정", description = "맵 노출여부 수정 api")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "201",
description = "수정 성공",
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = Void.class))),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PutMapping("/update-map/{uuid}")
public ApiResponseDto<Void> updateIsMap(@PathVariable UUID uuid, @RequestBody IsMapYn isMapYn) {
layerService.updateIsMap(uuid, isMapYn);
return ApiResponseDto.ok(null);
}
@Operation(summary = "wmts tile 조회", description = "wmts tile 조회 api")
@ApiResponses(
@@ -43,10 +202,10 @@ public class LayerApiController {
})
@GetMapping("/wmts/tile")
public ApiResponseDto<List<String>> getWmtsTile() {
return ApiResponseDto.ok(wmtsService.getTile());
return ApiResponseDto.ok(layerService.getWmtsTile());
}
@Operation(summary = "wmts tile 상세 조회", description = "wmts tile 상세 조회 api")
@Operation(summary = "wms tile 조회", description = "wms tile 조회 api")
@ApiResponses(
value = {
@ApiResponse(
@@ -55,16 +214,63 @@ public class LayerApiController {
content =
@Content(
mediaType = "application/json",
schema = @Schema(implementation = WmtsLayerInfo.class))),
array = @ArraySchema(schema = @Schema(implementation = String.class)))),
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@PostMapping("/wmts")
public ApiResponseDto<Void> getWmtsTileDetail(
@Parameter(description = "선택한 tile", example = "959022EFCAA448D1A325FA7B8ABEA10D")
@RequestBody
WmtsAddReqDto dto) {
wmtsService.save(dto);
return ApiResponseDto.ok(null);
@GetMapping("/wms/tile")
public ApiResponseDto<List<String>> getWmsTile() {
return ApiResponseDto.ok(layerService.getWmsTitle());
}
@Operation(summary = "변화지도 레이어 조회", description = "변화지도 레이어 조회")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "검색 성공",
content =
@Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = String.class)))),
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@GetMapping("/map/change-detection")
public ApiResponseDto<List<LayerMapDto>> changeDetectionMap() {
return ApiResponseDto.ok(layerService.findLayerMapList("change-detection"));
}
@Operation(summary = "라벨링 툴 레이어 조회", description = "라벨링 툴 레이어 조회")
@ApiResponses(
value = {
@ApiResponse(
responseCode = "200",
description = "검색 성공",
content =
@Content(
mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = String.class)))),
@ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
})
@GetMapping("/map/labeling")
public ApiResponseDto<List<LayerMapDto>> labelingMap() {
return ApiResponseDto.ok(layerService.findLayerMapList("labeling"));
}
@Operation(summary = "년도별 tile Url(before,after 모두 조회)", description = "년도별 tile Url")
@GetMapping("/tile-url")
public ApiResponseDto<LayerDto.YearTileDto> getChangeDetectionTileUrl(
@Parameter(description = "이전 년도", example = "2023") @RequestParam Integer beforeYear,
@Parameter(description = "이후 년도", example = "2024") @RequestParam Integer afterYear) {
return ApiResponseDto.ok(layerService.getChangeDetectionTileUrl(beforeYear, afterYear));
}
@Operation(summary = "년도별 tile Url(년도 1개만 조회)", description = "년도별 tile Url")
@GetMapping("/tile-url-year")
public ApiResponseDto<LayerDto.TileUrlDto> getChangeDetectionTileOneYearUrl(
@Parameter(description = "년도", example = "2023") @RequestParam Integer year) {
return ApiResponseDto.ok(layerService.getChangeDetectionTileOneYearUrl(year));
}
}

View File

@@ -0,0 +1,18 @@
package com.kamco.cd.kamcoback.layer.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
public class GeoJsonDto {
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class GeoJsonAddReqDto {
private String url;
private String description;
private String tag;
}
}

View File

@@ -0,0 +1,432 @@
package com.kamco.cd.kamcoback.layer.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
import io.swagger.v3.oas.annotations.media.Schema;
import java.math.BigDecimal;
import java.time.ZonedDateTime;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
public class LayerDto {
public enum MapType {
CHANGE_MAP,
LABELING_MAP
}
@Getter
@Setter
@AllArgsConstructor
@Schema(name = "LayerBasic")
public static class Basic {
@Schema(description = "uuid")
private UUID uuid;
@Schema(example = "WMTS", description = "유형 (TILE/GEOJSON/WMTS/WMS)")
private String layerType;
@Schema(description = "설명")
private String description;
@Schema(description = "태그")
private String tag;
@Schema(description = "순서")
private Long order;
@Schema(description = "변화지도 여부")
private Boolean isChangeMap;
@Schema(description = "라벨링지도 여부")
private Boolean isLabelingMap;
@JsonFormatDttm
@Schema(description = "등록일시")
private ZonedDateTime createdDttm;
}
@Getter
@Setter
@AllArgsConstructor
@Schema(name = "LayerDetail")
public static class Detail {
@Schema(description = "uuid")
private UUID uuid;
@Schema(description = "유형 (TILE/GEOJSON/WMTS/WMS)")
private String layerType;
@Schema(description = "title")
private String title;
@Schema(description = "설명")
private String description;
@Schema(description = "태그")
private String tag;
@Schema(description = "순서")
private Long order;
@Schema(description = "변화지도 여부")
private Boolean isChangeMap;
@Schema(description = "라벨링지도 여부")
private Boolean isLabelingMap;
@Schema(description = "url")
private String url;
@Schema(description = "좌측상단 경도", example = "126.0")
private BigDecimal minLon;
@Schema(description = "좌측상단 위도", example = "34.0")
private BigDecimal minLat;
@Schema(description = "우측하단 경도", example = "130.0")
private BigDecimal maxLon;
@Schema(description = "우측하단 위도", example = "38.5")
private BigDecimal maxLat;
@Schema(description = "zoom min", example = "5")
private Short min;
@Schema(description = "zoom max", example = "18")
private Short max;
@JsonFormatDttm
@Schema(description = "등록일시")
private ZonedDateTime createdDttm;
@Schema(description = "좌표계")
private String crs;
}
@Getter
@Setter
@AllArgsConstructor
@Schema(name = "LayerAddReq")
public static class AddReq {
@Schema(description = "title WMS, WMTS 선택한 tile")
private String title;
@Schema(description = "설명")
private String description;
@Schema(description = "태그")
private String tag;
@Schema(description = "url")
private String url;
@Schema(description = "좌측상단 경도", example = "126.0")
private BigDecimal minLon;
@Schema(description = "좌측상단 위도", example = "34.0")
private BigDecimal minLat;
@Schema(description = "우측하단 경도", example = "130.0")
private BigDecimal maxLon;
@Schema(description = "우측하단 위도", example = "38.5")
private BigDecimal maxLat;
@Schema(description = "zoom min", example = "5")
private Short min;
@Schema(description = "zoom max", example = "18")
private Short max;
@Schema(description = "좌표계", example = "EPSG_3857")
private String crs;
}
@Getter
@Setter
@AllArgsConstructor
@Schema(name = "LayerOrderReq")
public static class OrderReq {
@Schema(description = "uuid")
private UUID uuid;
@Schema(description = "레이어 순서")
private Long order;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class SearchReq {
private String tag;
private String layerType;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class TileAddReqDto {
@Schema(description = "설명", example = "배경지도 입니다.")
private String description;
@Schema(description = "url", example = "http://test.gs.dabeeo.com/tile/{z}/{x}/{y}.png")
private String url;
@Schema(description = "태그", example = "변화지도")
private String tag;
@Schema(description = "좌측상단 경도", example = "126.0")
private BigDecimal minLon;
@Schema(description = "좌측상단 위도", example = "34.0")
private BigDecimal minLat;
@Schema(description = "우측하단 경도", example = "130.0")
private BigDecimal maxLon;
@Schema(description = "우측하단 위도", example = "38.5")
private BigDecimal maxLat;
@Schema(description = "zoom min", example = "5")
private Short min;
@Schema(description = "zoom max", example = "18")
private Short max;
}
@Getter
@Setter
@Schema(name = "LayerMapDto")
public static class LayerMapDto {
@Schema(example = "WMTS", description = "유형 (TILE/GEOJSON/WMTS/WMS)")
private String layerType;
@Schema(description = "title")
private String title;
@Schema(description = "설명")
private String description;
@Schema(description = "태그")
private String tag;
@Schema(description = "순서")
private Long sortOrder;
@Schema(description = "url")
private String url;
@Schema(description = "좌측상단 경도", example = "126.0")
private BigDecimal minLon;
@Schema(description = "좌측상단 위도", example = "34.0")
private BigDecimal minLat;
@Schema(description = "우측하단 경도", example = "130.0")
private BigDecimal maxLon;
@Schema(description = "우측하단 위도", example = "38.5")
private BigDecimal maxLat;
@Schema(description = "zoom min", example = "5")
private Short minZoom;
@Schema(description = "zoom max", example = "18")
private Short maxZoom;
@Schema(description = "bbox")
private JsonNode bbox;
@JsonIgnore private String bboxGeometry;
@Schema(description = "uuid")
private UUID uuid;
@JsonIgnore private String rawJsonString;
@Schema(description = "rawJson")
private JsonNode rawJson;
@Schema(description = "crs")
private String crs;
public LayerMapDto(
String layerType,
String tag,
Long sortOrder,
String url,
BigDecimal minLon,
BigDecimal minLat,
BigDecimal maxLon,
BigDecimal maxLat,
Short minZoom,
Short maxZoom,
String bboxGeometry,
UUID uuid,
String rawJsonString,
String crs) {
this.layerType = layerType;
this.tag = tag;
this.sortOrder = sortOrder;
this.url = url;
this.minLon = minLon;
this.minLat = minLat;
this.maxLon = maxLon;
this.maxLat = maxLat;
this.minZoom = minZoom;
this.maxZoom = maxZoom;
this.bboxGeometry = bboxGeometry;
this.uuid = uuid;
this.rawJsonString = rawJsonString;
JsonNode geoJson = null;
JsonNode rawJson = null;
ObjectMapper mapper = new ObjectMapper();
if (bboxGeometry != null) {
try {
geoJson = mapper.readTree(bboxGeometry);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
if (rawJsonString != null) {
try {
rawJson = mapper.readTree(rawJsonString);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
this.rawJson = rawJson;
this.bbox = geoJson;
this.crs = crs;
}
@JsonProperty("workspace")
public String getWorkSpace() {
return "cd";
}
}
@Schema(name = "TileUrlDto", description = "Tile Url 정보")
@Getter
@Setter
@NoArgsConstructor
public static class TileUrlDto {
@Schema(description = "mngYyyy")
private Integer mngYyyy;
@Schema(description = "url")
private String url;
@Schema(description = "태그")
private String tag;
@Schema(description = "좌측상단 경도", example = "126.0")
private BigDecimal minLon;
@Schema(description = "좌측상단 위도", example = "34.0")
private BigDecimal minLat;
@Schema(description = "우측하단 경도", example = "130.0")
private BigDecimal maxLon;
@Schema(description = "우측하단 위도", example = "38.5")
private BigDecimal maxLat;
@Schema(description = "zoom min", example = "5")
private Short minZoom;
@Schema(description = "zoom max", example = "18")
private Short maxZoom;
@Schema(description = "bbox")
private JsonNode bbox;
@JsonIgnore private String bboxGeometry;
private String crs;
public TileUrlDto(
Integer mngYyyy,
String url,
String tag,
BigDecimal minLon,
BigDecimal minLat,
BigDecimal maxLon,
BigDecimal maxLat,
Short minZoom,
Short maxZoom,
String bboxGeometry,
String crs) {
this.mngYyyy = mngYyyy;
this.url = url;
this.tag = tag;
this.minLon = minLon;
this.minLat = minLat;
this.maxLon = maxLon;
this.maxLat = maxLat;
this.minZoom = minZoom;
this.maxZoom = maxZoom;
this.bboxGeometry = bboxGeometry;
JsonNode geoJson = null;
if (bboxGeometry != null) {
ObjectMapper mapper = new ObjectMapper();
try {
geoJson = mapper.readTree(bboxGeometry);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
this.bbox = geoJson;
this.crs = crs;
}
}
@Schema(name = "TileUrlDto", description = "Tile Url 정보")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class YearTileDto {
private TileUrlDto before;
private TileUrlDto after;
}
@Schema(name = "맵 노출 여부", description = "맵 노출 여부")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class IsMapYn {
@Schema(description = "CHANGE_MAP(변화지도), LABELING_MAP(라벨링지도)", example = "CHANGE_MAP")
private String mapType;
@Schema(description = "노출여부 true, false", example = "true")
private Boolean isMapYn;
}
}

View File

@@ -0,0 +1,30 @@
package com.kamco.cd.kamcoback.layer.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
public class WmsDto {
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class WmsAddReqDto {
private String title;
private String description;
private String tag;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public static class WmsAddDto {
private WmsLayerInfo wmsLayerInfo;
private String title;
private String description;
private String tag;
}
}

View File

@@ -0,0 +1,47 @@
package com.kamco.cd.kamcoback.layer.dto;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/** WMS 레이어 정보를 담는 DTO 클래스 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class WmsLayerInfo {
private String name;
private String title;
private String abstractText;
private List<String> keywords = new ArrayList<>();
private BoundingBox boundingBox;
/** 지원하는 좌표계 목록 */
private List<String> crs = new ArrayList<>();
/* ===== convenience methods ===== */
public void addKeyword(String keyword) {
this.keywords.add(keyword);
}
public void addCrs(String crsValue) {
this.crs.add(crsValue);
}
/** BoundingBox 정보를 담는 내부 클래스 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class BoundingBox {
private String crs;
private double minX;
private double minY;
private double maxX;
private double maxY;
}
}

View File

@@ -14,6 +14,7 @@ public class WmtsDto {
public static class WmtsAddReqDto {
private String title;
private String description;
private String tag;
}
@Getter
@@ -24,5 +25,6 @@ public class WmtsDto {
private WmtsLayerInfo wmtsLayerInfo;
private String title;
private String description;
private String tag;
}
}

View File

@@ -1,70 +1,51 @@
package com.kamco.cd.kamcoback.layer.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/** WMTS 레이어 정보를 담는 DTO 클래스 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class WmtsLayerInfo {
public String identifier;
public String title;
public String abstractText;
public List<String> keywords = new ArrayList<>();
public BoundingBox boundingBox;
public List<String> formats = new ArrayList<>();
public List<String> tileMatrixSetLinks = new ArrayList<>();
public List<ResourceUrl> resourceUrls = new ArrayList<>();
public List<Style> styles = new ArrayList<>();
private String identifier;
private String title;
private String abstractText;
public void setTitle(String title) {
this.title = title;
private List<String> keywords = new ArrayList<>();
private BoundingBox boundingBox;
private List<String> formats = new ArrayList<>();
private List<TileMatrixSetLink> tileMatrixSetLinks = new ArrayList<>();
private List<ResourceUrl> resourceUrls = new ArrayList<>();
private List<Style> styles = new ArrayList<>();
private List<String> matrixIds = new ArrayList<>(); // 20250130
private String workspace; // 20250130
private List<TileMatric> tileMatrices = new ArrayList<>();
// (선택) 기존 add 메서드 유지하고 싶으면 남겨도 됨
public void addTileMatric(TileMatric tileMatric) {
this.tileMatrices.add(tileMatric);
}
public void setAbstractText(String abstractText) {
this.abstractText = abstractText;
public void addMatrixId(String matrixId) {
this.matrixIds.add(matrixId);
}
public void setBoundingBox(BoundingBox boundingBox) {
this.boundingBox = boundingBox;
}
@Override
public String toString() {
return "WmtsLayerInfo{"
+ "identifier='"
+ identifier
+ '\''
+ ", title='"
+ title
+ '\''
+ ", abstractText='"
+ abstractText
+ '\''
+ ", keywords="
+ keywords
+ ", boundingBox="
+ boundingBox
+ ", formats="
+ formats
+ ", tileMatrixSetLinks="
+ tileMatrixSetLinks
+ ", resourceUrls="
+ resourceUrls
+ ", styles="
+ styles
+ '}';
}
public void addKeyword(String keywowrd) {
this.keywords.add(keywowrd);
public void addKeyword(String keyword) {
this.keywords.add(keyword);
}
public void addFormat(String format) {
this.formats.add(format);
}
public void addTileMatrixSetLink(String tileMatrixSetLink) {
public void addTileMatrixSetLink(TileMatrixSetLink tileMatrixSetLink) {
this.tileMatrixSetLinks.add(tileMatrixSetLink);
}
@@ -77,200 +58,61 @@ public class WmtsLayerInfo {
}
/** BoundingBox 정보를 담는 내부 클래스 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class BoundingBox {
public String crs;
public double lowerCornerX;
public double lowerCornerY;
public double upperCornerX;
public double upperCornerY;
public BoundingBox() {}
public BoundingBox(
String crs,
double lowerCornerX,
double lowerCornerY,
double upperCornerX,
double upperCornerY) {
this.crs = crs;
this.lowerCornerX = lowerCornerX;
this.lowerCornerY = lowerCornerY;
this.upperCornerX = upperCornerX;
this.upperCornerY = upperCornerY;
}
// Getters and Setters
public String getCrs() {
return crs;
}
public void setCrs(String crs) {
this.crs = crs;
}
public double getLowerCornerX() {
return lowerCornerX;
}
public void setLowerCornerX(double lowerCornerX) {
this.lowerCornerX = lowerCornerX;
}
public double getLowerCornerY() {
return lowerCornerY;
}
public void setLowerCornerY(double lowerCornerY) {
this.lowerCornerY = lowerCornerY;
}
public double getUpperCornerX() {
return upperCornerX;
}
public void setUpperCornerX(double upperCornerX) {
this.upperCornerX = upperCornerX;
}
public double getUpperCornerY() {
return upperCornerY;
}
public void setUpperCornerY(double upperCornerY) {
this.upperCornerY = upperCornerY;
}
@Override
public String toString() {
return "BoundingBox{"
+ "crs='"
+ crs
+ '\''
+ ", lowerCorner=["
+ lowerCornerX
+ ", "
+ lowerCornerY
+ ']'
+ ", upperCorner=["
+ upperCornerX
+ ", "
+ upperCornerY
+ ']'
+ '}';
}
private String crs;
private double lowerCornerX;
private double lowerCornerY;
private double upperCornerX;
private double upperCornerY;
}
/** ResourceURL 정보를 담는 내부 클래스 (타일 URL 템플릿) */
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class ResourceUrl {
private String format;
private String resourceType;
private String template;
public ResourceUrl() {}
public ResourceUrl(String format, String resourceType, String template) {
this.format = format;
this.resourceType = resourceType;
this.template = template;
}
// Getters and Setters
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
public String getResourceType() {
return resourceType;
}
public void setResourceType(String resourceType) {
this.resourceType = resourceType;
}
public String getTemplate() {
return template;
}
public void setTemplate(String template) {
this.template = template;
}
@Override
public String toString() {
return "ResourceUrl{"
+ "format='"
+ format
+ '\''
+ ", resourceType='"
+ resourceType
+ '\''
+ ", template='"
+ template
+ '\''
+ '}';
}
}
/** Style 정보를 담는 내부 클래스 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Style {
private String identifier;
private String title;
@JsonProperty("default")
private boolean isDefault;
public Style() {}
public Style(String identifier, String title, boolean isDefault) {
this.identifier = identifier;
this.title = title;
this.isDefault = isDefault;
}
// Getters and Setters
public String getIdentifier() {
return identifier;
/** TileMatrix 정보를 담는 내부 클래스 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class TileMatric {
private String identifier;
private String scaleDenominator;
private String topLeftCorner;
// private String tileWidth;
// private String tileHeight;
// private String matrixWidth;
// private String matrixHeight;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
/** TileMatrixSetLink 정보를 담는 내부 클래스 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class TileMatrixSetLink {
private String tileMatrixSet;
private List<String> zoomLevels = new ArrayList<>();
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean isDefault() {
return isDefault;
}
public void setDefault(boolean isDefault) {
this.isDefault = isDefault;
}
@Override
public String toString() {
return "Style{"
+ "identifier='"
+ identifier
+ '\''
+ ", title='"
+ title
+ '\''
+ ", isDefault="
+ isDefault
+ '}';
public void addZoomLevel(String zoomLevel) {
this.zoomLevels.add(zoomLevel);
}
}
}

View File

@@ -0,0 +1,221 @@
package com.kamco.cd.kamcoback.layer.service;
import com.kamco.cd.kamcoback.common.enums.LayerType;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.layer.dto.LayerDto;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.Basic;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.IsMapYn;
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;
import com.kamco.cd.kamcoback.postgres.core.MapLayerCoreService;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@RequiredArgsConstructor
@Service
@Transactional(readOnly = true)
public class LayerService {
private final MapLayerCoreService mapLayerCoreService;
private final WmtsService wmtsService;
private final WmsService wmsService;
@Value("${layer.geoserver-url}")
private String geoserverUrl;
@Value("${layer.wms-path}")
private String wmsPath;
@Value("${layer.wmts-path}")
private String wmtsPath;
/**
* 지도 레이어 관리 목록
*
* @return
*/
public List<Basic> getLayers(LayerDto.SearchReq searchReq) {
return mapLayerCoreService.getLayers(searchReq);
}
/**
* 레이어 저장
*
* @param type
* @param dto
* @return
*/
@Transactional
public UUID saveLayers(String type, LayerDto.AddReq dto) {
LayerType layerType =
LayerType.from(type)
.orElseThrow(() -> new CustomApiException("BAD_REQUEST", HttpStatus.BAD_REQUEST));
switch (layerType) {
case TILE -> {
return mapLayerCoreService.saveTile(dto);
}
case GEOJSON -> {
return mapLayerCoreService.saveGeoJson(dto);
}
case WMTS -> {
WmtsLayerInfo info = wmtsService.getDetail(dto.getTitle());
WmtsAddDto addDto = new WmtsAddDto();
addDto.setWmtsLayerInfo(info);
addDto.setDescription(dto.getDescription());
addDto.setTitle(dto.getTitle());
addDto.setTag(dto.getTag());
return mapLayerCoreService.saveWmts(addDto);
}
case WMS -> {
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);
}
default -> throw new CustomApiException("BAD_REQUEST", HttpStatus.BAD_REQUEST);
}
}
/**
* 순서 수정
*
* @param dtoList
*/
@Transactional
public void orderUpdate(List<OrderReq> dtoList) {
mapLayerCoreService.orderUpdate(dtoList);
}
/**
* 지도 레이어 관리 상세
*
* @param uuid
* @return
*/
public LayerDto.Detail getDetail(UUID uuid) {
return mapLayerCoreService.getLayers(uuid);
}
/**
* 삭제
*
* @param uuid
*/
@Transactional
public void delete(UUID uuid) {
mapLayerCoreService.delete(uuid);
}
/**
* 수정
*
* @param uuid
*/
@Transactional
public void update(UUID uuid, LayerDto.Detail dto) {
mapLayerCoreService.update(uuid, dto);
}
/**
* 맵 노출 여부 수정
*
* @param uuid
* @param isMapYn
*/
@Transactional
public void updateIsMap(UUID uuid, IsMapYn isMapYn) {
mapLayerCoreService.updateIsMap(uuid, isMapYn);
}
/**
* wmts tile 조회
*
* @return List<String>
*/
public List<String> getWmtsTile() {
return wmtsService.getTile();
}
/**
* wms title 조회
*
* @return
*/
public List<String> getWmsTitle() {
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(
dto -> {
if (dto.getLayerType().equals("WMS")) {
dto.setUrl(
String.format(
"%s/%s/%s",
trimSlash(geoserverUrl), trimSlash(wmsPath), dto.getLayerType().toLowerCase()));
} else if (dto.getLayerType().equals("WMTS")) {
dto.setUrl(
String.format(
"%s/%s/%s",
trimSlash(geoserverUrl),
trimSlash(wmtsPath),
dto.getLayerType().toLowerCase()));
}
});
return layerMapDtoList;
}
private String trimSlash(String s) {
if (s == null) {
return "";
}
return s.replaceAll("/+$", "").replaceAll("^/+", "");
}
public LayerDto.YearTileDto getChangeDetectionTileUrl(Integer beforeYear, Integer afterYear) {
return mapLayerCoreService.getChangeDetectionTileUrl(beforeYear, afterYear);
}
public TileUrlDto getChangeDetectionTileOneYearUrl(Integer year) {
return mapLayerCoreService.getChangeDetectionTileOneYearUrl(year);
}
}

View File

@@ -1,10 +0,0 @@
package com.kamco.cd.kamcoback.layer.service;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class TileService {}

View File

@@ -1,10 +1,254 @@
package com.kamco.cd.kamcoback.layer.service;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.layer.dto.WmsLayerInfo;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class WmsService {}
public class WmsService {
@Value("${layer.geoserver-url}")
private String geoserverUrl;
@Value("${layer.workspace}")
private String workspace;
public List<String> getTile() {
List<WmsLayerInfo> layers;
try {
layers = getAllLayers(geoserverUrl, workspace);
} catch (IOException | ParserConfigurationException | SAXException e) {
throw new CustomApiException("INTERNAL_SERVER_ERROR", HttpStatus.INTERNAL_SERVER_ERROR);
}
List<String> titles = new ArrayList<>();
for (WmsLayerInfo layer : layers) {
if (StringUtils.hasText(layer.getTitle())) {
titles.add(layer.getTitle());
}
}
return titles;
}
public WmsLayerInfo getDetail(String title) {
try {
// 특정 title로 레이어 찾기
WmsLayerInfo layerInfo = getLayerByTitle(geoserverUrl, workspace, title);
if (layerInfo != null) {
return layerInfo;
} else {
throw new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND);
}
} catch (Exception e) {
throw new CustomApiException("INTERNAL_SERVER_ERROR", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
public List<WmsLayerInfo> getAllLayers(String baseUrl, String workspace)
throws IOException, ParserConfigurationException, SAXException {
String capabilitiesUrl = buildGetCapabilitiesUrl(baseUrl, workspace);
Document doc = fetchAndParseXml(capabilitiesUrl);
List<WmsLayerInfo> layers = new ArrayList<>();
NodeList layerNodes = doc.getElementsByTagName("Layer");
for (int i = 0; i < layerNodes.getLength(); i++) {
Element layerElement = (Element) layerNodes.item(i);
// Name이 있는 레이어만 추가 (실제 레이어, 그룹 레이어 제외)
String name = getElementTextContent(layerElement, "Name");
if (name != null && !name.isEmpty()) {
layers.add(extractLayerInfo(layerElement));
}
}
return layers;
}
/** GetCapabilities URL 생성 */
private String buildGetCapabilitiesUrl(String baseUrl, String workspace) {
// URL 끝의 슬래시 처리
String cleanBaseUrl =
baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl;
return String.format(
"%s/geoserver/%s/wms?service=WMS&request=GetCapabilities", cleanBaseUrl, workspace);
}
/** URL에서 XML을 가져와 Document 객체로 파싱 */
private Document fetchAndParseXml(String urlString)
throws IOException, ParserConfigurationException, SAXException {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(10000); // 10초 타임아웃
conn.setReadTimeout(10000);
try (InputStream inputStream = conn.getInputStream()) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(inputStream);
} finally {
conn.disconnect();
}
}
/** Element에서 특정 태그명의 텍스트 내용 추출 */
private String getElementTextContent(Element parent, String tagName) {
NodeList nodeList = parent.getElementsByTagName(tagName);
if (nodeList.getLength() > 0) {
return nodeList.item(0).getTextContent();
}
return null;
}
/** Layer Element에서 WmsLayerInfo 객체 생성 */
private WmsLayerInfo extractLayerInfo(Element layerElement) {
WmsLayerInfo layerInfo = new WmsLayerInfo();
// Name
layerInfo.setName(getElementTextContent(layerElement, "Name"));
// Title
layerInfo.setTitle(getElementTextContent(layerElement, "Title"));
// Abstract
layerInfo.setAbstractText(getElementTextContent(layerElement, "Abstract"));
// Keywords
NodeList keywordNodes = layerElement.getElementsByTagName("Keyword");
for (int i = 0; i < keywordNodes.getLength(); i++) {
String keyword = keywordNodes.item(i).getTextContent();
if (keyword != null && !keyword.trim().isEmpty()) {
layerInfo.addKeyword(keyword.trim());
}
}
// CRS (좌표계)
NodeList crsNodes = layerElement.getElementsByTagName("CRS");
if (crsNodes.getLength() == 0) {
// WMS 1.1.1의 경우 SRS 사용
crsNodes = layerElement.getElementsByTagName("SRS");
}
for (int i = 0; i < crsNodes.getLength(); i++) {
String crs = crsNodes.item(i).getTextContent();
if (crs != null && !crs.trim().isEmpty()) {
layerInfo.addCrs(crs.trim());
}
}
// BoundingBox
NodeList bboxNodes = layerElement.getElementsByTagName("BoundingBox");
if (bboxNodes.getLength() > 0) {
Element bboxElement = (Element) bboxNodes.item(0);
String crs = bboxElement.getAttribute("CRS");
if (crs == null || crs.isEmpty()) {
crs = bboxElement.getAttribute("SRS"); // WMS 1.1.1 호환
}
try {
double minX = Double.parseDouble(bboxElement.getAttribute("minx"));
double minY = Double.parseDouble(bboxElement.getAttribute("miny"));
double maxX = Double.parseDouble(bboxElement.getAttribute("maxx"));
double maxY = Double.parseDouble(bboxElement.getAttribute("maxy"));
WmsLayerInfo.BoundingBox bbox = new WmsLayerInfo.BoundingBox(crs, minX, minY, maxX, maxY);
layerInfo.setBoundingBox(bbox);
} catch (NumberFormatException e) {
System.err.println("BoundingBox 파싱 오류: " + e.getMessage());
}
}
// EX_GeographicBoundingBox도 확인 (전역 범위)
if (layerInfo.getBoundingBox() == null) {
NodeList geoBboxNodes = layerElement.getElementsByTagName("EX_GeographicBoundingBox");
if (geoBboxNodes.getLength() > 0) {
Element geoBboxElement = (Element) geoBboxNodes.item(0);
try {
double westBound =
Double.parseDouble(getElementTextContent(geoBboxElement, "westBoundLongitude"));
double eastBound =
Double.parseDouble(getElementTextContent(geoBboxElement, "eastBoundLongitude"));
double southBound =
Double.parseDouble(getElementTextContent(geoBboxElement, "southBoundLatitude"));
double northBound =
Double.parseDouble(getElementTextContent(geoBboxElement, "northBoundLatitude"));
WmsLayerInfo.BoundingBox bbox =
new WmsLayerInfo.BoundingBox(
"EPSG:4326", westBound, southBound, eastBound, northBound);
layerInfo.setBoundingBox(bbox);
} catch (NumberFormatException e) {
System.err.println("GeographicBoundingBox 파싱 오류: " + e.getMessage());
}
}
}
return layerInfo;
}
/**
* GetCapabilities를 호출하고 title로 레이어 정보를 찾아 반환
*
* @param baseUrl GeoServer 기본 URL (예: http://localhost:8080)
* @param workspace 워크스페이스 이름
* @param targetTitle 찾고자 하는 레이어의 title
* @return WmsLayerInfo 객체, 찾지 못하면 null
* @throws Exception 네트워크 또는 파싱 오류 시
*/
public WmsLayerInfo getLayerByTitle(String baseUrl, String workspace, String targetTitle)
throws Exception {
// GetCapabilities URL 구성
String capabilitiesUrl = buildGetCapabilitiesUrl(baseUrl, workspace);
// GetCapabilities 요청 및 XML 파싱
Document doc = fetchAndParseXml(capabilitiesUrl);
// title로 레이어 찾기
return findLayerByTitle(doc, targetTitle);
}
/** XML Document에서 title로 레이어를 찾아 WmsLayerInfo 객체로 변환 */
private WmsLayerInfo findLayerByTitle(Document doc, String targetTitle) {
// Layer 요소들 찾기
NodeList layerNodes = doc.getElementsByTagName("Layer");
for (int i = 0; i < layerNodes.getLength(); i++) {
Element layerElement = (Element) layerNodes.item(i);
// Title 찾기
String title = getElementTextContent(layerElement, "Title");
// Title이 일치하면 레이어 정보 추출
if (title != null && title.equals(targetTitle)) {
return extractLayerInfo(layerElement);
}
}
return null; // 찾지 못한 경우
}
}

View File

@@ -1,7 +1,5 @@
package com.kamco.cd.kamcoback.layer.service;
import com.kamco.cd.kamcoback.layer.dto.WmtsDto.WmtsAddDto;
import com.kamco.cd.kamcoback.layer.dto.WmtsDto.WmtsAddReqDto;
import com.kamco.cd.kamcoback.layer.dto.WmtsLayerInfo;
import com.kamco.cd.kamcoback.postgres.core.MapLayerCoreService;
import java.net.URL;
@@ -38,43 +36,28 @@ public class WmtsService {
private static final String WMTS_GEOSERVER_URL = "/geoserver/";
private static final String WMTS_CAPABILITIES_URL = "/gwc/service/wmts?REQUEST=GetCapabilities";
/**
* tile 조회
*
* @return List<String>
*/
public List<String> getTile() {
List<WmtsLayerInfo> layers = getAllLayers(geoserverUrl, workspace);
List<String> titles = new ArrayList<>();
for (WmtsLayerInfo layer : layers) {
titles.add(layer.title);
titles.add(layer.getTitle()); // ✅ getter로 변경
}
return titles;
}
/**
* 선택 tile 저장
*
* @param dto
*/
@Transactional
public void save(WmtsAddReqDto dto) {
// 선택한 tile 상세정보 조회
WmtsLayerInfo info = getDetail(dto.getTitle());
WmtsAddDto addDto = new WmtsAddDto();
addDto.setWmtsLayerInfo(info);
addDto.setDescription(dto.getDescription());
addDto.setTitle(dto.getTitle());
mapLayerCoreService.save(addDto);
}
public WmtsLayerInfo getDetail(String tile) {
return getLayerInfoByTitle(geoserverUrl, workspace, tile);
}
private List<WmtsLayerInfo> getAllLayers(String geoserverUrl, String workspace) {
/**
* WMTS Capabilities URL에서 모든 레이어 정보를 가져옵니다.
*
* @param geoserverUrl 예: http://localhost:8080
* @param workspace 워크스페이스 이름
* @return 모든 레이어 정보 리스트
*/
public List<WmtsLayerInfo> getAllLayers(String geoserverUrl, String workspace) {
List<WmtsLayerInfo> layers = new ArrayList<>();
try {
// 1. XML 문서 로드 및 파싱
@@ -99,7 +82,7 @@ public class WmtsService {
String title = getChildValue(layerNode, "Title");
if (title != null && !title.trim().isEmpty()) {
WmtsLayerInfo layerInfo = parseLayerNode(layerNode, title);
WmtsLayerInfo layerInfo = parseLayerNode(workspace, doc, layerNode, title);
layers.add(layerInfo);
}
}
@@ -112,151 +95,6 @@ public class WmtsService {
return layers;
}
// 특정 노드 아래의 자식 태그 값 추출 (예: <Title>값)
private String getChildValue(Node parent, String childName) {
Node child = findChildNode(parent, childName);
return (child != null) ? child.getTextContent() : null;
}
// 이름으로 자식 노드 찾기 (Local Name 기준)
private Node findChildNode(Node parent, String localName) {
NodeList children = parent.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
// 네임스페이스 접두사(ows:, wmts:)를 무시하고 태그 이름 확인
if (node.getNodeName().endsWith(":" + localName) || node.getNodeName().equals(localName)) {
return node;
}
}
return null;
}
// 레이어 노드를 Java 객체로 변환
private WmtsLayerInfo parseLayerNode(Node layerNode, String title) {
WmtsLayerInfo info = new WmtsLayerInfo();
info.title = title;
info.identifier = getChildValue(layerNode, "Identifier");
info.abstractText = getChildValue(layerNode, "Abstract");
// Keywords 파싱
// 구조: <ows:Keywords><ows:Keyword>...</ows:Keyword></ows:Keywords>
info.keywords = getChildValues(layerNode, "Keywords", "Keyword");
// BoundingBox 파싱 (WGS84BoundingBox 기준)
info.boundingBox = parseBoundingBox(layerNode);
// Formats 파싱
info.formats = getChildValuesDirect(layerNode, "Format");
// TileMatrixSetLink 파싱
// 구조: <TileMatrixSetLink><TileMatrixSet>...</TileMatrixSet></TileMatrixSetLink>
info.tileMatrixSetLinks = getChildValues(layerNode, "TileMatrixSetLink", "TileMatrixSet");
// ResourceURL 파싱
info.resourceUrls = parseResourceUrls(layerNode);
// Styles 파싱
info.styles = parseStyles(layerNode);
return info;
}
// 특정 노드 아래의 반복되는 자식 구조 값 추출 (예: Keywords -> Keyword)
private List<String> getChildValues(Node parent, String wrapperName, String childName) {
List<String> results = new ArrayList<>();
Node wrapper = findChildNode(parent, wrapperName);
if (wrapper != null) {
NodeList children = wrapper.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeName().endsWith(childName)) {
results.add(node.getTextContent());
}
}
}
return results;
}
private WmtsLayerInfo.BoundingBox parseBoundingBox(Node layerNode) {
// 보통 <ows:WGS84BoundingBox>를 찾음
Node bboxNode = findChildNode(layerNode, "WGS84BoundingBox");
if (bboxNode == null) bboxNode = findChildNode(layerNode, "BoundingBox");
if (bboxNode != null) {
WmtsLayerInfo.BoundingBox bbox = new WmtsLayerInfo.BoundingBox();
bbox.crs = getAttributeValue(bboxNode, "crs"); // WGS84는 보통 CRS 속성이 없을 수 있음(Default EPSG:4326)
String lowerCorner = getChildValue(bboxNode, "LowerCorner");
String upperCorner = getChildValue(bboxNode, "UpperCorner");
if (lowerCorner != null) {
String[] coords = lowerCorner.split(" ");
bbox.lowerCornerX = Double.parseDouble(coords[0]);
bbox.lowerCornerY = Double.parseDouble(coords[1]);
}
if (upperCorner != null) {
String[] coords = upperCorner.split(" ");
bbox.upperCornerX = Double.parseDouble(coords[0]);
bbox.upperCornerY = Double.parseDouble(coords[1]);
}
return bbox;
}
return null;
}
private String getAttributeValue(Node node, String attrName) {
if (node.hasAttributes()) {
Node attr = node.getAttributes().getNamedItem(attrName);
if (attr != null) return attr.getNodeValue();
}
return null;
}
// Wrapper 없이 바로 반복되는 값 추출 (예: Format)
private List<String> getChildValuesDirect(Node parent, String childName) {
List<String> results = new ArrayList<>();
NodeList children = parent.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeName().endsWith(childName)) {
results.add(node.getTextContent());
}
}
return results;
}
private List<WmtsLayerInfo.ResourceUrl> parseResourceUrls(Node layerNode) {
List<WmtsLayerInfo.ResourceUrl> list = new ArrayList<>();
NodeList children = layerNode.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeName().contains("ResourceURL")) { // local-name check simplification
WmtsLayerInfo.ResourceUrl url = new WmtsLayerInfo.ResourceUrl();
url.setFormat(getAttributeValue(node, "format"));
url.setResourceType(getAttributeValue(node, "resourceType"));
url.setTemplate(getAttributeValue(node, "template"));
list.add(url);
}
}
return list;
}
private List<WmtsLayerInfo.Style> parseStyles(Node layerNode) {
List<WmtsLayerInfo.Style> styles = new ArrayList<>();
NodeList children = layerNode.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeName().endsWith("Style")) {
WmtsLayerInfo.Style style = new WmtsLayerInfo.Style();
style.setDefault(Boolean.parseBoolean(getAttributeValue(node, "isDefault")));
style.setIdentifier(getChildValue(node, "Identifier"));
style.setTitle(getChildValue(node, "Title"));
styles.add(style);
}
}
return styles;
}
/**
* WMTS Capabilities URL에서 특정 타이틀의 레이어 정보를 가져옵니다. // * @param capabilitiesUrl 예:
* http://localhost:8080/geoserver/gwc/service/wmts?REQUEST=GetCapabilities
@@ -292,7 +130,7 @@ public class WmtsService {
// 타이틀이 일치하면 객체 매핑 시작
if (title != null && title.trim().equals(targetTitle)) {
return parseLayerNode(layerNode, title);
return parseLayerNode(workspace, doc, layerNode, title);
}
}
@@ -303,4 +141,325 @@ public class WmtsService {
return null; // 찾지 못한 경우
}
// 레이어 노드를 Java 객체로 변환 20250130
private WmtsLayerInfo parseLayerNode(
String workspace, Document doc, Node layerNode, String title) {
WmtsLayerInfo info = new WmtsLayerInfo();
info.setWorkspace(workspace); // 20250130
info.setTitle(title);
info.setIdentifier(getChildValue(layerNode, "Identifier"));
info.setAbstractText(getChildValue(layerNode, "Abstract"));
// Keywords 파싱
info.setKeywords(getChildValues(layerNode, "Keywords", "Keyword"));
// BoundingBox 파싱 (WGS84BoundingBox 기준)
info.setBoundingBox(parseBoundingBox(layerNode));
// Formats 파싱
info.setFormats(getChildValuesDirect(layerNode, "Format"));
// TileMatrixSetLink 파싱 (TileMatrixSet + Zoom Levels)
info.setTileMatrixSetLinks(parseTileMatrixSetLinks(layerNode));
// TileMatrixSetLimits에서 줌 레벨 추출 (개별 zoom 리스트)
info.setMatrixIds(parseMatrixIds(layerNode)); // 20260130
// ResourceURL 파싱
info.setResourceUrls(parseResourceUrls(layerNode));
// Styles 파싱
info.setStyles(parseStyles(layerNode));
// TileMatrixSet의 TileMatrix 정보 파싱
List<String> tileMatrixSetNames = new ArrayList<>();
if (info.getTileMatrixSetLinks() != null) {
for (WmtsLayerInfo.TileMatrixSetLink link : info.getTileMatrixSetLinks()) {
tileMatrixSetNames.add(link.getTileMatrixSet());
}
}
info.setTileMatrices(parseTileMatrices(doc, tileMatrixSetNames));
return info;
}
// --- Helper Methods ---
private WmtsLayerInfo.BoundingBox parseBoundingBox(Node layerNode) {
// 보통 <ows:WGS84BoundingBox>를 찾음
Node bboxNode = findChildNode(layerNode, "WGS84BoundingBox");
if (bboxNode == null) bboxNode = findChildNode(layerNode, "BoundingBox");
if (bboxNode != null) {
WmtsLayerInfo.BoundingBox bbox = new WmtsLayerInfo.BoundingBox();
// WGS84는 CRS 속성이 없을 수 있음
bbox.setCrs(getAttributeValue(bboxNode, "crs"));
String lowerCorner = getChildValue(bboxNode, "LowerCorner");
String upperCorner = getChildValue(bboxNode, "UpperCorner");
if (lowerCorner != null) {
String[] coords = lowerCorner.split(" ");
bbox.setLowerCornerX(Double.parseDouble(coords[0]));
bbox.setLowerCornerY(Double.parseDouble(coords[1]));
}
if (upperCorner != null) {
String[] coords = upperCorner.split(" ");
bbox.setUpperCornerX(Double.parseDouble(coords[0]));
bbox.setUpperCornerY(Double.parseDouble(coords[1]));
}
return bbox;
}
return null;
}
private List<WmtsLayerInfo.ResourceUrl> parseResourceUrls(Node layerNode) {
List<WmtsLayerInfo.ResourceUrl> list = new ArrayList<>();
NodeList children = layerNode.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeName().contains("ResourceURL")) { // local-name check simplification
WmtsLayerInfo.ResourceUrl url = new WmtsLayerInfo.ResourceUrl();
url.setFormat(getAttributeValue(node, "format"));
url.setResourceType(getAttributeValue(node, "resourceType"));
url.setTemplate(getAttributeValue(node, "template"));
list.add(url);
}
}
return list;
}
private List<WmtsLayerInfo.Style> parseStyles(Node layerNode) {
List<WmtsLayerInfo.Style> styles = new ArrayList<>();
NodeList children = layerNode.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeName().endsWith("Style")) {
WmtsLayerInfo.Style style = new WmtsLayerInfo.Style();
style.setDefault(Boolean.parseBoolean(getAttributeValue(node, "isDefault")));
style.setIdentifier(getChildValue(node, "Identifier"));
style.setTitle(getChildValue(node, "Title"));
styles.add(style);
}
}
return styles;
}
/**
* TileMatrixSetLimits에서 줌 레벨을 추출합니다. 예: "EPSG:4326:0" → "0", "EPSG:4326:1" → "1"
*
* @param layerNode Layer 노드
* @return 줌 레벨 문자열 리스트
*/
private List<String> parseMatrixIds(Node layerNode) {
List<String> matrixIds = new ArrayList<>();
NodeList children = layerNode.getChildNodes();
// 모든 TileMatrixSetLink 찾기
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeName().contains("TileMatrixSetLink")) {
// TileMatrixSetLimits 찾기
Node limitsNode = findChildNode(node, "TileMatrixSetLimits");
if (limitsNode != null) {
NodeList limitsList = limitsNode.getChildNodes();
// 각 TileMatrixLimits 처리
for (int j = 0; j < limitsList.getLength(); j++) {
Node limitNode = limitsList.item(j);
if (limitNode.getNodeName().contains("TileMatrixLimits")) {
// TileMatrix 또는 Identifier 값 추출
String identifier = getChildValue(limitNode, "TileMatrix");
if (identifier == null) {
identifier = getChildValue(limitNode, "Identifier");
}
// 마지막 콜론 이후 값(줌 레벨) 추출
if (identifier != null && identifier.contains(":")) {
String[] parts = identifier.split(":");
String zoomLevel = parts[parts.length - 1];
matrixIds.add(zoomLevel);
}
}
}
}
}
}
return matrixIds;
}
/**
* TileMatrixSetLink 정보를 파싱합니다. 각 TileMatrixSetLink에서 TileMatrixSet 이름과 줌 레벨들을 추출합니다.
*
* @param layerNode Layer 노드
* @return TileMatrixSetLink 객체 리스트
*/
private List<WmtsLayerInfo.TileMatrixSetLink> parseTileMatrixSetLinks(Node layerNode) {
List<WmtsLayerInfo.TileMatrixSetLink> links = new ArrayList<>();
NodeList children = layerNode.getChildNodes();
// 모든 TileMatrixSetLink 찾기
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeName().contains("TileMatrixSetLink")) {
// TileMatrixSet 이름 추출
String tileMatrixSet = getChildValue(node, "TileMatrixSet");
// 줌 레벨들 추출
List<String> zoomLevels = new ArrayList<>();
Node limitsNode = findChildNode(node, "TileMatrixSetLimits");
if (limitsNode != null) {
NodeList limitsList = limitsNode.getChildNodes();
for (int j = 0; j < limitsList.getLength(); j++) {
Node limitNode = limitsList.item(j);
if (limitNode.getNodeName().contains("TileMatrixLimits")) {
// TileMatrix 또는 Identifier 값 추출
String identifier = getChildValue(limitNode, "TileMatrix");
if (identifier == null) {
identifier = getChildValue(limitNode, "Identifier");
}
// 마지막 콜론 이후 값(줌 레벨) 추출
if (identifier != null && identifier.contains(":")) {
String[] parts = identifier.split(":");
String zoomLevel = parts[parts.length - 1];
zoomLevels.add(zoomLevel);
}
}
}
}
// TileMatrixSetLink 객체 생성 및 추가
if (tileMatrixSet != null) {
WmtsLayerInfo.TileMatrixSetLink link =
new WmtsLayerInfo.TileMatrixSetLink(tileMatrixSet, zoomLevels);
links.add(link);
}
}
}
return links;
}
/**
* Document에서 TileMatrixSet의 TileMatrix 정보를 파싱합니다.
*
* @param doc WMTS Capabilities Document
* @param tileMatrixSetNames 조회할 TileMatrixSet 이름 리스트
* @return TileMatric 객체 리스트
*/
private List<WmtsLayerInfo.TileMatric> parseTileMatrices(
Document doc, List<String> tileMatrixSetNames) {
List<WmtsLayerInfo.TileMatric> allMatrices = new ArrayList<>();
try {
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
// 각 TileMatrixSet 이름에 대해 TileMatrix 찾기
for (String tileMatrixSetName : tileMatrixSetNames) {
// TileMatrixSet 찾기
String expression = "//*[local-name()='TileMatrixSet']";
NodeList tileMatrixSetNodes =
(NodeList) xpath.compile(expression).evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < tileMatrixSetNodes.getLength(); i++) {
Node tileMatrixSetNode = tileMatrixSetNodes.item(i);
String identifier = getChildValue(tileMatrixSetNode, "Identifier");
// 일치하는 TileMatrixSet 찾으면 TileMatrix 파싱
if (tileMatrixSetName.equals(identifier)) {
NodeList children = tileMatrixSetNode.getChildNodes();
for (int j = 0; j < children.getLength(); j++) {
Node node = children.item(j);
if (node.getNodeName().contains("TileMatrix")) {
WmtsLayerInfo.TileMatric tileMatric = new WmtsLayerInfo.TileMatric();
// TileMatrix 정보 추출
tileMatric.setScaleDenominator(getChildValue(node, "ScaleDenominator"));
tileMatric.setTopLeftCorner(getChildValue(node, "TopLeftCorner"));
tileMatric.setIdentifier(getChildValue(node, "Identifier"));
/* 미사용 정보 주석처리함
tileMatric.setTileWidth(getChildValue(node, "TileWidth"));
tileMatric.setTileHeight(getChildValue(node, "TileHeight"));
tileMatric.setMatrixWidth(getChildValue(node, "MatrixWidth"));
tileMatric.setMatrixHeight(getChildValue(node, "MatrixHeight"));
*/
allMatrices.add(tileMatric);
}
}
break; // 일치하는 TileMatrixSet 찾았으므로 다음으로
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return allMatrices;
}
// 특정 노드 아래의 자식 태그 값 추출 (예: <Title>값)
private String getChildValue(Node parent, String childName) {
Node child = findChildNode(parent, childName);
return (child != null) ? child.getTextContent() : null;
}
// 특정 노드 아래의 반복되는 자식 구조 값 추출 (예: Keywords -> Keyword)
private List<String> getChildValues(Node parent, String wrapperName, String childName) {
List<String> results = new ArrayList<>();
Node wrapper = findChildNode(parent, wrapperName);
if (wrapper != null) {
NodeList children = wrapper.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeName().endsWith(childName)) {
results.add(node.getTextContent());
}
}
}
return results;
}
// Wrapper 없이 바로 반복되는 값 추출 (예: Format)
private List<String> getChildValuesDirect(Node parent, String childName) {
List<String> results = new ArrayList<>();
NodeList children = parent.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeName().endsWith(childName)) {
results.add(node.getTextContent());
}
}
return results;
}
// 이름으로 자식 노드 찾기 (Local Name 기준)
private Node findChildNode(Node parent, String localName) {
NodeList children = parent.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
// 네임스페이스 접두사(ows:, wmts:)를 무시하고 태그 이름 확인
if (node.getNodeName().endsWith(":" + localName) || node.getNodeName().equals(localName)) {
return node;
}
}
return null;
}
private String getAttributeValue(Node node, String attrName) {
if (node.hasAttributes()) {
Node attr = node.getAttributes().getNamedItem(attrName);
if (attr != null) return attr.getNodeValue();
}
return null;
}
}

View File

@@ -7,6 +7,7 @@ import com.kamco.cd.kamcoback.common.utils.enums.EnumType;
import com.kamco.cd.kamcoback.common.utils.enums.Enums;
import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm;
import io.swagger.v3.oas.annotations.media.Schema;
import java.math.BigDecimal;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.UUID;
@@ -77,6 +78,34 @@ public class MapSheetMngDto {
@Schema(description = "선택폴더경로", example = "D:\\app\\original-images\\2022")
private String mngPath;
// Tile 등록 로직
@Schema(description = "url")
private String url;
@Schema(description = "좌측상단 경도", example = "126.0")
private BigDecimal minLon;
@Schema(description = "좌측상단 위도", example = "34.0")
private BigDecimal minLat;
@Schema(description = "우측하단 경도", example = "130.0")
private BigDecimal maxLon;
@Schema(description = "우측하단 위도", example = "38.5")
private BigDecimal maxLat;
@Schema(description = "zoom min", example = "5")
private Short minZoom;
@Schema(description = "zoom max", example = "18")
private Short maxZoom;
@Schema(description = "tag")
private String tag;
@Schema(description = "crs 좌표계")
private String crs;
@JsonIgnore private Long createdUid;
}
@@ -155,11 +184,14 @@ public class MapSheetMngDto {
}
public long getSyncErrorTotCnt() {
return this.syncNotPaireCnt + this.syncDuplicateCnt + this.syncFaultCnt;
return this.syncNotPaireCnt + this.syncDuplicateCnt + this.syncFaultCnt + this.syncNoFileCnt;
}
public long getSyncErrorExecTotCnt() {
return this.syncNotPaireExecCnt + this.syncDuplicateExecCnt + this.syncFaultExecCnt;
return this.syncNotPaireExecCnt
+ this.syncDuplicateExecCnt
+ this.syncFaultExecCnt
+ this.syncNoFileExecCnt;
}
public String getMngState() {

View File

@@ -182,6 +182,19 @@ public class MapSheetMngService {
MngFilesDto filesDto =
mapSheetMngCoreService.findYyyyToMapSheetFilePathRefer(errDto.getMngYyyy());
String referPath = filesDto.getFilePath();
Path path = Paths.get(referPath);
boolean isFiveDigitNumber =
path.getFileName() != null && path.getFileName().toString().matches("\\d{5}");
log.info("isFiveDigitNumber : " + isFiveDigitNumber);
if (isFiveDigitNumber) {
uploadPath =
Paths.get(referPath).getParent().toString()
+ "/"
+ errDto.getRefMapSheetNum()
+ "/"
+ errDto.getUuid();
} else {
uploadPath =
Paths.get(referPath).getParent().getParent().toString()
+ "/"
@@ -189,6 +202,7 @@ public class MapSheetMngService {
+ "/"
+ errDto.getUuid();
}
}
// 업로드 경로 확인(없으면 생성)
if (!FIleChecker.mkDir(uploadPath)) {
@@ -198,6 +212,8 @@ public class MapSheetMngService {
tfwTargetPath = Paths.get(uploadPath).resolve(tfwFile.getOriginalFilename());
tifTargetPath = Paths.get(uploadPath).resolve(tifFile);
log.info("tfwTargetPath : " + tfwTargetPath.toString());
log.info("tifTargetPath : " + tifTargetPath.toString());
if (!Files.exists(tifTargetPath)) {
return new DmlReturn("fail", "TIF 파일이 정상적으로 업로드 되지 않았습니다. 확인해주세요.");
}
@@ -240,6 +256,9 @@ public class MapSheetMngService {
addReq.setFileSize(tifFileSize);
mapSheetMngCoreService.mngFileSave(addReq);
// 사용할 수 있는 이전 년도 도엽 테이블 저장
mapSheetMngCoreService.saveSheetMngYear();
return new DmlReturn("success", "파일 업로드 완료되었습니다.");
}
@@ -322,12 +341,14 @@ public class MapSheetMngService {
String dirPath = syncRootDir + srchDto.getDirPath();
String sortType = "name desc";
List<FIleChecker.Folder> folderList = FIleChecker.getFolderAll(dirPath);
List<FIleChecker.Folder> folderList =
FIleChecker.getFolderAll(dirPath).stream()
.filter(dir -> dir.getIsValid().equals(true))
.toList();
int folderTotCnt = folderList.size();
int folderErrTotCnt =
(int)
folderList.stream().filter(dto -> dto.getIsValid().toString().equals("false")).count();
(int) folderList.stream().filter(dto -> dto.getIsValid().equals(false)).count();
return new FoldersDto(dirPath, folderTotCnt, folderErrTotCnt, folderList);
}
@@ -390,11 +411,20 @@ public class MapSheetMngService {
MngFilesDto filesDto =
mapSheetMngCoreService.findYyyyToMapSheetFilePathRefer(errDto.getMngYyyy());
String referPath = filesDto.getFilePath();
Path path = Paths.get(referPath);
boolean isFiveDigitNumber =
path.getFileName() != null && path.getFileName().toString().matches("\\d{5}");
log.info("isFiveDigitNumber : " + isFiveDigitNumber);
if (isFiveDigitNumber) {
uploadPath = Paths.get(referPath).getParent().toString() + "/" + errDto.getRefMapSheetNum();
} else {
uploadPath =
Paths.get(referPath).getParent().getParent().toString()
+ "/"
+ errDto.getRefMapSheetNum();
}
}
upAddReqDto.setFinalPath(uploadPath + "/");
upAddReqDto.setTempPath(upAddReqDto.getTempPath() + "/");

View File

@@ -111,8 +111,8 @@ public class MembersDto {
@EnumValid(enumClass = RoleType.class, message = "userRole은 ADMIN, LABELER, REVIEWER 만 가능합니다.")
private String userRole;
@Schema(description = "사번", example = "K20251212001")
@Size(max = 50)
@Schema(description = "사번", example = "123456")
@Size(max = 6)
private String employeeNo;
@Schema(description = "이름", example = "홍길동")

View File

@@ -11,7 +11,7 @@ import lombok.ToString;
@ToString(exclude = "password")
public class SignInRequest {
@Schema(description = "사용자 ID", example = "1234567")
@Schema(description = "사용자 ID", example = "123456")
private String username;
@Schema(description = "비밀번호", example = "qwe123!@#")

View File

@@ -56,6 +56,12 @@ public class ModelMngService {
@Value("${file.model-tmp-dir}")
private String modelTmpDir;
@Value("${file.pt-path}")
private String ptPath;
@Value("${file.pt-FileName}")
private String ptFileName;
public Page<ModelMngDto.ModelList> findModelMgmtList(
ModelMngDto.searchReq searchReq,
LocalDate startDate,
@@ -235,10 +241,7 @@ public class ModelMngService {
int endPos = 20;
List<Basic> files =
FIleChecker.getFilesFromAllDepth(
dirPath, "*", "pth,py,pt,json", 10, "name", startPos, endPos);
boolean hasPt = false; // pt 파일 존재 여부
FIleChecker.getFilesFromAllDepth(dirPath, "*", "pth,py,json", 10, "name", startPos, endPos);
for (Basic dto : files) {
// 예: 파일명 출력 및 추가 작업
@@ -253,11 +256,6 @@ public class ModelMngService {
modelUploadResDto.setCdModelConfigPath(foldNm);
modelUploadResDto.setCdModelConfigFileName(dto.getFileNm());
}
case "pt" -> {
modelUploadResDto.setClsModelPath(foldNm);
modelUploadResDto.setClsModelFileName(dto.getFileNm());
hasPt = true;
}
case "json" -> {
modelUploadResDto.setJsonPath(foldNm);
modelUploadResDto.setJsonFileName(dto.getFileNm());
@@ -265,10 +263,9 @@ public class ModelMngService {
}
}
if (!hasPt) {
String defaultPath = "/kamco-nfs/ckpt/classification/";
String defaultFileName = "v5-best.pt";
// cls model 적용
String defaultPath = ptPath;
String defaultFileName = ptFileName;
Path ptPath = Paths.get(defaultPath, defaultFileName);
@@ -276,7 +273,6 @@ public class ModelMngService {
modelUploadResDto.setClsModelPath(defaultPath);
modelUploadResDto.setClsModelFileName(defaultFileName);
}
}
// int fileListPos = 0;
// int fileTotCnt = files.size();

View File

@@ -1,7 +1,13 @@
package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.Basic;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LabelSendDto;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GukYuinLinkFacts;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.LearnInfo;
import com.kamco.cd.kamcoback.postgres.repository.Inference.MapSheetLearnRepository;
import com.kamco.cd.kamcoback.postgres.repository.gukyuin.GukYuinRepository;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -11,6 +17,7 @@ import org.springframework.stereotype.Service;
public class GukYuinCoreService {
private final MapSheetLearnRepository mapSheetLearnRepository;
private final GukYuinRepository gukYuinRepository;
/**
* 국유in연동 가능여부 확인
@@ -21,4 +28,53 @@ public class GukYuinCoreService {
public GukYuinLinkFacts findLinkFacts(UUID uuid) {
return mapSheetLearnRepository.findLinkFacts(uuid);
}
public void updateGukYuinMastRegResult(Basic resultBody) {
gukYuinRepository.updateGukYuinMastRegResult(resultBody);
}
public void updateGukYuinMastRegRemove(String chnDtctId) {
gukYuinRepository.updateGukYuinMastRegRemove(chnDtctId);
}
public void updateInferenceGeomDataPnuCnt(String chnDtctObjtId, long pnuCnt) {
gukYuinRepository.updateInferenceGeomDataPnuCnt(chnDtctObjtId, pnuCnt);
}
public Long findMapSheetAnalDataInferenceGeomUid(String chnDtctObjtId) {
return gukYuinRepository.findMapSheetAnalDataInferenceGeomUid(chnDtctObjtId);
}
public void insertGeoUidPnuData(Long geoUid, String[] pnuList, String chnDtctObjtId) {
gukYuinRepository.insertGeoUidPnuData(geoUid, pnuList, chnDtctObjtId);
}
public LearnInfo findMapSheetLearnInfo(UUID uuid) {
return gukYuinRepository.findMapSheetLearnInfo(uuid);
}
public Integer findMapSheetLearnYearStage(Integer compareYyyy, Integer targetYyyy) {
return gukYuinRepository.findMapSheetLearnYearStage(compareYyyy, targetYyyy);
}
public void updateAnalInferenceApplyDttm(Basic registRes) {
gukYuinRepository.updateAnalInferenceApplyDttm(registRes);
}
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

@@ -0,0 +1,27 @@
package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LearnKeyDto;
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 {
private final GukYuinRepository gukYuinRepository;
public GukYuinJobCoreService(GukYuinRepository gukYuinRepository) {
this.gukYuinRepository = gukYuinRepository;
}
@Transactional
public void updateGukYuinApplyStateComplete(Long id, GukYuinStatus status) {
gukYuinRepository.updateGukYuinApplyStateComplete(id, status);
}
public List<LearnKeyDto> findGukyuinApplyStatusUidList(List<String> gukYuinStatus) {
return gukYuinRepository.findGukyuinApplyStatusUidList(gukYuinStatus);
}
}

View File

@@ -0,0 +1,26 @@
package com.kamco.cd.kamcoback.postgres.core;
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 {
private final GukYuinLabelJobRepository gukYuinLabelRepository;
public GukYuinLabelJobCoreService(GukYuinLabelJobRepository gukYuinLabelRepository) {
this.gukYuinLabelRepository = gukYuinLabelRepository;
}
public List<GeomUidDto> findYesterdayLabelingCompleteList() {
return gukYuinLabelRepository.findYesterdayLabelingCompleteList();
}
@Transactional
public void updateAnalDataInferenceGeomSendDttm(Long geoUid) {
gukYuinLabelRepository.updateAnalDataInferenceGeomSendDttm(geoUid);
}
}

View File

@@ -0,0 +1,44 @@
package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LearnKeyDto;
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 {
private final GukYuinPnuJobRepository gukYuinPnuRepository;
public GukYuinPnuJobCoreService(GukYuinPnuJobRepository gukYuinPnuRepository) {
this.gukYuinPnuRepository = gukYuinPnuRepository;
}
public void updateGukYuinApplyStateComplete(Long id, GukYuinStatus status) {
gukYuinPnuRepository.updateGukYuinApplyStateComplete(id, status);
}
public List<LearnKeyDto> findGukyuinApplyStatusUidList(List<String> gukYuinStatus) {
return gukYuinPnuRepository.findGukyuinApplyStatusUidList(gukYuinStatus);
}
public long upsertMapSheetDataAnalGeomPnu(String chnDtctObjtId, String[] pnuList) {
return gukYuinPnuRepository.upsertMapSheetDataAnalGeomPnu(chnDtctObjtId, pnuList);
}
@Transactional
public void updateInferenceGeomDataPnuCnt(String chnDtctObjtId, long pnuCnt) {
gukYuinPnuRepository.updateInferenceGeomDataPnuCnt(chnDtctObjtId, pnuCnt);
}
public Long findMapSheetAnalDataInferenceGeomUid(String chnDtctObjtId) {
return gukYuinPnuRepository.findMapSheetAnalDataInferenceGeomUid(chnDtctObjtId);
}
@Transactional
public void insertGeoUidPnuData(Long geoUid, String[] pnuList, String chnDtctObjtId) {
gukYuinPnuRepository.insertGeoUidPnuData(geoUid, pnuList, chnDtctObjtId);
}
}

View File

@@ -0,0 +1,75 @@
package com.kamco.cd.kamcoback.postgres.core;
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;
import com.kamco.cd.kamcoback.postgres.repository.gukyuin.GukYuinStbltJobRepository;
import java.time.ZonedDateTime;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class GukYuinStbltJobCoreService {
private final GukYuinStbltJobRepository gukYuinStbltRepository;
public GukYuinStbltJobCoreService(GukYuinStbltJobRepository gukYuinStbltRepository) {
this.gukYuinStbltRepository = gukYuinStbltRepository;
}
public List<LearnKeyDto> findGukYuinEligibleForSurveyList(String status) {
return gukYuinStbltRepository.findGukYuinEligibleForSurveyList(status);
}
@Transactional
public void updateGukYuinEligibleForSurvey(String resultUid, RlbDtctMastDto stbltDto) {
String chnDtctObjtId = "";
PnuEntity entity =
gukYuinStbltRepository.findPnuEntityByResultUid(resultUid, stbltDto.getPnu());
if (entity != null) {
chnDtctObjtId = resultUid;
entity.setPnuDtctId(stbltDto.getPnuDtctId());
entity.setPnu(stbltDto.getPnu());
entity.setLrmSyncYmd(stbltDto.getLrmSyncYmd());
entity.setPnuSyncYmd(stbltDto.getPnuSyncYmd());
entity.setMpqdNo(stbltDto.getMpqdNo());
entity.setCprsYr(stbltDto.getCprsYr());
entity.setCrtrYr(stbltDto.getCrtrYr());
entity.setChnDtctSno(stbltDto.getChnDtctSno());
entity.setChnDtctId(stbltDto.getChnDtctId());
entity.setChnDtctMstId(stbltDto.getChnDtctMstId());
entity.setChnDtctObjtId(stbltDto.getChnDtctObjtId());
entity.setChnDtctContId(stbltDto.getChnDtctContId());
entity.setChnCd(stbltDto.getChnCd());
entity.setBfClsCd(stbltDto.getBfClsCd());
entity.setBfClsProb(stbltDto.getBfClsProb());
entity.setAfClsCd(stbltDto.getAfClsCd());
entity.setAfClsProb(stbltDto.getAfClsProb());
entity.setPnuSqms(stbltDto.getPnuSqms());
entity.setPnuDtctSqms(stbltDto.getPnuDtctSqms());
entity.setChnDtctSqms(stbltDto.getChnDtctSqms());
entity.setStbltYn(stbltDto.getStbltYn());
entity.setIncyCd(stbltDto.getIncyCd());
entity.setIncyRsnCont(stbltDto.getIncyRsnCont());
entity.setLockYn(stbltDto.getLockYn());
entity.setLblYn(stbltDto.getLblYn());
entity.setChgYn(stbltDto.getChgYn());
entity.setRsatctNo(stbltDto.getRsatctNo());
entity.setRmk(stbltDto.getRmk());
entity.setCrtDt(stbltDto.getCrtDt());
entity.setCrtEpno(stbltDto.getCrtEpno());
entity.setCrtIp(stbltDto.getCrtIp());
entity.setChgDt(stbltDto.getChgDt());
entity.setChgIp(stbltDto.getChgIp());
entity.setDelYn(stbltDto.getDelYn().equals("Y"));
entity.setCreatedDttm(ZonedDateTime.now());
gukYuinStbltRepository.save(entity);
//
}
}
}

View File

@@ -37,10 +37,12 @@ import jakarta.persistence.EntityNotFoundException;
import jakarta.validation.constraints.NotNull;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
@@ -81,23 +83,29 @@ public class InferenceResultCoreService {
* @param req
*/
public UUID saveInferenceInfo(InferenceResultDto.RegReq req, List<MngListDto> targetList) {
String firstMapSheetName = null;
String mapSheetName = "";
int detectingCnt = 0;
for (MngListDto dto : targetList) {
if (detectingCnt == 0) {
firstMapSheetName = dto.getMapSheetName();
}
detectingCnt++;
}
List<MngListDto> distinctList =
targetList.stream()
.filter(dto -> dto.getMapSheetName() != null && !dto.getMapSheetName().isBlank())
.collect(
Collectors.toMap(
MngListDto::getMapSheetName,
dto -> dto,
(existing, duplicate) -> existing,
LinkedHashMap::new))
.values()
.stream()
.toList();
int detectingCnt = distinctList.size();
String mapSheetName;
if (detectingCnt == 0) {
mapSheetName = "";
} else if (detectingCnt == 1) {
mapSheetName = firstMapSheetName + " 1건";
mapSheetName = distinctList.get(0).getMapSheetName() + " 1건";
} else {
mapSheetName = firstMapSheetName + "" + (detectingCnt - 1) + "";
mapSheetName = distinctList.get(0).getMapSheetName() + "" + (detectingCnt - 1) + "";
}
MapSheetLearnEntity mapSheetLearnEntity = new MapSheetLearnEntity();
@@ -113,7 +121,7 @@ public class InferenceResultCoreService {
mapSheetLearnEntity.setCreatedUid(userUtil.getId());
mapSheetLearnEntity.setMapSheetCnt(mapSheetName);
mapSheetLearnEntity.setDetectingCnt(0L);
mapSheetLearnEntity.setTotalJobs((long) detectingCnt);
mapSheetLearnEntity.setTotalJobs((long) targetList.size());
// 회차는 국유인 반영할때 update로 변경됨
// mapSheetLearnEntity.setStage(

View File

@@ -1,29 +1,277 @@
package com.kamco.cd.kamcoback.postgres.core;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kamco.cd.kamcoback.common.enums.LayerType;
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
import com.kamco.cd.kamcoback.common.utils.UserUtil;
import com.kamco.cd.kamcoback.layer.dto.LayerDto;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.IsMapYn;
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.WmtsDto.WmtsAddDto;
import com.kamco.cd.kamcoback.postgres.entity.MapLayerEntity;
import com.kamco.cd.kamcoback.postgres.repository.layer.MapLayerRepository;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class MapLayerCoreService {
private final MapLayerRepository mapLayerRepository;
private final UserUtil userUtil;
private final ObjectMapper objectMapper;
/**
* 지도 레이어 관리 목록
*
* @return
*/
public List<LayerDto.Basic> getLayers(LayerDto.SearchReq searchReq) {
return mapLayerRepository.findAllLayer(searchReq);
}
/**
* 지도 레이어 상세 목록
*
* @param uuid
* @return
*/
public LayerDto.Detail getLayers(UUID uuid) {
MapLayerEntity entity =
mapLayerRepository
.findDetailByUuid(uuid)
.orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND));
return entity.toDto();
}
/**
* 삭제
*
* @param uuid
*/
public void delete(UUID uuid) {
MapLayerEntity entity =
mapLayerRepository
.findDetailByUuid(uuid)
.orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND));
entity.setIsDeleted(true);
entity.setUpdatedUid(userUtil.getId());
entity.setUpdatedDttm(ZonedDateTime.now());
}
/**
* 수정
*
* @param uuid
*/
public void update(UUID uuid, LayerDto.Detail dto) {
MapLayerEntity entity =
mapLayerRepository
.findDetailByUuid(uuid)
.orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND));
if (dto.getDescription() != null) {
entity.setDescription(dto.getDescription());
}
if (dto.getUrl() != null) {
entity.setUrl(dto.getUrl());
}
if (dto.getTag() != null) {
entity.setTag(dto.getTag());
}
if (dto.getMinLon() != null) {
entity.setMinLon(dto.getMinLon());
}
if (dto.getMaxLon() != null) {
entity.setMaxLon(dto.getMaxLon());
}
if (dto.getMinLat() != null) {
entity.setMinLat(dto.getMinLat());
}
if (dto.getMaxLat() != null) {
entity.setMaxLat(dto.getMaxLat());
}
if (dto.getMin() != null) {
entity.setMinZoom(dto.getMin());
}
if (dto.getMax() != null) {
entity.setMaxZoom(dto.getMax());
}
if (dto.getIsChangeMap() != null) {
entity.setIsChangeMap(dto.getIsChangeMap());
}
if (dto.getIsLabelingMap() != null) {
entity.setIsLabelingMap(dto.getIsLabelingMap());
}
if (dto.getCrs() != null) {
entity.setCrs(dto.getCrs());
}
entity.setUpdatedUid(userUtil.getId());
entity.setUpdatedDttm(ZonedDateTime.now());
}
/**
* 맵 노출 여부
*
* @param uuid
* @param isMapYn
*/
public void updateIsMap(UUID uuid, IsMapYn isMapYn) {
MapLayerEntity entity =
mapLayerRepository
.findDetailByUuid(uuid)
.orElseThrow(() -> new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND));
LayerDto.MapType mapType;
try {
mapType = LayerDto.MapType.valueOf(isMapYn.getMapType());
} catch (IllegalArgumentException e) {
throw new CustomApiException("BAD_REQUEST", HttpStatus.BAD_REQUEST);
}
switch (mapType) {
case CHANGE_MAP -> entity.setIsChangeMap(isMapYn.getIsMapYn());
case LABELING_MAP -> entity.setIsLabelingMap(isMapYn.getIsMapYn());
}
}
/**
* 순서 수정
*
* @param dtoList
*/
public void orderUpdate(List<OrderReq> dtoList) {
if (dtoList == null || dtoList.isEmpty()) {
return;
}
List<UUID> uuids =
dtoList.stream().map(OrderReq::getUuid).filter(Objects::nonNull).distinct().toList();
if (uuids.isEmpty()) {
throw new CustomApiException("BAD_REQUEST", HttpStatus.BAD_REQUEST);
}
List<MapLayerEntity> entities = mapLayerRepository.findAllByUuidIn(uuids);
Map<UUID, MapLayerEntity> entityMap =
entities.stream().collect(Collectors.toMap(MapLayerEntity::getUuid, Function.identity()));
List<UUID> notFound = uuids.stream().filter(u -> !entityMap.containsKey(u)).toList();
if (!notFound.isEmpty()) {
throw new CustomApiException("NOT_FOUND_DATA", HttpStatus.NOT_FOUND);
}
Long uid = userUtil.getId();
ZonedDateTime now = ZonedDateTime.now();
for (OrderReq dto : dtoList) {
if (dto.getOrder() == null) {
throw new CustomApiException("INVALID_REQUEST", HttpStatus.BAD_REQUEST);
}
MapLayerEntity entity = entityMap.get(dto.getUuid());
entity.setOrder(dto.getOrder());
entity.setUpdatedUid(uid);
entity.setUpdatedDttm(now);
}
}
/**
* Tile 저장
*
* @param dto
*/
public UUID saveTile(LayerDto.AddReq dto) {
Long order = mapLayerRepository.findSortOrderDesc();
MapLayerEntity mapLayerEntity = new MapLayerEntity();
mapLayerEntity.setDescription(dto.getDescription());
mapLayerEntity.setUrl(dto.getUrl());
mapLayerEntity.setTag(dto.getTag());
mapLayerEntity.setMinLon(dto.getMinLon());
mapLayerEntity.setMinLat(dto.getMinLat());
mapLayerEntity.setMaxLon(dto.getMaxLon());
mapLayerEntity.setMaxLat(dto.getMaxLat());
mapLayerEntity.setMinZoom(dto.getMin());
mapLayerEntity.setMaxZoom(dto.getMax());
mapLayerEntity.setCrs(dto.getCrs());
mapLayerEntity.setCreatedUid(userUtil.getId());
mapLayerEntity.setIsChangeMap(true);
mapLayerEntity.setIsLabelingMap(true);
mapLayerEntity.setOrder(order + 1);
mapLayerEntity.setLayerType(LayerType.TILE.getId());
mapLayerEntity.setUpdatedDttm(ZonedDateTime.now());
return mapLayerRepository.save(mapLayerEntity).getUuid();
}
/**
* GeoJson 저장
*
* @param addDto
* @return
*/
public UUID saveGeoJson(LayerDto.AddReq addDto) {
Long order = mapLayerRepository.findSortOrderDesc();
MapLayerEntity mapLayerEntity = new MapLayerEntity();
mapLayerEntity.setDescription(addDto.getDescription());
mapLayerEntity.setUrl(addDto.getUrl());
mapLayerEntity.setTag(addDto.getTag());
mapLayerEntity.setCreatedUid(userUtil.getId());
mapLayerEntity.setIsChangeMap(true);
mapLayerEntity.setIsLabelingMap(true);
mapLayerEntity.setLayerType(LayerType.GEOJSON.getId());
mapLayerEntity.setCrs(addDto.getCrs());
mapLayerEntity.setUpdatedDttm(ZonedDateTime.now());
mapLayerEntity.setOrder(order + 1);
return mapLayerRepository.save(mapLayerEntity).getUuid();
}
/**
* wmts 저장
*
* @param addDto
*/
public void save(WmtsAddDto addDto) {
public UUID saveWmts(WmtsAddDto addDto) {
Long order = mapLayerRepository.findSortOrderDesc();
String rawJson = "";
try {
String rawJson = objectMapper.writeValueAsString(addDto.getWmtsLayerInfo()); // data 없는 형태로 저장
rawJson = objectMapper.writeValueAsString(addDto.getWmtsLayerInfo()); // data 없는 형태로 저장
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
MapLayerEntity mapLayerEntity = new MapLayerEntity();
mapLayerEntity.setTitle(addDto.getTitle());
mapLayerEntity.setDescription(addDto.getDescription());
@@ -31,13 +279,54 @@ public class MapLayerCoreService {
mapLayerEntity.setRawJson(rawJson);
mapLayerEntity.setIsChangeMap(true);
mapLayerEntity.setIsLabelingMap(true);
mapLayerEntity.setOrder(10L);
mapLayerEntity.setLayerType("WMTS");
mapLayerRepository.save(mapLayerEntity);
} catch (Exception e) {
e.printStackTrace();
mapLayerEntity.setOrder(order + 1);
mapLayerEntity.setLayerType(LayerType.WMTS.getId());
mapLayerEntity.setUpdatedDttm(ZonedDateTime.now());
mapLayerEntity.setTag(addDto.getTag());
return mapLayerRepository.save(mapLayerEntity).getUuid();
}
//
/**
* wms 저장
*
* @param addDto
* @return
*/
public UUID saveWms(WmsAddDto addDto) {
Long order = mapLayerRepository.findSortOrderDesc();
String rawJson = "";
try {
rawJson = objectMapper.writeValueAsString(addDto.getWmsLayerInfo()); // data 없는 형태로 저장
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
MapLayerEntity mapLayerEntity = new MapLayerEntity();
mapLayerEntity.setTitle(addDto.getTitle());
mapLayerEntity.setDescription(addDto.getDescription());
mapLayerEntity.setCreatedUid(userUtil.getId());
mapLayerEntity.setRawJson(rawJson);
mapLayerEntity.setIsChangeMap(true);
mapLayerEntity.setIsLabelingMap(true);
mapLayerEntity.setOrder(order + 1);
mapLayerEntity.setLayerType(LayerType.WMS.getId());
mapLayerEntity.setUpdatedDttm(ZonedDateTime.now());
mapLayerEntity.setTag(addDto.getTag());
return mapLayerRepository.save(mapLayerEntity).getUuid();
}
public List<LayerMapDto> findLayerMapList(String type) {
return mapLayerRepository.findLayerMapList(type);
}
public LayerDto.YearTileDto getChangeDetectionTileUrl(Integer beforeYear, Integer afterYear) {
return mapLayerRepository.getChangeDetectionTileUrl(beforeYear, afterYear);
}
public TileUrlDto getChangeDetectionTileOneYearUrl(Integer year) {
return mapLayerRepository.getChangeDetectionTileOneYearUrl(year);
}
}

View File

@@ -16,6 +16,7 @@ import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngEntity;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngHstEntity;
import com.kamco.cd.kamcoback.postgres.entity.YearEntity;
import com.kamco.cd.kamcoback.postgres.repository.mapsheet.MapSheetMngRepository;
import com.kamco.cd.kamcoback.postgres.repository.mapsheet.MapSheetMngYearRepository;
import jakarta.persistence.EntityNotFoundException;
import jakarta.validation.Valid;
import java.io.IOException;
@@ -44,6 +45,7 @@ import org.springframework.transaction.annotation.Transactional;
public class MapSheetMngCoreService {
private final MapSheetMngRepository mapSheetMngRepository;
private final MapSheetMngYearRepository mapSheetMngYearRepository;
@Value("${spring.profiles.active}")
private String activeEnv;
@@ -160,6 +162,9 @@ public class MapSheetMngCoreService {
saved.getMngYyyy(), saved.getMngPath());
mapSheetMngRepository.updateYearState(saved.getMngYyyy(), "DONE");
// 년도별 Tile 정보 등록
mapSheetMngRepository.insertMapSheetMngTile(addReq);
return hstCnt;
}
@@ -310,18 +315,23 @@ public class MapSheetMngCoreService {
return mapSheetMngRepository.findByHstMapSheetTargetList(mngYyyy, mapIds);
}
/**
* 변화탐지 실행 가능 비교년도 조회
*
* @param mngYyyy
* @param mapId
* @return
*/
public List<MngListCompareDto> getByHstMapSheetCompareList(int mngYyyy, List<String> mapId) {
return mapSheetMngRepository.findByHstMapSheetCompareList(mngYyyy, mapId);
}
public void updateMapSheetMngHstUploadId(Long hstUid, UUID uuid, String uploadId) {
mapSheetMngRepository.updateMapSheetMngHstUploadId(hstUid, uuid, uploadId);
}
/** 변화탐지 실행 가능 비교년도 저장 */
public void saveSheetMngYear() {
mapSheetMngYearRepository.saveFileInfo();
}
/**
* 변화탐지 실행 가능 비교년도 조회
*
* @param mngYyyy 비교년도
* @param mapId 5k 도엽번호
* @return List<MngListCompareDto>
*/
public List<MngListCompareDto> getByHstMapSheetCompareList(int mngYyyy, List<String> mapId) {
return mapSheetMngYearRepository.findByHstMapSheetCompareList(mngYyyy, mapId);
}
}

View File

@@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.common.enums.CommonUseStatus;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngFileEntity;
import com.kamco.cd.kamcoback.postgres.repository.mapsheet.MapSheetMngYearRepository;
import com.kamco.cd.kamcoback.postgres.repository.scheduler.MapSheetMngFileJobRepository;
import com.kamco.cd.kamcoback.scheduler.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.scheduler.dto.MapSheetMngDto.MngHstDto;
@@ -16,6 +17,7 @@ import org.springframework.stereotype.Service;
public class MapSheetMngFileJobCoreService {
private final MapSheetMngFileJobRepository mapSheetMngFileJobRepository;
private final MapSheetMngYearRepository mapSheetMngYearRepository;
public Page<MapSheetMngDto.MngDto> findMapSheetMngList(
MapSheetMngDto.@Valid MngSearchReq searchReq) {
@@ -73,4 +75,8 @@ public class MapSheetMngFileJobCoreService {
public void updateException5kMapSheet(String mapSheetNum, CommonUseStatus commonUseStatus) {
mapSheetMngFileJobRepository.updateException5kMapSheet(mapSheetNum, commonUseStatus);
}
public void saveSheetMngYear() {
mapSheetMngYearRepository.saveFileInfo();
}
}

View File

@@ -0,0 +1,36 @@
package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.postgres.repository.scheduler.TrainingDataLabelJobRepository;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.InspectorPendingDto;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.Tasks;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class TrainingDataLabelJobCoreService {
private final TrainingDataLabelJobRepository trainingDataLabelJobRepository;
public List<Tasks> findCompletedYesterdayUnassigned() {
return trainingDataLabelJobRepository.findCompletedYesterdayUnassigned();
}
public void assignReviewerBatch(List<UUID> assignmentUids, String reviewerId) {
trainingDataLabelJobRepository.assignReviewerBatch(assignmentUids, reviewerId);
}
public List<InspectorPendingDto> findInspectorPendingByRound(Long analUid) {
return trainingDataLabelJobRepository.findInspectorPendingByRound(analUid);
}
public void lockInspectors(Long analUid, List<String> reviewerIds) {
trainingDataLabelJobRepository.lockInspectors(analUid, reviewerIds);
}
public void updateGeomUidTestState(List<Long> geomUids) {
trainingDataLabelJobRepository.updateGeomUidTestState(geomUids);
}
}

View File

@@ -4,10 +4,7 @@ import com.kamco.cd.kamcoback.postgres.repository.scheduler.TrainingDataReviewJo
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.AnalCntInfo;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.AnalMapSheetList;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.CompleteLabelData;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.InspectorPendingDto;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.Tasks;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -17,34 +14,6 @@ public class TrainingDataReviewJobCoreService {
private final TrainingDataReviewJobRepository trainingDataReviewJobRepository;
public List<Tasks> findCompletedYesterdayUnassigned() {
return trainingDataReviewJobRepository.findCompletedYesterdayUnassigned();
}
public void assignReviewer(UUID assignmentUid, String reviewerId) {
trainingDataReviewJobRepository.assignReviewer(assignmentUid, reviewerId);
}
public void assignReviewerBatch(List<UUID> assignmentUids, String reviewerId) {
trainingDataReviewJobRepository.assignReviewerBatch(assignmentUids, reviewerId);
}
public Tasks findAssignmentTask(String assignmentUid) {
return trainingDataReviewJobRepository.findAssignmentTask(assignmentUid);
}
public List<InspectorPendingDto> findInspectorPendingByRound(Long analUid) {
return trainingDataReviewJobRepository.findInspectorPendingByRound(analUid);
}
public void lockInspectors(Long analUid, List<String> reviewerIds) {
trainingDataReviewJobRepository.lockInspectors(analUid, reviewerIds);
}
public void updateGeomUidTestState(List<Long> geomUids) {
trainingDataReviewJobRepository.updateGeomUidTestState(geomUids);
}
public List<CompleteLabelData> findCompletedYesterdayLabelingList(
Long analUid, String mapSheetNum) {
return trainingDataReviewJobRepository.findCompletedYesterdayLabelingList(analUid, mapSheetNum);

View File

@@ -1,5 +1,6 @@
package com.kamco.cd.kamcoback.postgres.entity;
import com.kamco.cd.kamcoback.layer.dto.LayerDto;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
@@ -73,10 +74,10 @@ public class MapLayerEntity {
@NotNull
@ColumnDefault("now()")
@Column(name = "created_dttm", nullable = false)
private ZonedDateTime createdAt = ZonedDateTime.now();
private ZonedDateTime createdDttm = ZonedDateTime.now();
@Column(name = "updated_dttm")
private ZonedDateTime updatedAt;
private ZonedDateTime updatedDttm;
@Column(name = "uuid")
private UUID uuid = UUID.randomUUID();
@@ -93,6 +94,36 @@ public class MapLayerEntity {
@Column(name = "is_labeling_map")
private Boolean isLabelingMap;
@Column(name = "order")
@Column(name = "sort_order")
private Long order;
@Column(name = "tag")
private String tag;
@Column(name = "is_deleted")
private Boolean isDeleted = false;
@Column(name = "crs")
private String crs;
public LayerDto.Detail toDto() {
return new LayerDto.Detail(
this.uuid,
this.layerType,
this.title,
this.description,
this.tag,
this.order,
this.isChangeMap,
this.isLabelingMap,
this.url,
this.minLon,
this.minLat,
this.maxLon,
this.maxLat,
this.minZoom,
this.maxZoom,
this.createdDttm,
this.crs);
}
}

View File

@@ -156,6 +156,12 @@ public class MapSheetAnalDataInferenceGeomEntity {
@JoinColumn(name = "map_5k_id", referencedColumnName = "fid")
private MapInkx5kEntity map5k;
@Column(name = "label_send_dttm")
private ZonedDateTime labelSendDttm;
@Column(name = "lock_yn")
private String lockYn;
public InferenceDetailDto.DetailListEntity toEntity() {
DetectionClassification classification = DetectionClassification.fromString(classBeforeCd);
Clazzes comparedClazz = new Clazzes(classification, classBeforeProb);

View File

@@ -199,6 +199,9 @@ public class MapSheetLearnEntity {
@Column(name = "total_jobs")
private Long totalJobs;
@Column(name = "chn_dtct_mst_id")
private String chnDtctMstId;
public InferenceResultDto.ResultList toDto() {
return new InferenceResultDto.ResultList(
this.uuid,

View File

@@ -0,0 +1,58 @@
package com.kamco.cd.kamcoback.postgres.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.ZonedDateTime;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.ColumnDefault;
@Getter
@Setter
@Entity
@Table(name = "tb_map_sheet_mng_tile")
public class MapSheetMngTileEntity {
@Id
@Column(name = "mng_yyyy", nullable = false)
private Integer mngYyyy;
@Column(name = "url", length = Integer.MAX_VALUE)
private String url;
@Column(name = "min_lon", precision = 10, scale = 7)
private BigDecimal minLon;
@Column(name = "min_lat", precision = 10, scale = 7)
private BigDecimal minLat;
@Column(name = "max_lon", precision = 10, scale = 7)
private BigDecimal maxLon;
@Column(name = "max_lat", precision = 10, scale = 7)
private BigDecimal maxLat;
@Column(name = "min_zoom")
private Short minZoom;
@Column(name = "max_zoom")
private Short maxZoom;
@Column(name = "tag")
private String tag;
@Column(name = "crs")
private String crs;
@NotNull
@ColumnDefault("now()")
@Column(name = "created_dttm", nullable = false)
private ZonedDateTime createdDttm = ZonedDateTime.now();
@Column(name = "updated_dttm")
private ZonedDateTime updatedDttm;
}

View File

@@ -0,0 +1,34 @@
package com.kamco.cd.kamcoback.postgres.entity;
import jakarta.persistence.Column;
import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import java.time.ZonedDateTime;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.ColumnDefault;
@Getter
@Setter
@Entity
@Table(name = "tb_map_sheet_mng_year_yn")
public class MapSheetMngYearYnEntity {
@EmbeddedId private MapSheetMngYearYnEntityId id;
@NotNull
@Column(name = "yn", nullable = false, length = Integer.MAX_VALUE)
private String yn;
@NotNull
@ColumnDefault("now()")
@Column(name = "created_dttm", nullable = false)
private ZonedDateTime createdDttm;
@NotNull
@ColumnDefault("now()")
@Column(name = "updated_dttm", nullable = false)
private ZonedDateTime updatedDttm;
}

View File

@@ -0,0 +1,46 @@
package com.kamco.cd.kamcoback.postgres.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.io.Serializable;
import java.util.Objects;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.Hibernate;
@Getter
@Setter
@Embeddable
public class MapSheetMngYearYnEntityId implements Serializable {
private static final long serialVersionUID = 6282262062316057898L;
@Size(max = 20)
@NotNull
@Column(name = "map_sheet_num", nullable = false, length = 20)
private String mapSheetNum;
@NotNull
@Column(name = "mng_yyyy", nullable = false)
private Integer mngYyyy;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) {
return false;
}
MapSheetMngYearYnEntityId entity = (MapSheetMngYearYnEntityId) o;
return Objects.equals(this.mngYyyy, entity.mngYyyy)
&& Objects.equals(this.mapSheetNum, entity.mapSheetNum);
}
@Override
public int hashCode() {
return Objects.hash(mngYyyy, mapSheetNum);
}
}

View File

@@ -12,7 +12,7 @@ import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.ColumnDefault;
@@ -39,7 +39,7 @@ public class PnuEntity {
private String pnu;
@Column(name = "created_dttm")
private OffsetDateTime createdDttm;
private ZonedDateTime createdDttm;
@Column(name = "created_uid")
private Long createdUid;
@@ -47,4 +47,140 @@ public class PnuEntity {
@ColumnDefault("false")
@Column(name = "del_yn")
private Boolean delYn;
@Size(max = 40)
@Column(name = "pnu_dtct_id", length = 40)
private String pnuDtctId;
@Size(max = 10)
@Column(name = "lrm_sync_ymd", length = 10)
private String lrmSyncYmd;
@Size(max = 10)
@Column(name = "pnu_sync_ymd", length = 10)
private String pnuSyncYmd;
@Size(max = 20)
@Column(name = "mpqd_no", length = 20)
private String mpqdNo;
@Size(max = 10)
@Column(name = "cprs_yr", length = 10)
private String cprsYr;
@Size(max = 10)
@Column(name = "crtr_yr", length = 10)
private String crtrYr;
@Size(max = 255)
@Column(name = "chn_dtct_id")
private String chnDtctId;
@Size(max = 10)
@Column(name = "chn_dtct_mst_id", length = 10)
private String chnDtctMstId;
@Size(max = 255)
@Column(name = "chn_dtct_objt_id")
private String chnDtctObjtId;
@Size(max = 255)
@Column(name = "chn_dtct_cont_id")
private String chnDtctContId;
@Size(max = 50)
@Column(name = "chn_cd", length = 50)
private String chnCd;
@Size(max = 50)
@Column(name = "chn_dtct_prob", length = 50)
private String chnDtctProb;
@Size(max = 50)
@Column(name = "bf_cls_cd", length = 50)
private String bfClsCd;
@Size(max = 50)
@Column(name = "bf_cls_prob", length = 50)
private String bfClsProb;
@Size(max = 50)
@Column(name = "af_cls_cd", length = 50)
private String afClsCd;
@Size(max = 50)
@Column(name = "af_cls_prob", length = 50)
private String afClsProb;
@Size(max = 100)
@Column(name = "pnu_sqms", length = 100)
private String pnuSqms;
@Size(max = 100)
@Column(name = "pnu_dtct_sqms", length = 100)
private String pnuDtctSqms;
@Size(max = 100)
@Column(name = "chn_dtct_sqms", length = 100)
private String chnDtctSqms;
@Size(max = 1)
@Column(name = "stblt_yn", length = 1)
private String stbltYn;
@Size(max = 30)
@Column(name = "incy_cd", length = 30)
private String incyCd;
@Size(max = 255)
@Column(name = "incy_rsn_cont")
private String incyRsnCont;
@Size(max = 1)
@Column(name = "lock_yn", length = 1)
private String lockYn;
@Size(max = 1)
@Column(name = "lbl_yn", length = 1)
private String lblYn;
@Size(max = 1)
@Column(name = "chg_yn", length = 1)
private String chgYn;
@Size(max = 50)
@Column(name = "rsatct_no", length = 50)
private String rsatctNo;
@Size(max = 100)
@Column(name = "rmk", length = 100)
private String rmk;
@Size(max = 20)
@Column(name = "crt_dt", length = 20)
private String crtDt;
@Size(max = 20)
@Column(name = "crt_epno", length = 20)
private String crtEpno;
@Size(max = 20)
@Column(name = "crt_ip", length = 20)
private String crtIp;
@Size(max = 20)
@Column(name = "chg_dt", length = 20)
private String chgDt;
@Size(max = 20)
@Column(name = "chg_epno", length = 20)
private String chgEpno;
@Size(max = 20)
@Column(name = "chg_ip", length = 20)
private String chgIp;
@Size(max = 10)
@Column(name = "chn_dtct_sno", length = 10)
private String chnDtctSno;
}

View File

@@ -0,0 +1,7 @@
package com.kamco.cd.kamcoback.postgres.repository.gukyuin;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetLearnEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface GukYuinLabelJobRepository
extends JpaRepository<MapSheetLearnEntity, Long>, GukYuinLabelJobRepositoryCustom {}

View File

@@ -0,0 +1,11 @@
package com.kamco.cd.kamcoback.postgres.repository.gukyuin;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GeomUidDto;
import java.util.List;
public interface GukYuinLabelJobRepositoryCustom {
List<GeomUidDto> findYesterdayLabelingCompleteList();
void updateAnalDataInferenceGeomSendDttm(Long geoUid);
}

View File

@@ -0,0 +1,77 @@
package com.kamco.cd.kamcoback.postgres.repository.gukyuin;
import static com.kamco.cd.kamcoback.postgres.entity.QLabelingAssignmentEntity.labelingAssignmentEntity;
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 com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GeomUidDto;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InspectState;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
@Repository
@RequiredArgsConstructor
public class GukYuinLabelJobRepositoryImpl implements GukYuinLabelJobRepositoryCustom {
private final JPAQueryFactory queryFactory;
@PersistenceContext private EntityManager em;
@Override
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(todayStart)
.and(labelingAssignmentEntity.inspectStatDttm.lt(tomorrowStart));
return queryFactory
.select(
Projections.constructor(
GeomUidDto.class,
labelingAssignmentEntity.inferenceGeomUid,
mapSheetAnalDataInferenceGeomEntity.resultUid))
.from(labelingAssignmentEntity)
.innerJoin(mapSheetAnalDataInferenceGeomEntity)
.on(
labelingAssignmentEntity.inferenceGeomUid.eq(
mapSheetAnalDataInferenceGeomEntity.geoUid))
.innerJoin(mapSheetAnalInferenceEntity)
.on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id))
.innerJoin(mapSheetLearnEntity)
.on(
mapSheetAnalInferenceEntity.learnId.eq(mapSheetLearnEntity.id),
mapSheetLearnEntity.applyStatus.in(
GukYuinStatus.GUK_COMPLETED.getId(), GukYuinStatus.PNU_COMPLETED.getId()))
.where(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId()), isYesterday)
.fetch();
}
@Override
public void updateAnalDataInferenceGeomSendDttm(Long geoUid) {
queryFactory
.update(mapSheetAnalDataInferenceGeomEntity)
.set(mapSheetAnalDataInferenceGeomEntity.labelSendDttm, ZonedDateTime.now())
.where(mapSheetAnalDataInferenceGeomEntity.geoUid.eq(geoUid))
.execute();
}
}

View File

@@ -0,0 +1,7 @@
package com.kamco.cd.kamcoback.postgres.repository.gukyuin;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetLearnEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface GukYuinPnuJobRepository
extends JpaRepository<MapSheetLearnEntity, Long>, GukYuinPnuJobRepositoryCustom {}

View File

@@ -0,0 +1,20 @@
package com.kamco.cd.kamcoback.postgres.repository.gukyuin;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LearnKeyDto;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus;
import java.util.List;
public interface GukYuinPnuJobRepositoryCustom {
void updateInferenceGeomDataPnuCnt(String chnDtctObjtId, long pnuCnt);
Long findMapSheetAnalDataInferenceGeomUid(String chnDtctObjtId);
void insertGeoUidPnuData(Long geoUid, String[] pnuList, String chnDtctObjtId);
void updateGukYuinApplyStateComplete(Long id, GukYuinStatus status);
List<LearnKeyDto> findGukyuinApplyStatusUidList(List<String> gukYuinStatus);
long upsertMapSheetDataAnalGeomPnu(String uid, String[] pnuList);
}

View File

@@ -0,0 +1,123 @@
package com.kamco.cd.kamcoback.postgres.repository.gukyuin;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity;
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.gukyuin.dto.ChngDetectMastDto.LearnKeyDto;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus;
import com.kamco.cd.kamcoback.postgres.entity.PnuEntity;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import java.time.ZonedDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
@Repository
@RequiredArgsConstructor
public class GukYuinPnuJobRepositoryImpl implements GukYuinPnuJobRepositoryCustom {
private final JPAQueryFactory queryFactory;
@PersistenceContext private EntityManager em;
@Override
public void updateInferenceGeomDataPnuCnt(String chnDtctObjtId, long pnuCnt) {
queryFactory
.update(mapSheetAnalDataInferenceGeomEntity)
.set(mapSheetAnalDataInferenceGeomEntity.pnu, pnuCnt)
.where(mapSheetAnalDataInferenceGeomEntity.resultUid.eq(chnDtctObjtId))
.execute();
}
@Override
public Long findMapSheetAnalDataInferenceGeomUid(String chnDtctObjtId) {
return queryFactory
.select(mapSheetAnalDataInferenceGeomEntity.geoUid)
.from(mapSheetAnalDataInferenceGeomEntity)
.where(mapSheetAnalDataInferenceGeomEntity.resultUid.eq(chnDtctObjtId))
.fetchOne();
}
@Override
public void insertGeoUidPnuData(Long geoUid, String[] pnuList, String chnDtctObjtId) {
for (String pnu : pnuList) {
PnuEntity entity =
queryFactory
.selectFrom(pnuEntity)
.where(pnuEntity.pnu.eq(pnu), pnuEntity.chnDtctObjtId.eq(chnDtctObjtId))
.fetchOne();
if (entity == null) {
queryFactory
.insert(pnuEntity)
.columns(
pnuEntity.geo.geoUid, pnuEntity.pnu, pnuEntity.createdDttm, pnuEntity.chnDtctObjtId)
.values(geoUid, pnu, ZonedDateTime.now(), chnDtctObjtId)
.execute();
}
}
}
@Override
public List<LearnKeyDto> findGukyuinApplyStatusUidList(List<String> status) {
return queryFactory
.select(
Projections.constructor(
LearnKeyDto.class,
mapSheetLearnEntity.id,
mapSheetLearnEntity.uid,
mapSheetLearnEntity.chnDtctMstId))
.from(mapSheetLearnEntity)
.where(mapSheetLearnEntity.applyStatus.in(status))
.fetch();
}
@Override
public long upsertMapSheetDataAnalGeomPnu(String chnDtctObjtId, String[] pnuList) {
long length = pnuList.length;
queryFactory
.update(mapSheetAnalDataInferenceGeomEntity)
.set(mapSheetAnalDataInferenceGeomEntity.pnu, length)
.where(mapSheetAnalDataInferenceGeomEntity.resultUid.eq(chnDtctObjtId))
.execute();
Long geoUid =
queryFactory
.select(mapSheetAnalDataInferenceGeomEntity.geoUid)
.from(mapSheetAnalDataInferenceGeomEntity)
.where(mapSheetAnalDataInferenceGeomEntity.resultUid.eq(chnDtctObjtId))
.fetchOne();
long succCnt = 0;
for (String pnu : pnuList) {
long result =
queryFactory
.insert(pnuEntity)
.columns(
pnuEntity.geo.geoUid,
pnuEntity.pnu,
pnuEntity.createdDttm,
pnuEntity.chnDtctObjtId)
.values(geoUid, pnu, ZonedDateTime.now(), chnDtctObjtId)
.execute();
if (result > 0) {
succCnt++;
}
}
return succCnt;
}
@Override
@Transactional
public void updateGukYuinApplyStateComplete(Long id, GukYuinStatus status) {
queryFactory
.update(mapSheetLearnEntity)
.set(mapSheetLearnEntity.applyStatus, status.getId())
.set(mapSheetLearnEntity.applyStatusDttm, ZonedDateTime.now())
.where(mapSheetLearnEntity.id.eq(id))
.execute();
}
}

View File

@@ -0,0 +1,7 @@
package com.kamco.cd.kamcoback.postgres.repository.gukyuin;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetLearnEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface GukYuinRepository
extends JpaRepository<MapSheetLearnEntity, Long>, GukYuinRepositoryCustom {}

View File

@@ -0,0 +1,48 @@
package com.kamco.cd.kamcoback.postgres.repository.gukyuin;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.Basic;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LabelSendDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LearnKeyDto;
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 java.time.LocalDate;
import java.util.List;
import java.util.UUID;
public interface GukYuinRepositoryCustom {
void updateGukYuinMastRegResult(Basic resultBody);
void updateGukYuinMastRegRemove(String chnDtctId);
void updateInferenceGeomDataPnuCnt(String chnDtctObjtId, long pnuCnt);
Long findMapSheetAnalDataInferenceGeomUid(String chnDtctObjtId);
void insertGeoUidPnuData(Long geoUid, String[] pnuList, String chnDtctObjtId);
void updateGukYuinApplyStateComplete(Long id, GukYuinStatus status);
List<LearnKeyDto> findGukyuinApplyStatusUidList(List<String> gukYuinStatus);
long upsertMapSheetDataAnalGeomPnu(String uid, String[] pnuList);
LearnInfo findMapSheetLearnInfo(UUID uuid);
Integer findMapSheetLearnYearStage(Integer compareYyyy, Integer targetYyyy);
void updateAnalInferenceApplyDttm(Basic registRes);
List<GeomUidDto> findYesterdayLabelingCompleteList();
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

@@ -0,0 +1,331 @@
package com.kamco.cd.kamcoback.postgres.repository.gukyuin;
import static com.kamco.cd.kamcoback.postgres.entity.QLabelingAssignmentEntity.labelingAssignmentEntity;
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.QPnuEntity.pnuEntity;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.Basic;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LabelSendDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LearnKeyDto;
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;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.NumberExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
@Repository
@RequiredArgsConstructor
public class GukYuinRepositoryImpl implements GukYuinRepositoryCustom {
private final JPAQueryFactory queryFactory;
@PersistenceContext private EntityManager em;
@Override
public void updateGukYuinMastRegResult(Basic resultBody) {
int excnPgrt = Integer.parseInt(resultBody.getExcnPgrt());
int stage = Integer.parseInt(resultBody.getChnDtctSno());
GukYuinStatus status = GukYuinStatus.IN_PROGRESS;
if (excnPgrt == 100) {
status = GukYuinStatus.GUK_COMPLETED;
}
queryFactory
.update(mapSheetLearnEntity)
.set(mapSheetLearnEntity.stage, stage)
.set(mapSheetLearnEntity.applyStatus, status.getId())
.set(mapSheetLearnEntity.applyStatusDttm, ZonedDateTime.now())
.set(mapSheetLearnEntity.chnDtctMstId, resultBody.getChnDtctMstId())
.set(mapSheetLearnEntity.applyYn, true)
.set(mapSheetLearnEntity.applyDttm, ZonedDateTime.now())
.where(mapSheetLearnEntity.uid.eq(resultBody.getChnDtctId()))
.execute();
}
@Override
public void updateGukYuinMastRegRemove(String chnDtctId) {
queryFactory
.update(mapSheetLearnEntity)
.set(mapSheetLearnEntity.applyStatus, GukYuinStatus.CANCELED.getId())
.set(mapSheetLearnEntity.applyStatusDttm, ZonedDateTime.now())
.set(mapSheetLearnEntity.applyYn, false)
.where(mapSheetLearnEntity.uid.eq(chnDtctId))
.execute();
}
@Override
public void updateInferenceGeomDataPnuCnt(String chnDtctObjtId, long pnuCnt) {
queryFactory
.update(mapSheetAnalDataInferenceGeomEntity)
.set(mapSheetAnalDataInferenceGeomEntity.pnu, pnuCnt)
.where(mapSheetAnalDataInferenceGeomEntity.resultUid.eq(chnDtctObjtId))
.execute();
}
@Override
public Long findMapSheetAnalDataInferenceGeomUid(String chnDtctObjtId) {
return queryFactory
.select(mapSheetAnalDataInferenceGeomEntity.geoUid)
.from(mapSheetAnalDataInferenceGeomEntity)
.where(mapSheetAnalDataInferenceGeomEntity.resultUid.eq(chnDtctObjtId))
.fetchOne();
}
@Override
public void insertGeoUidPnuData(Long geoUid, String[] pnuList, String chnDtctObjtId) {
for (String pnu : pnuList) {
PnuEntity entity =
queryFactory
.selectFrom(pnuEntity)
.where(
pnuEntity.geo.geoUid.eq(geoUid),
pnuEntity.pnu.eq(pnu),
pnuEntity.chnDtctObjtId.eq(chnDtctObjtId))
.fetchOne();
if (entity == null) {
queryFactory
.insert(pnuEntity)
.columns(
pnuEntity.geo.geoUid, pnuEntity.pnu, pnuEntity.createdDttm, pnuEntity.chnDtctObjtId)
.values(geoUid, pnu, ZonedDateTime.now(), chnDtctObjtId)
.execute();
}
}
}
@Override
public List<LearnKeyDto> findGukyuinApplyStatusUidList(List<String> status) {
return queryFactory
.select(
Projections.constructor(
LearnKeyDto.class,
mapSheetLearnEntity.id,
mapSheetLearnEntity.uid,
mapSheetLearnEntity.chnDtctMstId))
.from(mapSheetLearnEntity)
.where(mapSheetLearnEntity.applyStatus.in(status))
.fetch();
}
@Override
public long upsertMapSheetDataAnalGeomPnu(String chnDtctObjtId, String[] pnuList) {
long length = pnuList.length;
queryFactory
.update(mapSheetAnalDataInferenceGeomEntity)
.set(mapSheetAnalDataInferenceGeomEntity.pnu, length)
.where(mapSheetAnalDataInferenceGeomEntity.resultUid.eq(chnDtctObjtId))
.execute();
Long geoUid =
queryFactory
.select(mapSheetAnalDataInferenceGeomEntity.geoUid)
.from(mapSheetAnalDataInferenceGeomEntity)
.where(mapSheetAnalDataInferenceGeomEntity.resultUid.eq(chnDtctObjtId))
.fetchOne();
long succCnt = 0;
for (String pnu : pnuList) {
long result =
queryFactory
.insert(pnuEntity)
.columns(pnuEntity.geo.geoUid, pnuEntity.pnu, pnuEntity.createdDttm)
.values(geoUid, pnu, ZonedDateTime.now())
.execute();
if (result > 0) {
succCnt++;
}
}
return succCnt;
}
@Override
public LearnInfo findMapSheetLearnInfo(UUID uuid) {
return queryFactory
.select(
Projections.constructor(
LearnInfo.class,
mapSheetLearnEntity.id,
mapSheetLearnEntity.uuid,
mapSheetLearnEntity.compareYyyy,
mapSheetLearnEntity.targetYyyy,
mapSheetLearnEntity.stage,
mapSheetLearnEntity.uid,
mapSheetLearnEntity.applyStatus,
mapSheetLearnEntity.applyYn))
.from(mapSheetLearnEntity)
.where(mapSheetLearnEntity.uuid.eq(uuid))
.fetchOne();
}
@Override
public Integer findMapSheetLearnYearStage(Integer compareYyyy, Integer targetYyyy) {
NumberExpression<Integer> stageExpr =
Expressions.numberTemplate(Integer.class, "coalesce({0}, 0)", mapSheetLearnEntity.stage);
return queryFactory
.select(stageExpr.max().coalesce(0))
.from(mapSheetLearnEntity)
.where(
mapSheetLearnEntity.compareYyyy.eq(compareYyyy),
mapSheetLearnEntity.targetYyyy.eq(targetYyyy),
mapSheetLearnEntity.applyStatus.isNotNull(),
mapSheetLearnEntity.applyStatus.ne(GukYuinStatus.PENDING.getId()))
.fetchOne();
}
@Override
public void updateAnalInferenceApplyDttm(Basic registRes) {
Long learnId =
queryFactory
.select(mapSheetLearnEntity.id)
.from(mapSheetLearnEntity)
.where(mapSheetLearnEntity.uid.eq(registRes.getChnDtctId()))
.fetchOne();
queryFactory
.update(mapSheetAnalInferenceEntity)
.set(mapSheetAnalInferenceEntity.gukyuinUsed, "Y")
.set(mapSheetAnalInferenceEntity.gukyuinApplyDttm, ZonedDateTime.now())
.set(mapSheetAnalInferenceEntity.stage, Integer.parseInt(registRes.getChnDtctSno()))
.where(mapSheetAnalInferenceEntity.learnId.eq(learnId))
.execute();
}
@Override
public List<GeomUidDto> findYesterdayLabelingCompleteList() {
ZoneId zone = ZoneId.of("Asia/Seoul");
ZonedDateTime todayStart = ZonedDateTime.now(zone).toLocalDate().atStartOfDay(zone);
ZonedDateTime yesterdayStart = todayStart.minusDays(1);
BooleanExpression isYesterday =
labelingAssignmentEntity
.inspectStatDttm
.goe(yesterdayStart)
.and(labelingAssignmentEntity.inspectStatDttm.lt(todayStart));
return queryFactory
.select(
Projections.constructor(
GeomUidDto.class,
labelingAssignmentEntity.inferenceGeomUid,
mapSheetAnalDataInferenceGeomEntity.resultUid))
.from(labelingAssignmentEntity)
.innerJoin(mapSheetAnalDataInferenceGeomEntity)
.on(
labelingAssignmentEntity.inferenceGeomUid.eq(
mapSheetAnalDataInferenceGeomEntity.geoUid))
.innerJoin(mapSheetAnalInferenceEntity)
.on(labelingAssignmentEntity.analUid.eq(mapSheetAnalInferenceEntity.id))
.innerJoin(mapSheetLearnEntity)
.on(
mapSheetAnalInferenceEntity.learnId.eq(mapSheetLearnEntity.id),
mapSheetLearnEntity.applyStatus.in(
GukYuinStatus.GUK_COMPLETED.getId(), GukYuinStatus.PNU_COMPLETED.getId()))
.where(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId()), isYesterday)
.fetch();
}
@Override
public void updateAnalDataInferenceGeomSendDttm(Long geoUid) {
queryFactory
.update(mapSheetAnalDataInferenceGeomEntity)
.set(mapSheetAnalDataInferenceGeomEntity.labelSendDttm, ZonedDateTime.now())
.where(mapSheetAnalDataInferenceGeomEntity.geoUid.eq(geoUid))
.execute();
}
@Override
public List<LabelSendDto> findLabelingCompleteSendList(LocalDate yesterday) {
ZoneId zone = ZoneId.of("Asia/Seoul");
ZonedDateTime from = yesterday.atStartOfDay(zone);
ZonedDateTime to = from.plusDays(1);
BooleanExpression isYesterday =
labelingAssignmentEntity
.inspectStatDttm
.goe(from)
.and(labelingAssignmentEntity.inspectStatDttm.lt(to));
return queryFactory
.select(
Projections.constructor(
LabelSendDto.class,
mapSheetAnalDataInferenceGeomEntity.resultUid,
labelingAssignmentEntity.workerUid,
labelingAssignmentEntity.workStatDttm,
labelingAssignmentEntity.inspectorUid,
labelingAssignmentEntity.inspectStatDttm,
mapSheetAnalDataInferenceGeomEntity.labelSendDttm))
.from(labelingAssignmentEntity)
.innerJoin(mapSheetAnalDataInferenceGeomEntity)
.on(
labelingAssignmentEntity.inferenceGeomUid.eq(
mapSheetAnalDataInferenceGeomEntity.geoUid))
.where(labelingAssignmentEntity.inspectState.eq(InspectState.COMPLETE.getId()), isYesterday)
.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) {
queryFactory
.update(mapSheetLearnEntity)
.set(mapSheetLearnEntity.applyStatus, status.getId())
.set(mapSheetLearnEntity.applyStatusDttm, ZonedDateTime.now())
.where(mapSheetLearnEntity.id.eq(id))
.execute();
}
}

View File

@@ -0,0 +1,7 @@
package com.kamco.cd.kamcoback.postgres.repository.gukyuin;
import com.kamco.cd.kamcoback.postgres.entity.PnuEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface GukYuinStbltJobRepository
extends JpaRepository<PnuEntity, Long>, GukYuinStbltJobRepositoryCustom {}

View File

@@ -0,0 +1,15 @@
package com.kamco.cd.kamcoback.postgres.repository.gukyuin;
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;
import java.util.List;
public interface GukYuinStbltJobRepositoryCustom {
List<LearnKeyDto> findGukYuinEligibleForSurveyList(String status);
void updateGukYuinEligibleForSurvey(String resultUid, RlbDtctMastDto stbltDto);
PnuEntity findPnuEntityByResultUid(String resultUid, String pnu);
}

View File

@@ -0,0 +1,93 @@
package com.kamco.cd.kamcoback.postgres.repository.gukyuin;
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.QPnuEntity.pnuEntity;
import com.kamco.cd.kamcoback.common.enums.ImageryFitStatus;
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;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetAnalDataInferenceGeomEntity;
import com.kamco.cd.kamcoback.postgres.entity.PnuEntity;
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;
@Repository
@RequiredArgsConstructor
public class GukYuinStbltJobRepositoryImpl implements GukYuinStbltJobRepositoryCustom {
private final JPAQueryFactory queryFactory;
@PersistenceContext private EntityManager em;
@Override
public List<LearnKeyDto> findGukYuinEligibleForSurveyList(String status) {
return queryFactory
.select(
Projections.constructor(
LearnKeyDto.class,
mapSheetLearnEntity.id,
mapSheetLearnEntity.uid,
mapSheetLearnEntity.chnDtctMstId))
.from(mapSheetLearnEntity)
.innerJoin(mapSheetAnalInferenceEntity)
.on(mapSheetLearnEntity.id.eq(mapSheetAnalInferenceEntity.learnId))
.innerJoin(mapSheetAnalDataInferenceEntity)
.on(mapSheetAnalInferenceEntity.id.eq(mapSheetAnalDataInferenceEntity.analUid))
.innerJoin(mapSheetAnalDataInferenceGeomEntity)
.on(mapSheetAnalDataInferenceEntity.id.eq(mapSheetAnalDataInferenceGeomEntity.dataUid))
.where(
mapSheetLearnEntity.applyStatus.eq(GukYuinStatus.PNU_COMPLETED.getId()),
mapSheetAnalDataInferenceGeomEntity.pnu.gt(0),
mapSheetAnalDataInferenceGeomEntity.fitState.isNull())
.groupBy(mapSheetLearnEntity.id, mapSheetLearnEntity.uid, mapSheetLearnEntity.chnDtctMstId)
.having(mapSheetAnalDataInferenceGeomEntity.geoUid.count().gt(1L))
.fetch();
}
@Override
public void updateGukYuinEligibleForSurvey(String resultUid, RlbDtctMastDto stbltDto) {
MapSheetAnalDataInferenceGeomEntity geomEntity =
queryFactory
.selectFrom(mapSheetAnalDataInferenceGeomEntity)
.where(mapSheetAnalDataInferenceGeomEntity.resultUid.eq(resultUid))
.fetchOne();
if (geomEntity != null) {
PnuEntity pnuEt =
queryFactory
.selectFrom(pnuEntity)
.where(pnuEntity.chnDtctObjtId.eq(resultUid))
.fetchFirst();
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
public PnuEntity findPnuEntityByResultUid(String resultUid, String pnu) {
return queryFactory
.selectFrom(pnuEntity)
.where(pnuEntity.pnu.eq(pnu), pnuEntity.chnDtctObjtId.eq(resultUid))
.fetchOne();
}
}

View File

@@ -8,6 +8,7 @@ import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceG
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalInferenceEntity.mapSheetAnalInferenceEntity;
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;
@@ -82,7 +83,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),
@@ -126,8 +129,8 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
"""
insert into tb_labeling_assignment
(assignment_uid, inference_geom_uid, worker_uid,
work_state, assign_group_id, anal_uid, pnu)
values (?, ?, ?, ?, ?, ?, ?)
work_state, assign_group_id, anal_uid)
values (?, ?, ?, ?, ?, ?)
""";
try (PreparedStatement ps = connection.prepareStatement(sql)) {
@@ -140,7 +143,6 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
ps.setString(4, LabelState.ASSIGNED.getId());
ps.setString(5, String.valueOf(info.getMapSheetNum()));
ps.setLong(6, analEntity.getId());
ps.setLong(7, info.getPnu());
ps.addBatch();
batchSize++;
@@ -190,7 +192,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();
@@ -381,9 +385,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();
@@ -555,11 +560,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();
}
@@ -576,8 +579,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 =
@@ -602,6 +604,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())
@@ -614,6 +623,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) {
@@ -621,7 +631,7 @@ public class LabelAllocateRepositoryImpl implements LabelAllocateRepositoryCusto
}
long inspectionTotal = labelingTotal;
long inspectionRemaining = inspectionTotal - inspectCompleted - skipped;
long inspectionRemaining = inspectionTotal - inspectCompleted - inspectExcepted;
if (inspectionRemaining < 0) {
inspectionRemaining = 0;
}
@@ -658,7 +668,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)
@@ -740,11 +750,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,

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;
@@ -294,14 +295,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 +345,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 +364,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 +445,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 +496,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 +515,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())
@@ -549,7 +556,19 @@ public class LabelWorkRepositoryImpl implements LabelWorkRepositoryCustom {
@Override
public LabelWorkMngDetail findLabelWorkMngDetail(UUID uuid) {
NumberExpression<Long> labelTotCnt = mapSheetAnalDataInferenceGeomEntity.geoUid.count();
NumberExpression<Long> labelTotCnt =
new CaseBuilder()
// .when(mapSheetAnalDataInferenceGeomEntity.pnu.isNotNull())
.when(
mapSheetAnalDataInferenceGeomEntity
.pnu
.gt(0)
.and(
mapSheetAnalDataInferenceGeomEntity.fitState.eq(
ImageryFitStatus.UNFIT.getId())))
.then(1L)
.otherwise(0L)
.sum();
NumberExpression<Long> labelerCnt = labelingAssignmentEntity.workerUid.count();
NumberExpression<Long> reviewerCnt = labelingAssignmentEntity.inspectorUid.count();

View File

@@ -1,3 +1,27 @@
package com.kamco.cd.kamcoback.postgres.repository.layer;
public interface MapLayerRepositoryCustom {}
import com.kamco.cd.kamcoback.layer.dto.LayerDto;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.LayerMapDto;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.TileUrlDto;
import com.kamco.cd.kamcoback.postgres.entity.MapLayerEntity;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
public interface MapLayerRepositoryCustom {
Long findSortOrderDesc();
List<LayerDto.Basic> findAllLayer(LayerDto.SearchReq searchReq);
Optional<MapLayerEntity> findDetailByUuid(UUID uuid);
List<MapLayerEntity> findAllByUuidIn(Collection<UUID> uuids);
List<LayerMapDto> findLayerMapList(String type);
LayerDto.YearTileDto getChangeDetectionTileUrl(Integer beforeYear, Integer afterYear);
TileUrlDto getChangeDetectionTileOneYearUrl(Integer year);
}

View File

@@ -1,6 +1,228 @@
package com.kamco.cd.kamcoback.postgres.repository.layer;
import static com.kamco.cd.kamcoback.postgres.entity.QMapLayerEntity.mapLayerEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngTileEntity.mapSheetMngTileEntity;
import com.kamco.cd.kamcoback.layer.dto.LayerDto;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.LayerMapDto;
import com.kamco.cd.kamcoback.layer.dto.LayerDto.TileUrlDto;
import com.kamco.cd.kamcoback.postgres.entity.MapLayerEntity;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.NumberExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
@Repository
public class MapLayerRepositoryImpl {}
@RequiredArgsConstructor
public class MapLayerRepositoryImpl implements MapLayerRepositoryCustom {
private final JPAQueryFactory queryFactory;
@Override
public Long findSortOrderDesc() {
return queryFactory
.select(mapLayerEntity.order.max().coalesce(0L))
.from(mapLayerEntity)
.where(mapLayerEntity.order.isNotNull())
.fetchOne();
}
@Override
public List<LayerDto.Basic> findAllLayer(LayerDto.SearchReq searchReq) {
BooleanBuilder whereBuilder = new BooleanBuilder();
whereBuilder.and(mapLayerEntity.isDeleted.isFalse());
if (searchReq != null) {
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()));
}
}
return queryFactory
.select(
Projections.constructor(
LayerDto.Basic.class,
mapLayerEntity.uuid,
mapLayerEntity.layerType,
mapLayerEntity.description,
mapLayerEntity.tag,
mapLayerEntity.order,
mapLayerEntity.isChangeMap,
mapLayerEntity.isLabelingMap,
mapLayerEntity.createdDttm))
.from(mapLayerEntity)
.where(whereBuilder)
.orderBy(mapLayerEntity.order.asc())
.fetch();
}
@Override
public Optional<MapLayerEntity> findDetailByUuid(UUID uuid) {
return Optional.ofNullable(
queryFactory
.select(mapLayerEntity)
.from(mapLayerEntity)
.where(mapLayerEntity.uuid.eq(uuid).and(mapLayerEntity.isDeleted.isFalse()))
.orderBy(mapLayerEntity.order.asc())
.fetchOne());
}
@Override
public List<MapLayerEntity> findAllByUuidIn(Collection<UUID> uuids) {
return queryFactory
.select(mapLayerEntity)
.from(mapLayerEntity)
.where(mapLayerEntity.uuid.in(uuids).and(mapLayerEntity.isDeleted.isFalse()))
.orderBy(mapLayerEntity.order.asc())
.fetch();
}
@Override
public List<LayerMapDto> findLayerMapList(String type) {
NumberExpression<Integer> crsInt =
Expressions.numberTemplate(
Integer.class, "cast(replace({0}, 'EPSG_', '') as integer)", mapLayerEntity.crs);
return queryFactory
.select(
Projections.constructor(
LayerMapDto.class,
mapLayerEntity.layerType,
mapLayerEntity.tag,
mapLayerEntity.order,
mapLayerEntity.url,
mapLayerEntity.minLon,
mapLayerEntity.minLat,
mapLayerEntity.maxLon,
mapLayerEntity.maxLat,
mapLayerEntity.minZoom,
mapLayerEntity.maxZoom,
Expressions.stringTemplate(
"ST_AsGeoJSON(ST_Transform(ST_MakeEnvelope({0}, {1}, {2}, {3}, 4326), {4}))",
mapLayerEntity.minLon,
mapLayerEntity.minLat,
mapLayerEntity.maxLon,
mapLayerEntity.maxLat,
crsInt),
mapLayerEntity.uuid,
Expressions.stringTemplate("cast({0} as text)", mapLayerEntity.rawJson),
mapLayerEntity.crs))
.from(mapLayerEntity)
.where(layerTypeCondition(type), mapLayerEntity.isDeleted.isFalse())
.orderBy(mapLayerEntity.order.asc())
.fetch();
}
@Override
public LayerDto.YearTileDto getChangeDetectionTileUrl(Integer beforeYear, Integer afterYear) {
NumberExpression<Integer> crsInt =
Expressions.numberTemplate(
Integer.class, "cast(replace({0}, 'EPSG_', '') as integer)", mapSheetMngTileEntity.crs);
LayerDto.TileUrlDto before =
queryFactory
.select(
Projections.constructor(
LayerDto.TileUrlDto.class,
mapSheetMngTileEntity.mngYyyy,
mapSheetMngTileEntity.tag,
mapSheetMngTileEntity.url,
mapSheetMngTileEntity.minLon,
mapSheetMngTileEntity.minLat,
mapSheetMngTileEntity.maxLon,
mapSheetMngTileEntity.maxLat,
mapSheetMngTileEntity.minZoom,
mapSheetMngTileEntity.maxZoom,
Expressions.stringTemplate(
"ST_AsGeoJSON(ST_Transform(ST_MakeEnvelope({0}, {1}, {2}, {3}, 4326), {4}))",
mapSheetMngTileEntity.minLon,
mapSheetMngTileEntity.minLat,
mapSheetMngTileEntity.maxLon,
mapSheetMngTileEntity.maxLat,
crsInt),
mapSheetMngTileEntity.crs))
.from(mapSheetMngTileEntity)
.where(mapSheetMngTileEntity.mngYyyy.eq(beforeYear))
.fetchOne();
LayerDto.TileUrlDto after =
queryFactory
.select(
Projections.constructor(
LayerDto.TileUrlDto.class,
mapSheetMngTileEntity.mngYyyy,
mapSheetMngTileEntity.tag,
mapSheetMngTileEntity.url,
mapSheetMngTileEntity.minLon,
mapSheetMngTileEntity.minLat,
mapSheetMngTileEntity.maxLon,
mapSheetMngTileEntity.maxLat,
mapSheetMngTileEntity.minZoom,
mapSheetMngTileEntity.maxZoom,
Expressions.stringTemplate(
"ST_AsGeoJSON(ST_Transform(ST_MakeEnvelope({0}, {1}, {2}, {3}, 4326), {4}))",
mapSheetMngTileEntity.minLon,
mapSheetMngTileEntity.minLat,
mapSheetMngTileEntity.maxLon,
mapSheetMngTileEntity.maxLat,
crsInt),
mapSheetMngTileEntity.crs))
.from(mapSheetMngTileEntity)
.where(mapSheetMngTileEntity.mngYyyy.eq(afterYear))
.fetchOne();
return new LayerDto.YearTileDto(before, after);
}
@Override
public TileUrlDto getChangeDetectionTileOneYearUrl(Integer year) {
NumberExpression<Integer> crsInt =
Expressions.numberTemplate(
Integer.class, "cast(replace({0}, 'EPSG_', '') as integer)", mapSheetMngTileEntity.crs);
return queryFactory
.select(
Projections.constructor(
LayerDto.TileUrlDto.class,
mapSheetMngTileEntity.mngYyyy,
mapSheetMngTileEntity.tag,
mapSheetMngTileEntity.url,
mapSheetMngTileEntity.minLon,
mapSheetMngTileEntity.minLat,
mapSheetMngTileEntity.maxLon,
mapSheetMngTileEntity.maxLat,
mapSheetMngTileEntity.minZoom,
mapSheetMngTileEntity.maxZoom,
Expressions.stringTemplate(
"ST_AsGeoJSON(ST_Transform(ST_MakeEnvelope({0}, {1}, {2}, {3}, 4326), {4}))",
mapSheetMngTileEntity.minLon,
mapSheetMngTileEntity.minLat,
mapSheetMngTileEntity.maxLon,
mapSheetMngTileEntity.maxLat,
crsInt),
mapSheetMngTileEntity.crs))
.from(mapSheetMngTileEntity)
.where(mapSheetMngTileEntity.mngYyyy.eq(year))
.fetchOne();
}
private BooleanExpression layerTypeCondition(String type) {
return type.equals("change-detection")
? mapLayerEntity.isChangeMap.isTrue()
: mapLayerEntity.isLabelingMap.isTrue();
}
}

View File

@@ -56,7 +56,7 @@ public class ErrorLogRepositoryImpl extends QuerydslRepositorySupport
errorLogEntity.errorMessage.as("errorMessage"),
errorLogEntity.stackTrace.as("errorDetail"),
Expressions.stringTemplate(
"to_char({0}, 'YYYY-MM-DD')", errorLogEntity.createdDate)))
"to_char({0}, 'YYYY-MM-DD HH24:MI:SS.FF3')", errorLogEntity.createdDate)))
.from(errorLogEntity)
.leftJoin(auditLogEntity)
.on(errorLogEntity.id.eq(auditLogEntity.errorLogUid))

View File

@@ -3,7 +3,7 @@ package com.kamco.cd.kamcoback.postgres.repository.mapsheet;
import com.kamco.cd.kamcoback.common.geometry.GeoJsonFileWriter.ImageFeature;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngListCompareDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.AddReq;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngListDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.YearSearchReq;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngHstEntity;
@@ -67,8 +67,6 @@ public interface MapSheetMngRepositoryCustom {
List<MngListDto> findByHstMapSheetTargetList(int mngYyyy, List<String> mapIds);
List<MngListCompareDto> findByHstMapSheetCompareList(int mngYyyy, List<String> mapId);
MapSheetMngDto.MngFilesDto findByFileUidMapSheetFile(Long fileUid);
void updateHstFileSizes(Long hstUid, long tifSizeBytes, long tfwSizeBytes, long totalSizeBytes);
@@ -80,4 +78,6 @@ public interface MapSheetMngRepositoryCustom {
List<ImageFeature> getSceneInference(String yyyy, List<String> mapSheetNums);
void updateMapSheetMngHstUploadId(Long hstUid, UUID uuid, String uploadId);
void insertMapSheetMngTile(@Valid AddReq addReq);
}

View File

@@ -4,6 +4,7 @@ import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx5kEntity.mapInkx5kE
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngEntity.mapSheetMngEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngFileEntity.mapSheetMngFileEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngHstEntity.mapSheetMngHstEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngTileEntity.mapSheetMngTileEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QYearEntity.yearEntity;
import static com.querydsl.core.types.dsl.Expressions.nullExpression;
@@ -12,7 +13,7 @@ import com.kamco.cd.kamcoback.common.geometry.GeoJsonFileWriter.ImageFeature;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto;
import com.kamco.cd.kamcoback.inference.dto.InferenceResultDto.MapSheetScope;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngListCompareDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.AddReq;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngListDto;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.YearSearchReq;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngHstEntity;
@@ -206,7 +207,7 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
.on(mapSheetMngEntity.mngYyyy.eq(mapSheetMngHstEntity.mngYyyy))
.leftJoin(mapInkx5kEntity)
.on(mapSheetMngHstEntity.mapSheetNum.eq(mapInkx5kEntity.mapidcdNo))
.where(whereBuilder)
.where(mapInkx5kEntity.useInference.eq(CommonUseStatus.USE))
// .offset(pageable.getOffset())
// .limit(pageable.getPageSize())
.orderBy(mapSheetMngEntity.mngYyyy.desc())
@@ -253,7 +254,9 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
public MapSheetMngDto.MngDto findMapSheetMng(int mngYyyy) {
BooleanBuilder whereBuilder = new BooleanBuilder();
whereBuilder.and(mapSheetMngEntity.mngYyyy.eq(mngYyyy));
whereBuilder
.and(mapSheetMngEntity.mngYyyy.eq(mngYyyy))
.and(mapInkx5kEntity.useInference.eq(CommonUseStatus.USE));
MapSheetMngDto.MngDto foundContent =
queryFactory
@@ -648,53 +651,6 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
.fetch();
}
/**
* 변화탐지 실행 가능 비교년도 조회
*
* @param mngYyyy
* @param mapIds
* @return
*/
@Override
public List<MngListCompareDto> findByHstMapSheetCompareList(int mngYyyy, List<String> mapIds) {
String sql =
"""
SELECT
t.map_sheet_num,
t.map_years,
COALESCE(s.target_year, 0) AS before_year
FROM public.tb_map_sheet_years_map t
LEFT JOIN LATERAL (
SELECT x::int AS target_year
FROM unnest(string_to_array(t.map_years, '>')) AS x
WHERE x::int <= :mngYyyy
ORDER BY x::int DESC
LIMIT 1
) s ON true
INNER JOIN tb_map_inkx_5k tmik
ON t.map_sheet_num = tmik.mapidcd_no AND tmik.use_inference = 'USE'
WHERE t.map_sheet_num = ANY(:mapIds)
""";
@SuppressWarnings("unchecked")
List<Object[]> rows =
em.createNativeQuery(sql)
.setParameter("mngYyyy", mngYyyy)
.setParameter("mapIds", mapIds.toArray(new String[0]))
.getResultList();
return rows.stream()
.map(
r ->
new MngListCompareDto(
(String) r[1], // map_years
(String) r[0], // map_sheet_num
((Number) r[2]).intValue() // before_year
))
.toList();
}
@Override
public List<MapSheetMngDto.MngFilesDto> findHstUidToMapSheetFileList(Long hstUid) {
BooleanBuilder whereBuilder = new BooleanBuilder();
@@ -1088,6 +1044,36 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
.execute();
}
@Override
public void insertMapSheetMngTile(AddReq addReq) {
long execute =
queryFactory
.insert(mapSheetMngTileEntity)
.columns(
mapSheetMngTileEntity.mngYyyy,
mapSheetMngTileEntity.url,
mapSheetMngTileEntity.minLon,
mapSheetMngTileEntity.minLat,
mapSheetMngTileEntity.maxLon,
mapSheetMngTileEntity.maxLat,
mapSheetMngTileEntity.minZoom,
mapSheetMngTileEntity.maxZoom,
mapSheetMngTileEntity.tag,
mapSheetMngTileEntity.crs)
.values(
addReq.getMngYyyy(),
addReq.getUrl(),
addReq.getMinLon(),
addReq.getMinLat(),
addReq.getMaxLon(),
addReq.getMaxLat(),
addReq.getMinZoom(),
addReq.getMaxZoom(),
addReq.getTag(),
addReq.getCrs())
.execute();
}
private BooleanExpression eqYearStatus(QYearEntity years, String status) {
if (status == null) {
return null;

View File

@@ -0,0 +1,9 @@
package com.kamco.cd.kamcoback.postgres.repository.mapsheet;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngYearYnEntity;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngYearYnEntityId;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MapSheetMngYearRepository
extends JpaRepository<MapSheetMngYearYnEntity, MapSheetMngYearYnEntityId>,
MapSheetMngYearRepositoryCustom {}

View File

@@ -0,0 +1,10 @@
package com.kamco.cd.kamcoback.postgres.repository.mapsheet;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngListCompareDto;
import java.util.List;
public interface MapSheetMngYearRepositoryCustom {
void saveFileInfo();
List<MngListCompareDto> findByHstMapSheetCompareList(int mngYyyy, List<String> mapIds);
}

View File

@@ -0,0 +1,101 @@
package com.kamco.cd.kamcoback.postgres.repository.mapsheet;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto.MngListCompareDto;
import com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngYearYnEntity;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.StringExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
@Repository
@RequiredArgsConstructor
public class MapSheetMngYearRepositoryImpl implements MapSheetMngYearRepositoryCustom {
private final JPAQueryFactory queryFactory;
private final EntityManager em;
/** 변화탐지 실행 가능 비교년도 저장 */
@Override
public void saveFileInfo() {
em.createNativeQuery("TRUNCATE TABLE tb_map_sheet_mng_year_yn").executeUpdate();
String sql =
"""
WITH bounds AS (
SELECT
map_sheet_num,
MIN(mng_yyyy::int) AS min_y,
MAX(mng_yyyy::int) AS max_y
FROM tb_map_sheet_mng_files
GROUP BY map_sheet_num
),
years AS (
SELECT
b.map_sheet_num,
gs.y AS mng_yyyy
FROM bounds b
CROSS JOIN LATERAL generate_series(b.min_y, b.max_y) AS gs(y)
),
exist AS (
SELECT DISTINCT
map_sheet_num,
mng_yyyy::int AS mng_yyyy
FROM tb_map_sheet_mng_files
),
src AS (
SELECT
y.map_sheet_num,
y.mng_yyyy,
CASE
WHEN e.map_sheet_num IS NULL THEN 'N'
ELSE 'Y'
END AS yn
FROM years y
LEFT JOIN exist e
ON e.map_sheet_num = y.map_sheet_num
AND e.mng_yyyy = y.mng_yyyy
)
INSERT INTO tb_map_sheet_mng_year_yn
(map_sheet_num, mng_yyyy, yn)
SELECT
map_sheet_num,
mng_yyyy,
yn
FROM src
ON CONFLICT (map_sheet_num, mng_yyyy)
DO UPDATE SET
yn = EXCLUDED.yn,
updated_dttm = now()
""";
em.createNativeQuery(sql).executeUpdate();
}
/**
* 변화탐지 실행 가능 비교년도 조회
*
* @param mngYyyy
* @param mapIds
* @return
*/
@Override
public List<MngListCompareDto> findByHstMapSheetCompareList(int mngYyyy, List<String> mapIds) {
QMapSheetMngYearYnEntity y = QMapSheetMngYearYnEntity.mapSheetMngYearYnEntity;
StringExpression mngYyyyStr = Expressions.stringTemplate("concat({0}, '')", mngYyyy);
return queryFactory
.select(
Projections.constructor(
MngListCompareDto.class, mngYyyyStr, y.id.mapSheetNum, y.id.mngYyyy.max()))
.from(y)
.where(y.id.mapSheetNum.in(mapIds), y.yn.eq("Y"), y.id.mngYyyy.loe(mngYyyy))
.groupBy(y.id.mapSheetNum)
.fetch();
}
}

View File

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

View File

@@ -0,0 +1,17 @@
package com.kamco.cd.kamcoback.postgres.repository.scheduler;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.InspectorPendingDto;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.Tasks;
import java.util.List;
import java.util.UUID;
public interface TrainingDataLabelJobRepositoryCustom {
List<Tasks> findCompletedYesterdayUnassigned();
List<InspectorPendingDto> findInspectorPendingByRound(Long analUid);
void assignReviewerBatch(List<UUID> assignmentUids, String reviewerId);
void updateGeomUidTestState(List<Long> geomUids);
}

View File

@@ -0,0 +1,119 @@
package com.kamco.cd.kamcoback.postgres.repository.scheduler;
import static com.kamco.cd.kamcoback.postgres.entity.QLabelingAssignmentEntity.labelingAssignmentEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QLabelingInspectorEntity.labelingInspectorEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceGeomEntity.mapSheetAnalDataInferenceGeomEntity;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InspectState;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelState;
import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.InspectorPendingDto;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.Tasks;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.StringExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.UUID;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;
@Repository
public class TrainingDataLabelJobRepositoryImpl extends QuerydslRepositorySupport
implements TrainingDataLabelJobRepositoryCustom {
private final JPAQueryFactory queryFactory;
private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)");
public TrainingDataLabelJobRepositoryImpl(JPAQueryFactory queryFactory) {
super(LabelingAssignmentEntity.class);
this.queryFactory = queryFactory;
}
@Override
public List<Tasks> findCompletedYesterdayUnassigned() {
ZoneId zone = ZoneId.of("Asia/Seoul");
ZonedDateTime todayStart = ZonedDateTime.now(zone).toLocalDate().atStartOfDay(zone);
ZonedDateTime yesterdayStart = todayStart.minusDays(1);
BooleanExpression isYesterday =
labelingAssignmentEntity
.workStatDttm
.goe(yesterdayStart)
.and(labelingAssignmentEntity.workStatDttm.lt(todayStart));
return queryFactory
.select(
Projections.constructor(
Tasks.class,
labelingAssignmentEntity.assignmentUid,
labelingAssignmentEntity.inferenceGeomUid,
labelingAssignmentEntity.analUid))
.from(labelingAssignmentEntity)
.where(
labelingAssignmentEntity.workState.in(LabelState.SKIP.getId(), LabelState.DONE.getId()),
labelingAssignmentEntity.inspectorUid.isNull(),
isYesterday)
.orderBy(
labelingAssignmentEntity.analUid.asc(),
labelingAssignmentEntity.assignGroupId.asc(),
labelingAssignmentEntity.inferenceGeomUid.asc())
.fetch();
}
/**
* 해당 회차에 라벨링 할당받은 검수자별 완료 건수 count(), 완료한 게 적은 순으로 해야 일이 한 사람에게 몰리지 않음
*
* @param analUid
* @return
*/
@Override
public List<InspectorPendingDto> findInspectorPendingByRound(Long analUid) {
return queryFactory
.select(
Projections.constructor(
InspectorPendingDto.class,
labelingInspectorEntity.inspectorUid,
labelingAssignmentEntity.assignmentUid.count()))
.from(labelingInspectorEntity)
.leftJoin(labelingAssignmentEntity)
.on(
labelingInspectorEntity.inspectorUid.eq(labelingAssignmentEntity.inspectorUid),
labelingAssignmentEntity.inspectState.in(
InspectState.EXCEPT.getId(), InspectState.COMPLETE.getId()))
.where(labelingInspectorEntity.analUid.eq(analUid))
.groupBy(labelingInspectorEntity.inspectorUid)
.orderBy(labelingAssignmentEntity.assignmentUid.count().asc())
.fetch();
}
/**
* 배치용 여러 건 update
*
* @param assignmentUids
* @param reviewerId
*/
@Override
public void assignReviewerBatch(List<UUID> assignmentUids, String reviewerId) {
queryFactory
.update(labelingAssignmentEntity)
.set(labelingAssignmentEntity.inspectorUid, reviewerId)
.set(labelingAssignmentEntity.inspectState, InspectState.UNCONFIRM.getId())
.set(labelingAssignmentEntity.modifiedDate, ZonedDateTime.now())
.where(labelingAssignmentEntity.assignmentUid.in(assignmentUids))
.execute();
}
@Override
public void updateGeomUidTestState(List<Long> geomUids) {
queryFactory
.update(mapSheetAnalDataInferenceGeomEntity)
.set(mapSheetAnalDataInferenceGeomEntity.testState, InspectState.UNCONFIRM.getId())
.set(mapSheetAnalDataInferenceGeomEntity.updatedDttm, ZonedDateTime.now())
.where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(geomUids))
.execute();
}
}

View File

@@ -3,25 +3,10 @@ package com.kamco.cd.kamcoback.postgres.repository.scheduler;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.AnalCntInfo;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.AnalMapSheetList;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.CompleteLabelData;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.InspectorPendingDto;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.Tasks;
import java.util.List;
import java.util.UUID;
public interface TrainingDataReviewJobRepositoryCustom {
List<Tasks> findCompletedYesterdayUnassigned();
List<InspectorPendingDto> findInspectorPendingByRound(Long analUid);
void assignReviewer(UUID assignmentUid, String reviewerId);
void assignReviewerBatch(List<UUID> assignmentUids, String reviewerId);
Tasks findAssignmentTask(String assignmentUid);
void updateGeomUidTestState(List<Long> geomUids);
List<CompleteLabelData> findCompletedYesterdayLabelingList(Long analUid, String mapSheetNum);
List<AnalMapSheetList> findCompletedAnalMapSheetList(Long analUid);

View File

@@ -1,24 +1,18 @@
package com.kamco.cd.kamcoback.postgres.repository.scheduler;
import static com.kamco.cd.kamcoback.postgres.entity.QLabelingAssignmentEntity.labelingAssignmentEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QLabelingInspectorEntity.labelingInspectorEntity;
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.QMapSheetLearnDataGeomEntity.mapSheetLearnDataGeomEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnEntity.mapSheetLearnEntity;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.InspectState;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelMngState;
import com.kamco.cd.kamcoback.label.dto.LabelAllocateDto.LabelState;
import com.kamco.cd.kamcoback.postgres.entity.LabelingAssignmentEntity;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.AnalCntInfo;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.AnalMapSheetList;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.CompleteLabelData;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.CompleteLabelData.Properties;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.InspectorPendingDto;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.Tasks;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.CaseBuilder;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.NumberExpression;
@@ -29,9 +23,10 @@ import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.UUID;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
import org.springframework.stereotype.Repository;
@Repository
public class TrainingDataReviewJobRepositoryImpl extends QuerydslRepositorySupport
implements TrainingDataReviewJobRepositoryCustom {
@@ -43,121 +38,6 @@ public class TrainingDataReviewJobRepositoryImpl extends QuerydslRepositorySuppo
this.queryFactory = queryFactory;
}
@Override
public List<Tasks> findCompletedYesterdayUnassigned() {
ZoneId zone = ZoneId.of("Asia/Seoul");
ZonedDateTime todayStart = ZonedDateTime.now(zone).toLocalDate().atStartOfDay(zone);
ZonedDateTime yesterdayStart = todayStart.minusDays(1);
BooleanExpression isYesterday =
labelingAssignmentEntity
.workStatDttm
.goe(yesterdayStart)
.and(labelingAssignmentEntity.workStatDttm.lt(todayStart));
return queryFactory
.select(
Projections.constructor(
Tasks.class,
labelingAssignmentEntity.assignmentUid,
labelingAssignmentEntity.inferenceGeomUid,
labelingAssignmentEntity.analUid))
.from(labelingAssignmentEntity)
.where(
labelingAssignmentEntity.workState.in(LabelState.SKIP.getId(), LabelState.DONE.getId()),
labelingAssignmentEntity.inspectorUid.isNull(),
isYesterday)
.orderBy(
labelingAssignmentEntity.analUid.asc(),
labelingAssignmentEntity.assignGroupId.asc(),
labelingAssignmentEntity.inferenceGeomUid.asc())
.fetch();
}
/**
* 해당 회차에 라벨링 할당받은 검수자별 완료 건수 count(), 완료한 게 적은 순으로 해야 일이 한 사람에게 몰리지 않음
*
* @param analUid
* @return
*/
@Override
public List<InspectorPendingDto> findInspectorPendingByRound(Long analUid) {
return queryFactory
.select(
Projections.constructor(
InspectorPendingDto.class,
labelingInspectorEntity.inspectorUid,
labelingAssignmentEntity.assignmentUid.count()))
.from(labelingInspectorEntity)
.leftJoin(labelingAssignmentEntity)
.on(
labelingInspectorEntity.inspectorUid.eq(labelingAssignmentEntity.inspectorUid),
labelingAssignmentEntity.inspectState.in(
InspectState.EXCEPT.getId(), InspectState.COMPLETE.getId()))
.where(labelingInspectorEntity.analUid.eq(analUid))
.groupBy(labelingInspectorEntity.inspectorUid)
.orderBy(labelingAssignmentEntity.assignmentUid.count().asc())
.fetch();
}
/**
* 실시간 분배용 1건 update
*
* @param assignmentUid
* @param reviewerId
*/
@Override
public void assignReviewer(UUID assignmentUid, String reviewerId) {
queryFactory
.update(labelingAssignmentEntity)
.set(labelingAssignmentEntity.inspectorUid, reviewerId)
.set(labelingAssignmentEntity.inspectState, InspectState.UNCONFIRM.getId())
.set(labelingAssignmentEntity.modifiedDate, ZonedDateTime.now())
.where(labelingAssignmentEntity.assignmentUid.eq(assignmentUid))
.execute();
}
/**
* 배치용 여러 건 update
*
* @param assignmentUids
* @param reviewerId
*/
@Override
public void assignReviewerBatch(List<UUID> assignmentUids, String reviewerId) {
queryFactory
.update(labelingAssignmentEntity)
.set(labelingAssignmentEntity.inspectorUid, reviewerId)
.set(labelingAssignmentEntity.inspectState, InspectState.UNCONFIRM.getId())
.set(labelingAssignmentEntity.modifiedDate, ZonedDateTime.now())
.where(labelingAssignmentEntity.assignmentUid.in(assignmentUids))
.execute();
}
@Override
public Tasks findAssignmentTask(String assignmentUid) {
return queryFactory
.select(
Projections.constructor(
Tasks.class,
labelingAssignmentEntity.assignmentUid,
labelingAssignmentEntity.inferenceGeomUid,
labelingAssignmentEntity.analUid))
.from(labelingAssignmentEntity)
.where(labelingAssignmentEntity.assignmentUid.eq(UUID.fromString(assignmentUid)))
.fetchOne();
}
@Override
public void updateGeomUidTestState(List<Long> geomUids) {
queryFactory
.update(mapSheetAnalDataInferenceGeomEntity)
.set(mapSheetAnalDataInferenceGeomEntity.testState, InspectState.UNCONFIRM.getId())
.set(mapSheetAnalDataInferenceGeomEntity.updatedDttm, ZonedDateTime.now())
.where(mapSheetAnalDataInferenceGeomEntity.geoUid.in(geomUids))
.execute();
}
@Override
public List<CompleteLabelData> findCompletedYesterdayLabelingList(
Long analUid, String mapSheetNum) {

View File

@@ -6,6 +6,7 @@ import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx5kEntity.mapInkx5kE
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.QMapSheetLearnDataGeomEntity.mapSheetLearnDataGeomEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QPnuEntity.pnuEntity;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -466,6 +467,14 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport
}
// 5. DTO 생성
// pnu list 조회
List<String> pnuList =
queryFactory
.select(pnuEntity.pnu)
.from(pnuEntity)
.where(pnuEntity.geo.geoUid.eq(mapSheetAnalDataInferenceGeomEntityEntity.getGeoUid()))
.fetch();
var changeDetectionInfo =
ChangeDetectionInfo.builder()
.mapSheetInfo(mapSheetEntity != null ? mapSheetEntity.getMapidNm() : "")
@@ -507,10 +516,7 @@ public class TrainingDataLabelRepositoryImpl extends QuerydslRepositorySupport
mapSheetAnalDataInferenceGeomEntityEntity.getCdProb() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getCdProb()
: 0.0)
.pnu(
mapSheetAnalDataInferenceGeomEntityEntity.getPnu() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getPnu()
: 0L)
.pnu(pnuList)
.mapSheetNum(
mapSheetAnalDataInferenceGeomEntityEntity.getMapSheetNum() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getMapSheetNum()

View File

@@ -7,6 +7,7 @@ import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalDataInferenceG
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetAnalInferenceEntity.mapSheetAnalInferenceEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetLearnDataGeomEntity.mapSheetLearnDataGeomEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QMemberEntity.memberEntity;
import static com.kamco.cd.kamcoback.postgres.entity.QPnuEntity.pnuEntity;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -494,6 +495,14 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport
}
// 5. DTO 생성
// pnu list 조회
List<String> pnuList =
queryFactory
.select(pnuEntity.pnu)
.from(pnuEntity)
.where(pnuEntity.geo.geoUid.eq(mapSheetAnalDataInferenceGeomEntityEntity.getGeoUid()))
.fetch();
var changeDetectionInfo =
ChangeDetectionInfo.builder()
.mapSheetInfo(mapSheetEntity != null ? mapSheetEntity.getMapidNm() : "")
@@ -535,10 +544,7 @@ public class TrainingDataReviewRepositoryImpl extends QuerydslRepositorySupport
mapSheetAnalDataInferenceGeomEntityEntity.getCdProb() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getCdProb()
: 0.0)
.pnu(
mapSheetAnalDataInferenceGeomEntityEntity.getPnu() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getPnu()
: 0L)
.pnu(pnuList)
.mapSheetNum(
mapSheetAnalDataInferenceGeomEntityEntity.getMapSheetNum() != null
? mapSheetAnalDataInferenceGeomEntityEntity.getMapSheetNum()

View File

@@ -0,0 +1,55 @@
package com.kamco.cd.kamcoback.scheduler.service;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinDto.GeomUidDto;
import com.kamco.cd.kamcoback.gukyuin.service.GukYuinApiService;
import com.kamco.cd.kamcoback.postgres.core.GukYuinLabelJobCoreService;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Log4j2
@Service
@RequiredArgsConstructor
public class GukYuinApiLabelJobService {
private final GukYuinLabelJobCoreService gukYuinLabelJobCoreService;
private final GukYuinApiService gukYuinApiService;
@Value("${spring.profiles.active}")
private String profile;
/**
* 실행중인 profile
*
* @return
*/
private boolean isLocalProfile() {
return "local".equalsIgnoreCase(profile);
}
/** 어제 라벨링 검수 완료된 것 -> 국유인에 전송 */
@Scheduled(cron = "0 0 2 * * *")
public void findLabelingCompleteSend() {
if (isLocalProfile()) {
return;
}
List<GeomUidDto> list = gukYuinLabelJobCoreService.findYesterdayLabelingCompleteList();
if (list.isEmpty()) {
return;
}
for (GeomUidDto gto : list) {
ChngDetectContDto.ResultLabelDto dto =
gukYuinApiService.updateChnDtctObjtLabelingYn(gto.getResultUid(), "Y");
if (dto.getSuccess()) {
// inference_geom 에 label_send_dttm 업데이트 하기
gukYuinLabelJobCoreService.updateAnalDataInferenceGeomSendDttm(gto.getGeoUid());
}
}
}
}

View File

@@ -0,0 +1,110 @@
package com.kamco.cd.kamcoback.scheduler.service;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto.ContBasic;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectContDto.ResultContDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LearnKeyDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.ResultDto;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus;
import com.kamco.cd.kamcoback.gukyuin.service.GukYuinApiService;
import com.kamco.cd.kamcoback.postgres.core.GukYuinPnuJobCoreService;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Log4j2
@Service
@RequiredArgsConstructor
public class GukYuinApiPnuJobService {
private final GukYuinPnuJobCoreService gukYuinPnuJobCoreService;
private final GukYuinApiService gukYuinApiService;
@Value("${spring.profiles.active}")
private String profile;
/**
* 실행중인 profile
*
* @return
*/
private boolean isLocalProfile() {
return "local".equalsIgnoreCase(profile);
}
/** 국유인 등록 완료 후, 탐지객체 조회해서 PNU 업데이트 하는 스케줄링 하루 1번 새벽 1시에 실행 */
@Scheduled(cron = "0 0 1 * * *")
public void findGukYuinContListPnuUpdate() {
if (isLocalProfile()) {
return;
}
List<LearnKeyDto> list =
gukYuinPnuJobCoreService.findGukyuinApplyStatusUidList(
List.of(GukYuinStatus.GUK_COMPLETED.getId(), GukYuinStatus.PNU_FAILED.getId()));
if (list.isEmpty()) {
return;
}
for (LearnKeyDto dto : list) {
try {
processUid(dto.getUid(), dto.getUid());
gukYuinPnuJobCoreService.updateGukYuinApplyStateComplete(
dto.getId(), GukYuinStatus.PNU_COMPLETED);
} catch (Exception e) {
log.error("[GUKYUIN] failed uid={}", dto.getUid(), e);
gukYuinPnuJobCoreService.updateGukYuinApplyStateComplete(
dto.getId(), GukYuinStatus.PNU_FAILED);
}
}
}
private void processUid(String chnDtctId, String uid) {
ResultDto result = gukYuinApiService.listChnDtctId(chnDtctId);
if (result == null || result.getResult() == null || result.getResult().isEmpty()) {
return;
}
ChngDetectMastDto.Basic basic = result.getResult().get(0);
String chnDtctCnt = basic.getChnDtctCnt();
if (chnDtctCnt == null || chnDtctCnt.isEmpty()) {
return;
}
// page 계산
int pageSize = 100;
int totalCount = Integer.parseInt(chnDtctCnt);
int totalPages = (totalCount + pageSize - 1) / pageSize;
for (int page = 0; page < totalPages; page++) {
processPage(uid, page, pageSize);
}
}
private void processPage(String uid, int page, int pageSize) {
ResultContDto resContList = gukYuinApiService.findChnContList(uid, page, pageSize);
if (resContList.getResult() == null || resContList.getResult().isEmpty()) {
return; // 외부 API 이상 방어
}
List<ContBasic> contList = resContList.getResult();
for (ContBasic cont : contList) {
String[] pnuList = cont.getPnuList();
long pnuCnt = pnuList == null ? 0 : pnuList.length;
if (cont.getChnDtctObjtId() != null) {
gukYuinPnuJobCoreService.updateInferenceGeomDataPnuCnt(cont.getChnDtctObjtId(), pnuCnt);
if (pnuCnt > 0) {
Long geoUid =
gukYuinPnuJobCoreService.findMapSheetAnalDataInferenceGeomUid(
cont.getChnDtctObjtId());
gukYuinPnuJobCoreService.insertGeoUidPnuData(geoUid, pnuList, cont.getChnDtctObjtId());
}
}
}
}
}

View File

@@ -0,0 +1,71 @@
package com.kamco.cd.kamcoback.scheduler.service;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto;
import com.kamco.cd.kamcoback.gukyuin.dto.ChngDetectMastDto.LearnKeyDto;
import com.kamco.cd.kamcoback.gukyuin.dto.GukYuinStatus;
import com.kamco.cd.kamcoback.gukyuin.service.GukYuinApiService;
import com.kamco.cd.kamcoback.postgres.core.GukYuinJobCoreService;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Log4j2
@Service
@RequiredArgsConstructor
public class GukYuinApiStatusJobService {
private final GukYuinJobCoreService gukYuinJobCoreService;
private final GukYuinApiService gukYuinApiService;
@Value("${spring.profiles.active}")
private String profile;
/**
* 실행중인 profile
*
* @return
*/
private boolean isLocalProfile() {
return "local".equalsIgnoreCase(profile);
}
/** 국유인 연동 후, 100% 되었는지 확인하는 스케줄링 매 10분마다 호출 */
@Scheduled(cron = "0 0/10 * * * *")
public void findGukYuinMastCompleteYn() {
if (isLocalProfile()) {
return;
}
List<LearnKeyDto> list =
gukYuinJobCoreService.findGukyuinApplyStatusUidList(
List.of(GukYuinStatus.IN_PROGRESS.getId()));
if (list.isEmpty()) {
return;
}
for (LearnKeyDto dto : list) {
try {
ChngDetectMastDto.ResultDto result = gukYuinApiService.listChnDtctId(dto.getUid());
if (result == null || result.getResult() == null || result.getResult().isEmpty()) {
log.warn("[GUKYUIN] empty result chnDtctMstId={}", dto.getChnDtctMstId());
continue;
}
ChngDetectMastDto.Basic basic = result.getResult().getFirst();
Integer progress =
basic.getExcnPgrt() == null ? null : Integer.parseInt(basic.getExcnPgrt().trim());
if (progress != null && progress == 100) {
gukYuinJobCoreService.updateGukYuinApplyStateComplete(
dto.getId(), GukYuinStatus.GUK_COMPLETED);
}
} catch (Exception e) {
log.error("[GUKYUIN] failed uid={}", dto.getChnDtctMstId(), e);
}
}
}
}

View File

@@ -0,0 +1,76 @@
package com.kamco.cd.kamcoback.scheduler.service;
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 lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Log4j2
@Service
@RequiredArgsConstructor
public class GukYuinApiStbltJobService {
private final GukYuinStbltJobCoreService gukYuinStbltJobCoreService;
private final GukYuinApiService gukYuinApiService;
@Value("${spring.profiles.active}")
private String profile;
/**
* 실행중인 profile
*
* @return
*/
private boolean isLocalProfile() {
return "local".equalsIgnoreCase(profile);
}
/** 국유인 연동 후, 실태조사 적합여부 확인하여 update */
@Scheduled(cron = "0 0 3 * * *") // 0 0 3 * * *
public void findGukYuinEligibleForSurvey() {
if (isLocalProfile()) {
return;
}
List<LearnKeyDto> list =
gukYuinStbltJobCoreService.findGukYuinEligibleForSurveyList(
GukYuinStatus.PNU_COMPLETED.getId());
if (list.isEmpty()) {
return;
}
for (LearnKeyDto dto : list) {
try {
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());
continue;
}
for (RlbDtctMastDto stbltDto : result.getResult()) {
String resultUid = stbltDto.getChnDtctObjtId();
gukYuinStbltJobCoreService.updateGukYuinEligibleForSurvey(resultUid, stbltDto);
}
} catch (Exception e) {
log.error("[GUKYUIN] failed uid={}", dto.getChnDtctMstId(), e);
}
}
}
}

View File

@@ -28,7 +28,6 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -39,21 +38,6 @@ public class MapSheetMngFileJobService {
private final MapSheetMngFileJobCoreService mapSheetMngFileJobCoreService;
@Value("${file.sync-root-dir}")
private String syncRootDir;
@Value("${file.sync-tmp-dir}")
private String syncTmpDir;
@Value("${file.sync-file-extention}")
private String syncFileExtention;
@Value("${file.sync-auto-exception-start-year}")
private int syncAutoExceptionStartYear;
@Value("${file.sync-auto-exception-before-year-cnt}")
private int syncAutoExceptionBeforeYearCnt;
public Integer checkMngFileSync() {
return mapSheetMngFileJobCoreService.findNotYetMapSheetMng();
}
@@ -121,11 +105,11 @@ public class MapSheetMngFileJobService {
int tfwCnt =
(int)
basicList.stream().filter(dto -> dto.getExtension().toString().equals("tfw")).count();
basicList.stream().filter(dto -> dto.getExtension().equalsIgnoreCase("tfw")).count();
int tifCnt =
(int)
basicList.stream().filter(dto -> dto.getExtension().toString().equals("tif")).count();
basicList.stream().filter(dto -> dto.getExtension().equalsIgnoreCase("tif")).count();
syncState = "";
syncCheckState = "";
@@ -199,6 +183,9 @@ public class MapSheetMngFileJobService {
mngHstDataSyncStateUpdate(item);
}
// 사용할 수 있는 이전 년도 도엽 테이블 저장
mapSheetMngFileJobCoreService.saveSheetMngYear();
Long notyetCnt = this.mngDataStateDoneUpdate(mngYyyy);
}

View File

@@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.scheduler.service;
import com.kamco.cd.kamcoback.common.service.ExternalJarRunner;
import com.kamco.cd.kamcoback.scheduler.config.ShpKeyLock;
import java.nio.file.Paths;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.scheduling.annotation.Async;
@@ -29,7 +30,9 @@ public class ShpPipelineService {
externalJarRunner.run(jarPath, batchId, inferenceId, "", "MERGED");
// uid 기준 shp 파일 geoserver 등록
String register = datasetDir + "/" + inferenceId + "/merge/" + inferenceId + ".shp";
String register =
Paths.get(datasetDir, inferenceId, "merge", inferenceId + ".shp").toString();
log.info("register={}", register);
externalJarRunner.run(jarPath, register, inferenceId);
// uid 기준 도엽별 shp, geojson 파일 생성

View File

@@ -0,0 +1,112 @@
package com.kamco.cd.kamcoback.scheduler.service;
import com.kamco.cd.kamcoback.postgres.core.TrainingDataLabelJobCoreService;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.InspectorPendingDto;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.Tasks;
import jakarta.transaction.Transactional;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Log4j2
@Service
@RequiredArgsConstructor
public class TrainingDataLabelJobService {
private final TrainingDataLabelJobCoreService trainingDataLabelJobCoreService;
@Value("${spring.profiles.active}")
private String profile;
private boolean isLocalProfile() {
return "local".equalsIgnoreCase(profile);
}
@Transactional
@Scheduled(cron = "0 0 0 * * *")
public void assignReviewerYesterdayLabelComplete() {
if (isLocalProfile()) {
return;
}
try {
List<Tasks> tasks = trainingDataLabelJobCoreService.findCompletedYesterdayUnassigned();
if (tasks.isEmpty()) {
return;
}
// 회차별로 그룹핑
Map<Long, List<Tasks>> taskByRound =
tasks.stream().collect(Collectors.groupingBy(Tasks::getAnalUid));
// 회차별 분배
for (Map.Entry<Long, List<Tasks>> entry : taskByRound.entrySet()) {
Long analUid = entry.getKey();
List<Tasks> analTasks = entry.getValue();
// pending 계산
List<InspectorPendingDto> pendings =
trainingDataLabelJobCoreService.findInspectorPendingByRound(analUid);
if (pendings.isEmpty()) {
continue;
}
List<String> reviewerIds =
pendings.stream().map(InspectorPendingDto::getInspectorUid).toList();
// Lock 걸릴 수 있기 때문에 엔티티 조회하는 Repository 에서 구현
trainingDataLabelJobCoreService.lockInspectors(analUid, reviewerIds);
// 균등 분배
Map<String, List<Tasks>> assignMap = distributeByLeastPending(analTasks, reviewerIds);
// reviewer별 batch update
assignMap.forEach(
(reviewerId, assignedTasks) -> {
if (assignedTasks.isEmpty()) {
return;
}
List<UUID> assignmentUids =
assignedTasks.stream().map(Tasks::getAssignmentUid).toList();
trainingDataLabelJobCoreService.assignReviewerBatch(assignmentUids, reviewerId);
List<Long> geomUids = assignedTasks.stream().map(Tasks::getInferenceUid).toList();
trainingDataLabelJobCoreService.updateGeomUidTestState(geomUids);
});
}
} catch (Exception e) {
log.error("배치 처리 중 예외", e);
}
}
private Map<String, List<Tasks>> distributeByLeastPending(
List<Tasks> tasks, List<String> reviewerIds) {
Map<String, List<Tasks>> result = new LinkedHashMap<>();
// 순서 유지 중요 (ASC 정렬된 상태)
for (String reviewerId : reviewerIds) {
result.put(reviewerId, new ArrayList<>());
}
int reviewerCount = reviewerIds.size();
for (int i = 0; i < tasks.size(); i++) {
String reviewerId = reviewerIds.get(i % reviewerCount);
result.get(reviewerId).add(tasks.get(i));
}
return result;
}
}

View File

@@ -8,20 +8,13 @@ import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.AnalMapShee
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.CompleteLabelData;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.CompleteLabelData.GeoJsonFeature;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.FeatureCollection;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.InspectorPendingDto;
import com.kamco.cd.kamcoback.scheduler.dto.TrainingDataReviewJobDto.Tasks;
import jakarta.transaction.Transactional;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
@@ -46,114 +39,13 @@ public class TrainingDataReviewJobService {
}
@Transactional
@Scheduled(cron = "0 0 0 * * *")
public void assignReviewerYesterdayLabelComplete() {
@Scheduled(cron = "0 0 2 * * *")
public void exportGeojsonLabelingGeom() {
if (isLocalProfile()) {
return;
}
try {
List<Tasks> tasks = trainingDataReviewJobCoreService.findCompletedYesterdayUnassigned();
if (tasks.isEmpty()) {
return;
}
// 회차별로 그룹핑
Map<Long, List<Tasks>> taskByRound =
tasks.stream().collect(Collectors.groupingBy(Tasks::getAnalUid));
// 회차별 분배
for (Map.Entry<Long, List<Tasks>> entry : taskByRound.entrySet()) {
Long analUid = entry.getKey();
List<Tasks> analTasks = entry.getValue();
// pending 계산
List<InspectorPendingDto> pendings =
trainingDataReviewJobCoreService.findInspectorPendingByRound(analUid);
if (pendings.isEmpty()) {
continue;
}
List<String> reviewerIds =
pendings.stream().map(InspectorPendingDto::getInspectorUid).toList();
// Lock 걸릴 수 있기 때문에 엔티티 조회하는 Repository 에서 구현
trainingDataReviewJobCoreService.lockInspectors(analUid, reviewerIds);
// 균등 분배
Map<String, List<Tasks>> assignMap = distributeByLeastPending(analTasks, reviewerIds);
// reviewer별 batch update
assignMap.forEach(
(reviewerId, assignedTasks) -> {
if (assignedTasks.isEmpty()) {
return;
}
List<UUID> assignmentUids =
assignedTasks.stream().map(Tasks::getAssignmentUid).toList();
trainingDataReviewJobCoreService.assignReviewerBatch(assignmentUids, reviewerId);
List<Long> geomUids = assignedTasks.stream().map(Tasks::getInferenceUid).toList();
trainingDataReviewJobCoreService.updateGeomUidTestState(geomUids);
});
}
} catch (Exception e) {
log.error("배치 처리 중 예외", e);
}
}
private Map<String, List<Tasks>> distributeByLeastPending(
List<Tasks> tasks, List<String> reviewerIds) {
Map<String, List<Tasks>> result = new LinkedHashMap<>();
// 순서 유지 중요 (ASC 정렬된 상태)
for (String reviewerId : reviewerIds) {
result.put(reviewerId, new ArrayList<>());
}
int reviewerCount = reviewerIds.size();
for (int i = 0; i < tasks.size(); i++) {
String reviewerId = reviewerIds.get(i % reviewerCount);
result.get(reviewerId).add(tasks.get(i));
}
return result;
}
// 라벨러 완료,SKIP 시 호출 -> 미사용
@Transactional
public void assignRealtime(String assignmentUid) {
Tasks task = trainingDataReviewJobCoreService.findAssignmentTask(assignmentUid);
Long analUid = task.getAnalUid();
// pending 계산
List<InspectorPendingDto> pendings =
trainingDataReviewJobCoreService.findInspectorPendingByRound(analUid);
if (pendings.isEmpty()) {
return;
}
List<String> order = pendings.stream().map(InspectorPendingDto::getInspectorUid).toList();
trainingDataReviewJobCoreService.lockInspectors(analUid, order);
trainingDataReviewJobCoreService.assignReviewer(task.getAssignmentUid(), order.getFirst());
List<Long> geomUids = new ArrayList<>();
geomUids.add(task.getInferenceUid());
trainingDataReviewJobCoreService.updateGeomUidTestState(geomUids);
}
@Transactional
@Scheduled(cron = "0 0 2 * * *")
public void exportGeojsonLabelingGeom() {
// 1) 경로/파일명 결정
String targetDir =
"local".equals(profile) ? System.getProperty("user.home") + "/geojson" : trainingDataDir;

View File

@@ -3,6 +3,7 @@ package com.kamco.cd.kamcoback.trainingdata;
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ResponseObj;
import com.kamco.cd.kamcoback.scheduler.service.TrainingDataLabelJobService;
import com.kamco.cd.kamcoback.scheduler.service.TrainingDataReviewJobService;
import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto;
import com.kamco.cd.kamcoback.trainingdata.dto.TrainingDataReviewDto.ReviewGeometryInfo;
@@ -32,6 +33,7 @@ import org.springframework.web.bind.annotation.RestController;
public class TrainingDataReviewApiController {
private final TrainingDataReviewService trainingDataReviewService;
private final TrainingDataLabelJobService trainingDataLabelJobService;
private final TrainingDataReviewJobService trainingDataReviewJobService;
@Operation(summary = "목록 조회", description = "검수 할당 목록 조회")
@@ -562,7 +564,7 @@ public class TrainingDataReviewApiController {
description = "스케줄링이 실패한 경우 수동 호출하는 API, 어제 라벨링 완료된 것을 해당 검수자들에게 할당함")
@GetMapping("/run-schedule")
public ApiResponseDto<Void> runTrainingReviewSchedule() {
trainingDataReviewJobService.assignReviewerYesterdayLabelComplete();
trainingDataLabelJobService.assignReviewerYesterdayLabelComplete();
return ApiResponseDto.ok(null);
}

View File

@@ -358,7 +358,7 @@ public class TrainingDataLabelDto {
private Double detectionAccuracy;
@Schema(description = "PNU (필지고유번호)", example = "36221202306020")
private Long pnu;
private List<String> pnu;
@Schema(description = "도엽번호 (map_sheet_num)", example = "34602057")
private Long mapSheetNum;

View File

@@ -351,7 +351,7 @@ public class TrainingDataReviewDto {
private Double detectionAccuracy;
@Schema(description = "PNU (필지고유번호)", example = "36221202306020")
private Long pnu;
private List<String> pnu;
@Schema(description = "도엽번호 (map_sheet_num)", example = "34602057")
private Long mapSheetNum;

View File

@@ -104,21 +104,26 @@ file:
model-tmp-dir: ${file.model-dir}tmp/
model-file-extention: pth,json,py
pt-path: /kamco-nfs/ckpt/model/v6-cls-checkpoints/
pt-FileName: yolov8_6th-6m.pt
inference:
url: http://10.100.0.11:8000/jobs
batch-url: http://10.100.0.11:8000/batches
url: http://192.168.2.183:8000/jobs
batch-url: http://192.168.2.183:8000/batches
geojson-dir: /kamco-nfs/requests/
jar-path: /kamco-nfs/dataset/shp/shp-exporter-1.0.0.jar
jar-path: /kamco-nfs/dataset/shp/shp-exporter.jar
inference-server-name: server1,server2,server3,server4
gukyuin:
#url: http://localhost:8080
url: http://192.168.2.129:5301
mast: ${gukyuin.url}/api/kcd/cdi/chn/mast
cdi: ${gukyuin.url}/api/kcd/cdi
training-data:
geojson-dir: /kamco-nfs/model_output/labeling/
layer:
geoserver-url: https://kamco.geo-dev.gs.dabeeo.com
wms-path: geoserver/cd
wmts-path: geoserver/cd/gwc/service
workspace: cd

View File

@@ -6,7 +6,7 @@ spring:
jpa:
show-sql: false
hibernate:
ddl-auto: update # 로컬만 완화(시킬려면 update으로 변경)
ddl-auto: validate # 로컬만 완화(시킬려면 update으로 변경)
properties:
hibernate:
default_batch_fetch_size: 100 # ✅ 성능 - N+1 쿼리 방지
@@ -16,9 +16,11 @@ spring:
datasource:
url: jdbc:postgresql://192.168.2.127:15432/kamco_cds
#url: jdbc:postgresql://localhost:15432/kamco_cds # 로컬호스트
# url: jdbc:postgresql://localhost:5432/local_0128
username: kamco_cds
password: kamco_cds_Q!W@E#R$
# username: postgres
# password: 1234
hikari:
minimum-idle: 1
maximum-pool-size: 5
@@ -68,22 +70,41 @@ mapsheet:
file:
sync-root-dir: D:/kamco-nfs/images/
sync-root-dir: C:/Users/gypark/kamco-nfs/images/
#sync-root-dir: /kamco-nfs/images/
sync-tmp-dir: ${file.sync-root-dir}/tmp
sync-tmp-dir: ${file.sync-root-dir}/tmp/
sync-file-extention: tfw,tif
sync-auto-exception-start-year: 2025
sync-auto-exception-before-year-cnt: 3
dataset-dir: D:/kamco-nfs/dataset/
dataset-dir: C:/Users/gypark/kamco-nfs/dataset/
#dataset-dir: /kamco-nfs/dataset/export/
dataset-tmp-dir: ${file.dataset-dir}tmp/
model-dir: D:/kamco-nfs/ckpt/model/
model-dir: C:/Users/gypark/kamco-nfs/ckpt/model/
#model-dir: /kamco-nfs/ckpt/model/
model-tmp-dir: ${file.model-dir}tmp/
model-file-extention: pth,json,py
pt-path: /kamco-nfs/ckpt/classification/
pt-FileName: v5-best.pt
inference:
url: http://10.100.0.11:8000/jobs
batch-url: http://10.100.0.11:8000/batches
geojson-dir: /kamco-nfs/requests/
jar-path: jar/makeshp-1.0.0.jar
inference-server-name: server1,server2,server3,server4
gukyuin:
#url: http://localhost:8080
url: http://192.168.2.129:5301
cdi: ${gukyuin.url}/api/kcd/cdi
training-data:
geojson-dir: /kamco-nfs/model_output/labeling/
layer:
geoserver-url: https://kamco.geo-dev.gs.dabeeo.com
path: /geoserver/cd/gwc/service/
workspace: cd

View File

@@ -59,21 +59,26 @@ file:
model-tmp-dir: ${file.model-dir}tmp/
model-file-extention: pth,json,py
pt-path: /kamco-nfs/ckpt/model/v6-cls-checkpoints/
pt-FileName: yolov8_6th-6m.pt
inference:
url: http://10.100.0.11:8000/jobs
batch-url: http://10.100.0.11:8000/batches
url: http://192.168.2.183:8000/jobs
batch-url: http://192.168.2.183:8000/batches
geojson-dir: /kamco-nfs/requests/
jar-path: /kamco-nfs/dataset/shp/shp-exporter-1.0.0.jar
jar-path: /kamco-nfs/dataset/shp/shp-exporter.jar
inference-server-name: server1,server2,server3,server4
gukyuin:
#url: http://localhost:8080
url: http://192.168.2.129:5301
mast: ${gukyuin.url}/api/kcd/cdi/chn/mast
cdi: ${gukyuin.url}/api/kcd/cdi
training-data:
geojson-dir: /kamco-nfs/model_output/labeling/
layer:
geoserver-url: https://kamco.geo-dev.gs.dabeeo.com
wms-path: geoserver/cd
wmts-path: geoserver/cd/gwc/service
workspace: cd