Compare commits

...

376 Commits

Author SHA1 Message Date
lkd9125(이경도) 14b71a677c log 삭제 10 months ago
lkd9125(이경도) dfdf739ec4 /docs/index.html RestDocs경로 허용 추가 10 months ago
lkd9125(이경도) f8fcd0d49b SpringRestDocs 예제 추가 10 months ago
lkd9125(이경도) 606dd2dad8 anls/smlt 패키지 주석추가 10 months ago
lkd9125(이경도) d66b221762 anls/hstry 패키지 주석추가 10 months ago
lkd9125(이경도) 211ce9ae82 terms패키지 주석추가 10 months ago
lkd9125(이경도) a255674a66 jwt패키지 추석 추가 10 months ago
lkd9125(이경도) e71de75916 cstmr 패키지 주석추가 10 months ago
lkd9125(이경도) e2d33ba02f Merge commit '29f63b91c25c734b0ae7a95fe09224c6bcc7c51d' into develop 10 months ago
lkd9125(이경도) 6e4fa96498 crtfyhp 패키지 주석 추가 10 months ago
지대한 29f63b91c2 TS 연동 성공시 param 전송 10 months ago
지대한 0eac2f6c40 외부 호출 security 제외 10 months ago
'kyw546' 8bdfad57bd 불법드론 연계를 위한 변경 10 months ago
지대한 a992564662 Merge remote-tracking branch 'origin/develop' into develop 10 months ago
지대한 3dd6c8d707 서버이전으로 인한 변경 10 months ago
lkd9125(이경도) 302ed20574 롤백 10 months ago
lkd9125(이경도) 8e909cdb05 좌표로 관할청 매핑된곳 가져오기 10 months ago
지대한 e6acfea39c 순환참조로 인한 수정 10 months ago
지대한 f4a6203a83 TS - 드론원스탑 비행계획서 받기 10 months ago
지대한 96fde678d5 TS - 불법드론 1~2초 마다 전송 10 months ago
lkd9125(이경도) 679ca7d467 비행승인 연산 수정 10 months ago
lkd9125(이경도) b47c6b2297 Merge commit 'd17ee11825ae516073261f377d0fea31e5269029' into develop 10 months ago
lkd9125(이경도) 77f86393a0 회원가입 시 국가코드 하드코딩 처리 10 months ago
지대한 d17ee11825 QR 확인 에러 수정 10 months ago
지대한 88ef91e5c5 TS 비행계획서 1차 완료 10 months ago
lkd9125(이경도) 4524a9da29 문자 전송 시 intime 데이터추가 10 months ago
지대한 ddd03bf0c3 TS qr code 구현 10 months ago
지대한 5a0971d942 TS qr 코드 10 months ago
지대한 327e844850 드론 비행 현황시 cptAuthCode가 없을 경우 조회가 안되는 현상 임시 수정 10 months ago
lkd9125(이경도) 0a785e4e76 Merge commit '4a93fa0793c717d7bd66e86946106cd80a0038f0' into develop 10 months ago
lkd9125(이경도) cc20b63e81 Instant Convert 수정 10 months ago
지대한 4a93fa0793 통계 serviceType 수정 10 months ago
지대한 42ea6bd207 통계 serviceType 수정 10 months ago
지대한 ef7d88ec18 통계 serviceType 수정 10 months ago
지대한 4e6ae1b998 비행건수 계획서 없는데 완료 카운트 되는 현상 수정 10 months ago
지대한 1e2fe13cdc 비행건수 계획서 없는데 완료 카운트 되는 현상 수정 10 months ago
lkd9125(이경도) 80ddc8039e 비행시뮬레이션 Date오류 수정 10 months ago
lkd9125(이경도) 4a48a20807 운항스케줄 Date오류 수정 10 months ago
지대한 60349d12fd 의존성 주입 재정의 10 months ago
지대한 225dfb8120 메인 대시보드 serviceType 적용 10 months ago
지대한 8ede6560f4 Merge remote-tracking branch 'origin/develop' into develop 10 months ago
지대한 3215b07e8a laanc validate 재구성(적용x) 10 months ago
leehagjoon(이학준) 228b5d22fa Merge remote-tracking branch 'origin/develop' into develop 10 months ago
leehagjoon(이학준) becb63dff1 [일일비행횟수현황] groupby 추가 - 추후 변경 예정 10 months ago
지대한 b79e8d818f profile 조회시 cptAuthCode 항목 추가 10 months ago
지대한 139fe34db0 profile 조회시 cptAuthCode 항목 추가 10 months ago
지대한 1178bcfb37 Merge branch 'release-1.0.0' into develop 10 months ago
daeha 5cdc4f3d2d lib 10 months ago
박재우 6e57de92b9 eclipse mapstruct 설정 10 months ago
박재우 251c9f038a Merge branch 'develop' of http://gitea.palntour.com/pav/pav-be-kac.git into develop 10 months ago
박재우 6d27936d26 GpScheduler - 화면 노출시간이 1시간으로 되어있어 변경 10 months ago
lkd9125(이경도) f961187e20 비행실적 top 5 Value추가 10 months ago
lkd9125(이경도) 8223d15865 포맷팅변경 10 months ago
박재우 287a1e58fe endPoint 수정 10 months ago
박재우 565c577532 top5 지역별 통계 -> 카운팅 기준 비행 종료 시점으로 변경 10 months ago
lkd9125(이경도) e749e6a7dc Merge commit 'f5844dd36067af533e89093fa17493b083cac4bb' into develop 10 months ago
lkd9125(이경도) 258c5a4d6b 비정상상황통계 상단데이터 10 months ago
박재우 f5844dd360 . 10 months ago
박재우 dd7f4286b4 . 10 months ago
박재우 f556933189 data key 변경 10 months ago
박재우 88f15b1c56 query where절 변경 10 months ago
박재우 f8558654b6 기준 수정(오늘 날렸거나, 오늘 비행계획서 등록한 건만 표출되도록) 10 months ago
박재우 4d2cd49705 log 10 months ago
박재우 263afa106a 임시 테스트용 KAC 권한 하드코딩, 로직 변경 10 months ago
박재우 93ce5bc2ba query instant 형변환 변경 , 조건 변경 10 months ago
leehagjoon(이학준) 823909fa36 [일일 비행횟수 현황] - long -> int 타입 변경 10 months ago
박재우 19bfc06908 조건 변경 10 months ago
지대한 82b8d0c60d 드론 상세정보 데이터 누락 10 months ago
lkd9125(이경도) bcb2c9c782 관제종료시 관제건 업데이트 시간 인서트 10 months ago
박재우 0f3e6ef86c Merge branch 'develop' of http://gitea.palntour.com/pav/pav-be-kac.git into develop 10 months ago
박재우 a6eef7d349 드론 비행 더미데이터 파일 10 months ago
lkd9125(이경도) 033a500423 개발용 로그삭제 10 months ago
lkd9125(이경도) c04cbda460 Merge commit '0cd99c47816eed890d777a6773591838f573e769' into develop 10 months ago
lkd9125(이경도) 089ac26b56 비행, 실적, 비정상상황 통계 serviceType으로 조건 변경 10 months ago
leehagjoon(이학준) 0cd99c4781 [일일 비행횟수 현황] - 쿼리 수정 10 months ago
lkd9125(이경도) 5c2e35ad39 Merge commit 'ad7dde789e1e9d02178d4295c8c08b49346ca453' into develop 10 months ago
lkd9125(이경도) 2c75ced8e5 일일 비정상상황, 비행통계 RS 변경 10 months ago
지대한 ad7dde789e 모든 비행구역 나오는 현상 수정 10 months ago
지대한 3c05b88a42 모든 비행구역 나오는 현상 수정 10 months ago
지대한 2d1577f7fe 스웨거 설명 수정(비행횟수 > 비행건수) 10 months ago
지대한 29ed289ab8 자동 재시작 제거 10 months ago
lkd9125(이경도) e580006e30 Instant 타입 변경 10 months ago
lkd9125(이경도) eace93dfad 타입변경 10 months ago
박재우 2aaf61fab3 Merge branch 'develop' of http://gitea.palntour.com/pav/pav-be-kac.git into develop 10 months ago
박재우 8c663f0ec9 . 10 months ago
lkd9125(이경도) deecd68945 Merge commit '57699c83da38b382358421999ff0e5b6c73cfc66' into develop 10 months ago
lkd9125(이경도) 5c23f805ea NPE방지 코드추가 10 months ago
박재우 57699c83da Merge branch 'develop' of http://gitea.palntour.com/pav/pav-be-kac.git into develop 10 months ago
박재우 8fb8d4f430 rollback 10 months ago
지대한 82a8d1ea12 Merge pull request 'feature/main/dailyflight' (#15) from feature/main/dailyflight into develop 10 months ago
지대한 f68773d718 비행구역조회 10 months ago
lkd9125(이경도) 2bb0b2cb11 조건절 변경 10 months ago
박재우 be8c4e1634 드론관제 드론 상세정보 querydsl 오류 수정 10 months ago
박재우 206dec0183 드론현황 수정 10 months ago
박재우 eadb1bfaee 비행운항목록 조건에 맞게 수정 10 months ago
박재우 25de8eff0b webSocket 데이터 중복송신 제거 10 months ago
leehagjoon(이학준) efb8e810f3 충돌 해결 10 months ago
leehagjoon(이학준) fcf21b9510 Merge branch 'develop' into feature/main/dailyflight 10 months ago
lkd9125(이경도) 077cc56319 스웨거 어노테이션 추가 10 months ago
leehagjoon(이학준) d72ceca0d8 로그 제거 10 months ago
leehagjoon(이학준) 3d0209c0cb 충돌 해결 10 months ago
leehagjoon(이학준) b5603dc2da Merge branch 'develop' into feature/main/dailyflight 10 months ago
지대한 ab6c2442d8 Merge pull request 'feature/current/flight-plan' (#13) from feature/current/flight-plan into develop 10 months ago
leehagjoon(이학준) 2aa5f84505 [메인] 일일 비행횟수 현황 - 비행완료, 미 비행, 비고 추가 10 months ago
lkd9125(이경도) 14b2dab58a 임포트문 추가 10 months ago
lkd9125(이경도) cbc8f3f502 Merge commit '86e2daeb494da96aed6171d406b65a894fa605d5' into feature/current/flight-plan 10 months ago
지대한 86e2daeb49 Merge pull request 'feature/current/flight-warn' (#14) from feature/current/flight-warn into develop 10 months ago
lkd9125(이경도) 3414b7fc76 QueryDSL GroupBY절 추가 10 months ago
lkd9125(이경도) d3615c121a Merge commit 'ca86a2debdd264d10972bb1db00fe044b2678f54' into feature/current/flight-warn 10 months ago
lkd9125(이경도) 4c34b1e081 일일 비정상 상황 추가 10 months ago
박재우 ca86a2debd . 10 months ago
박재우 814adff88e 드론통계 rq 수정 10 months ago
lkd9125(이경도) a65fc6be8c Merge commit '254771dc4278d3145de39d1017ef1c72a892b60b' into feature/current/flight-plan 10 months ago
lkd9125(이경도) 8bd4de84b2 Merge commit 'c4a9683ee0d84b023e21722962fcdffe224fd926' into feature/current/flight-plan 10 months ago
박재우 254771dc42 드론현황 10 months ago
lkd9125(이경도) a30bd26ccd 합계 => 승인된 비행계획서 건수로 변경 10 months ago
lkd9125(이경도) c4a9683ee0 비행실적 groupby 추가 10 months ago
지대한 5a92ff7a75 기존 어드민 권한에 해당 담당관할 코드가 있을 경우 token 에 주입 10 months ago
leehagjoon(이학준) 2e6a99922f Merge branch 'develop' into feature/main/dailyflight 10 months ago
lkd9125(이경도) 1daea5d280 일일 시간데이터 포맷 변경 10 months ago
lkd9125(이경도) 29053dd347 Merge commit '076b2922faff4b572200793c54565aa3ddcb842e' into feature/current/flight-plan 10 months ago
lkd9125(이경도) a04740a7b3 일일비정상 상황 임시커밋 10 months ago
leehagjoon(이학준) c9cb343175 Merge branch 'develop' into feature/main/dailyflight 10 months ago
박재우 076b2922fa 좌표로 법정동 코드 찾는 유틸 -> 성능 향상 , 인접한 바다의 좌표도 가장 가까운 육지의 담당자 찾을 수 있는 기능 추가 10 months ago
박재우 c8f5547f52 queryDSL where절 Timezone 수정 10 months ago
lkd9125(이경도) a03ff7a516 메소드명 변경 10 months ago
lkd9125(이경도) 67c911d94c Merge commit '5d6e3ff6780c7e47b5e113b1180a899692087e12' into feature/current/flight-plan 10 months ago
hagjoon(이학준) f06c7fca31 [메인] 일일 비행횟수 현황 : 비행계획서 승인 항목 표출 완료 10 months ago
lkd9125(이경도) f709d99133 메인화면 일일비행 추가 10 months ago
hagjoon(이학준) a527959cf2 [메인] 일일 비행횟수 현황 : 비행계획서 승인 항목 작업중 10 months ago
박재우 5d6e3ff678 . 10 months ago
박재우 61e5381ba0 Merge pull request 'feature/jaewoo' (#12) from feature/jaewoo into develop 10 months ago
박재우 7623b90d47 Merge pull request '드론운항 통계' (#11) from develop into feature/jaewoo 10 months ago
박재우 a1083804be 드론운항목록 10 months ago
지대한 65ac7f880b propeties 수정 ip 변경 10 months ago
지대한 f6f1a23536 좌표에 따른 지표면 고도 조회 기능 10 months ago
lkd9125(이경도) 3d2931484f 권한 확인 Exception추가 10 months ago
lkd9125(이경도) 25b59937bd 비정상상황 권한개입추가 10 months ago
lkd9125(이경도) 53452ebcce 비행실적 권한 개입 추가 10 months ago
lkd9125(이경도) 820a3998f9 비행통계 권한개입 추가 10 months ago
lkd9125(이경도) 71c4e13170 비행통계 상단데이터 권한개입 추가 10 months ago
lkd9125(이경도) 5b7daabf68 비행실적 통계 - 비행계획 groupBy추가 10 months ago
lkd9125(이경도) 5ced3a65dd 통계 NPE 방지 코드 추가 10 months ago
lkd9125(이경도) a85492032b 비행실적통계 API 추가 10 months ago
lkd9125(이경도) 817a00fd04 비행실적 상단 고정데이터 AP추가 10 months ago
lkd9125(이경도) a415ca94fe 비정상상황 로그 queryRepository 추가 10 months ago
lkd9125(이경도) e1b3255819 비정상상황 상단 고정데이터 년,월,일 추가 10 months ago
lkd9125(이경도) 9ad0763121 비행통계 상단 년월일 추가 10 months ago
lkd9125(이경도) 669ed742f0 통계패키지 모델 이동 11 months ago
lkd9125(이경도) 60a6e25bce 통계 패키지 분리 11 months ago
lkd9125(이경도) 4d857ba9a4 비정상 상황 통계 API 추가 11 months ago
lkd9125(이경도) 7006e88ade 비정상 상황 상단 고정데이터 API 추가 11 months ago
지대한 1dd7fe3e31 Merge remote-tracking branch 'origin/develop' into develop 11 months ago
지대한 63d17ff450 수치표고모델 해상도(/4) 및 크기(한반도 -> 남한) 수정 11 months ago
lkd9125(이경도) db8017f560 Merge commit '99d49ca2d6098846649b63f47693fea415347073' into develop 11 months ago
lkd9125(이경도) 9348e201ad 비행통계 API 추가 11 months ago
지대한 99d49ca2d6 . 11 months ago
지대한 05e984d91d 고도 변환 11 months ago
지대한 d4f05efbab docker local 테스트 환경 11 months ago
lkd9125(이경도) 1a81341c7f 통계 API, 비행상단 고정 데이터 API추가 11 months ago
지대한 86994aaa1e dem(tiff) - 지형고도 11 months ago
지대한 2ad49b5e44 Merge remote-tracking branch 'origin/develop' into develop 11 months ago
지대한 da1689437e dem(tiff) - 지형고도 11 months ago
lkd9125(이경도) c28bd422ef 비행 종료시 컨트롤아이디에 해당하는 건의 총 비행거리 값 추가 11 months ago
박재우 bc6e536d52 Merge branch 'develop' of http://gitea.palntour.com/pav/pav-be-kac.git into develop 11 months ago
박재우 efdf974e24 법정동 코드 리턴 유틸 - 특정 depth까지만 추출하는 기능 추가 ( 광역시 / 시군구 / 읍면동 / 리 ) 11 months ago
lkd9125(이경도) 5c57c80352 GeoJson프로퍼티 수정 11 months ago
박재우 1ac6d5a470 . 11 months ago
박재우 22a86d2efb . 11 months ago
박재우 d325a1eeab linux 환경에 맞게 경로 구분자 수정 11 months ago
박재우 c15853e6a1 test controller(임시) 11 months ago
lkd9125(이경도) 9868daaf1b 전국 GeoJson 분할 프로그램 추가 11 months ago
박재우 e0b83bd98d Merge branch 'develop' of http://gitea.palntour.com/pav/pav-be-kac.git into develop 11 months ago
박재우 0cb72deaa9 path properties yml에서 관리하게 변경 , util @value 추가하기 위해 컴포넌트 어노테이션 사용 11 months ago
지대한 38d210acd3 refresh token 요청시 token 자체 검증만 진행 11 months ago
지대한 34a214fadb refresh token 요청시 새로운 refresh 토큰 저장 11 months ago
지대한 6d9ed107b5 법정동 글자 깨짐 수정 11 months ago
박재우 ffeeb96663 좌표로 법정동코드 찾기(beta) 11 months ago
박재우 0fefce3cb4 Merge branch 'develop' of http://gitea.palntour.com/pav/pav-be-kac.git into develop 11 months ago
박재우 3d9aff1a26 좌표로 법정동코드 찾기(beta) 11 months ago
지대한 a82e6e8ab2 Ts 에러시 서버 에러가 아닌 false로 떨궈줌 11 months ago
지대한 95c163888b TS - 조종사 자격 증명 여부 및 기체 보혐 여부 확인 api 11 months ago
지대한 ca6cea96b1 허용고도 조회시 값이 안맞는 현상 11 months ago
지대한 e683b01621 파일 수정 및 상세 수정 11 months ago
지대한 05e0043f4f 법정동 저장(로컬용) 11 months ago
지대한 5eea14db01 법정동 파일 및 지역 매핑 entity 11 months ago
지대한 207dd6aec0 파일이 없을 경우 에러 수정 11 months ago
지대한 3a4ef8d16e 특수비행-야간 제외 11 months ago
지대한 7f51aeac43 공역(금지구역) 포함여부 api 11 months ago
지대한 1fb70081dd 허용고도 api, ts연동 api 11 months ago
지대한 f388ea2b97 qna 답변시 사용자 조회가 안되는 현상 수정 11 months ago
박재우 623b1f4544 coordinate convert util 추가 11 months ago
지대한 39b5a0694d 빈값일 경우 where조건 제외 11 months ago
지대한 f49d34627c merge 11 months ago
지대한 f094d97648 Merge pull request 'feature/laanc/sun-vaildation' (#10) from feature/laanc/sun-vaildation into develop 11 months ago
지대한 e5e0cd4833 - 승인목록 pdf download url(pdfUrl) 추가 11 months ago
지대한 ddb7c79267 pdf path nullod -> od 11 months ago
지대한 b26db5c7e4 qna add contract field 11 months ago
지대한 62b5a204ac qna field add answer information. 11 months ago
지대한 1ab250463b cstmr bas return type error 11 months ago
지대한 650256d8b6 qna admin 검색조건 수정 및 작성자명 추가 11 months ago
lkd9125(이경도) a65588baff Merge commit '665ffc5989b582b8977fb32500df0daaebfee834' into feature/laanc/sun-vaildation 11 months ago
지대한 665ffc5989 승인 목록 신청일 기준 최신순으로 정렬 11 months ago
지대한 d5ce02101a 승인목록 페이징 없는 api 생성 11 months ago
지대한 c978a9171a FAQ, QnA 생성일시 최근일 순으로 정렬 11 months ago
지대한 56ffa8fcc7 신청 목록 신청일자 기준 검색 11 months ago
지대한 b567f3941f qna 설계 변경으로 인한 수정 11 months ago
지대한 2ee86cadcd qna 설계 변경으로 인한 수정 11 months ago
lkd9125(이경도) 42f6538ae3 체크용 로그 삭제 11 months ago
lkd9125(이경도) 06e097f881 주석추가 11 months ago
lkd9125(이경도) d4760093ab Laanc 검증 RS파라미터 적용 11 months ago
lkd9125(이경도) d1df3b400d 테스트 변경 11 months ago
lkd9125(이경도) 76a4aa0e63 Merge commit '49c2798356cf0525e6a6972e4252ed93510df6f5' into feature/laanc/sun-vaildation 11 months ago
lkd9125(이경도) b21670ed3f Laanc 검증 추가 11 months ago
지대한 49c2798356 qna url 수정 11 months ago
지대한 694be4caf1 faq 수정 11 months ago
지대한 7dabd67695 일몰 일출 api 추가 - 해당 좌표에 근접한 지역의 6개월치 데이터 11 months ago
지대한 d98025b99f 일몰 일출 api 추가 - 해당 좌표에 근접한 지역의 6개월치 데이터 11 months ago
지대한 82d60d62dd 승인목록 rq 변경 11 months ago
지대한 29e578c6cb LAANC 검증시 기체 중복 및 비행 구역 중복 제외 11 months ago
지대한 4b5e79f2ce 좌표로 가장 근접한 지역의 일몰/일출 정보 조회 11 months ago
지대한 493f5db580 일출/일몰 지역별 조회 11 months ago
lkd9125(이경도) f20ada92ab QnA업데이트 시간 추가 11 months ago
lkd9125 6229cb4af9 Merge pull request 'feature/cns/faq-qna' (#9) from feature/cns/faq-qna into develop 11 months ago
lkd9125(이경도) 2b76d6488c files 저장 경로 변경 11 months ago
lkd9125(이경도) 58709feba3 Qna File 개별삭제 [파일 업데이트 기획이 없어 만듬] 11 months ago
lkd9125(이경도) fb214e0323 File update추가 11 months ago
qkr7828(박재우) 82d69eb940 faq crud 11 months ago
lkd9125 6e3e83d04e Qna 삭제 추가 11 months ago
lkd9125 9736eab347 Qna 업데이트 기능 추가 / 파일 업데이트 제외 11 months ago
lkd9125 f43e284a1f Merge commit 'edc3503cc7dc9f407b29fcd0c1bb8f35ba3320d5' into feature/cns/faq-qna 11 months ago
lkd9125 227302dc70 Qna 상세 불러오기 추가 11 months ago
qkr7828(박재우) edc3503cc7 . 11 months ago
lkd9125 5c282da7d8 QnaList 조회 추가 11 months ago
lkd9125 69e44f00d8 Qna 추가 기능 11 months ago
lkd9125 3d029ec84e DB Insert추가 11 months ago
lkd9125 fceb5159cf file업로드 추가 11 months ago
qkr7828(박재우) d7037f9f90 list , detail 완료 11 months ago
lkd9125 80057475e5 롤백 11 months ago
lkd9125 73c1ed6f73 . 11 months ago
lkd9125 8443dbc260 Class 정리 11 months ago
lkd9125 3b414f174e Merge commit '0dd9e2267891467c1ad70462c183feb4aface963' into feature/cns/faq-qna 11 months ago
lkd9125 c3b141bd85 QNA 기본작업 커밋 11 months ago
qkr7828(박재우) 0dd9e22678 . 11 months ago
qkr7828(박재우) 33d751629c repo 11 months ago
lkd9125 9fe2faf362 Merge commit '08c7c58d0ead94ff7ac68169acffb3f20a94ebf2' into feature/cns/faq-qna 11 months ago
lkd9125 b55bfc8c35 Entity 및 기본 클래스 생성 11 months ago
qkr7828(박재우) 08c7c58d0e detail merge 11 months ago
leehagjoon(이학준) f94caa0885 날씨 API url 및 servicekey -> properties 관리 11 months ago
지대한 076be728b7 . 11 months ago
지대한 7ef7106a82 . 11 months ago
지대한 797432b1d4 . 11 months ago
지대한 667a2f3a50 laanc 승인 목록 검색조건 추가 11 months ago
지대한 941de40021 승인 목록 및 상세 기본올림 12 months ago
지대한 4598e0624e 승인시 문자전송 12 months ago
지대한 f05de5e47e 승인시 문자전송 12 months ago
지대한 57f0eb7e05 승인시 문자전송 12 months ago
지대한 78770e79e7 식별번호 및 항공기기체 생략 가능 12 months ago
지대한 3e1521db05 pdf template 수정 12 months ago
지대한 27c21e388e code "-" front에서 불가 12 months ago
지대한 6a7f345c75 다운로드 url public 으로 변경 12 months ago
지대한 182e19491e 파일 경로 12 months ago
지대한 d5265b8fa1 주소 잘못 입력함 12 months ago
지대한 d6c8fa19ca image 못읽음 12 months ago
지대한 f00388da34 valid 수정 12 months ago
지대한 329ead43b8 resource 파일 못읽음 12 months ago
지대한 b4f447d641 resource 파일 못읽음 12 months ago
지대한 164a393ca8 resource 파일 못읽음 12 months ago
지대한 bddcdc5ca6 resource 파일 못읽음 12 months ago
지대한 b70de5b021 resource 파일 못읽음 12 months ago
지대한 505a8f6ca5 laanc 승인시 첫좌표로 주소 받아오기 12 months ago
지대한 43a632aaa3 laanc 날 수 있는 boolean 추가 12 months ago
지대한 b98f5fe915 비행가능여부 추가 12 months ago
지대한 583e77a9db laanc 검증 1차안 12 months ago
지대한 7aba2ee31d code enum 처리 12 months ago
지대한 98ab8d343d . 12 months ago
지대한 bc3888ec94 laanc 새로운 페이지에 따른 api 생성 1 year ago
lkd9125 5ba0ee1810 import 정리 1 year ago
지대한 d578d5d297 laanc 새로운 페이지에 따른 api 생성 1 year ago
지대한 7c8f1ce6e2 Merge remote-tracking branch 'origin/develop' into develop 1 year ago
lkd9125 e62562e0f1 PDF 다운로드 주석추가 1 year ago
lkd9125 22059b0427 Swagger 어노테이션 추가 1 year ago
lkd9125 fa5499fe00 Merge pull request '비정상상황 통계 추가' (#7) from feature/main/warning-flight-statistics into develop 1 year ago
lkd9125 87377baa1c 비정상상황 통계 추가 1 year ago
lkd9125 728095f32e Merge pull request 'feature/main/drone-flight-statistics' (#6) from feature/main/drone-flight-statistics into develop 1 year ago
lkd9125 0532e5740c 필수 파라미터 지정 idntfNum 1 year ago
lkd9125 5b75e00e57 Merge commit 'c42d2b5e7585465dbe97a31bee97a390a1ab0c88' into feature/main/drone-flight-statistics 1 year ago
지대한 49db329500 기존 flight 롤백 1 year ago
lkd9125 c42d2b5e75 Instant Convert Log제거 1 year ago
lkd9125 43a78e7a63 드론별 비행이력 통계 추가 1 year ago
lkd9125 83512429cd Merge pull request 'feature/lannc/pdf-download' (#4) from feature/lannc/pdf-download into develop 1 year ago
lkd9125 d3f2a2fcaa Merge commit '92be3047ce0305adc9dc861570276c845dd08995' into feature/lannc/pdf-download 1 year ago
lkd9125 bfb27e137b Merge commit '92be3047ce0305adc9dc861570276c845dd08995' into feature/main/drone-flight-statistics 1 year ago
지대한 92be3047ce airgeo 롤백 1 year ago
지대한 f2bd8ac39d epsg 추가 1 year ago
lkd9125 91caa4aa3f 메소드 명 변경 1 year ago
lkd9125 9addd8e841 Merge commit 'dbb8cfa222707f826a4d3bdeec0341fafd3a22bf' into feature/lannc/pdf-download 1 year ago
지대한 dbb8cfa222 LAANC 프로세스 변경에 따른 수정 1 year ago
지대한 903af28cf5 Merge pull request 'feature/lannc/pdf-create' (#3) from feature/lannc/pdf-create into develop 1 year ago
lkd9125 273f2a2039 Exception추가 1 year ago
lkd9125 b0b633e8a1 코드정리 1 year ago
lkd9125 05c5aff86c 스웨거 추가, 클래스 분리 1 year ago
lkd9125 3e03e57101 파일 다운로드 추가 1 year ago
지대한 a333551eff LAANC 기준 바뀜에 따른 처리 1 year ago
lkd9125 a2601eed60 Merge commit '3f9d486c588f239bb513de4bd338b93c7ebe386b' into feature/lannc/pdf-download 1 year ago
lkd9125 3f9d486c58 파일경로 추가 1 year ago
lkd9125 412720800b 패키지 변경 1 year ago
lkd9125 4207cc4071 Merge commit '946945e86ba7ef82edaade24dc518b47c6a74531' into feature/lannc/pdf-download 1 year ago
lkd9125 946945e86b Merge commit 'd060491c6156927fe8018de0950251800bc3b3a4' into feature/lannc/pdf-create 1 year ago
lkd9125 8f3055561a 서비스 분리 1 year ago
qkr7828(박재우) d060491c61 컬럼 형식 수정 1 year ago
lkd9125 0adb107151 Merge commit '0c1111c6575d0291b7d0e43e49255a4b6866afeb' into feature/lannc/pdf-create 1 year ago
lkd9125 ed383f6098 주석 해제 1 year ago
lkd9125 92be0cbafa 패키지 편경 1 year ago
lkd9125 9a00161ce6 다운로드 틀 추가 1 year ago
지대한 0c1111c657 LAANC 임시 코드 및 비행계획서 등록/수정 1 year ago
lkd9125 52857d45a3 URL 오타 수정 1 year ago
lkd9125 bcd3de7cf9 Merge commit 'f298886491cc56a93da8678a73d0f3ec9795a547' into feature/lannc/pdf-download 1 year ago
lkd9125 f298886491 코드 정리 1 year ago
lkd9125 651da27170 Merge commit 'c358419a2922a26d10a16daf8b129c170323790d' into feature/lannc/pdf-create 1 year ago
lkd9125 442319035e 오류수정 1 year ago
lkd9125 1832faf12e VO추가 , 폴더경로추가 1 year ago
지대한 6724b4f49a 공역 유틸 생성 - singleton pattern 1 year ago
lkd9125 30a9f2dd2f DB Table Insert추가 1 year ago
qkr7828(박재우) c358419a29 드론관제 - 비행 종료된 드론에 대한 정보 제공 기능 추가 1 year ago
lkd9125 57aac511d8 PDF CSS 적용 1 year ago
lkd9125 55a84cb7b9 Template HTML -> Pdf변환 1 year ago
지대한 fcced5261c . 1 year ago
지대한 c88b96faf5 Merge remote-tracking branch 'origin/develop' into develop 1 year ago
지대한 339cadfe65 비행계획서 등록 반환 객체 변경 1 year ago
lkd9125 23b43acc60 Merge commit '1bbb9d4b0d73686083b2e76f3cd432aa185012c7' into feature/lannc/pdf-create 1 year ago
지대한 1bbb9d4b0d Merge pull request 'feature/main/plan-allow-statistics' (#2) from feature/main/plan-allow-statistics into develop 1 year ago
lkd9125 c129b50416 ComFileBas Entity 추가, Repository추가 1 year ago
lkd9125 efc3052646 Merge commit '4f9de497e6bd1f4c06fd75a4d9d8d0f53f230443' into feature/main/plan-allow-statistics 1 year ago
lkd9125 56b38cef4e 로그파일 삭제 1 year ago
lkd9125 01280c335e 승인일시 쿼리 추가, 파라미터명 및 URL 변경 1 year ago
lkd9125 4462ee2470 비행계획서 Entity 승인일시 컬럼추가 1 year ago
lkd9125 4f9de497e6 로그 삭제 1 year ago
lkd9125 07016b5591 Merge commit '03c6c9071504e89244d71207dcdb96f7ef710ee6' into feature/main/plan-allow-statistics 1 year ago
지대한 03c6c90715 Merge pull request 'feature/main/date-statistics' (#1) from feature/main/date-statistics into develop 1 year ago
lkd9125 cc5d154928 롤백 1 year ago
lkd9125 902d39df2b URL 변경 /stcs/flight/date/{type} 로 변경 1 year ago
lkd9125 8d2d097438 URL /kac 제거 1 year ago
lkd9125 ce24478c6a 파라미터명 변경 1 year ago
lkd9125 37d996b3cf URL 변경 1 year ago
lkd9125 631755b5ef Merge commit '4a3756fc6cd2d768545453359dee7c1768d2fa8c' into feature/main/date-statistics 1 year ago
lkd9125 b5198c37fa Merge commit '3ae1f4e7c60047303bf013108138b866559c9dbf' into feature/main/date-statistics 1 year ago
lkd9125 3ae1f4e7c6 연,월,일 별 통계조회을 위한 URL추가 1 year ago
지대한 4a3756fc6c 전화번호, 이메일 복호화 1 year ago
지대한 9426e71fe4 jackson 라이브러리 충돌 1 year ago
지대한 f559a34b45 로그인시 기본정보 추가 1 year ago
지대한 269d056441 kac 전용 패키지 삭제 - 기존 프로세스 사용 1 year ago
지대한 1e4baae8f8 common 라이브러리 추가 1 year ago
lkd9125 76af7ac8af Merge commit '0ae4b21f91cfeb6786416efbc07c6907acfe5059' into feature/main/date-statistics 1 year ago
lkd9125 0ae4b21f91 연단위 조건 수정 1 year ago
lkd9125 318e03121f 비행실적 통계 API 추가 1 year ago
lkd9125 468a00aff3 Merge commit 'e6d85130db9ad5b4c50209d8cd60314b7b47fd47' into feature/main/plan-allow-statistics 1 year ago
lkd9125 e6d85130db 주석 및 코드정리 1 year ago
lkd9125 4323f77762 연,월,일 통계 API 추가 1 year ago
lkd9125 60e2d42eaf Get요청 시 Instant 파라미터 변환코드 주석 해제 1 year ago
지대한 d8673a2d3d DB 추가 필드에 대한 비행계획서 등록/수정/조회/상세조회 모델 변경 1 year ago
지대한 24fa9841e2 DB 추가 필드에 대한 비행계획서 등록/수정/조회/상세조회 모델 변경 1 year ago
지대한 82c7f168fd entity 수정 및 controller 직렬화/역직렬화 1 year ago
lkd9125 843b29613a Merge commit '067cacdc3edfd01e05b8d52108d55b41902600ee' into develop 1 year ago
lkd9125 067cacdc3e Merge commit '3a2a2f5d7cbe8eca946a16fd22a00936e232d632' into feature/repactoring/date_to_instant 1 year ago
lkd9125 4af4af42f7 Socket, WebSocket Instant 변경추가 1 year ago
lkd9125 b032fdefdd PavServer instant객체 추가 변경 1 year ago
지대한 3a2a2f5d7c 추가 필드 및 date to instant 변경 1 year ago
지대한 c1b51eb8f7 Merge remote-tracking branch 'origin/feature/repactoring/date_to_instant' into develop 1 year ago
lkd9125 aadf2b9f4d Merge commit '5e3474cc305e7f3e796f1f01648bd788e7d08265' into feature/repactoring/date_to_instant 1 year ago
lkd9125 743e233488 QueryDSL-SQL라이브러리 추가 1 year ago
lkd9125 d0af58023c 비행계획서 관련 부분 Instnat 오류 수정 1 year ago
lkd9125 29bf17be1d Instant 타입 파라미터 컨버터 추가, 로그인 정보 조회 시 회원이름 암호화 해제 1 year ago
lkd9125 e9b968d8ba Instant Converting 추가 1 year ago
lkd9125 32234211ad JPA 관련 Instant타입 어노테이션 변경, 컨버터 작업 준비 1 year ago
lkd9125 6d850d3fdf PavServer -> Date 객체 Instant로 1차 변경 1 year ago
  1. 12
      document/dron_test/pav-warning.js
  2. 66
      pav-server/build.gradle
  3. 31
      pav-server/src/docs/asciidoc/index.adoc
  4. 146
      pav-server/src/main/java/com/palnet/biz/api/acnt/crtfyhp/controller/AcntCrtfyhpController.java
  5. 113
      pav-server/src/main/java/com/palnet/biz/api/acnt/crtfyhp/service/AcntCrtfyhpService.java
  6. 118
      pav-server/src/main/java/com/palnet/biz/api/acnt/cstmr/controller/AcntCstmrController.java
  7. 2
      pav-server/src/main/java/com/palnet/biz/api/acnt/cstmr/model/AnctCstmerRlModel.java
  8. 115
      pav-server/src/main/java/com/palnet/biz/api/acnt/cstmr/service/AcntCstmrService.java
  9. 58
      pav-server/src/main/java/com/palnet/biz/api/acnt/jwt/controller/JwtAuthenticationController.java
  10. 4
      pav-server/src/main/java/com/palnet/biz/api/acnt/jwt/model/JwtProfileRsModel.java
  11. 33
      pav-server/src/main/java/com/palnet/biz/api/acnt/jwt/service/JwtService.java
  12. 4
      pav-server/src/main/java/com/palnet/biz/api/acnt/jwt/utils/JwtTokenUtil.java
  13. 8
      pav-server/src/main/java/com/palnet/biz/api/acnt/terms/controller/AcntTermsController.java
  14. 5
      pav-server/src/main/java/com/palnet/biz/api/acnt/terms/service/AcntTermsService.java
  15. 52
      pav-server/src/main/java/com/palnet/biz/api/anls/hstry/controller/AnlsHstryController.java
  16. 49
      pav-server/src/main/java/com/palnet/biz/api/anls/hstry/service/AnlsHstryService.java
  17. 54
      pav-server/src/main/java/com/palnet/biz/api/anls/smlt/controller/AnlsSmltController.java
  18. 20
      pav-server/src/main/java/com/palnet/biz/api/anls/smlt/service/AnlsSmltService.java
  19. 20
      pav-server/src/main/java/com/palnet/biz/api/bas/flight/model/BasFlightPlanAreaModel.java
  20. 60
      pav-server/src/main/java/com/palnet/biz/api/bas/laanc/controller/BasLaancController.java
  21. 15
      pav-server/src/main/java/com/palnet/biz/api/bas/laanc/model/BasLaancQrcodeRq.java
  22. 15
      pav-server/src/main/java/com/palnet/biz/api/bas/laanc/model/BasLaancQrcodeRs.java
  23. 81
      pav-server/src/main/java/com/palnet/biz/api/bas/laanc/model/BasLaancValidatedRs.java
  24. 402
      pav-server/src/main/java/com/palnet/biz/api/bas/laanc/service/BasLaancService.java
  25. 30
      pav-server/src/main/java/com/palnet/biz/api/ctr/cntrl/service/SocketReceiverService.java
  26. 130
      pav-server/src/main/java/com/palnet/biz/api/external/controller/ExternalLaancController.java
  27. 102
      pav-server/src/main/java/com/palnet/biz/api/external/model/TsPlanRq.java
  28. 28
      pav-server/src/main/java/com/palnet/biz/api/external/model/TsQrcodeRq.java
  29. 31
      pav-server/src/main/java/com/palnet/biz/api/external/model/TsQrcodeRs.java
  30. 63
      pav-server/src/main/java/com/palnet/biz/api/external/service/TsService.java
  31. 18
      pav-server/src/main/java/com/palnet/biz/api/main/dash/controller/MainDashController.java
  32. 266
      pav-server/src/main/java/com/palnet/biz/api/main/dash/service/MainDashService.java
  33. 127
      pav-server/src/main/java/com/palnet/biz/api/main/statistics/service/MainStatisticsService.java
  34. 6
      pav-server/src/main/java/com/palnet/biz/config/WebMvcConfig.java
  35. 6
      pav-server/src/main/java/com/palnet/biz/config/WebSecurityConfig.java
  36. 15
      pav-server/src/main/java/com/palnet/biz/config/convert/CodeToFltPurposeBinding.java
  37. 24
      pav-server/src/main/java/com/palnet/biz/config/convert/InstantStringDeserializer.java
  38. 2
      pav-server/src/main/java/com/palnet/biz/jpa/entity/CnsFaqBas.java
  39. 58
      pav-server/src/main/java/com/palnet/biz/jpa/entity/ComConfirmBas.java
  40. 13
      pav-server/src/main/java/com/palnet/biz/jpa/repository/com/ComConfirmBasRepository.java
  41. 1213
      pav-server/src/main/java/com/palnet/biz/jpa/repository/ctr/CtrCntrlQueryRepository.java
  42. 10
      pav-server/src/main/java/com/palnet/biz/jpa/repository/ctr/CtrCntrlWarnLogQueryRepository.java
  43. 10
      pav-server/src/main/java/com/palnet/biz/jpa/repository/flt/FltPlanBasRepository.java
  44. 56
      pav-server/src/main/java/com/palnet/biz/jpa/repository/flt/FltPlanQueryRepository.java
  45. 24
      pav-server/src/main/java/com/palnet/biz/jpa/repository/pty/PtyCrtfyhpBasQueryRepository.java
  46. 180
      pav-server/src/main/java/com/palnet/biz/jpa/repository/pty/PtyCstmrQueryRepository.java
  47. 28
      pav-server/src/main/java/com/palnet/biz/jpa/repository/pty/PtyTermsQueryRepository.java
  48. 24
      pav-server/src/main/java/com/palnet/biz/sample/controller/UtmSampleTestController.java
  49. 87
      pav-server/src/main/java/com/palnet/comn/code/ErrorCode.java
  50. 2
      pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java
  51. 5
      pav-server/src/main/java/com/palnet/comn/utils/InstantUtils.java
  52. 4
      pav-server/src/main/resources/application-database.yml
  53. 1
      pav-server/src/main/resources/application.properties
  54. 12
      pav-server/src/main/resources/application.yml
  55. 2
      pav-server/src/main/resources/config/log/logback-spring.xml
  56. 572
      pav-server/src/main/resources/static/docs/index.html
  57. 4
      pav-server/src/test/java/com/palnet/biz/api/bas/laanc/service/BasLaancAprvServiceTest.java
  58. 2
      pav-server/src/test/java/com/palnet/biz/api/comn/file/service/ComnFileServiceTest.java
  59. 3
      pav-server/src/test/java/com/palnet/biz/api/comn/sms/service/ComnSmsServiceTest.java
  60. 4
      pav-server/src/test/java/com/palnet/biz/api/external/service/SunRiseSetServiceTest.java
  61. 2
      pav-server/src/test/java/com/palnet/biz/api/external/service/TsServiceTest.java
  62. 116
      pav-server/src/test/java/com/palnet/biz/api/main/statistics/StatisticsTests.java
  63. 4
      pav-server/src/test/java/com/palnet/biz/jpa/repository/flt/FltPlanQueryRepositoryTest.java
  64. 2
      pav-server/src/test/java/com/palnet/biz/scheduler/ctr/service/CtrTrnsLctnServiceTest.java
  65. 3
      pav-server/src/test/java/com/palnet/exec/TempAdmDistrictServiceTest.java
  66. 43
      pav-socket/src/main/java/com/palnet/comn/collection/GPCollection.java
  67. 4
      pav-socket/src/main/java/com/palnet/comn/model/GPModel.java
  68. 37
      pav-socket/src/main/java/com/palnet/comn/model/UtmModel.java
  69. 83
      pav-socket/src/main/java/com/palnet/server/task/server/service/TaskServerService.java
  70. 6
      pav-socket/src/main/resources/application.yml
  71. 4
      pav-websocket/src/main/java/com/palnet/server/controller/SocketReceiverController.java
  72. 1
      pav-websocket/src/main/resources/application.yml

12
document/dron_test/pav-warning.js

@ -10,11 +10,11 @@ const port = 8082;
const prefix = 'PALUTM-';
const pathSampleCoord = [
[37.523771, 126.720982],
[37.524841, 126.723106],
[37.524337, 126.72333],
[37.524841, 126.723106],
[37.523771, 126.720982]
[37.571954, 126.775258],
[37.566375, 126.781266],
[37.562361, 126.783584],
[37.558143, 126.785987],
[37.553039, 126.788819]
];
// const pathSampleCoord = [
// [42.5515, 126.655],
@ -48,7 +48,7 @@ const getCoords = coords => {
};
const getClient = () => {
const dronName = prefix + '010';
const dronName = prefix + '095';
const client = {};
client.dronName = dronName;

66
pav-server/build.gradle

@ -3,6 +3,7 @@ plugins {
id 'org.springframework.boot' version '2.5.1'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
id 'com.ewerk.gradle.plugins.querydsl' version '1.0.10'
id "org.asciidoctor.jvm.convert" version "3.3.2"
}
group = 'com.palnet'
@ -30,8 +31,16 @@ repositories {
}
jar {
enabled = false
// jar {
// enabled = true
// }
configurations {
querydsl.extendsFrom compileClasspath
compileOnly {
extendsFrom annotationProcessor
}
asciidoctorExt
}
dependencies {
@ -63,6 +72,9 @@ dependencies {
implementation 'org.springframework.cloud:spring-cloud-aws-context:1.2.1.RELEASE'
implementation 'org.springframework.cloud:spring-cloud-aws-autoconfigure:2.0.1.RELEASE'
// RestDocs
asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' // 2
// lombok, mapstruct
compileOnly 'org.projectlombok:lombok:1.18.28'
annotationProcessor 'org.projectlombok:lombok:1.18.28'
@ -101,12 +113,17 @@ dependencies {
implementation 'org.geotools:gt-geotiff:29.2'
implementation 'org.geotools:gt-epsg-hsql:29.2'
// QR Code
implementation 'com.google.zxing:core:3.5.2'
implementation 'com.google.zxing:javase:3.5.2'
testCompileOnly 'org.projectlombok:lombok:1.18.28'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.28'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testAnnotationProcessor "org.mapstruct:mapstruct-processor:1.5.5.Final"
testAnnotationProcessor "org.mapstruct:mapstruct-processor:1.5.5.Final"
// RestDocs
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
}
@ -120,7 +137,7 @@ tasks.withType(JavaCompile) {
}
tasks.withType(Test) {
enabled = false
enabled = true
}
def querydslDir = "$buildDir/generated/querydsl"
@ -143,9 +160,42 @@ sourceSets.each { srcSet ->
println ""
}
configurations {
querydsl.extendsFrom compileClasspath
}
compileQuerydsl {
options.annotationProcessorPath = configurations.querydsl
}
ext {
snippetsDir = file('build/generated-snippets')
}
test {
useJUnitPlatform()
outputs.dir snippetsDir
}
asciidoctor {
dependsOn test
inputs.dir snippetsDir
}
bootJar {
dependsOn asciidoctor
from ("${asciidoctor.outputDir}/html5") {
into 'static/docs'
}
}
asciidoctor.doFirst {
delete file('src/main/resources/static/docs')
}
task copyDocument(type: Copy) {
dependsOn asciidoctor
from file("build/docs/asciidoc")
into file("src/main/resources/static/docs")
}
build {
dependsOn copyDocument
}

31
pav-server/src/docs/asciidoc/index.adoc

@ -0,0 +1,31 @@
ifndef::snippets[]
:snippets: ./build/generated-snippets
endif::[]
= PAV-KAC REST Docs
API 문서
:doctype: book
:icons: font
:source-highlighter: highlightjs
:toc: left
:toclevels: 2
:sectlinks:
[[메인통계-API]]
== 메인통계 API
[[메인통계]]
=== [비행통계 상단 고정데이터]
==== [Request]
include::{snippets}/main/statistics/flight-static/http-request.adoc[]
// ==== [Request-Fields]
// include::{snippets}/main/statistics/flight-static/request-fields.adoc[]
==== [Response]
include::{snippets}/main/statistics/flight-static/http-response.adoc[]
==== [ResponseFields]
include::{snippets}/main/statistics/flight-static/response-fields.adoc[]

146
pav-server/src/main/java/com/palnet/biz/api/acnt/crtfyhp/controller/AcntCrtfyhpController.java

@ -43,47 +43,65 @@ public class AcntCrtfyhpController {
@Autowired
private PtyCstmrQueryRepository ptyCstmrQueryRepository;
/**
* 인증번호를 발송하는 기능,
* hpno 값은 휴대폰번호입니다. 번호에 인증번호를 발송합니다.
* @param hpno
* @return
*/
@GetMapping(value = "/register/send")
@Tag(name = "휴대폰 인증 관리", description = "회원 휴대폰 인증 관련 API")
@ApiImplicitParam(name = "hnpo",value = "휴대폰번호", dataTypeClass = String.class)
public ResponseEntity<? extends BasicResponse> send(String hpno) {
Map<String , Object> resultMap = new HashMap<String,Object>();
Map<String , Object> resultMap = new HashMap<String,Object>(); // 결과 반환을 위한 객체선언
try {
if(hpno == null) {
return ResponseEntity.status(HttpStatus.OK)
if(hpno == null) { // hpno[휴대폰번호] 가 없을시 서버에서 파라미터가 없다는 "의도적인" 에러 반환
return ResponseEntity.status(HttpStatus.OK) // "의도적인" 에러 반환코드
.body(new ErrorResponse(RSErrorCode.ER_PARAM));
}
//회원정보에 동일한 휴대폰 번호가 있는지 확인 , 암호화 해서 검색
String encHpno = EncryptUtils.encrypt(hpno);
// 휴대폰 번호가 종복이면 isHpno가 True
boolean isHpno = ptyCstmrQueryRepository.findCstmrByHpno(encHpno);
if(isHpno) {
resultMap.put("result" , false);
if(isHpno) { // 휴대폰 번호 중복인 경우
resultMap.put("result" , false); // 성공하지 못함을 의미
resultMap.put("code" , -1); // 동일한 휴대폰 번호 존재
}else {
boolean result = service.registerSend(hpno);
resultMap.put("result" , result);
}else { // 휴대폰 번호 중복이 아닌경우
boolean result = service.registerSend(hpno); // 해당 휴대폰번호로 문자 메세지 발송
resultMap.put("result" , result); // 메세지 발송이 성공일 경우 true
}
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
}
// 문제없을 시 결과값을 최종적으로 리턴해줌
return ResponseEntity.ok().body(new SuccessResponse<Map>(resultMap));
}
/**
* 인증메세지를 받은 사용자가 인증번호를 입력하여 인증처리하는 기능입니다.
* @param hpno
* @param crtfyNo
* @return
*/
@GetMapping(value = "/register/confirm")
@Tag(name = "휴대폰 인증 관리", description = "회원 휴대폰 인증 관련 API")
@ApiImplicitParams({
@ -93,22 +111,25 @@ public class AcntCrtfyhpController {
public ResponseEntity<? extends BasicResponse> confirm(String hpno , String crtfyNo) {
Map<String , Boolean> resultMap = new HashMap<String,Boolean>();
Map<String , Boolean> resultMap = new HashMap<String,Boolean>(); // 결과 반환을 위한 객체선언
if(hpno == null || crtfyNo == null) {
return ResponseEntity.status(HttpStatus.OK)
if(hpno == null || crtfyNo == null) { // hpno[휴대폰번호], crtfyNo[인증번호] 값이 없을 시 서버에서 파라미터가 없다는 "의도적인" 에러 반환
return ResponseEntity.status(HttpStatus.OK)// "의도적인" 에러 반환코드
.body(new ErrorResponse(RSErrorCode.ER_PARAM));
}
try {
boolean result = service.registerConfirm(hpno, crtfyNo);
resultMap.put("result" , result);
try {
boolean result = service.registerConfirm(hpno, crtfyNo); // 휴대폰번호로 전송된 인증번호가 맞는지 확인하는 코드
resultMap.put("result" , result); // 인증성공하면 true
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
@ -118,7 +139,12 @@ public class AcntCrtfyhpController {
}
//아이디 찾기 시 인증번호 발송 로직
/**
* 아이디 찾기 인증번호 발송 로직
* @param memberName
* @param hpno
* @return
*/
@GetMapping(value = "/find/sendForId")
@ApiOperation(value = "아이디 찾기 시 인증번호 발송")
@Tag(name = "휴대폰 인증 관리", description = "회원 휴대폰 인증 관련 API")
@ -127,15 +153,15 @@ public class AcntCrtfyhpController {
@ApiImplicitParam(name = "hpno", value = "휴대폰 번호", dataTypeClass = String.class)
})
public ResponseEntity<? extends BasicResponse> sendForId(String memberName, String hpno) {
Map<String, Object> resultMap = new HashMap<String, Object>();
Map<String, Object> resultMap = new HashMap<String, Object>(); // 결과 반환을 위한 객체선언
if(memberName == null || hpno == null) {
return ResponseEntity.status(HttpStatus.OK)
if(memberName == null || hpno == null) { // hpno[휴대폰번호]와 memberName[회원이름]이 없을시 서버에서 파라미터가 없다는 "의도적인" 에러 반환
return ResponseEntity.status(HttpStatus.OK) // "의도적인" 에러 반환코드
.body(new ErrorResponse(RSErrorCode.ER_PARAM));
}
try {
boolean result = service.certifNum(memberName, hpno);
boolean result = service.certifNum(memberName, hpno); //
resultMap.put("result" , result);
if(!result) {
resultMap.put("code", -1); //일치하는 회원 없음
@ -143,6 +169,13 @@ public class AcntCrtfyhpController {
resultMap.put("code", 0); //일치하는 회원 존재
}
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
@ -150,7 +183,12 @@ public class AcntCrtfyhpController {
return ResponseEntity.ok().body(new SuccessResponse<Map>(resultMap));
}
//아이디 찾기
/**
* 아이디 찾기
* @param memberName
* @param hpno
* @return
*/
@GetMapping(value = "/find/findUserId")
@ApiOperation(value = "회원 아이디 찾기")
@Tag(name = "휴대폰 인증 관리", description = "회원 휴대폰 인증 관련 API")
@ -159,10 +197,10 @@ public class AcntCrtfyhpController {
@ApiImplicitParam(name = "hpno",value = "휴대폰번호", dataTypeClass = String.class)
})
public ResponseEntity<? extends BasicResponse> findUserId(String memberName, String hpno) {
Map<String, Object> resultMap = new HashMap<String, Object>();
Map<String, Object> resultMap = new HashMap<String, Object>(); // 결과 반환을 위한 객체선언
if(memberName == null || hpno == null) {
return ResponseEntity.status(HttpStatus.OK)
if(memberName == null || hpno == null) { // hpno[휴대폰번호]와 memberName[회원이름]이 없을시 서버에서 파라미터가 없다는 "의도적인" 에러 반환
return ResponseEntity.status(HttpStatus.OK) // "의도적인" 에러 반환코드
.body(new ErrorResponse(RSErrorCode.ER_PARAM));
}
@ -184,7 +222,12 @@ public class AcntCrtfyhpController {
return ResponseEntity.ok().body( new SuccessResponse<Map>(resultMap));
}
//비밀번호 찾기 시 인증번호 발송 로직
/**
* 비밀번호 찾기 인증번호 발송 로직
* @param userId
* @param hpno
* @return
*/
@GetMapping(value = "/find/sendForPw")
@ApiOperation(value = "비밀번호 찾기 시 인증번호 발송")
@Tag(name = "휴대폰 인증 관리", description = "회원 휴대폰 인증 관련 API")
@ -195,13 +238,13 @@ public class AcntCrtfyhpController {
public ResponseEntity<? extends BasicResponse> sendForPw(String userId, String hpno) {
Map<String, Object> resultMap = new HashMap<String, Object>();
if(userId == null || hpno == null) {
return ResponseEntity.status(HttpStatus.OK)
if(userId == null || hpno == null) { // userId[회원아이디]와 memberName[회원이름]이 없을시 서버에서 파라미터가 없다는 "의도적인" 에러 반환
return ResponseEntity.status(HttpStatus.OK) // "의도적인" 에러 반환코드
.body(new ErrorResponse(RSErrorCode.ER_PARAM));
}
try {
boolean result = service.certifPw(userId, hpno);
boolean result = service.certifPw(userId, hpno); // 회원 ID와 휴대폰번호로 인증메세지 보내는 기능
resultMap.put("result", result);
if(!result) {
resultMap.put("code", -1); //일치하는 회원 없음
@ -209,6 +252,13 @@ public class AcntCrtfyhpController {
resultMap.put("code", 0); //일치하는 회원 존재
}
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
@ -217,7 +267,14 @@ public class AcntCrtfyhpController {
return ResponseEntity.ok().body( new SuccessResponse<Map>(resultMap));
}
/**
* 비밀번호 찾기 업데이트
* @param userId
* @param hpno
* @param newPw
* @return
* @throws Exception
*/
@GetMapping(value = "/find/updatePw")
@ApiOperation(value = "비밀번호 찾기 및 업데이트")
@Tag(name = "휴대폰 인증 관리", description = "회원 휴대폰 인증 관련 API")
@ -229,13 +286,13 @@ public class AcntCrtfyhpController {
public ResponseEntity<? extends BasicResponse> updatePw(String userId, String hpno, String newPw) throws Exception {
Map<String, Object> resultMap = new HashMap<String, Object>();
if(hpno == null || newPw == null) {
return ResponseEntity.status(HttpStatus.OK)
if(hpno == null || newPw == null) { // hpno[휴대폰번호]와 newPw[새로운 비밀번호]가 없을시 서버에서 파라미터가 없다는 "의도적인" 에러 반환
return ResponseEntity.status(HttpStatus.OK) // "의도적인" 에러 반환코드
.body(new ErrorResponse(RSErrorCode.ER_PARAM));
}
try {
boolean result = service.updatePw(userId, hpno, newPw);
try {
boolean result = service.updatePw(userId, hpno, newPw); // 사용자가 입력한 새로운 암호로 업데이트
resultMap.put("result", result);
if(!result) {
resultMap.put("code", -1);
@ -243,6 +300,13 @@ public class AcntCrtfyhpController {
resultMap.put("code", 0);
}
} catch(Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));

113
pav-server/src/main/java/com/palnet/biz/api/acnt/crtfyhp/service/AcntCrtfyhpService.java

@ -19,6 +19,7 @@ import com.palnet.biz.jpa.repository.pty.PtyCstmrBasRepository;
import com.palnet.biz.jpa.repository.pty.PtyCstmrQueryRepository;
import com.palnet.biz.jpa.repository.pty.SuredataRepository;
import com.palnet.comn.utils.EncryptUtils;
import com.palnet.comn.utils.InstantUtils;
@Service
public class AcntCrtfyhpService {
@ -105,9 +106,16 @@ public class AcntCrtfyhpService {
//
// return true;
// }
/**
* hpno에 있는 번호로 인증번호 메세지 발송하는 기능
* @param hpno
* @return
* @throws Exception
*/
public boolean registerSend(String hpno) throws Exception{
//인증번호 만들기 ( 6자리)
//인증번호 만들기 (6자리)
String certifyNo = numberGen(6, 2);
//메시지 만들기
@ -125,13 +133,25 @@ public class AcntCrtfyhpService {
ptyEntity.setCrtfyhpYn("N");
ptyCrtfyhpBasRepository.save(ptyEntity);
logger.info("certifyNo :: " + certifyNo);
logger.info("certifyNo :: {}", certifyNo); // 로그로 인증번호 값을 찍어줌
// 현재시간 값을 구해옴 예시 => nowStr = "20231206135600"
String nowStr = InstantUtils.toDatetimeStringByFormat(Instant.now(), "yyyyMMddHHmmss");
//발송 테이블 입력
SuredataEntity entity = new SuredataEntity();
entity.setIntime(nowStr);
entity.setCallphone(hpno);
entity.setMsg(msg);
/**
* Message 기본값들 applcation-local[dev,prod등].properties 파일에서 확인할 있음
* local,dev,prod는 서버가 돌아가는 환경 옵션입니다.
* local - 개발자 개인 컴퓨터 환경
* dev - 상용서버 배포전 테스트할 서버 환경[테스트서버]
* prod - 상용화 환경
*/
entity.setSubject(SUBJECT_CETIFY);
entity.setCallname(CALLNAME_CERTIFY);
entity.setUsercode(USER_CODE);
@ -143,9 +163,11 @@ public class AcntCrtfyhpService {
entity.setKind(KIND);
SuredataEntity result = sureDataRepository.save(entity);
if(result == null) {
SuredataEntity result = sureDataRepository.save(entity); // 데이터 베이스에 저장[Data Insert]
// Save했을시 성공하지 못하면 result는 null됨
// 그래서 null경우 성공하지 못한다고 판단
if(result == null) {
return false;
}
@ -153,14 +175,33 @@ public class AcntCrtfyhpService {
}
/**
* 휴대폰 번호에 전송된 인증번호가 맞는지 확인하는 기능
* @param hpno
* @param crtfyNo
* @return
* @throws Exception
*/
public boolean registerConfirm(String hpno , String crtfyNo ) throws Exception{
hpno = EncryptUtils.encrypt(hpno); //암호화 해서 검색
List<PtyCrtfyhpBas> entity = query.confirmSms(hpno , crtfyNo);
List<PtyCrtfyhpBas> entity = query.confirmSms(hpno , crtfyNo); // 데이터 베이스에서 휴대폰 번호와 인증번호 맞는지 체크
return entity.size() == 0 ? false : true;
/**
* entity.size() 값은 인증성공하면 1이상 인증이 실패하면 0입니다.
* 그래서, [0]이면 false [인증실패]
* [1]이면 true [인증성공]
*/
return entity.size() == 0 ? false : true;
}
/**
* len의 크기만큼 난수 생성,
* dupCd가 [1]이면 [중복허용], [2] [중복불가]
* @param len
* @param dupCd
* @return
*/
public static String numberGen(int len, int dupCd){
Random rand = new Random();
String numStr = ""; //난수가 저장될 변수
@ -184,46 +225,78 @@ public class AcntCrtfyhpService {
}
return numStr;
}
/**
* 휴대폰 번호와 회원이름으로 회원 휴대폰에 인증번호 발송하는 기능
* @param memberName
* @param hpno
* @return
* @throws Exception
*/
public boolean certifNum(String memberName, String hpno) throws Exception{
// String name = EncryptUtils.encrypt(memberName);
String phone = EncryptUtils.encrypt(hpno);
boolean certifNum = cstmrQuery.certifNum(memberName , phone);
if(certifNum) {
registerSend(hpno);
if(certifNum) { // 회원정보가 있어 true면 인증문자 발송
registerSend(hpno); // hpno번호에 있는 번호로 문자발송
}
return certifNum;
}
/**
* 휴대폰 번호와 회원 명으로 회원 ID 찾는 기능
* @param memberName
* @param hpno
* @return
* @throws Exception
*/
public String findUserId(String memberName, String hpno) throws Exception{
// String name = EncryptUtils.encrypt(memberName);
String phone = EncryptUtils.encrypt(hpno);
String resultFindId = cstmrQuery.findUserId(memberName,phone);
String phone = EncryptUtils.encrypt(hpno); // 번호 암호화
String resultFindId = cstmrQuery.findUserId(memberName,phone); // 휴대폰번호[hpno]와 회원명[memberName]으로 ID찾기
return resultFindId;
}
/**
* 회원 ID와 휴대폰번호로 인증메세지 보내는 기능
* @param userId
* @param hpno
* @return
* @throws Exception
*/
public boolean certifPw(String userId, String hpno) throws Exception{
String phone = EncryptUtils.encrypt(hpno);
String phone = EncryptUtils.encrypt(hpno); // 번호 암호화
PtyCstmrBas certifNum = cstmrQuery.findUserPw(userId , phone);
boolean result = false;
if(certifNum != null) {
//certifNum이 값이 있을경우 메세지 전송, 값이 있다는것은 데이터베이스에 ID와 휴대폰번호[hpno]가 일치한다는 것
if(certifNum != null) {
registerSend(hpno);
result = true;
}
return result;
}
/**
* 사용자가 입력한 새로운 암호로 변경[수정]하는 기능
* @param userId
* @param hpno
* @param newPw
* @return
* @throws Exception
*/
public boolean updatePw(String userId, String hpno, String newPw) throws Exception{
String phone = EncryptUtils.encrypt(hpno);
PtyCstmrBas certifNum = cstmrQuery.findUserPw(userId , phone);
String phone = EncryptUtils.encrypt(hpno); // 휴대폰번호 암호화
PtyCstmrBas certifNum = cstmrQuery.findUserPw(userId , phone); // 회원 아이디와 휴대폰번호로 데이터베이스에서 조회
boolean result = false;
if(certifNum != null) {
if(certifNum != null) { //certifNum이 값이 있을경우 메세지 전송, 값이 있다는것은 데이터베이스에 ID와 휴대폰번호[hpno]가 일치한다는 것
String encryptPw = EncryptUtils.sha256Encrypt(newPw);
certifNum.setUserPswd(encryptPw);
certifNum.setPswdUpdtDt(Instant.now());
ptyCstmrBasRepository.save(certifNum);
ptyCstmrBasRepository.save(certifNum); // 바뀐 암호로 변경[수정] 하는 코드
result = true;
}
return result;

118
pav-server/src/main/java/com/palnet/biz/api/acnt/cstmr/controller/AcntCstmrController.java

@ -32,6 +32,11 @@ public class AcntCstmrController {
private final AcntCstmrService service;
/**
* 회원가입 기능, AcntCstmrRqModel에 사용자가 입력한 회원 정보가 들어있음
* @param rq
* @return
*/
@PostMapping(value = "/register")
@ApiOperation(value = "회원 가입")
@Tag(name = "회원관리", description = "회원 관련 API")
@ -44,11 +49,18 @@ public class AcntCstmrController {
// result = service.list(rq);
log.debug(">>> bd : {}", rq.getBrthdyDate());
log.debug(">>> bd : {}", rq.getBrthdyDate().atZone(ZoneId.of("Asia/Seoul")).toLocalDateTime());
log.debug(">>> td : {}", rq.getTestDt());
log.debug(">>> td : {}", rq.getTestDt().atZone(ZoneId.of("Asia/Seoul")).toLocalDateTime());
result = service.register(rq);
// log.debug(">>> td : {}", rq.getTestDt());
// log.debug(">>> td : {}", rq.getTestDt().atZone(ZoneId.of("Asia/Seoul")).toLocalDateTime());
result = service.register(rq); // 회원정보를 데이터베이스에 추가[INSERT]함.
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
@ -57,6 +69,12 @@ public class AcntCstmrController {
return ResponseEntity.ok().body(new SuccessResponse<AcntCstmrRsModel>(result));
}
/**
* 회원 조회하는 기능, cstmrSno는 회원 고유번호 입니다.
* 고유번호로 회원의 정보를 조회합니다.
* @param cstmrSno
* @return
*/
@GetMapping(value = "/profile/{cstmrSno}")
@ApiOperation(value = "회원 정보")
@Tag(name = "회원관리", description = "회원 관련 API")
@ -66,9 +84,16 @@ public class AcntCstmrController {
try {
result = service.list(cstmrSno);
result = service.list(cstmrSno); // 회원고유번호[cstmrSno]로 회원정보를 조회 함.
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
@ -78,22 +103,43 @@ public class AcntCstmrController {
return ResponseEntity.ok().body(new SuccessResponse<List>(result));
}
/**
* 회원 계정 암호 변경하는 기능,
* AcntCstmrPwModel애 회원이 입력한 기존암호, 변경할 암호값이 있습니다.
* @param rq
* @return
*/
@PostMapping(value = "/profile/pswdupdate")
@ApiOperation(value = "회원 패스워드 변경")
@Tag(name = "회원관리", description = "회원 관련 API")
public ResponseEntity<? extends BasicResponse> passwordupdate(@RequestBody AcntCstmrPwModel rq){
Map<String, Object> resultMap = new HashMap<String, Object>();
try {
PtyCstmrBas result = service.updatepas(rq);
PtyCstmrBas result = service.updatepas(rq); // 입력받은 값으로 회원계정 암호변경.
resultMap.put("result", result);
} catch (CustomException e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* CustomException은 개발자가 "의도적으로" 예외처리,
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNOE : {}", e);
resultMap.put("result", false);
resultMap.put("errorCode", e.getErrorCode());
resultMap.put("errorMessage", e.getMessage());
return ResponseEntity.ok().body(new SuccessResponse<Map>(resultMap));
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGONE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResponse("Server Error", "-1"));
}
@ -101,22 +147,43 @@ public class AcntCstmrController {
return ResponseEntity.ok().body(new SuccessResponse<>(resultMap));
}
/**
* 회원 기존 패스워드 확인,
* userPswd 값에 있는 회원 암호가 맞는지 확인합니다.
* @param userPswdMap
* @return
*/
@PostMapping(value = "/profile/pwcheck")
@ApiOperation(value = "회원 기존 패스워드 확인")
@Tag(name = "회원관리", description = "회원 관련 API")
public ResponseEntity<? extends BasicResponse> extendpsw(@RequestBody Map<String,String> userPswdMap){
Map<String, Object> resultMap = new HashMap<String, Object>();
try {
boolean result = service.extendpsw(userPswdMap.get("userPswd"));
boolean result = service.extendpsw(userPswdMap.get("userPswd")); // 기존 암호가 맞는지 확인하는 기능.
resultMap.put("result", result);
} catch (CustomException e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* CustomException은 개발자가 "의도적으로" 예외처리,
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNOE : {}", e);
resultMap.put("result", false);
resultMap.put("errorCode", e.getErrorCode());
resultMap.put("errorMessage", e.getMessage());
return ResponseEntity.ok().body(new SuccessResponse<Map>(resultMap));
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGONE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResponse("Server Error", "-1"));
}
@ -124,6 +191,12 @@ public class AcntCstmrController {
return ResponseEntity.ok().body(new SuccessResponse<>(resultMap));
}
/**
* 회원정보 수정하는 기능,
* AcntCstmrEmModel에 회원이 입력한 수정할 정보들로 수정합니다.
* @param rq
* @return
*/
@PutMapping(value = "/profile/update")
@ApiOperation(value = "회원 정보 변경 (이메일,핸드폰)")
@Tag(name = "회원관리", description = "회원 관련 API")
@ -131,10 +204,18 @@ public class AcntCstmrController {
Map<String, Object> resultMap = new HashMap<String, Object>();
try {
PtyCstmrDtl result = service.updateEmail(rq);
PtyCstmrDtl result = service.updateEmail(rq); // 이메일과 휴대폰번호를 업데이트 하는 기능
resultMap.put("result", result);
} catch (CustomException e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* CustomException은 개발자가 "의도적으로" 예외처리,
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNOE : {}", e);
resultMap.put("result", false);
resultMap.put("errorCode", e.getErrorCode());
@ -142,6 +223,13 @@ public class AcntCstmrController {
return ResponseEntity.ok().body(new SuccessResponse<Map>(resultMap));
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGONE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResponse("Server Error", "-1"));
@ -149,6 +237,12 @@ public class AcntCstmrController {
return ResponseEntity.ok().body(new SuccessResponse<>(resultMap));
}
/**
* 회원 탈퇴 처리하는 기능,
* 회원고유[cstmrSno] 값으로 회원탈퇴처리함.
* @param cstmrSno
* @return
*/
@PostMapping(value = "/profile/delete/{cstmrSno}")
@ApiOperation(value = "회원 탈퇴")
@Tag(name = "회원관리", description = "회원 관련 API")
@ -157,11 +251,19 @@ public class AcntCstmrController {
Map<String, Object> resultMap = new HashMap<String, Object>();
try {
boolean result = service.userDelete(cstmrSno);
boolean result = service.userDelete(cstmrSno); // 회원고유[cstmrSno] 값으로 회원탈퇴처리함.
resultMap.put("result", result);
} catch (CustomException e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* CustomException은 개발자가 "의도적으로" 예외처리,
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNOE : {}", e);
resultMap.put("result", false);
resultMap.put("errorCode", e.getErrorCode());

2
pav-server/src/main/java/com/palnet/biz/api/acnt/cstmr/model/AnctCstmerRlModel.java

@ -1,5 +1,6 @@
package com.palnet.biz.api.acnt.cstmr.model;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.palnet.biz.config.convert.InstantDateStrSerializer;
import lombok.Data;
@ -28,6 +29,7 @@ public class AnctCstmerRlModel {
private String updateuserId;
@JsonInclude(JsonInclude.Include.ALWAYS)
private String cptAuthCode;
}

115
pav-server/src/main/java/com/palnet/biz/api/acnt/cstmr/service/AcntCstmrService.java

@ -5,15 +5,14 @@ import java.util.List;
import javax.persistence.EntityManagerFactory;
import com.palnet.biz.api.acnt.cstmr.model.AcntCstmrEmModel;
import com.palnet.biz.api.acnt.cstmr.model.AcntCstmrPwModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.palnet.biz.api.acnt.cstmr.model.AcntCstmrEmModel;
import com.palnet.biz.api.acnt.cstmr.model.AcntCstmrPwModel;
import com.palnet.biz.api.acnt.cstmr.model.AcntCstmrRqModel;
import com.palnet.biz.api.acnt.cstmr.model.AcntCstmrRsModel;
import com.palnet.biz.api.acnt.cstmr.model.AnctCstmerRlModel;
@ -33,7 +32,6 @@ import com.palnet.biz.jpa.repository.pty.PtyGroupBasRepository;
import com.palnet.biz.jpa.repository.pty.PtyTermsAgreeTxnRepository;
import com.palnet.comn.code.ErrorCode;
import com.palnet.comn.exception.CustomException;
import com.palnet.comn.utils.DateUtils;
import com.palnet.comn.utils.EncryptUtils;
import com.palnet.comn.utils.HttpUtils;
@ -74,7 +72,7 @@ public class AcntCstmrService {
/**
*
*
* AcntCstmrRqModel에 담겨있는 회원정보를 데이터베이스에 추가하는 기능
* @param rq
* @return
*/
@ -89,7 +87,7 @@ public class AcntCstmrService {
//사전 체크. 동일한 ID 존재 여부 확인
isUserIdFind = query.findCstmrByUserId(rq.getUserId());
if(isUserIdFind) {
if(isUserIdFind) { // 중복되면 에러코드 반환
rs.setErrCode(-1);
return rs;
}
@ -119,21 +117,27 @@ public class AcntCstmrService {
}
}
//성공 파람 담기
//성공 데이터 담기
if(basEntity != null) {
rs.setErrCode(1);
rs.setLoginId(basEntity.getUserId());
}
}
}catch(Exception e) {
log.error("IGNORE : {}", e);
rs.setErrCode(-2);
return rs;
}
return rs;
}
/**
* AcntCstmrRqModel에 담겨있는 회원정보를 데이터베이스에 추가[INSERT]하는 기능.
* @param rq
* @return
* @throws Exception
*/
public PtyCstmrBas savePtyCstmrBas(AcntCstmrRqModel rq) throws Exception{
@ -153,7 +157,19 @@ public class AcntCstmrService {
}
/**
* AcntCstmrRqModel에 담겨있는 상세정보를 데이터베이스에 추가[INSERT].
* @param rq
* @param basEntity
* @return
* @throws Exception
*/
public PtyCstmrDtl savePtyCstmrDtl(AcntCstmrRqModel rq , PtyCstmrBas basEntity) throws Exception{
if(rq.getCntryCd() == null || rq.getCntryCd().equals("")){
rq.setCntryCd("KOR");
}
PtyCstmrDtl dtlEntity = new PtyCstmrDtl();
dtlEntity.setCstmrSno(basEntity.getCstmrSno());
dtlEntity.setIpinCi(rq.getIpinCi());
@ -189,20 +205,30 @@ public class AcntCstmrService {
return ptyTermsAgreeTxnRepository.save(agreeEntity);
}
/**
* 회원 고유번호[cstmrSno] 회원정보를 조회하는 기능.
* @param cstmrSno
* @return
*/
public List<AnctCstmerRlModel> list(int cstmrSno) {
List<AnctCstmerRlModel> resultList = query.list(cstmrSno);
List<AnctCstmerRlModel> resultList = query.list(cstmrSno); // 회원고유번호[cstmrSno]로 회원정보를 조회 함.
for(AnctCstmerRlModel model : resultList) {
model.setEmail(EncryptUtils.decrypt(model.getEmail()));
model.setHpno(EncryptUtils.decrypt(model.getHpno()));
model.setEmail(EncryptUtils.decrypt(model.getEmail())); // 이메일은 회원추가할 때 암호화하기에 다시 복호화를 함
model.setHpno(EncryptUtils.decrypt(model.getHpno())); // 휴대폰 번호는 회원추가할 때 암호화하기에 다시 복호화를 함
}
return resultList;
}
/**
* 회원에게 입력받은 암호로 변경하는 기능
* @param rq
* @return
*/
public PtyCstmrBas updatepas(AcntCstmrPwModel rq) {
// 1. 토큰 유저 정보 불러오기
Integer userId = jwtTokenUtil.getCstmrSnoByToken();
@ -228,6 +254,11 @@ public class AcntCstmrService {
return updateUserEntity;
}
/**
* 기존 암호가 맞는지 확인하는 기능.
* @param userPswd
* @return
*/
public boolean extendpsw(String userPswd){
boolean result = false;
// 1. 토큰 유저 정보 불러오기
@ -258,36 +289,57 @@ public class AcntCstmrService {
return result;
}
/**
* 이메일과 휴대폰번호를 업데이트 하는 기능.
* @param rq
* @return
*/
public PtyCstmrDtl updateEmail(AcntCstmrEmModel rq) {
Integer cstmrSno = jwtTokenUtil.getCstmrSnoByToken();
String userId = jwtTokenUtil.getUserIdByToken();
String newEmail = EncryptUtils.encrypt(rq.getEmail());
String newHpno = EncryptUtils.encrypt(rq.getHpno());
Integer cstmrSno = jwtTokenUtil.getCstmrSnoByToken(); // 회원 인가할 정보에 있는 회원 고유번호
String userId = jwtTokenUtil.getUserIdByToken(); // 회원 인가할 정보에 있는 회원 아이디
String newEmail = EncryptUtils.encrypt(rq.getEmail()); // 바뀔 이메일 암호화
String newHpno = EncryptUtils.encrypt(rq.getHpno()); // 바뀔 휴대폰번호 암호화
// 회원 고유번호로 회원정보를 데이터베이스에서 가져옴
PtyCstmrDtl userEntity = ptyCstmrDtlRepository.findById(cstmrSno).orElse(null);
// 바뀔 내용 넣어줌
userEntity.setEmail(newEmail);
userEntity.setUpdateDt(Instant.now() );
userEntity.setUpdateUserId(userId);
userEntity.setHpno(newHpno);
// 바뀔 내용을 데이터베이스에 수정함
PtyCstmrDtl updateEmailEntity = ptyCstmrDtlRepository.save(userEntity);
return updateEmailEntity;
}
/**
* 회원고유[cstmrSno] 값으로 회원탈퇴처리 하는 기능.
* @param cstmrSno
* @return
*/
public boolean userDelete(int cstmrSno) {
List<JwtGroupModel> groupInfo = jwtTokenUtil.getGroupAuthByToken();
List<JwtGroupModel> groupInfo = jwtTokenUtil.getGroupAuthByToken(); // 회원의 속한 그룹을 조회
for(JwtGroupModel group : groupInfo) {
// if(group.getGroupAuthCd().equals("CREATER")) {
// 회원의 그룹 권한이 MASTER 일 경우
if(group.getGroupAuthCd().equals("MASTER")) {
PtyGroupBas groupEntity = ptyGroupBasRepository.findByGroupId(group.getGroupId());
PtyGroupBas groupEntity = ptyGroupBasRepository.findByGroupId(group.getGroupId());
// 그룹이 있을경우 그룹의 사용여부 "N" 값으로 저장
if(!(groupEntity == null)) {
groupEntity.setUseYn("N");
ptyGroupBasRepository.save(groupEntity);
}
List<PtyCstmrGroup> cstmrEntity = ptyCstmrGroupRepository.changeGroupJoinYn(group.getGroupId());
List<PtyCstmrGroup> cstmrEntity = ptyCstmrGroupRepository.changeGroupJoinYn(group.getGroupId());
// cstmrEntity 값이 있을 경우 참여여부 "N" 값으로 저장
if(!(cstmrEntity == null)) {
for(PtyCstmrGroup cstmr : cstmrEntity) {
cstmr.setJoinYn("N");
@ -295,20 +347,29 @@ public class AcntCstmrService {
}
}
}
// 회원 고유번호로 데이터베이스에서 그룹참여정보 가져옴
List<PtyCstmrGroup> AprvlEntity = ptyCstmrGroupRepository.changeGroupAprvlYn(cstmrSno);
// AprvlEntity[그룹참여 정보가] 있을경우
if(!(AprvlEntity == null)) {
// 그룹 승인여부를 "N"값으로 저장
for(PtyCstmrGroup Aprvl : AprvlEntity) {
Aprvl.setAprvlYn("N");
Aprvl.setAprvlDt(null);
ptyCstmrGroupRepository.save(Aprvl);
}
PtyCstmrGroup cstmrEntity = ptyCstmrGroupRepository.findGroupId(group.getGroupId(), cstmrSno);
if(!(cstmrEntity == null)) {
cstmrEntity.setJoinYn("N");
ptyCstmrGroupRepository.save(cstmrEntity);
// 그룹 참여여부를 "N"값으로 저장
PtyCstmrGroup cstmrEntity = ptyCstmrGroupRepository.findGroupId(group.getGroupId(), cstmrSno);
if(!(cstmrEntity == null)) {
cstmrEntity.setJoinYn("N");
ptyCstmrGroupRepository.save(cstmrEntity);
}
}
}
}
// 데이터베이스에 있는 회원 정보를 탈퇴처리 후 저장함
PtyCstmrBas userEntity = ptyCstmrBasRepository.findByUserGroupId(cstmrSno);
userEntity.setCstmrStatusCd("W");
userEntity.setCstmrStatusCngDt(Instant.now() );

58
pav-server/src/main/java/com/palnet/biz/api/acnt/jwt/controller/JwtAuthenticationController.java

@ -41,20 +41,30 @@ public class JwtAuthenticationController {
@Autowired
private JwtService service;
/**
* 로그인 기능,
* JwtRqModel에 입력받은 회원아이디, 입력받은 회원 비밀번호로 인증처리를 .
* @param authenticationRequest
* @return
* @throws Exception
*/
@PostMapping(value = "/login")
@ApiOperation(value = "로그인")
@Tag(name = "JWT 토큰 이용", description = "JWT 토큰 관련 API")
public ResponseEntity<? extends BasicResponse> createAuthenticationToken(@RequestBody JwtRqModel authenticationRequest) throws Exception {
// 로그인 프로세스
Map<String , Object> resultMap = service.loginProcess(authenticationRequest);
Map<String , Object> resultMap = service.loginProcess(authenticationRequest);
int loginError = (int) resultMap.get("loginError");
int loginError = (int) resultMap.get("loginError");
// loginError 은 1이 정상, - 값은 모두 로그인 실패임
if(loginError < 0) {
String errorMessage = (String) resultMap.get("errorMessage");
// 로그인 실패시 로그인 실패한 사유를 반환함
return ResponseEntity.status(HttpStatus.OK)
.body(new ErrorResponse(errorMessage, loginError + "")); // 계정 사용하지 못함
}else {
@ -65,49 +75,70 @@ public class JwtAuthenticationController {
}
/**
* 로그인 회원 정보,
* 회원고유번호[cstmrSno] 조회를 .
* @param cstmrSno
* @return
* @throws Exception
*/
@GetMapping(value = "/profile/{cstmrSno}")
@ApiOperation(value = "로그인한 회원의 정보")
@Tag(name = "JWT 토큰 이용", description = "JWT 토큰 관련 API")
@ApiImplicitParam(name = "cstmrSno",value = "고객일련번호", dataTypeClass = Integer.class)
public ResponseEntity<? extends BasicResponse> proflie(@PathVariable Integer cstmrSno) throws Exception{
JwtProfileRsModel result = service.profile(cstmrSno);
JwtProfileRsModel result = service.profile(cstmrSno); // 회원고유번호로 회원정보를 가져오는 기능.
if(result == null) {
// 반환받은 회원정보가 없을시 "의도적인" 예외코드를 반환해줌
return ResponseEntity.status(HttpStatus.OK)
.body(new ErrorResponse(RSErrorCode.DATA_NOTFOUNT));
}
return ResponseEntity.ok().body(new SuccessResponse<JwtProfileRsModel>(result));
}
/**
* 회원의 인가정보 유효기간 종료시,
* 다시 인가정보[토큰] 받는 기능
* @param body
* @return
* @throws Exception
*/
@PostMapping(value = "/refresh")
@Tag(name = "JWT 토큰 이용", description = "JWT 토큰 관련 API")
// public ResponseEntity<? extends BasicResponse> refresh(@RequestParam("cstmrSno") int cstmrSno , @RequestParam("refreshToken") String refreshToken) throws Exception{
public ResponseEntity<? extends BasicResponse> refresh(@RequestBody Map body) throws Exception{
//입력값 검증
// 회원고유번호[cstmrSno], 회원고유번호[cstmrSno]가 Integer타입인지, 인가정보를 다시받을 토큰값 [refreshToken] 입력값에 대한 검증처리
if(body.get("cstmrSno") == null || body.get("refreshToken") == null || !(body.get("cstmrSno") instanceof Integer)) {
// 검증이 되지 않으면 "의도적인" 예외코드를 반환해줌
return ResponseEntity.status(HttpStatus.OK)
.body(new ErrorResponse(RSErrorCode.ER_PARAM));
}
int cstmrSno = (int)body.get("cstmrSno");
String refreshToken = (String)body.get("refreshToken");
JwtRsModel result = service.findRefreshtoken(cstmrSno, refreshToken);
// 재 인가토큰 발급
JwtRsModel result = service.findRefreshtoken(cstmrSno, refreshToken);
// JwtRsModel result = null;
if(result ==null) {
// 토큰발행 실패 시 "의도적인" 예외코드를 반환해줌
return ResponseEntity.status(HttpStatus.OK)
.body(new ErrorResponse(RSErrorCode.DATA_NOTFOUNT));
}
return ResponseEntity.ok().body(new SuccessResponse<JwtRsModel>(result));
}
/**
* 로그아웃 기능.
* @param cstmrSno
* @return
* @throws Exception
*/
@GetMapping(value = "/logout/{cstmrSno}")
@ApiOperation(value = "로그아웃 한 회원의 정보")
@Tag(name = "JWT 토큰 이용", description = "JWT 토큰 관련 API")
@ -120,10 +151,11 @@ public class JwtAuthenticationController {
// }
// int cstmrSno = (int)body.get("cstmrSno");
// 로그아웃 할 프로세스
PtyCstmrBas bas = service.logoutProcess(cstmrSno);
if(bas == null) {
// 로그아웃 프로세스 실패 시 "의도적인" 예외코드를 반환해줌
return ResponseEntity.status(HttpStatus.OK)
.body(new ErrorResponse(RSErrorCode.DATA_NOTFOUNT));
}

4
pav-server/src/main/java/com/palnet/biz/api/acnt/jwt/model/JwtProfileRsModel.java

@ -1,5 +1,6 @@
package com.palnet.biz.api.acnt.jwt.model;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
@Data
@ -15,5 +16,8 @@ public class JwtProfileRsModel {
private String memberName;
private String trmnlId;
@JsonInclude(JsonInclude.Include.ALWAYS)
private String cptAuthCode;
}

33
pav-server/src/main/java/com/palnet/biz/api/acnt/jwt/service/JwtService.java

@ -39,8 +39,7 @@ public class JwtService {
private final JwtTokenUtil jwtTokenUtil;
/**
* 로그인 처리
*
* 로그인 처리하는 기능.
* @param rq
* @return
*/
@ -78,8 +77,8 @@ public class JwtService {
}
}
if (loginError < 0) {
//loginError 값이 - 인경우 에러 메세지와 함꼐 반환
if (loginError < 0) {
String errorMessage = "";
if (loginError == -100) {
@ -103,11 +102,13 @@ public class JwtService {
return resultMap;
} else {
} else { //loginError 값이 + 값이라면 로긍니 성공
String accessToken = jwtTokenUtil.generateToken(userDetails);
// 인증이후 인가할 정보 만듬.
String accessToken = jwtTokenUtil.generateToken(userDetails);
String refreshToken = jwtTokenUtil.generateRefreshToken(userDetails);
// 반환할 객체 설정.
JwtRsModel result = new JwtRsModel();
result.setAccessToken(accessToken);
result.setRefreshToken(refreshToken);
@ -139,9 +140,18 @@ public class JwtService {
}
/**
* 로그아웃 하는 기능.
* @param cstmrSno
* @return
* @throws Exception
*/
public PtyCstmrBas logoutProcess(int cstmrSno) throws Exception {
// 회원의 정보를 받아옴
Optional<PtyCstmrBas> optional = ptyCstmrBasRepository.findById(cstmrSno);
// 회원의 인가정보를 만료시킴
if (optional.isPresent()) {
PtyCstmrBas entity = optional.get();
entity.setRfrshToken("");
@ -175,7 +185,7 @@ public class JwtService {
}
/**
* refresh Token 저장 처리
* refresh Token 저장 처리 기능
*
* @param cstmrSno
* @param refreshToken
@ -197,8 +207,7 @@ public class JwtService {
}
/**
* 프로필 조회
*
* 회원의 프로필을 조회하는 기능.
* @param cstmrSno
* @return
* @throws Exception
@ -211,8 +220,7 @@ public class JwtService {
}
/**
* token 만료시 refresh 토큰으로 재검색
*
* token 만료시 refresh 토큰으로 재검색 하는 기능.
* @param cstmrSno
* @param refreshToken
* @return
@ -231,7 +239,8 @@ public class JwtService {
Claims claims = jwtTokenUtil.getAllClaimsFromToken(refreshToken);
Integer cstmrSnoByRefreshToken = claims.get("cstmrSno", Integer.class);
if(cstmrSnoByRefreshToken != cstmrSno) return null;
// 인가 토큰 발행할수 있게 필요한 회원 정보들을 데이터베이스에서 조회함.
JwtUserModel userDetails = query.findByIdForrefreshToken(cstmrSno);
String createAccessToken = jwtTokenUtil.generateToken(userDetails);

4
pav-server/src/main/java/com/palnet/biz/api/acnt/jwt/utils/JwtTokenUtil.java

@ -146,6 +146,10 @@ public class JwtTokenUtil implements Serializable {
return cstmrSno;
}
/**
* 회원 인가정보로 그룹
* @return
*/
public List<JwtGroupModel> getGroupAuthByToken() {
HttpServletRequest rq = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = rq.getHeader("Authorization");

8
pav-server/src/main/java/com/palnet/biz/api/acnt/terms/controller/AcntTermsController.java

@ -28,6 +28,12 @@ public class AcntTermsController {
private final AcntTermsService service;
/**
* 약관정보 들을 가져오는 기능,
* AcntTermsRqModel에 입력받은 약관타입에 따른 약관항목을 반환함.
* @param rq
* @return
*/
@GetMapping(value = "/list")
@Tag(name = "약관 기본", description = "약관 관련 API")
@ApiOperation(value = "약관 기본 정보")
@ -37,7 +43,7 @@ public class AcntTermsController {
log.debug("RQ>>>>>>>>" , rq.toString());
try {
result = service.list(rq);
result = service.list(rq); // 입력받은 값에 따른 약관항목을 반환하는 기능.
} catch (Exception e) {

5
pav-server/src/main/java/com/palnet/biz/api/acnt/terms/service/AcntTermsService.java

@ -16,6 +16,11 @@ public class AcntTermsService {
private final PtyTermsQueryRepository query;
/**
* 입력받은 값에 따른 약관항목을 반환하는 기능.
* @param rq
* @return
*/
public List<AcntTermsRsModel> list(AcntTermsRqModel rq) {
return query.list(rq);
}

52
pav-server/src/main/java/com/palnet/biz/api/anls/hstry/controller/AnlsHstryController.java

@ -33,6 +33,12 @@ public class AnlsHstryController {
private final AnlsHstryService service;
/**
* 비행현황 목록 리스트 조회하는 기능,
* AnlsHstryGroupModel에 따른 리스트를 조회함.
* @param rq
* @return
*/
@GetMapping(value = "/list")
@ApiOperation(value = "비행 현황 목록 출력")
@Tag(name = "비행 이력 현황", description = "비행 이력 현황 관련 API")
@ -40,16 +46,24 @@ public class AnlsHstryController {
List<AnlsHstryModel> rs = null;
ComnPagingRs<AnlsHstryModel> response;
//입력값 검증
// 검색 시작일 날짜[stDate], 검색 끝일 날짜 날짜값[endDate], 날짜값이 10자리인지 확인[정해진 포맷팅인지 확인하는 것] 입력값 검증처리
if(rq.getStDate() == null || !(rq.getStDate().length() == 10) || rq.getEndDate() ==null || !(rq.getEndDate().length() == 10) ) {
return ResponseEntity.status(HttpStatus.OK)
// 검증통과하지 못할 시 서버에서 "의도적인" 에러 반환
return ResponseEntity.status(HttpStatus.OK) // "의도적인" 에러 반환코드
.body(new ErrorResponse(RSErrorCode.ER_PARAM));
}
try {
response = service.list(rq);
response = service.list(rq); // 비행현황 목록 조회하는 기능.
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
@ -59,6 +73,12 @@ public class AnlsHstryController {
}
/**
* 비행현황의 상세정보를 조회함,
* 비행ID[CNTRL_ID] 조회함
* @param id
* @return
*/
@GetMapping(value = "/detail/{id}")
@ApiOperation(value = "비행 현황 상세")
@Tag(name = "비행 이력 현황", description = "비행 이력 현황 관련 API")
@ -67,9 +87,16 @@ public class AnlsHstryController {
AnlsHstryModel result = null;
try {
result = service.detail(id);
result = service.detail(id); // 비행ID[CNTRL_ID]로 비행 상세정보를 조회하는 기능.
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
@ -80,16 +107,29 @@ public class AnlsHstryController {
}
/**
* 비행이력을 조회함,
* 비행ID[CNTRL_ID] 조회함
* @param id
* @return
*/
@GetMapping(value = "/log/{id}")
@ApiOperation(value = "비행 이력 데이터")
@Tag(name = "비행 이력 현황", description = "비행 이력 현황 관련 API")
@ApiImplicitParam(name = "id",value = "관제ID", dataTypeClass = String.class)
public ResponseEntity<? extends BasicResponse> log(@PathVariable String id) {
List<AnlsHstryDetailModel> result = null;
try {
result = service.hstryList(id);
result = service.hstryList(id); // 비행이력을 비행ID[CNTRL_ID] 조회하는 기능.
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));

49
pav-server/src/main/java/com/palnet/biz/api/anls/hstry/service/AnlsHstryService.java

@ -67,18 +67,27 @@ public class AnlsHstryService {
@Autowired
private JwtTokenUtil jwtTokenUtil;
//비행이력현황 list
/**
* 비행현황 목록 조회하는 기능.
* @param rq
* @return
*/
public ComnPagingRs<AnlsHstryModel> list(AnlsHstryGroupModel rq){
// 조회에 필요한 기본값 선언
Integer cstmrSno = jwtTokenUtil.getCstmrSnoByToken();
List<JwtGroupModel> groupAuthList = jwtTokenUtil.getGroupAuthByToken();
List<JwtGroupModel> adminAuth = new ArrayList<>();
String groupAuth = null;
String appAuth = jwtTokenUtil.getUserAuthByToken();
// 페이징 처리를 위한 객체 선언
PageImpl<AnlsHstryModel>resultList;
ComnPagingRs<AnlsHstryModel> response = new ComnPagingRs<>();
Pageable pageable = PageRequest.of(rq.getPage()-1, rq.getRecord());
// 유저의 권한은 확인함
if("USER".equals(appAuth) || "ROLE_USER".equals(appAuth)) {
for(JwtGroupModel list : groupAuthList) {
if(list.getGroupId().equals(rq.getGroupId())) {
@ -86,23 +95,30 @@ public class AnlsHstryService {
}
}
}
// 그룹에서의 권한이 NORMAL인 경우
if("NORMAL".equals(groupAuth)) {
for (JwtGroupModel list : groupAuthList) {
if("MASTER".equals(list.getGroupAuthCd()) || "LEADER".equals(list.getGroupAuthCd())) {
adminAuth.add(list);
}
}
List<ComIdntfBas> idntfList = comIdntBasRepository.findIdntfNumber(cstmrSno);
List<FltPlanBas> basResult = fltPlanBasRepository.findByPlanSno(cstmrSno);
List<FltPlanPilot> pilotList = fltPlanPilotRepository.findByPlanSno(cstmrSno);
List<ComIdntfBas> idntfList = comIdntBasRepository.findIdntfNumber(cstmrSno); // 회원 고유번호와 맞는 기체 고유번호 조회
List<FltPlanBas> basResult = fltPlanBasRepository.findByPlanSno(cstmrSno); // 회원 고유번호와 맞는 비행계획서 조회
List<FltPlanPilot> pilotList = fltPlanPilotRepository.findByPlanSno(cstmrSno); // 회원 고유번호와 맞는 조종사 조회
List<FltPlanBas> pilotResult = new ArrayList<>();
for(FltPlanPilot list : pilotList) {
pilotResult = fltPlanBasRepository.findBasList(list.getPlanSno());
pilotResult = fltPlanBasRepository.findBasList(list.getPlanSno()); // 조종사번호와 맞는 비행계획서 조회
}
// 위 조건들에 부합하는 데이터를 조회함
resultList = query.cntrlBasNormalHstryList(rq, pageable, idntfList, basResult, pilotResult);
// 위 조건들에 부합하여 조회한 데이터의 갯수를 조회함
long total = query.cntrlBasNormalHstryCount(rq, idntfList, basResult, pilotResult);
long totalPage = total % rq.getRecord() > 0 ? total/rq.getRecord() + 1 : total/rq.getRecord();
@ -125,19 +141,27 @@ public class AnlsHstryService {
return response;
}
/**
* 비행ID[CNTRL_ID] 비행 상세정보를 조회하는 기능.
* @param cntrlId
* @return
* @throws Exception
*/
public AnlsHstryModel detail(String cntrlId) throws Exception{
AnlsHstryModel model = new AnlsHstryModel();
Optional<CtrCntrlBas> optional = ctrCntrlBasRepository.findById(cntrlId);
Optional<CtrCntrlBas> optional = ctrCntrlBasRepository.findById(cntrlId); //
if (!optional.isPresent()) {
// 데이터베이스에 조회하려는 데이터가 없을시 서버에서 파라미터가 없다는 "의도적인" 에러 반환
throw new CustomException(ErrorCode.DATA_NOTFIND);
}
CtrCntrlBas entity = optional.get();
// Entity에 담겨있는 값을 반환 model로 복제함
BeanUtils.copyProperties(entity , model);
@ -145,6 +169,11 @@ public class AnlsHstryService {
}
/**
* 비행이력을 비행ID[CNTRL_ID] 조회하는 기능.
* @param id
* @return
*/
public List<AnlsHstryDetailModel> hstryList(@PathVariable String id) {
List<AnlsHstryDetailModel> result = query.listCntrlHstryPage(id);

54
pav-server/src/main/java/com/palnet/biz/api/anls/smlt/controller/AnlsSmltController.java

@ -42,7 +42,8 @@ public class AnlsSmltController {
private final AnlsSmltService service;
/**
* 비행 현황 목록
* 비행현황 목록 리스트 조회하는 기능,
* AnlsHstryRqModel 따른 리스트를 조회함.
* @param rq
* @return
*/
@ -55,17 +56,25 @@ public class AnlsSmltController {
log.debug("JSON>>>>>>>>" , JsonUtils.toJson(rq));
log.debug("Param" + rq.getStDate() + "::" + rq.getEndDate());
//입력값 검증
// 검색 시작일 날짜[stDate], 검색 끝일 날짜 날짜값[endDate], 날짜값이 10자리인지 확인[정해진 포맷팅인지 확인하는 것] 입력값 검증처리
if(rq.getStDate() == null || !(rq.getStDate().length() == 10) || rq.getEndDate() ==null || !(rq.getEndDate().length() == 10) ) {
return ResponseEntity.status(HttpStatus.OK)
// 검증통과하지 못할 시 서버에서 "의도적인" 에러 반환
return ResponseEntity.status(HttpStatus.OK) // "의도적인" 에러 반환코드
.body(new ErrorResponse(RSErrorCode.ER_PARAM));
}
try {
result = service.list(rq);
result = service.list(rq); // 비행현황 목록 조회하는 기능.
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
@ -77,7 +86,8 @@ public class AnlsSmltController {
/**
* 비행 이력 데이터 조회
* 비행 이력 데이터 조회하는 기능,
* 비행ID[CNTRL_ID] 조회함
* @param rq
* @return
*/
@ -90,9 +100,16 @@ public class AnlsSmltController {
try {
// result = service.list(rq);
result = service.histList(id);
result = service.histList(id); // 비행ID[CNTRL_ID]로 비행이력을 조회하는 기능.
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
@ -104,7 +121,8 @@ public class AnlsSmltController {
/**
* 통계 데이터 조회
* 통계 데이터 조회,
* 비행ID[CNTRL_ID] 조회함
* @param rq
* @return
*/
@ -117,10 +135,16 @@ public class AnlsSmltController {
try {
result = service.stcsList(id);
result = service.stcsList(id); // 통계 데이터 조회하는 기능
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
@ -131,7 +155,8 @@ public class AnlsSmltController {
}
/**
* 비행 상세정보 조회
* 비행 상세정보 조회,
* 비행ID[CNTRL_ID] 조회함
* @param id
* @return
*/
@ -143,9 +168,16 @@ public class AnlsSmltController {
AnlsSmltDetailModel result = null;
try {
result = service.detail(id);
result = service.detail(id); // 비행ID[CNTRL_ID]로 비행상세정보 조회함
} catch (Exception e) {
/**
* try{
...
}
* try 영역 코드들중 문제가 생기면 오는 .
* log.error 로그로 원인 파악과 함께 API를 호출한 곳에 서버에러 내려줌
*/
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));

20
pav-server/src/main/java/com/palnet/biz/api/anls/smlt/service/AnlsSmltService.java

@ -61,7 +61,7 @@ public class AnlsSmltService {
/**
* 비행 현황 목록
* 비행현황 목록 조회하는 기능.
* @param rq
* @return
*/
@ -106,6 +106,7 @@ public class AnlsSmltService {
for(FltPlanPilot list : pilotList) {
pilotResult = fltPlanBasRepository.findBasList(list.getPlanSno());
}
result = query.cntrlBasNormalSmltList(rq, pageable, adminAuth, idntfList, basResult, pilotResult); // App 권한은 user이지만 group 권한이 LEADER / MASTER인 그룹이 있는 경우 해당 비행 이력 목록 표출
// group 권한이 Normal인 경우 본인이 작성한 비행계획서의 이력 / 본인이 조종사인 기체 이력/ 본인이 등록한 기체 이력 표출
@ -122,12 +123,13 @@ public class AnlsSmltService {
}
/**
*
* @param rq비행 이력 데이터 조회
* 비행ID[CNTRL_ID] 비행이력을 조회하는 기능.
* @param rq
* @return
*/
public List<AnlsHstryDetailModel> histList(String id){
// 비행ID[CNTRL_ID]로 비행이력을 데이터베이스에서 조회함.
List<AnlsHstryDetailModel> resultList = query.listCntrlHstry(id);
//정렬 순서 뒤집기 처리
@ -138,14 +140,13 @@ public class AnlsSmltService {
/**
* 통계 데이터 조회
* 통계 데이터 조회하는 기능
* @param rq
* @return
*/
public List<AnlsSmltStcsModel> stcsList(String id){
List<AnlsSmltStcsModel> result = query.anlsSmltStcs(id);
List<AnlsSmltStcsModel> result = query.anlsSmltStcs(id); // 비행관제 ID[CNTRL_ID]로 데이터베이스에서 시뮬레이션 통계데이터를 조회함.
//통계 데이터 가공 처리
//소수점 자리 1자리로 컷트
@ -162,7 +163,8 @@ public class AnlsSmltService {
/**
* 비행 상세정보 조회
* 비행 상세정보 조회,
* 비행ID[CNTRL_ID] 조회함
* @param cntrlId
* @return
* @throws Exception
@ -172,7 +174,7 @@ public class AnlsSmltService {
AnlsSmltDetailModel result = new AnlsSmltDetailModel();
result = query.anlsSmltDetail(cntrlId);
result = query.anlsSmltDetail(cntrlId); // 비행ID[CNTRL_ID]로 데이터베이스에서 비행상세 정보 조회함
// Optional<CtrCntrlBas> optional = ctrCntrlBasRepository.findById(cntrlId);
//

20
pav-server/src/main/java/com/palnet/biz/api/bas/flight/model/BasFlightPlanAreaModel.java

@ -1,6 +1,5 @@
package com.palnet.biz.api.bas.flight.model;
import com.palnet.biz.jpa.entity.type.FltMethod;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -32,22 +31,5 @@ public class BasFlightPlanAreaModel {
// kac 추가 필드
private String fltMothoeRm;
// public BasFlightPlanAreaModel(Integer planAreaSno, Integer planSno, String areaType, FltMethod fltMethod, String fltAreaAddr, Integer bufferZone, String fltElev, String createUserId, Instant createDt, String updateUserId, Instant updateDt, String docState, List<BasFlightPlanAreaCoordModel> coordList, List<BasFlightPlanAreaCoordModel> bufferCoordList, String fltMothoeRm) {
// this.planAreaSno = planAreaSno;
// this.planSno = planSno;
// this.areaType = areaType;
// this.fltMethod = fltMethod.getCode();
// this.fltMethodNm = fltMethod.getValue();
// this.fltAreaAddr = fltAreaAddr;
// this.bufferZone = bufferZone;
// this.fltElev = fltElev;
// this.createUserId = createUserId;
// this.createDt = createDt;
// this.updateUserId = updateUserId;
// this.updateDt = updateDt;
// this.docState = docState;
// this.coordList = coordList;
// this.bufferCoordList = bufferCoordList;
// this.fltMothoeRm = fltMothoeRm;
// }
}

60
pav-server/src/main/java/com/palnet/biz/api/bas/laanc/controller/BasLaancController.java

@ -5,6 +5,7 @@ import com.palnet.biz.api.bas.laanc.service.BasLaancService;
import com.palnet.biz.api.comn.response.BasicResponse;
import com.palnet.biz.api.comn.response.ErrorResponse;
import com.palnet.biz.api.comn.response.SuccessResponse;
import com.palnet.biz.api.external.model.PilotValidRs;
import com.palnet.comn.exception.CustomException;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -13,10 +14,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
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;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
@ -134,7 +132,7 @@ public class BasLaancController {
resultMap.put("result", false);
resultMap.put("errorCode", e.getErrorCode());
resultMap.put("errorMessage", e.getMessage());
return ResponseEntity.ok().body(new SuccessResponse<Map>(resultMap));
return ResponseEntity.ok().body(new SuccessResponse<>(resultMap));
} catch (Exception e) {
log.error("IGNORE : ", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
@ -158,7 +156,7 @@ public class BasLaancController {
resultMap.put("result", false);
resultMap.put("errorCode", e.getErrorCode());
resultMap.put("errorMessage", e.getMessage());
return ResponseEntity.ok().body(new SuccessResponse<Map>(resultMap));
return ResponseEntity.ok().body(new SuccessResponse<>(resultMap));
} catch (Exception e) {
log.error("IGNORE : ", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
@ -168,4 +166,54 @@ public class BasLaancController {
return ResponseEntity.ok().body(new SuccessResponse<>(rs));
}
@GetMapping(value = "/ts/qr")
@ApiOperation(value = "TS QR 코드 생성")
@Tag(name = "LAANC", description = "LAANC 관련 API")
public ResponseEntity<? extends BasicResponse> getQrCode(BasLaancQrcodeRq rq) {
BasLaancQrcodeRs rs = null;
try {
rs = basLaancService.createQrcode(rq);
} catch (CustomException e) {
Map<String, Object> resultMap = new HashMap<>();
log.error("IGNORE : ", e);
resultMap.put("result", false);
resultMap.put("errorCode", e.getErrorCode());
resultMap.put("errorMessage", e.getMessage());
return ResponseEntity.ok().body(new SuccessResponse<>(resultMap));
} catch (Exception e) {
log.error("IGNORE : ", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
}
return new ResponseEntity<>(new SuccessResponse<>(rs), HttpStatus.OK);
}
@GetMapping(value = "/ts/qr/{confirmKey}")
@ApiOperation(value = "TS QR 코드 확인 - RS왔는지 확인")
@Tag(name = "LAANC", description = "LAANC 관련 API")
public ResponseEntity<? extends BasicResponse> checkRqcodeRs(@PathVariable("confirmKey") String confirmKey) {
PilotValidRs rs = null;
try {
rs = basLaancService.checkQrcode(confirmKey);
} catch (CustomException e) {
Map<String, Object> resultMap = new HashMap<>();
log.error("IGNORE : ", e);
resultMap.put("result", false);
resultMap.put("errorCode", e.getErrorCode());
resultMap.put("errorMessage", e.getMessage());
if (e.getParamArray() != null) {
resultMap.put("params", e.getParamArray());
}
return ResponseEntity.ok().body(new SuccessResponse<>(resultMap));
} catch (Exception e) {
log.error("IGNORE : ", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("Server Error", "-1"));
}
return new ResponseEntity<>(new SuccessResponse<>(rs), HttpStatus.OK);
}
}

15
pav-server/src/main/java/com/palnet/biz/api/bas/laanc/model/BasLaancQrcodeRq.java

@ -0,0 +1,15 @@
package com.palnet.biz.api.bas.laanc.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BasLaancQrcodeRq {
// private String fltPurpose; // 비행목적
private String idntfNum; // 기체신고번호
}

15
pav-server/src/main/java/com/palnet/biz/api/bas/laanc/model/BasLaancQrcodeRs.java

@ -0,0 +1,15 @@
package com.palnet.biz.api.bas.laanc.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BasLaancQrcodeRs {
private byte[] qrcode; // qr코드
private String confirmKey; // 인증번호
}

81
pav-server/src/main/java/com/palnet/biz/api/bas/laanc/model/BasLaancValidatedRs.java

@ -1,14 +1,10 @@
package com.palnet.biz.api.bas.laanc.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.palnet.biz.api.external.model.PilotValidRs;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* packageName : com.palnet.biz.api.bas.laanc.model
* fileName : BasLaancValidatedRs
@ -26,66 +22,39 @@ import java.util.List;
@AllArgsConstructor
public class BasLaancValidatedRs {
// // TS 연동
// private String corpRegYn; // 사업자 여부
// private List<PilotValidRs> pilotValidRsList; // 자격여부
private boolean isPilotQlfc; // 자격여부
private boolean isArcrftInsurance; // 항공기보험여부
// 비행유형 여부
private boolean isCommercial; // 사업자 - true, 비사업자 - false
// 관제권
private boolean isEvaluatedTargetArea; // 평가대상지역여부 - 공역과 겹칠때만 true
private boolean isFlightArea; // 비행가능여부 - 비행가능 true
// 고도
private boolean isElev; // 고도여부 - 관제권내 설정고도 이하, 권제권밖 150m 이하 true
// 기체중량
private boolean isArcrftWeight; // 항공기중량여부 - 25kg 이하 true
// 비행방식
private boolean isFltMethod; // 비행방식 - 군집비행 false, 그외 true
// 비행시간
private boolean isSpacialFlight; // 특별비행여부 - true (야간비행)
// 자격여부
private boolean isPilotQlfc; // 자격여부
// 기체보험여부
private boolean isArcrftInsurance; // 기체보험여부
private boolean isElev; // 고도여부 - 150m 이하 true
private boolean isReport; // 신고 대상 - 비상업적이고 기체중량 2kg미만일 경우 - false / 그외 true
// 추가....
private boolean isCommercial; // 비행유형 사업자 - true / 비사업자 - false
private boolean isSpacialFlight; // 특별비행여부 - true
// TS 연동
// private String corpRegYn; // 사업자 여부
private List<PilotValidRs> pilotValidRsList; // 자격여부
// 활용안함.
// private boolean isArcrftDuplicated; // 기체 중복여부
// private boolean isPlanAreaDuplicatd; // 비행계획서비행구역 중복여부
// 최종여부
public boolean isValid() {
if (isReport) {
return isPilotQlfc
&& isArcrftInsurance
// && !isArcrftDuplicated // 기체 중복여부
// && !isPlanAreaDuplicatd // 비행구역 중복여부
&& isFlightArea // 비행가능여부
&& isCheckingLance();
}
return isFlightArea
// && !isPlanAreaDuplicatd
// && !isArcrftDuplicated
&& isCheckingLance();
return !isNonAprove() && !isNonAproveFlight();
}
public boolean isFlight() {
return !isCheckingLance() || isValid();
// 미승인
public boolean isNonAprove() {
return isFltMethod && !isSpacialFlight && isElev && isPilotQlfc && isArcrftInsurance;
}
// LAANC 승인 대상 여부
@JsonIgnore
public boolean isCheckingLance() {
return isEvaluatedTargetArea // 관제구역여부
/*
관제권 고도 150m초과에 대해서 승인 대상이나 담당자와의 협의가 필요하여 미승인 처리함
|| !isElev // 150m 초과 -
*/
|| !isArcrftWeight; // 25kg 초과
// 비행가능여부(미승인-날수있음)
public boolean isNonAproveFlight() {
return !isCommercial && !isEvaluatedTargetArea && isElev && isArcrftWeight;
}
// 특별승인 대상 여부
@JsonIgnore
public boolean isTargetSpacialFlight() {
return false;
}
}

402
pav-server/src/main/java/com/palnet/biz/api/bas/laanc/service/BasLaancService.java

@ -1,47 +1,28 @@
package com.palnet.biz.api.bas.laanc.service;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import com.palnet.biz.api.bas.laanc.model.*;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import com.google.zxing.WriterException;
import com.palnet.biz.api.acnt.cstmr.model.AnctCstmrModel;
import com.palnet.biz.api.acnt.cstmr.model.AnctCstmrTermsModel;
import com.palnet.biz.api.acnt.jwt.utils.JwtTokenUtil;
import com.palnet.biz.api.bas.laanc.model.*;
import com.palnet.biz.api.comn.file.model.LaancPdfModel;
import com.palnet.biz.api.comn.file.service.ComnFileService;
import com.palnet.biz.api.comn.sms.model.ComnSmsLaancAprovModel;
import com.palnet.biz.api.comn.sms.service.ComnSmsService;
import com.palnet.biz.api.comn.sunriseset.model.ComnSunrisesetCoordRq;
import com.palnet.biz.api.comn.sunriseset.model.ComnSunrisesetRs;
import com.palnet.biz.api.external.model.PilotValidRq;
import com.palnet.biz.api.external.model.PilotValidRs;
import com.palnet.biz.api.external.model.TsPlanRq;
import com.palnet.biz.api.external.model.TsQrcodeRq;
import com.palnet.biz.api.external.service.TsService;
import com.palnet.biz.jpa.entity.ComFileBas;
import com.palnet.biz.jpa.entity.FltPlanArcrft;
import com.palnet.biz.jpa.entity.FltPlanArea;
import com.palnet.biz.jpa.entity.FltPlanAreaCoord;
import com.palnet.biz.jpa.entity.FltPlanBas;
import com.palnet.biz.jpa.entity.FltPlanPilot;
import com.palnet.biz.jpa.entity.PtyGroupBas;
import com.palnet.biz.jpa.entity.PtyTermsAgreeTxn;
import com.palnet.biz.jpa.entity.*;
import com.palnet.biz.jpa.entity.type.ArcrftWghtCd;
import com.palnet.biz.jpa.entity.type.FltMethod;
import com.palnet.biz.jpa.entity.type.FltType;
import com.palnet.biz.jpa.repository.com.ComConfirmBasRepository;
import com.palnet.biz.jpa.repository.com.ComRiseSetQueryRepository;
import com.palnet.biz.jpa.repository.flt.FltPlanArcrftRepository;
import com.palnet.biz.jpa.repository.flt.FltPlanAreaCoordRepository;
import com.palnet.biz.jpa.repository.flt.FltPlanAreaRepository;
import com.palnet.biz.jpa.repository.flt.FltPlanBasRepository;
import com.palnet.biz.jpa.repository.flt.FltPlanPilotRepository;
import com.palnet.biz.jpa.repository.flt.*;
import com.palnet.biz.jpa.repository.pty.PtyCstmrQueryRepository;
import com.palnet.biz.jpa.repository.pty.PtyGroupBasRepository;
import com.palnet.biz.jpa.repository.pty.PtyTermsAgreeTxnRepository;
@ -49,13 +30,25 @@ import com.palnet.biz.scheduler.ctr.model.CtrTrnsLctnModel;
import com.palnet.biz.scheduler.ctr.service.CtrTrnsLctnService;
import com.palnet.comn.code.ErrorCode;
import com.palnet.comn.exception.CustomException;
import com.palnet.comn.utils.AirspaceUtils;
import com.palnet.comn.utils.AreaUtils;
import com.palnet.comn.utils.HttpUtils;
import com.palnet.comn.utils.InstantUtils;
import com.palnet.comn.utils.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
/**
* packageName : com.palnet.biz.api.bas.laanc.service
@ -87,6 +80,15 @@ public class BasLaancService {
private final ComnSmsService comnSmsService;
private final JwtTokenUtil jwtTokenUtil;
private final AreaUtils areaUtils;
private final ComRiseSetQueryRepository comRiseSetQueryRepository;
private final ComConfirmBasRepository comConfirmBasRepository;
@Value("${app.host}")
private String APP_HOST;
@Value("${external.ts.return.uri}")
private String TS_RETURN_URI;
// LAANC 검증
public BasLaancValidatedRs validationLaanc(BasLaancPlanRq rq) {
@ -94,63 +96,66 @@ public class BasLaancService {
BasLaancValidatedRs rs = new BasLaancValidatedRs();
// 조종사 자격 확인 - 무게가 2kg 초과이거나 상업적일 경우에만 진행
// 상업 여부 - 상업(true)
boolean isCommercial = FltType.COMMERCIAL == rq.getFltType();
rs.setCommercial(isCommercial);
// 2kg 초과 기체신고번호
List<String> idntfNumList = rq.getArcrftList().stream().filter(arcrft -> arcrft.getArcrftWghtCd() != ArcrftWghtCd.W250G_LOE && arcrft.getArcrftWghtCd() != ArcrftWghtCd.W250G_W2KG).map(BasLaancArcrftModel::getIdntfNum).collect(Collectors.toList());
// 신고 여부 - 비상업적이고 기체중량 2kg이하일 경우 - false, 상업적이거나 기체중량 2kg초과일 경우 - true
boolean isReport = !idntfNumList.isEmpty() || isCommercial;
rs.setReport(isReport);
// 고도 150m 이하 - true
boolean isElev = rq.getAreaList().stream().anyMatch(area -> area.getFltElev() != null && Integer.parseInt(area.getFltElev()) <= 150);
rs.setElev(isElev);
// 기체중량 25kg 이하
boolean isArcrftWeight = rq.getArcrftList().stream().anyMatch(arcrft -> arcrft.getArcrftWghtCd() != ArcrftWghtCd.W25KG_GO && arcrft.getArcrftWghtCd() != ArcrftWghtCd.W25KG_GO_TEST);
rs.setArcrftWeight(isArcrftWeight);
// TODO start - 조종사 자격 및 기체보험 확인
if (isReport) {
List<PilotValidRq> pilotValidRqList = idntfNumList.stream().map(idntfNum -> {
// TS 자격 판별 - 조종사 자격증명, 기체 보험
List<String> idntfNumList = rq.getArcrftList().stream().filter(arcrft -> arcrft.getIdntfNum() != null && !arcrft.getIdntfNum().isBlank()).map(BasLaancArcrftModel::getIdntfNum).collect(Collectors.toList());
Integer cstmrSno = jwtTokenUtil.getCstmrSnoByToken();
AnctCstmrModel cstmrInfo = ptyCstmrQueryRepository.findByCstmrSno(cstmrSno);
String userCi = cstmrInfo.getIpinCi();
List<PilotValidRq> pilotValidRqList = new ArrayList<>();
if (!idntfNumList.isEmpty()) {
pilotValidRqList = idntfNumList.stream().map(idntfNum -> {
// TODO 기체보험 확인, 조종사 자격 확인
return PilotValidRq.builder()
.pilotci("조종사CI")
.pilotci(userCi)
.declarationnum(idntfNum)
.build();
}).collect(Collectors.toList());
} else {
pilotValidRqList.add(PilotValidRq.builder()
.pilotci(userCi)
.build());
}
List<PilotValidRs> pilotValidRsList = tsService.getAccountValidate(pilotValidRqList);
if (pilotValidRsList.isEmpty()) {
rs.setPilotQlfc(false);
rs.setArcrftInsurance(false);
} else {
rs.setPilotValidRsList(pilotValidRsList);
rs.setPilotQlfc(pilotValidRsList.stream().allMatch(pilotValidRs -> "Y".equals(pilotValidRs.getPilotcredentialyn())));
rs.setArcrftInsurance(pilotValidRsList.stream().allMatch(pilotValidRs -> "Y".equals(pilotValidRs.getArcrftinsuranceyn())));
}
List<PilotValidRs> pilotValidRsList = tsService.getAccountValidate(pilotValidRqList);
if (pilotValidRsList.isEmpty()) {
rs.setPilotQlfc(false);
rs.setArcrftInsurance(false);
} else {
rs.setPilotQlfc(pilotValidRsList.stream().allMatch(pilotValidRs -> "Y".equals(pilotValidRs.getPilotcredentialyn())));
rs.setArcrftInsurance(pilotValidRsList.stream().allMatch(pilotValidRs -> "Y".equals(pilotValidRs.getArcrftinsuranceyn())));
}
// TODO end - 조종사 자격 및 기체보험 확인
// 비행유형 판별 - 상업 - true
boolean isCommercial = FltType.COMMERCIAL == rq.getFltType();
rs.setCommercial(isCommercial);
// 관제권 여부 판별
BasLaancValidatedRs validationPlanDbRs = this.validationPlanAirspace(rq);
boolean isEvaluatedTargetArea = validationPlanDbRs.isEvaluatedTargetArea();
rs.setEvaluatedTargetArea(isEvaluatedTargetArea);
/* 비행구역 기체 중복여부 확인 안하기로 .
// 비행구역 중복여부, 기체 중복여부
BasLaancValidatedRs validationPlanAirspaceRs = this.validationPlanAreaAndArcrft(rq);
rs.setPlanAreaDuplicatd(validationPlanAirspaceRs.isPlanAreaDuplicatd());
rs.setArcrftDuplicated(validationPlanAirspaceRs.isArcrftDuplicated());
*/
// 고도여부 - 관제권내 설정고도 이하, 권제권밖 150m 이하 true
if (isEvaluatedTargetArea) {
// 관제권 내부 - 설정고도 이하
rs.setElev(validationPlanDbRs.isElev());
} else {
// 관제권 외부 - 150m 이하
boolean isElev = rq.getAreaList().stream().allMatch(area -> area.getFltElev() != null && Integer.parseInt(area.getFltElev()) <= 150);
rs.setElev(isElev);
}
// 기체중량 판별 - 25kg 이하 true
boolean isArcrftWeight = rq.getArcrftList().stream().allMatch(arcrft -> arcrft.getArcrftWghtCd() != ArcrftWghtCd.W25KG_GO && arcrft.getArcrftWghtCd() != ArcrftWghtCd.W25KG_GO_TEST);
rs.setArcrftWeight(isArcrftWeight);
// 판단구역 - 공역과 겹칠 경우, 비행가능여부
BasLaancValidatedRs validationPlanDbRs = this.validationPlanAirspace(rq);
rs.setEvaluatedTargetArea(validationPlanDbRs.isEvaluatedTargetArea());
rs.setFlightArea(validationPlanDbRs.isFlightArea());
// 특별비행여부 판별 - 야간/주간 - 야간 true
boolean isSpcialFlight = this.validationPlanSpecialFlight(rq);
rs.setSpacialFlight(isSpcialFlight);
// 비행방식 - 군집비행 false, 그외 true
boolean isFltMethod = rq.getAreaList().stream().allMatch(area -> FltMethod.CLUSTER_FLIGHT != area.getFltMethod());
rs.setFltMethod(isFltMethod);
return rs;
@ -208,7 +213,7 @@ public class BasLaancService {
corpRegYn = isCorpReg ? "Y" : "N";
}
fltPlanBas.setCorpRegYn(corpRegYn); // 사업자유무
fltPlanBas.setServiceType("PAV-KAC");
fltPlanBas.setServiceType("F0002");
FltPlanBas rBasEntity = fltPlanBasRepository.save(fltPlanBas);
Integer planSno = rBasEntity.getPlanSno();
@ -369,113 +374,13 @@ public class BasLaancService {
return rs;
}
// LAANC 검증
/*
private BasLaancValidatedRs validationPlanAreaAndArcrft(BasLaancPlanRq rq) {
// 초기화
BasLaancValidatedRs rs = BasLaancValidatedRs.builder()
.isPlanAreaDuplicatd(false) // 비행구역 중복여부
.isArcrftDuplicated(false) // 기체 중복여부
.build();
// 비행계획서
List<FltPlanBas> fltPlanBasList = fltPlanBasRepository.findBySchFltStDtLessThanEqualAndSchFltEndDtGreaterThanEqualAndAprvlYnAndDelYn(rq.getSchFltEndDt(), rq.getSchFltStDt(), "Y", "N");
if (fltPlanBasList != null && !fltPlanBasList.isEmpty()) {
if (rq.getPlanSno() != null) {
// 동일한 비행계획서는 검증에서 제외 처리
fltPlanBasList = fltPlanBasList.stream().filter(fltPlanBas -> !rq.getPlanSno().equals(fltPlanBas.getPlanSno())).collect(Collectors.toList());
}
// 비행계획서 planSno 모음
List<Integer> planSnoList = fltPlanBasList.stream().map(FltPlanBas::getPlanSno).collect(Collectors.toList());
// 지역
// List<FltPlanArea> fltPlanAreaList = fltPlanAreaRepository.findByPlanSnoIn(planSnoList);
for (FltPlanBas fltPlanBas : fltPlanBasList) {
// 1. 구역조회
List<FltPlanArea> fltPlanAreaList = fltPlanAreaRepository.findByPlanSnoOrderByPlanAreaSnoAsc(fltPlanBas.getPlanSno());
// 2. 좌표 조회 -> 영역 포함 여부 확인
for (FltPlanArea fltPlanArea : fltPlanAreaList) {
String effectiveFltElev = fltPlanArea.getFltElev();
List<FltPlanAreaCoord> fltPlanAreaCoordList = fltPlanAreaCoordRepository.findByPlanAreaSnoOrderByPlanAreaCoordSnoAsc(fltPlanArea.getPlanAreaSno());
if (fltPlanAreaCoordList == null || fltPlanAreaCoordList.isEmpty()) continue;
// 2-1 영역 좌표
List<Coordinate> effectiveCoordList = fltPlanAreaCoordList.stream().map(fltPlanAreaCoord -> new Coordinate(fltPlanAreaCoord.getLon(), fltPlanAreaCoord.getLat())).collect(Collectors.toList());
List<Coordinate> effectiveCoordBufferList = new ArrayList<>();
// Query에서 조회한 좌표로 버퍼좌표 생성
if ("LINE".equals(fltPlanArea.getAreaType())) {
List<Coordinate> trans = areaUtils.transform(effectiveCoordList, "EPSG:4326", "EPSG:5181");
List<Coordinate> bufferList = areaUtils.buffer(trans, fltPlanArea.getBufferZone());
effectiveCoordBufferList = areaUtils.transform(bufferList, "EPSG:5181", "EPSG:4326");
}
if ("POLYGON".equals(fltPlanArea.getAreaType())) {
effectiveCoordBufferList.addAll(effectiveCoordList);
}
if ("CIRCLE".equals(fltPlanArea.getAreaType())) {
effectiveCoordBufferList = areaUtils.createCircle(effectiveCoordList.get(0), fltPlanArea.getBufferZone());
}
for (BasLaancAreaModel basLaancAreaModel : rq.getAreaList()) {
String targetFltElev = basLaancAreaModel.getFltElev();
// TODO 추후 특정 고도 범위 확인
boolean isEqualsFltElev = effectiveFltElev.equals(targetFltElev);
// rq로 들어온 좌표로 버퍼좌표 생성
List<Coordinate> targetCoords = basLaancAreaModel.getCoordList().stream().map(coord -> new Coordinate(coord.getLon(), coord.getLat())).collect(Collectors.toList());
List<Coordinate> targetBufferCoords = new ArrayList<>();
if ("LINE".equals(basLaancAreaModel.getAreaType())) {
List<Coordinate> trans = areaUtils.transform(targetCoords, "EPSG:4326", "EPSG:5181");
List<Coordinate> bufferList = areaUtils.buffer(trans, fltPlanArea.getBufferZone());
targetBufferCoords = areaUtils.transform(bufferList, "EPSG:5181", "EPSG:4326");
} else if ("POLYGON".equals(basLaancAreaModel.getAreaType())) {
targetBufferCoords.addAll(targetCoords);
} else if ("CIRCLE".equals(basLaancAreaModel.getAreaType())) {
targetBufferCoords = areaUtils.createCircle(targetCoords.get(0), fltPlanArea.getBufferZone());
}
// 검증
Geometry targetGeometry = areaUtils.coordinateToGeometry(targetBufferCoords);
Geometry effectiveGeometry = areaUtils.coordinateToGeometry(effectiveCoordBufferList);
if (targetGeometry.intersects(effectiveGeometry) && isEqualsFltElev) {
rs.setPlanAreaDuplicatd(true);
}
}
}
}
// 기체 중복 여부 확인
List<BasLaancArcrftModel> arcrftList = rq.getArcrftList();
if (arcrftList != null && !arcrftList.isEmpty()) {
List<FltPlanArcrft> fltPlanArcrftList = fltPlanArcrftRepository.findByPlanSnoIn(planSnoList);
if (fltPlanArcrftList != null && !fltPlanArcrftList.isEmpty()) {
boolean isDuplicatedArcrft = arcrftList.stream().anyMatch(arcrft ->
fltPlanArcrftList.stream().anyMatch(fltPlanArcrft ->
arcrft.getIdntfNum().equals(fltPlanArcrft.getIdntfNum())
)
);
if (isDuplicatedArcrft) {
rs.setArcrftDuplicated(true);
}
}
}
}
return rs;
}
*/
private BasLaancValidatedRs validationPlanAirspace(BasLaancPlanRq rq) {
// 초기화
BasLaancValidatedRs rs = BasLaancValidatedRs.builder()
.isEvaluatedTargetArea(false) // 판단구역 - 공역과 겹칠 경우
.isFlightArea(false) // 비행가능여부
.isElev(false) // 비행가능여부
.build();
// 공역 중복 확인
@ -507,17 +412,9 @@ public class BasLaancService {
boolean duplicatedAirspace = airspaceUtils.isDuplicatedAirspace(featureInfo);
rs.setEvaluatedTargetArea(duplicatedAirspace);
// 비행 가능 지역 판단
// if (duplicatedAirspace) {
// boolean validLaancAirspace = airspaceUtils.isValidLaancAirspace(featureInfo);
// rs.setFlightAreaYn(validLaancAirspace ? "Y" : "N");
// } else {
// rs.setFlightAreaYn("N");
// }
// 비행 가능 지역 판단
boolean validLaancAirspace = airspaceUtils.isValidLaancAirspace(featureInfo);
rs.setFlightArea(validLaancAirspace);
rs.setElev(validLaancAirspace);
}
return rs;
@ -571,6 +468,29 @@ public class BasLaancService {
return true;
}
private boolean validationPlanSpecialFlight(BasLaancPlanRq rq) {
String[] stringStDt = InstantUtils.toDatetimeString(rq.getSchFltStDt()).split(" ");
String[] stringEndDt = InstantUtils.toDatetimeString(rq.getSchFltEndDt()).split(" ");
ComnSunrisesetCoordRq comnSunrisesetCoordRq = new ComnSunrisesetCoordRq(stringStDt[0].replace("-", ""), stringEndDt[0].replace("-", ""), null, null);
ComnSunrisesetRs comnSunrisesetRs = comRiseSetQueryRepository.findBySearchCoordDateTransform(comnSunrisesetCoordRq);
LocalTime sunUp = this.convertStringToTime(comnSunrisesetRs.getCivilm(), "HHmmss");
LocalTime sunDown = this.convertStringToTime(comnSunrisesetRs.getCivile(), "HHmmss");
LocalTime stringStTm = this.convertStringToTime(stringStDt[1].replace(":", ""), "HHmmss");
LocalTime stringEndTm = this.convertStringToTime(stringEndDt[1].replace(":", ""), "HHmmss");
boolean stTmValid = this.isBetweenSunriseAndSunset(sunUp, sunDown, stringStTm);
boolean endTmValid = this.isBetweenSunriseAndSunset(sunUp, sunDown, stringEndTm);
if (!stTmValid || !endTmValid) return false;
return true;
}
/**
* String to LocalTime - Instant는 시간정보만 담을 없음..
*
@ -689,4 +609,108 @@ public class BasLaancService {
return rs;
}
// QR code 생성
public BasLaancQrcodeRs createQrcode(BasLaancQrcodeRq rq) {
Integer cstmrSno = jwtTokenUtil.getCstmrSnoByToken();
String userId = jwtTokenUtil.getUserIdByToken();
AnctCstmrModel cstmrInfo = ptyCstmrQueryRepository.findByCstmrSno(cstmrSno);
String userCi = cstmrInfo.getIpinCi();
String idntfNum = null;
if (rq != null && rq.getIdntfNum() != null && !rq.getIdntfNum().isEmpty()) {
idntfNum = rq.getIdntfNum();
}
String confirmKey = UUID.randomUUID().toString();
String jsonParams = null;
byte[] qr = null;
try {
TsQrcodeRq tsRq = TsQrcodeRq.builder()
.rtnUrl(APP_HOST + TS_RETURN_URI)
.reqId(confirmKey)
.submittype(idntfNum)
.applyUser(userCi)
.build();
jsonParams = JsonUtils.toJson(tsRq);
qr = tsService.createQrcode(jsonParams);
} catch (WriterException | IOException e) {
log.error("ERROR: ", e);
throw new CustomException(ErrorCode.FAIL, "QR코드 생성 실패");
}
// db 저장 - confirmKey(uuid)
ComConfirmBas comConfirmBas = ComConfirmBas.builder()
.confirmKey(confirmKey)
.status("GENERATED")
.targetType("TS_QRCODE")
.rqData(jsonParams)
.createUserId(userId)
.updateUserId(userId)
.build();
comConfirmBasRepository.save(comConfirmBas);
return BasLaancQrcodeRs.builder()
.qrcode(qr)
.confirmKey(confirmKey)
.build();
}
// QR code 확인
public PilotValidRs checkQrcode(String confirmKey) {
String userIdByToken = jwtTokenUtil.getUserIdByToken();
ComConfirmBas entity = comConfirmBasRepository.findFirstByConfirmKeyOrderByCreateDtDesc(confirmKey);
if(entity == null) throw new CustomException(ErrorCode.DATA_NOTFIND, "QR코드 조회 실패");
if (!"RECEIVED".equals(entity.getStatus())){
Map<String, String> errorParam = new HashMap<>();
errorParam.put("status", entity.getStatus());
throw new CustomException(ErrorCode.DATA_NOTFIND, errorParam);
}
// TODO 일자 검증 - 3분 초과
Instant createDt = entity.getCreateDt().plus(3, ChronoUnit.MINUTES);
boolean flag = !createDt.isAfter(Instant.now());
if (!flag) {
entity.setStatus("EXPIRED");
entity.setUpdateUserId(userIdByToken);
comConfirmBasRepository.save(entity);
comConfirmBasRepository.flush();
throw new CustomException(ErrorCode.FAIL, "QR 기간 만료");
}
PilotValidRs rs = null;
String rsData = entity.getRsData();
if(rsData != null && !rsData.isEmpty()){
rs = JsonUtils.fromJson(rsData, PilotValidRs.class);
}
return rs;
}
// TS 비행계획서
public void createPlanDos(TsPlanRq tsPlanRq) {
// convert
BasLaancPlanRq rq = tsPlanRq.toBasLaancPlanRq();
// 기존 로직대로 수행
BasLaancValidatedRs basLaancValidatedRs = this.validationLaanc(rq);
if (!basLaancValidatedRs.isValid()) {
log.info("ts dron one stop validation fail : {}", basLaancValidatedRs);
return;
}
try {
BasLaancLastRs flightPlan = this.createFlightPlan(rq);
} catch (Exception e) {
log.error("ts dron one stop create flight plan fail", e);
}
}
}

30
pav-server/src/main/java/com/palnet/biz/api/ctr/cntrl/service/SocketReceiverService.java

@ -62,27 +62,41 @@ public class SocketReceiverService {
ComIdntfBas idntfBas = idntBasRepository.findById(model.getObjectId()).orElse(null);
// 1-1. 식별 번호의 모델 정보 조회
ComArcrftBas arcrftBas = arcrftBasRepository.findById(idntfBas.getArcrftSno()).orElse(null);
// PAV-KAC에서는 기초데이터가 필수가 아니여서 idntBas가 null일 수 있음.
ComArcrftBas arcrftBas = null;
if (idntfBas != null && idntfBas.getArcrftSno() > 0) {
arcrftBas = arcrftBasRepository.findById(idntfBas.getArcrftSno()).orElse(null);
}
if(ctrCntrlBas != null) {
if (ctrCntrlBas.getCntrlId() != null && !ctrCntrlBas.getCntrlId().isEmpty())
fltPlanCtrCntrlRel.setCntrlId(ctrCntrlBas.getCntrlId());
if (ctrCntrlBas.getIdntfNum() != null && !ctrCntrlBas.getIdntfNum().isEmpty())
fltPlanCtrCntrlRel.setIdntfNum(ctrCntrlBas.getIdntfNum());
}
if (idntfBas != null && arcrftBas != null) {
fltPlanCtrCntrlRel.setCntrlId(ctrCntrlBas.getCntrlId());
fltPlanCtrCntrlRel.setIdntfNum(ctrCntrlBas.getIdntfNum());
if (idntfBas != null && idntfBas.getCstmrSno() != null) {
fltPlanCtrCntrlRel.setIdntfCstmrSno(idntfBas.getCstmrSno());
}
if (arcrftBas != null && arcrftBas.getGroupId() != null && !arcrftBas.getGroupId().isEmpty()){
fltPlanCtrCntrlRel.setGroupId(arcrftBas.getGroupId());
}
// 2. 해당 되는 비행계획서 정보 저장.
List<FltPlanBas> planArcrft =
fltPlanQueryRepository.findByFlightPlanArcrft(ctrCntrlBas.getIdntfNum(), dbModel.getServerRcvDt());
List<FltPlanBas> planArcrft = null;
if (ctrCntrlBas != null && ctrCntrlBas.getCntrlId() != null && !ctrCntrlBas.getCntrlId().isEmpty()){
planArcrft = fltPlanQueryRepository.findByFlightPlanArcrft(ctrCntrlBas.getIdntfNum(), dbModel.getServerRcvDt());
}
if (!planArcrft.isEmpty()) {
if (planArcrft != null && !planArcrft.isEmpty()) {
for (FltPlanBas plan : planArcrft) {
fltPlanCtrCntrlRel.setPlanSno(plan.getPlanSno());
}
}
// 3. mapping 정보 주입.
if (!fltPlanCtrCntrlRel.getCntrlId().isEmpty()) {
if (fltPlanCtrCntrlRel.getCntrlId() != null && !fltPlanCtrCntrlRel.getCntrlId().isEmpty() && fltPlanCtrCntrlRel.getPlanSno() != null) {
ctrCntrlRelRepository.save(fltPlanCtrCntrlRel);
}
}

130
pav-server/src/main/java/com/palnet/biz/api/external/controller/ExternalLaancController.java vendored

@ -0,0 +1,130 @@
package com.palnet.biz.api.external.controller;
import com.palnet.biz.api.bas.laanc.service.BasLaancService;
import com.palnet.biz.api.external.model.TsPlanRq;
import com.palnet.biz.api.external.model.TsQrcodeRs;
import com.palnet.biz.api.external.service.TsService;
import com.palnet.comn.code.ErrorCode;
import com.palnet.comn.exception.CustomException;
import com.palnet.comn.utils.JsonUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
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;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/api/external/laanc")
@RestController
public class ExternalLaancController {
private final TsService tsService;
private final BasLaancService basLaancService;
/*
error code
200 - 정상적으로 수신되었습니다.
300 - 메시지 규격이 다릅니다. - Json 포멧이 틀린 경우
301 - 필수 항목이 누락되었습니다. - 필수 항목이 누락된 경우
302 - 메시지 타입이 맞지 않습니다. - 메시지내 파라미터의 타입이 잘못된 경우
500 - 서버 연결이 되지 않습니다. - call측 network exception 처리
501 - 네트워크 연결이 지연 됩니다. - call측 network exception 처리
600 - 인증키가 유효하지 않습니다.
700 - 기타 오류 - 정의된 내용이 아닌 기타 오류인 경우
*/
// TS로 부터 비행 신청 정보 - endpoint
@PostMapping("/plan/dos")
public ResponseEntity<?> createTsFltPlan(@RequestBody String body) {
log.info(">>>> /plan/ost body: {}", body);
TsPlanRq tsPlanRq;
try {
tsPlanRq = JsonUtils.fromJson(body, TsPlanRq.class);
} catch (Exception e) {
ErrorCode errorCode = ErrorCode.TS_PARAM;
Map<String, String> error = new HashMap<>();
error.put("rspCode", "300");
error.put("rspMessage", errorCode.message());
return ResponseEntity.status(300).body(error);
}
try {
basLaancService.createPlanDos(tsPlanRq);
} catch (CustomException e) {
log.error("IGNORE: ", e);
ErrorCode errorCode = ErrorCode.fromCode(e.getErrorCode());
if (errorCode == null) errorCode = ErrorCode.TS_ETC;
String tsErrorCode = errorCode.code().replaceAll("TS", "");
Map<String, String> error = new HashMap<>();
error.put("rspCode", tsErrorCode);
error.put("rspMessage", errorCode.message());
return ResponseEntity.status(Integer.parseInt(tsErrorCode)).body(error);
} catch (Exception e) {
log.error("IGNORE: ", e);
Map<String, String> error = new HashMap<>();
error.put("rspCode", ErrorCode.TS_ETC.code());
error.put("rspMessage", ErrorCode.TS_ETC.message());
return ResponseEntity.status(700).body(error);
}
Map<String, String> successRs = new HashMap<>();
successRs.put("rspCode", ErrorCode.TS_SUCCESS.code().replaceAll("TS", ""));
successRs.put("rspMessage", ErrorCode.TS_SUCCESS.message());
return ResponseEntity.ok().body(successRs);
}
// TS VC 유효성 검토 callback url - endpoint
@PostMapping("/vc/callback")
public ResponseEntity<?> vcCallback(@RequestBody String body) {
log.info(">>>> vc/callback body: {}", body);
TsQrcodeRs rs;
try {
rs = JsonUtils.fromJson(body, TsQrcodeRs.class);
} catch (Exception e) {
ErrorCode errorCode = ErrorCode.TS_PARAM;
Map<String, String> error = new HashMap<>();
error.put("rspCode", "300");
error.put("rspMessage", errorCode.message());
return ResponseEntity.status(300).body(error);
}
try {
tsService.vcCallback(rs);
} catch (CustomException e) {
log.error("IGNORE: ", e);
ErrorCode errorCode = ErrorCode.fromCode(e.getErrorCode());
if (errorCode == null) errorCode = ErrorCode.TS_ETC;
String tsErrorCode = errorCode.code().replaceAll("TS", "");
Map<String, String> error = new HashMap<>();
error.put("rspCode", tsErrorCode);
error.put("rspMessage", errorCode.message());
return ResponseEntity.status(Integer.parseInt(tsErrorCode)).body(error);
} catch (Exception e) {
log.error("IGNORE: ", e);
Map<String, String> error = new HashMap<>();
error.put("rspCode", ErrorCode.TS_ETC.code().replaceAll("TS", ""));
error.put("rspMessage", ErrorCode.TS_ETC.message());
return ResponseEntity.status(700).body(error);
}
Map<String, String> successRs = new HashMap<>();
successRs.put("rspCode", ErrorCode.TS_SUCCESS.code().replaceAll("TS", ""));
successRs.put("rspMessage", ErrorCode.TS_SUCCESS.message());
return ResponseEntity.ok().body(successRs);
}
}

102
pav-server/src/main/java/com/palnet/biz/api/external/model/TsPlanRq.java vendored

@ -0,0 +1,102 @@
package com.palnet.biz.api.external.model;
import com.palnet.biz.api.bas.laanc.model.BasLaancPlanRq;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class TsPlanRq {
private List<TsFlightapprovalInfo> flightapprovalInfo;
private List<TsArcrftInfo> arcrftInfo;
private List<TsBusinessinfo> businessinfo;
private List<TsFlightInfo> flightInfo;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class TsFlightapprovalInfo {
private List<Operatorinfo> operatorinfo;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Operatorinfo {
private String pilotname;
private String pilotcredentialno;
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class TsArcrftInfo {
private String arcrfttype;
private String declarationnum;
private String arcrftmodelnm;
private String prdctcmpnnm;
private String prdctnum;
private String arcrftlwh;
private String arcrftwght;
private String ownernm;
private String corporationnm;
private String insrncyn;
private String arcrftinsuranceyn;
private String insuranceexperiod;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class TsBusinessinfo {
private String corpregyn;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class TsFlightInfo {
private String fltareacnt;
private String fltmethod;
private String pltstdt;
private String pltenddt;
private String pltpurpose;
private List<TsAreaInfo> areaInfo;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class TsAreaInfo {
private String addr;
private String coord;
private String elev;
private String radius;
}
}
// Laanc RQ로 변형
public BasLaancPlanRq toBasLaancPlanRq() {
BasLaancPlanRq rq = new BasLaancPlanRq();
return rq;
}
}

28
pav-server/src/main/java/com/palnet/biz/api/external/model/TsQrcodeRq.java vendored

@ -0,0 +1,28 @@
package com.palnet.biz.api.external.model;
import lombok.Builder;
import lombok.Data;
@Data
public class TsQrcodeRq {
private String type; // 5 (한국공항공사) - 고정
private String rtnUrl; // 리턴 url - 고정
private String reqId; // 추적 코드
private String submittype; // 기체신고번호
private String applyUser; // 사용자 인증 코드 ci
public TsQrcodeRq() {
this.type = "5";
this.rtnUrl = "";
}
@Builder
public TsQrcodeRq(String rtnUrl, String reqId, String submittype, String applyUser) {
this.type = "5";
this.rtnUrl = rtnUrl;
this.reqId = reqId;
this.submittype = submittype;
this.applyUser = applyUser;
}
}

31
pav-server/src/main/java/com/palnet/biz/api/external/model/TsQrcodeRs.java vendored

@ -0,0 +1,31 @@
package com.palnet.biz.api.external.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* packageName : com.palnet.biz.api.external.model
* fileName : PilotValidRq
* author : dhji
* date : 2023-09-21(021)
* description :
* ===========================================================
* DATE AUTHOR NOTE
* -----------------------------------------------------------
* 2023-09-21(021) dhji 최초 생성
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TsQrcodeRs {
private String rspCode; // 결과코드
private String rspMessage; // 결과메시지
private String rqID; // 요청ID-UUID
private String pilotcredentialyn; // 조종사자격증명여부
private String arcrftinsuranceyn; // 기체보험가입여부
private String arcrftdeclaration; // 기체신고여부
private String corpregyn; // 사업자유무
}

63
pav-server/src/main/java/com/palnet/biz/api/external/service/TsService.java vendored

@ -1,7 +1,22 @@
package com.palnet.biz.api.external.service;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.palnet.biz.api.bas.laanc.model.BasLaancLastRs;
import com.palnet.biz.api.bas.laanc.model.BasLaancPlanRq;
import com.palnet.biz.api.bas.laanc.model.BasLaancValidatedRs;
import com.palnet.biz.api.bas.laanc.service.BasLaancService;
import com.palnet.biz.api.external.model.PilotValidRq;
import com.palnet.biz.api.external.model.PilotValidRs;
import com.palnet.biz.api.external.model.TsPlanRq;
import com.palnet.biz.api.external.model.TsQrcodeRs;
import com.palnet.biz.jpa.entity.ComConfirmBas;
import com.palnet.biz.jpa.repository.com.ComConfirmBasRepository;
import com.palnet.comn.utils.JsonUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
@ -15,6 +30,10 @@ import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@ -39,7 +58,10 @@ public class TsService {
private String TS_HOST;
private final String ACCOUNT_VALIDATE_URI = "/api/account/getValidate";
private final ComConfirmBasRepository comConfirmBasRepository;
// 이전 TS 연동
public List<PilotValidRs> getAccountValidate(List<PilotValidRq> rqList) {
List<PilotValidRs> rsList = new ArrayList<>();
@ -58,6 +80,7 @@ public class TsService {
}
// 이전 TS 연동
public PilotValidRs callAccountValidate(PilotValidRq rq) {
String pilotciEnc = UriUtils.encode(rq.getPilotci(), StandardCharsets.UTF_8);
@ -87,7 +110,7 @@ public class TsService {
log.error("TS API 호출 중 오류가 발생하였습니다. {}", e.getMessage());
String erroCode = "500";
String errorMessage = "TS API error";
if(e instanceof WebClientResponseException){
if (e instanceof WebClientResponseException) {
WebClientResponseException wcre = (WebClientResponseException) e;
erroCode = String.valueOf(wcre.getRawStatusCode());
errorMessage = wcre.getStatusText();
@ -110,4 +133,42 @@ public class TsService {
return rs;
}
// QR 코드 생성
public byte[] createQrcode(String params) throws WriterException, IOException {
// 바코드 색상 값
// int qrcodeColor = 0xFF2e4e96;
int qrcodeColor = 0xFF000000;
// 배경 색상 값
int backgroundColor = 0xFFFFFFFF;
QRCodeWriter qrCodeWriter = new QRCodeWriter();
// 300x300
BitMatrix bitMatrix = qrCodeWriter.encode(params, BarcodeFormat.QR_CODE, 300, 300);
MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(qrcodeColor, backgroundColor);
BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix, matrixToImageConfig);
// ImageIO를 사용한 바코드 파일쓰기
// boolean png = ImageIO.write(bufferedImage, "png", new File("stoneQR2.png"));
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "png", outputStream);
return outputStream.toByteArray();
}
// QR return url
public void vcCallback(TsQrcodeRs rs) {
String rspCode = rs.getRspCode();
ComConfirmBas entity = comConfirmBasRepository.findFirstByConfirmKey(rs.getRqID());
if (entity != null) {
String rsJsonStr = JsonUtils.toJson(rs);
entity.setRsData(rsJsonStr);
entity.setStatus(("200".equals(rspCode)) ? "RECEIVED" : "FAILED");
comConfirmBasRepository.save(entity);
}
}
}

18
pav-server/src/main/java/com/palnet/biz/api/main/dash/controller/MainDashController.java

@ -43,7 +43,7 @@ public class MainDashController {
* @return
*/
@GetMapping(value = "/stcs/day")
@ApiOperation(value = "일 별 비행수 통계")
@ApiOperation(value = "일 별 비행수 통계")
@Tag(name = "메인화면 컨트롤러", description = "메인화면 관련 API")
@ApiImplicitParam(name = "yyyymm",value = "날짜", dataTypeClass = String.class)
public ResponseEntity<? extends BasicResponse> stcsDay(String yyyymm) {
@ -83,8 +83,6 @@ public class MainDashController {
public ResponseEntity<? extends BasicResponse> stcsArea(String yyyymm) {
List<MainDashStcsModel> result = null;
// log.debug(yyyymm);
if(yyyymm == null || !(yyyymm.length() == 7) ) {
return ResponseEntity.status(HttpStatus.OK)
.body(new ErrorResponse(RSErrorCode.ER_PARAM));
@ -340,14 +338,14 @@ public class MainDashController {
@ApiOperation(value = "일일 비정상상황 통계")
@Tag(name = "메인화면 컨트롤러", description = "메인화면 관련 API")
@ApiImplicitParams({
@ApiImplicitParam(name = "groupId",value = "그룹아이디", dataTypeClass = String.class)
@ApiImplicitParam(name = "serviceType",value = "관할기관코드(cptAuthCode)", dataTypeClass = String.class)
})
public ResponseEntity<? extends BasicResponse> currentFlightWarn(@RequestParam(required = false) String groupId){
public ResponseEntity<? extends BasicResponse> currentFlightWarn(@RequestParam(required = false) String serviceType){
List<MainDashWarnNumStcsModel> result = new ArrayList<>();
try {
result = service.currentFlightWarn(groupId);
result = service.currentFlightWarn(serviceType);
}catch (Exception e) {
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
@ -361,13 +359,13 @@ public class MainDashController {
@ApiOperation(value = "일일 비행계획 통계")
@Tag(name = "메인화면 컨트롤러", description = "메인화면 관련 API")
@ApiImplicitParams({
@ApiImplicitParam(name = "groupId",value = "그룹아이디", dataTypeClass = String.class)
@ApiImplicitParam(name = "serviceType",value = "관할기관코드(cptAuthCode)", dataTypeClass = String.class)
})
public ResponseEntity<? extends BasicResponse> currentFlightPlan(@RequestParam(required = false) String groupId){
public ResponseEntity<? extends BasicResponse> currentFlightPlan(@RequestParam(required = false) String serviceType){
List<MainDashPlanNumStcsModel> result = new ArrayList<>();
try {
result = service.currentFlightPlan(groupId);
result = service.currentFlightPlan(serviceType);
} catch (Exception e){
log.error("IGNORE : {}", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
@ -381,7 +379,7 @@ public class MainDashController {
@GetMapping("/stcs/dailyflight")
@ApiOperation(value = "일일 비행수 현황")
@ApiOperation(value = "일일 비행수 현황")
@Tag(name = "메인화면 컨트롤러",description = "메인화면 관련 API")
public ResponseEntity<? extends BasicResponse> getDailyFlightNumOfStcs(){
List<MainDashFlightNumStcsModel> result = null;

266
pav-server/src/main/java/com/palnet/biz/api/main/dash/service/MainDashService.java

@ -1,78 +1,69 @@
package com.palnet.biz.api.main.dash.service;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import com.palnet.biz.api.acnt.jwt.model.JwtGroupModel;
import com.palnet.biz.api.acnt.jwt.utils.JwtTokenUtil;
import com.palnet.biz.api.bas.group.model.BasGroupModel;
import com.palnet.biz.api.main.dash.model.*;
import com.palnet.biz.api.main.statistics.service.MainStatisticsService;
import com.palnet.biz.jpa.entity.CtrCntrlWarnLog;
import com.palnet.biz.jpa.entity.FltPlanBas;
import com.palnet.biz.jpa.entity.type.WarnType;
import com.palnet.biz.jpa.repository.ctr.CtrCntrlQueryRepository;
import com.palnet.biz.jpa.repository.ctr.CtrCntrlWarnLogQueryRepository;
import com.palnet.biz.jpa.repository.flt.FltPlanArcrftRepository;
import com.palnet.biz.jpa.repository.flt.FltPlanBasRepository;
import com.palnet.biz.jpa.repository.pty.*;
import com.palnet.biz.jpa.repository.flt.FltPlanQueryRepository;
import com.palnet.biz.jpa.repository.pty.PtyDronQueryRepository;
import com.palnet.biz.jpa.repository.pty.PtyGroupQueryRepository;
import com.palnet.comn.code.ErrorCode;
import com.palnet.comn.exception.CustomException;
import com.querydsl.core.Tuple;
import com.querydsl.core.BooleanBuilder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.palnet.biz.jpa.entity.CtrCntrlWarnLog;
import com.palnet.biz.jpa.entity.type.WarnType;
import com.palnet.biz.jpa.repository.ctr.CtrCntrlQueryRepository;
import com.palnet.biz.jpa.repository.ctr.CtrCntrlWarnLogQueryRepository;
import com.palnet.biz.jpa.repository.flt.FltPlanArcrftRepository;
import com.palnet.biz.jpa.repository.flt.FltPlanQueryRepository;
import java.time.Instant;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@Slf4j
@Service
@RequiredArgsConstructor
public class MainDashService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private PtyDronQueryRepository ptyDronQueryRepository;
@Autowired
private PtyGroupQueryRepository ptyGroupQueryRepository;
@Autowired
private FltPlanQueryRepository fltPlanQueryRepository;
@Autowired
private CtrCntrlWarnLogQueryRepository ctrCntrlWarnLogQueryRepository;
@Autowired
private CtrCntrlQueryRepository query;
@Autowired
private MainStatisticsService mainStatisticsService;
@Autowired
private FltPlanArcrftRepository fltPlanArcrftRepository;
@Autowired
private FltPlanBasRepository fltPlanBasRepository;
@Autowired
private JwtTokenUtil token;
private final PtyDronQueryRepository ptyDronQueryRepository;
private final PtyGroupQueryRepository ptyGroupQueryRepository;
private final FltPlanQueryRepository fltPlanQueryRepository;
private final CtrCntrlWarnLogQueryRepository ctrCntrlWarnLogQueryRepository;
private final CtrCntrlQueryRepository query;
private final MainStatisticsService mainStatisticsService;
private final FltPlanArcrftRepository fltPlanArcrftRepository;
private final FltPlanBasRepository fltPlanBasRepository;
private final JwtTokenUtil token;
/**
* 일별 비행 통계
* 일별 비행건수 통계
* @param rq
* @return
*/
public List<MainDashStcsModel> mainDashStcsDay(String yyyymm){
List<MainDashStcsModel> resultList = query.mainDashStcsDay(yyyymm);
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String serviceType = "";
String userAuthByToken = token.getUserAuthByToken();
String cptAuthCodeByToken = token.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
serviceType = cptAuthCodeByToken;
}
List<MainDashStcsModel> resultList = query.mainDashStcsDay(yyyymm, serviceType);
return resultList;
}
@ -83,10 +74,17 @@ public class MainDashService {
* @return
*/
public List<MainDashStcsModel> mainDashStcsArea(String yyyymm){
List<MainDashStcsModel> resultList = query.mainDashStcsArea(yyyymm);
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String serviceType = "";
String userAuthByToken = token.getUserAuthByToken();
String cptAuthCodeByToken = token.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
serviceType = cptAuthCodeByToken;
}
List<MainDashStcsModel> resultList = query.mainDashStcsArea(yyyymm, serviceType);
return resultList;
}
@ -108,9 +106,9 @@ public class MainDashService {
}
resultList = resultList.stream().sorted((o2, o1) -> o1.get("createDt").toString().compareTo(o2.get("createDt").toString())).collect(Collectors.toList());
return resultList;
}
@ -158,16 +156,24 @@ public class MainDashService {
public Map<String, String> mainDashDronFlightStcs() throws Exception{
String cptAuth = token.getCptAuthCodeByToken();
String cptAuth = "";
cptAuth = "KAC"; // 임시 테스트용으로 KAC 권한 부여
// cptAuth = "KAC"; // 임시 테스트용으로 KAC 권한 부여
if(cptAuth == null) {
log.error("cptAuth가 부여되지 않은 계정입니다");
throw new Exception();
// if(cptAuth == null) {
//
// log.error("cptAuth가 부여되지 않은 계정입니다");
// throw new Exception();
//
// }
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String userAuthByToken = token.getUserAuthByToken();
String cptAuthCodeByToken = token.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
cptAuth = cptAuthCodeByToken;
}
Map<String, String> resultList = new HashMap<>();
@ -284,16 +290,23 @@ public class MainDashService {
public List<MainDashPlanNumStcsModel> currentFlightPlan(String groupId){
public List<MainDashPlanNumStcsModel> currentFlightPlan(String serviceType){
// boolean authCheck = mainStatisticsService.authCheck(groupId);
boolean authCheck = mainStatisticsService.authCheck(groupId);
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String userAuthByToken = token.getUserAuthByToken();
String cptAuthCodeByToken = token.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
serviceType = cptAuthCodeByToken;
}
String[] dateCate = {"beforeYesterday", "yesterday", "today", "tomorrow"}; // 2일전, 전일, 금일, 명일
List<MainDashPlanNumStcsModel> result = new ArrayList<>();
for(String cate : dateCate){
List<FltPlanBas> fltPlanBas = fltPlanQueryRepository.currentFlightStcs(groupId, authCheck, cate);
List<FltPlanBas> fltPlanBas = fltPlanQueryRepository.currentFlightStcs(serviceType, cate);
int plan = fltPlanBas.size();
int aprvnCount = (int)fltPlanBas.stream().filter(value -> value.getAprvlYn().equals("Y")).count();
@ -331,16 +344,22 @@ public class MainDashService {
public List<MainDashWarnNumStcsModel> currentFlightWarn(String groupId){
boolean authCheck = mainStatisticsService.authCheck(groupId);
public List<MainDashWarnNumStcsModel> currentFlightWarn(String serviceType){
// boolean authCheck = mainStatisticsService.authCheck(groupId);
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String userAuthByToken = token.getUserAuthByToken();
String cptAuthCodeByToken = token.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
serviceType = cptAuthCodeByToken;
}
String[] dateCate = {"beforeYesterday", "yesterday", "today", "tomorrow"}; // 2일전, 전일, 금일, 명일
List<MainDashWarnNumStcsModel> result = new ArrayList<>();
for(String cate : dateCate){
List<CtrCntrlWarnLog> cntrlWarnLogs = ctrCntrlWarnLogQueryRepository.currentStcs(groupId, authCheck, cate);
List<CtrCntrlWarnLog> cntrlWarnLogs = ctrCntrlWarnLogQueryRepository.currentStcs(serviceType, cate);
int count = cntrlWarnLogs.size(); //
@ -379,48 +398,75 @@ public class MainDashService {
return result;
}
public List<MainDashFlightNumStcsModel> dailyFlightNumOfStcs(){
// 1. 전일 , 금일, 명일(내일)
Instant yesterdayStart = Instant.now().minus(1, ChronoUnit.DAYS).truncatedTo(ChronoUnit.DAYS);
Instant yesterdayEnd = Instant.now().truncatedTo(ChronoUnit.DAYS).minus(1, ChronoUnit.SECONDS);
Instant todayStart = Instant.now().truncatedTo(ChronoUnit.DAYS);
Instant todayEnd = Instant.now().plus(1, ChronoUnit.DAYS).minus(1, ChronoUnit.SECONDS);
Instant tomorrowStart = Instant.now().plus(1, ChronoUnit.DAYS).truncatedTo(ChronoUnit.DAYS);
Instant tomorrowEnd = Instant.now().plus(2, ChronoUnit.DAYS).minus(1, ChronoUnit.SECONDS);
// 2. 비행계획서 승인 항목 : 비행계획서 제출기준(승인된 건수로봐도 동일)
int yesterdayCount = fltPlanBasRepository.countByAprvlYnAndAprvlDtBetween("Y", yesterdayStart, yesterdayEnd);
int todayCount = fltPlanBasRepository.countByAprvlYnAndAprvlDtBetween("Y", todayStart, todayEnd);
int tomorrowCount = fltPlanBasRepository.countByAprvlYnAndAprvlDtBetween("Y", tomorrowStart, tomorrowEnd);
// 3. 비행 완료 항목 : 실제 비행이 완료된 건수
int yesterdayCompleteCount = query.completeFlight(yesterdayStart,yesterdayEnd).size();
int todayCompleteCount = query.completeFlight(todayStart,todayEnd).size();
int tomorrowCompleteCount = query.completeFlight(tomorrowStart,tomorrowEnd).size();
// 4. 미 비행 항목 : 비행계획서는 제출했으나,실제 비행안한 건수
int yesterdayNotFlight = query.notFlight(yesterdayStart,yesterdayEnd).size();
int todayNotFlight = query.notFlight(todayStart, todayEnd).size();
int tomorrowNotFlight = query.notFlight(tomorrowStart,tomorrowEnd).size();
// 5. 비고 : 비행 완료 건수를 기준으로 상승 또는 하락폭 적용
// ex) 오늘 기준 오늘은 어제의 비행 완료 건수를 비교해서 적용
// 전일(어제)은 2일전 비행 완료 건수를 비교해서 적용
// 명일(내일)은 오늘 비행 완료 건수를 비교해서 적용
int yesterdayNote = yesterdayCompleteCount - query.completeFlight(yesterdayStart.minus(1, ChronoUnit.DAYS), yesterdayEnd.minus(1, ChronoUnit.DAYS)).size();
double yesterdayNotePercent = yesterdayCompleteCount != 0 ? ((double) yesterdayNote / yesterdayCompleteCount) * 100.0 : 0.0;
double todayNotePercent = yesterdayCompleteCount != 0 ? ((double)(todayCompleteCount - yesterdayCompleteCount) / yesterdayCompleteCount) * 100.0 : 0.0;
double tomorrowNotePercent = todayCompleteCount != 0 ? ((double) (tomorrowCompleteCount - todayCompleteCount) / todayCompleteCount) * 100.0 : 0.0;
List<MainDashFlightNumStcsModel> result = new ArrayList<>();
result.add(createModel("yesterday", yesterdayCount,yesterdayCompleteCount,yesterdayNotFlight,yesterdayNotePercent));
result.add(createModel("today", todayCount,todayCompleteCount,todayNotFlight,todayNotePercent));
result.add(createModel("tomorrow", tomorrowCount,tomorrowCompleteCount,tomorrowNotFlight,tomorrowNotePercent));
return result;
}
public List<MainDashFlightNumStcsModel> dailyFlightNumOfStcs() {
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String userAuthByToken = token.getUserAuthByToken();
String cptAuthCodeByToken = token.getCptAuthCodeByToken();
String serviceType = "";
if (!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)) {
serviceType = cptAuthCodeByToken;
}
// 1. 전일 , 금일, 명일(내일)
// ZoneId zoneId = ZoneId.systemDefault();
ZoneId zoneId = ZoneId.of("Asia/Seoul");
Instant yesterdayStart = Instant.now().atZone(zoneId).minusDays(1).truncatedTo(ChronoUnit.DAYS).toInstant();
Instant yesterdayEnd = Instant.now().atZone(zoneId).truncatedTo(ChronoUnit.DAYS).toInstant();
Instant todayStart = Instant.now().atZone(zoneId).truncatedTo(ChronoUnit.DAYS).toInstant();
Instant todayEnd = Instant.now().atZone(zoneId).plusDays(1).truncatedTo(ChronoUnit.DAYS).toInstant();
Instant tomorrowStart = Instant.now().atZone(zoneId).plusDays(1).truncatedTo(ChronoUnit.DAYS).toInstant();
Instant tomorrowEnd = Instant.now().atZone(zoneId).plusDays(2).truncatedTo(ChronoUnit.DAYS).toInstant();
// 2. 비행계획서 승인 항목 : 비행계획서 제출기준(승인된 건수로봐도 동일)
int yesterdayCount = 0;
int todayCount = 0;
int tomorrowCount = 0;
if (serviceType != null && !serviceType.isEmpty()) {
yesterdayCount = fltPlanBasRepository.countByAprvlYnAndSchFltStDtLessThanAndSchFltEndDtGreaterThanEqualAndServiceType("Y", yesterdayEnd, yesterdayStart, serviceType);
todayCount = fltPlanBasRepository.countByAprvlYnAndSchFltStDtLessThanAndSchFltEndDtGreaterThanEqualAndServiceType("Y", todayEnd, todayStart, serviceType);
tomorrowCount = fltPlanBasRepository.countByAprvlYnAndSchFltStDtLessThanAndSchFltEndDtGreaterThanEqualAndServiceType("Y", tomorrowEnd, tomorrowStart, serviceType);
} else {
yesterdayCount = fltPlanBasRepository.countByAprvlYnAndSchFltStDtLessThanAndSchFltEndDtGreaterThanEqual("Y", yesterdayEnd, yesterdayStart);
todayCount = fltPlanBasRepository.countByAprvlYnAndSchFltStDtLessThanAndSchFltEndDtGreaterThanEqual("Y", todayEnd, todayStart);
tomorrowCount = fltPlanBasRepository.countByAprvlYnAndSchFltStDtLessThanAndSchFltEndDtGreaterThanEqual("Y", tomorrowEnd, tomorrowStart);
}
// int yesterdayCount = serviceType != null && !serviceType.isEmpty()
// ? fltPlanBasRepository.countByAprvlYnAndAprvlDtBetweenAndServiceType("Y", yesterdayStart, yesterdayEnd, serviceType);
// : fltPlanBasRepository.countByAprvlYnAndAprvlDtBetween("Y", yesterdayStart, yesterdayEnd)
// int todayCount = serviceType != null && !serviceType.isEmpty()
// ? fltPlanBasRepository.countByAprvlYnAndAprvlDtBetweenAndServiceType("Y", todayStart, todayEnd, serviceType);
// : fltPlanBasRepository.countByAprvlYnAndAprvlDtBetween("Y", todayStart, todayEnd)
// int tomorrowCount = serviceType != null && !serviceType.isEmpty()
// ? fltPlanBasRepository.countByAprvlYnAndAprvlDtBetweenAndServiceType("Y", tomorrowStart, tomorrowEnd, serviceType);
// : fltPlanBasRepository.countByAprvlYnAndAprvlDtBetween("Y", tomorrowStart, tomorrowEnd)
// 3. 비행 완료 항목 : 실제 비행이 완료된 건수
int yesterdayCompleteCount = query.completeFlight(yesterdayStart, yesterdayEnd, serviceType).size();
int todayCompleteCount = query.completeFlight(todayStart, todayEnd, serviceType).size();
int tomorrowCompleteCount = query.completeFlight(tomorrowStart, tomorrowEnd, serviceType).size();
// 4. 미 비행 항목 : 비행계획서는 제출했으나,실제 비행안한 건수
int yesterdayNotFlight = query.notFlight(yesterdayStart, yesterdayEnd, serviceType).size();
int todayNotFlight = query.notFlight(todayStart, todayEnd, serviceType).size();
int tomorrowNotFlight = query.notFlight(tomorrowStart, tomorrowEnd, serviceType).size();
// 5. 비고 : 비행 완료 건수를 기준으로 상승 또는 하락폭 적용
// ex) 오늘 기준 오늘은 어제의 비행 완료 건수를 비교해서 적용
// 전일(어제)은 2일전 비행 완료 건수를 비교해서 적용
// 명일(내일)은 오늘 비행 완료 건수를 비교해서 적용
int yesterdayNote = yesterdayCompleteCount - query.completeFlight(yesterdayStart.minus(1, ChronoUnit.DAYS), yesterdayEnd.minus(1, ChronoUnit.DAYS), serviceType).size();
double yesterdayNotePercent = yesterdayCompleteCount != 0 ? ((double) yesterdayNote / yesterdayCompleteCount) * 100.0 : 0.0;
double todayNotePercent = yesterdayCompleteCount != 0 ? ((double) (todayCompleteCount - yesterdayCompleteCount) / yesterdayCompleteCount) * 100.0 : 0.0;
double tomorrowNotePercent = todayCompleteCount != 0 ? ((double) (tomorrowCompleteCount - todayCompleteCount) / todayCompleteCount) * 100.0 : 0.0;
List<MainDashFlightNumStcsModel> result = new ArrayList<>();
result.add(createModel("yesterday", yesterdayCount, yesterdayCompleteCount, yesterdayNotFlight, yesterdayNotePercent));
result.add(createModel("today", todayCount, todayCompleteCount, todayNotFlight, todayNotePercent));
result.add(createModel("tomorrow", tomorrowCount, tomorrowCompleteCount, tomorrowNotFlight, tomorrowNotePercent));
return result;
}
private MainDashFlightNumStcsModel createModel(String dateType, int flightPlanCount, int completeCount, int notFlight, double note) {
MainDashFlightNumStcsModel model = new MainDashFlightNumStcsModel();

127
pav-server/src/main/java/com/palnet/biz/api/main/statistics/service/MainStatisticsService.java

@ -146,7 +146,15 @@ public class MainStatisticsService {
public List<FlightStcsValueModel> getFlightStaticStcs(String serviceType){
// 권한이 유저권한이 user면 true, user가 아닐 경우 false;
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
boolean authCheck = "USER".equals(jwtTokenUtil.getUserAuthByToken());
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String userAuthByToken = jwtTokenUtil.getUserAuthByToken();
String cptAuthCodeByToken = jwtTokenUtil.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
serviceType = cptAuthCodeByToken;
authCheck = false;
}
FlightStcsValueModel time = cntrlQueryRepository.getFlightTimeStcs(authCheck, serviceType);
FlightStcsValueModel distance = cntrlQueryRepository.getFlightDistanceStcs(authCheck, serviceType);
@ -167,21 +175,30 @@ public class MainStatisticsService {
public List<FlightStcsValueModel> fltStatics(FlightStcsRQ rq, String[] formatParam){
// 권한이 유저권한이 user면 true, user가 아닐 경우 false;
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String serviceType = rq.getServiceType();
String userAuthByToken = jwtTokenUtil.getUserAuthByToken();
String cptAuthCodeByToken = jwtTokenUtil.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
serviceType = cptAuthCodeByToken;
authCheck = false;
}
List<FlightStcsValueModel> resultList = new ArrayList<>();
switch (rq.getCate()) {
case "TIME":
resultList = cntrlQueryRepository.fltTimeStcs(rq.getDate(), rq.getServiceType(), authCheck, formatParam);
resultList = cntrlQueryRepository.fltTimeStcs(rq.getDate(), serviceType, authCheck, formatParam);
break;
case "DISTANCE":
resultList = cntrlQueryRepository.fltDistanceStcs(rq.getDate(), rq.getServiceType(), authCheck, formatParam);
resultList = cntrlQueryRepository.fltDistanceStcs(rq.getDate(), serviceType, authCheck, formatParam);
break;
case "FLT_COUNT":
resultList = cntrlQueryRepository.fltCountStcs(rq.getDate(), rq.getServiceType(), authCheck, formatParam);
resultList = cntrlQueryRepository.fltCountStcs(rq.getDate(), serviceType, authCheck, formatParam);
break;
default :
@ -206,21 +223,30 @@ public class MainStatisticsService {
public List<FlightStcsValueModel> fltTopStatics(FlightStcsRQ rq, String[] formatParam){
// 권한이 유저권한이 user면 true, user가 아닐 경우 false;
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String serviceType = rq.getServiceType();
String userAuthByToken = jwtTokenUtil.getUserAuthByToken();
String cptAuthCodeByToken = jwtTokenUtil.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
serviceType = cptAuthCodeByToken;
authCheck = false;
}
List<FlightStcsValueModel> resultList = new ArrayList<>();
switch (rq.getCate()) {
case "TIME":
resultList = cntrlQueryRepository.fltTopTimeStcs(rq.getDate(), rq.getServiceType(), authCheck, formatParam);
resultList = cntrlQueryRepository.fltTopTimeStcs(rq.getDate(), serviceType, authCheck, formatParam);
break;
case "DISTANCE":
resultList = cntrlQueryRepository.fltTopDistanceStcs(rq.getDate(), rq.getServiceType(), authCheck, formatParam);
resultList = cntrlQueryRepository.fltTopDistanceStcs(rq.getDate(), serviceType, authCheck, formatParam);
break;
case "FLT_COUNT":
resultList = cntrlQueryRepository.fltTopCountStcs(rq.getDate(), rq.getServiceType(), authCheck, formatParam);
resultList = cntrlQueryRepository.fltTopCountStcs(rq.getDate(), serviceType, authCheck, formatParam);
break;
default :
@ -242,7 +268,15 @@ public class MainStatisticsService {
public List<FlightStcsValueModel> getWarnStaticStcs(String serviceType){
// 권한이 유저권한이 user면 true, user가 아닐 경우 false;
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String userAuthByToken = jwtTokenUtil.getUserAuthByToken();
String cptAuthCodeByToken = jwtTokenUtil.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
serviceType = cptAuthCodeByToken;
authCheck = false;
}
// TODO:: 비행경로이탈, 고도이탈, 충돌위험 임시코드
String[] cate = {"PLAN" ,"ALTITUDE", "CRASH"};
@ -272,9 +306,18 @@ public class MainStatisticsService {
public List<FlightStcsValueModel> warnStatics(FlightStcsRQ rq, String[] formatParam){
// 권한이 유저권한이 user면 true, user가 아닐 경우 false;
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String serviceType = rq.getServiceType();
String userAuthByToken = jwtTokenUtil.getUserAuthByToken();
String cptAuthCodeByToken = jwtTokenUtil.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
serviceType = cptAuthCodeByToken;
authCheck = false;
}
List<FlightStcsValueModel> resultList = ctrCntrlWarnLogQueryRepository.warnStcs(rq.getCate(), rq.getDate(), rq.getServiceType(), authCheck, formatParam);
List<FlightStcsValueModel> resultList = ctrCntrlWarnLogQueryRepository.warnStcs(rq.getCate(), rq.getDate(), serviceType, authCheck, formatParam);
for(FlightStcsValueModel node : resultList){
if(node.getName() == null || node.getName().equals("")) node.setName(" ");
@ -293,9 +336,18 @@ public class MainStatisticsService {
public List<FlightStcsValueModel> warnTopStatics(FlightStcsRQ rq, String[] formatParam){
// 권한이 유저권한이 user면 true, user가 아닐 경우 false;
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String serviceType = rq.getServiceType();
String userAuthByToken = jwtTokenUtil.getUserAuthByToken();
String cptAuthCodeByToken = jwtTokenUtil.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
serviceType = cptAuthCodeByToken;
authCheck = false;
}
List<FlightStcsValueModel> resultList = ctrCntrlWarnLogQueryRepository.warnTopStcs(rq.getCate(), rq.getDate(), rq.getServiceType(), authCheck, formatParam);
List<FlightStcsValueModel> resultList = ctrCntrlWarnLogQueryRepository.warnTopStcs(rq.getCate(), rq.getDate(), serviceType, authCheck, formatParam);
return resultList;
}
@ -307,7 +359,15 @@ public class MainStatisticsService {
public List<FlightStcsValueModel> getFltResultStaticStcs(String serviceType){
// 권한이 유저권한이 user면 true, user가 아닐 경우 false;
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String userAuthByToken = jwtTokenUtil.getUserAuthByToken();
String cptAuthCodeByToken = jwtTokenUtil.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
serviceType = cptAuthCodeByToken;
authCheck = false;
}
FlightStcsValueModel fltResult = fltPlanQueryRepository.getFltResultStaticStcs(authCheck, serviceType);
FlightStcsValueModel fltPlan = fltPlanQueryRepository.getFltPlanStaticStcs(authCheck, serviceType);
@ -329,19 +389,29 @@ public class MainStatisticsService {
List<FlightStcsValueModel> resultList = null;
// 권한이 유저권한이 user면 true, user가 아닐 경우 false;
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String serviceType = rq.getServiceType();
String userAuthByToken = jwtTokenUtil.getUserAuthByToken();
String cptAuthCodeByToken = jwtTokenUtil.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
serviceType = cptAuthCodeByToken;
authCheck = false;
}
switch (rq.getCate()) {
case "FLT_RESULT":
resultList = fltPlanQueryRepository.fltResultStcs(rq.getDate(), rq.getServiceType(), authCheck, formatParam);
resultList = fltPlanQueryRepository.fltResultStcs(rq.getDate(), serviceType, authCheck, formatParam);
break;
case "FLT_PLAN":
resultList = fltPlanQueryRepository.fltPlanStcs(rq.getDate(), rq.getServiceType(), authCheck, formatParam);
resultList = fltPlanQueryRepository.fltPlanStcs(rq.getDate(), serviceType, authCheck, formatParam);
break;
case "FLT_PLAN_APRVN":
resultList = fltPlanQueryRepository.fltPlanAprvnStcs(rq.getDate(), rq.getServiceType(), authCheck, formatParam);
resultList = fltPlanQueryRepository.fltPlanAprvnStcs(rq.getDate(), serviceType, authCheck, formatParam);
break;
default :
@ -361,19 +431,28 @@ public class MainStatisticsService {
List<FlightStcsValueModel> resultList = null;
// 권한이 유저권한이 user면 true, user가 아닐 경우 false;
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
boolean authCheck = jwtTokenUtil.getUserAuthByToken().equals("USER");
// SUPER 권한일 경우와 KAC의 기관코드일 경우 전체적으로 모니터링 가능해야한다. 그외는 자신의 기관에 해당하는 데이터 볼 수 있어야 한다.
String serviceType = rq.getServiceType();
String userAuthByToken = jwtTokenUtil.getUserAuthByToken();
String cptAuthCodeByToken = jwtTokenUtil.getCptAuthCodeByToken();
if(!"SUPER".equals(userAuthByToken) && !"KAC".equals(cptAuthCodeByToken)){
serviceType = cptAuthCodeByToken;
authCheck = false;
}
switch (rq.getCate()) {
case "FLT_RESULT":
resultList = fltPlanQueryRepository.fltTopResultStcs(rq.getDate(), rq.getServiceType(), authCheck, formatParam);
resultList = fltPlanQueryRepository.fltTopResultStcs(rq.getDate(), serviceType, authCheck, formatParam);
break;
case "FLT_PLAN":
resultList = fltPlanQueryRepository.fltTopPlanStcs(rq.getDate(), rq.getServiceType(), authCheck, formatParam);
resultList = fltPlanQueryRepository.fltTopPlanStcs(rq.getDate(), serviceType, authCheck, formatParam);
break;
case "FLT_PLAN_APRVN":
resultList = fltPlanQueryRepository.fltTopPlanAprvnStcs(rq.getDate(), rq.getServiceType(), authCheck, formatParam);
resultList = fltPlanQueryRepository.fltTopPlanAprvnStcs(rq.getDate(), serviceType, authCheck, formatParam);
break;
default :

6
pav-server/src/main/java/com/palnet/biz/config/WebMvcConfig.java

@ -1,7 +1,6 @@
package com.palnet.biz.config;
import java.time.format.DateTimeFormatter;
import com.palnet.biz.config.convert.CodeToFltPurposeBinding;
import com.palnet.biz.config.convert.StringToInstantBinding;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -13,6 +12,8 @@ import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter;
import java.time.format.DateTimeFormatter;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer{
@ -93,6 +94,7 @@ public class WebMvcConfig implements WebMvcConfigurer{
registrar.registerFormatters(registry);
registry.addConverter(new StringToInstantBinding());
registry.addConverter(new CodeToFltPurposeBinding());
/* ISO 타입.
registrar.setUseIsoFormat(true);

6
pav-server/src/main/java/com/palnet/biz/config/WebSecurityConfig.java

@ -41,6 +41,9 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
"/api/server/**",
"/api/comn/file/download",
"/api/comn/file/download/**",
"/api/external/laanc/**",
// TEST
"/api/v1/utm",
/* swagger v2 */
"/v2/api-docs",
"/swagger-resources",
@ -51,7 +54,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
"/webjars/**",
/* swagger v3 */
"/v3/api-docs/**",
"/swagger-ui/**"
"/swagger-ui/**",
"/docs/index.html"
};
@Autowired

15
pav-server/src/main/java/com/palnet/biz/config/convert/CodeToFltPurposeBinding.java

@ -0,0 +1,15 @@
package com.palnet.biz.config.convert;
import com.palnet.biz.jpa.entity.type.FltPurpose;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.convert.converter.Converter;
@Slf4j
public class CodeToFltPurposeBinding implements Converter<String, FltPurpose> {
@Override
public FltPurpose convert(String code) {
return FltPurpose.fromCode(code);
}
}

24
pav-server/src/main/java/com/palnet/biz/config/convert/InstantStringDeserializer.java

@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.palnet.comn.utils.InstantUtils;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
@ -45,6 +46,14 @@ public class InstantStringDeserializer extends JsonDeserializer<Instant> {
LocalDate localDate = LocalDate.parse(dateString, formatter);
return localDate.atStartOfDay(ZoneId.of(ZONE)).toInstant();
} else {
boolean doubleCheck = isValidDouble(dateString);
if(doubleCheck){
return InstantUtils.fromDatetimeDouble(Double.parseDouble(dateString));
}
return Instant.parse(dateString);
}
} catch (Exception e) {
@ -66,5 +75,20 @@ public class InstantStringDeserializer extends JsonDeserializer<Instant> {
}
}
public boolean isValidDouble(String dateString){
boolean result = false;
try{
Double.parseDouble(dateString);
result = true;
}catch (NumberFormatException e){
result = false;
}
return result;
}
}

2
pav-server/src/main/java/com/palnet/biz/jpa/entity/CnsFaqBas.java

@ -40,7 +40,7 @@ public class CnsFaqBas implements Serializable {
@Column(name="DEL_YN")
private String delYn = "N";
@Column(name="CREATE_USER_ID")
@Column(name="CREATE_USER_ID", updatable = false)
private String createUserId;
@CreationTimestamp

58
pav-server/src/main/java/com/palnet/biz/jpa/entity/ComConfirmBas.java

@ -0,0 +1,58 @@
package com.palnet.biz.jpa.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.*;
import java.time.Instant;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "COM_CONFIRM_BAS")
public class ComConfirmBas {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "CONFIRM_SNO")
private Integer confirmSno;
@Column(name = "STATUS")
private String status; // GENERATED, RECEIVED, CHECKED, FAILED, EXPIRED
@Column(name = "CONFIRM_KEY")
private String confirmKey;
@Column(name = "TARGET_TYPE")
private String targetType;
@Column(name = "RQ_DATA")
private String rqData;
@Column(name = "RS_DATA")
private String rsData;
@Column(name = "RM")
private String rm;
@Column(name = "CREATE_USER_ID")
private String createUserId;
@CreationTimestamp
@Column(name = "CREATE_DT", columnDefinition = "TIMESTAMP", updatable = false)
private Instant createDt;
@Column(name = "UPDATE_USER_ID")
private String updateUserId;
@UpdateTimestamp
@Column(name = "UPDATE_DT", columnDefinition = "TIMESTAMP")
private Instant updateDt;
}

13
pav-server/src/main/java/com/palnet/biz/jpa/repository/com/ComConfirmBasRepository.java

@ -0,0 +1,13 @@
package com.palnet.biz.jpa.repository.com;
import com.palnet.biz.jpa.entity.ComConfirmBas;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ComConfirmBasRepository extends JpaRepository<ComConfirmBas, Integer> {
ComConfirmBas findFirstByConfirmKey(String confirmKey);
ComConfirmBas findFirstByConfirmKeyOrderByCreateDtDesc(String confirmKey);
}

1213
pav-server/src/main/java/com/palnet/biz/jpa/repository/ctr/CtrCntrlQueryRepository.java

File diff suppressed because it is too large Load Diff

10
pav-server/src/main/java/com/palnet/biz/jpa/repository/ctr/CtrCntrlWarnLogQueryRepository.java

@ -284,12 +284,12 @@ public class CtrCntrlWarnLogQueryRepository {
return result;
}
public List<CtrCntrlWarnLog> currentStcs(String groupId, boolean authCheck, String cate){
public List<CtrCntrlWarnLog> currentStcs(String groupId, String cate){
QFltPlanBas qFltPlanBas = QFltPlanBas.fltPlanBas;
QFltPlanCtrCntrlRel qFltPlanCtrCntrlRel = QFltPlanCtrCntrlRel.fltPlanCtrCntrlRel;
QCtrCntrlWarnLog qCtrCntrlWarnLog = QCtrCntrlWarnLog.ctrCntrlWarnLog;
BooleanBuilder builder = getCurrentBooleanBuilder(groupId, authCheck, cate, qFltPlanBas, qCtrCntrlWarnLog);
BooleanBuilder builder = getCurrentBooleanBuilder(groupId, cate, qFltPlanBas, qCtrCntrlWarnLog);
List<CtrCntrlWarnLog> stcsValues = query
.select(
@ -310,11 +310,11 @@ public class CtrCntrlWarnLogQueryRepository {
return stcsValues;
}
private BooleanBuilder getCurrentBooleanBuilder(String groupId, boolean authCheck, String cate, QFltPlanBas qFltPlanBas, QCtrCntrlWarnLog qCtrCntrlWarnLog){
private BooleanBuilder getCurrentBooleanBuilder(String serviceType, String cate, QFltPlanBas qFltPlanBas, QCtrCntrlWarnLog qCtrCntrlWarnLog){
BooleanBuilder builder = new BooleanBuilder();
if(groupId != null && !(groupId.equals("")))builder.and(qFltPlanBas.groupId.eq(groupId));
if(authCheck) builder.and(qFltPlanBas.cstmrSno.eq(jwtTokenUtil.getCstmrSnoByToken()));
if(serviceType != null && !serviceType.isEmpty())builder.and(qFltPlanBas.serviceType.eq(serviceType));
// if(authCheck) builder.and(qFltPlanBas.cstmrSno.eq(jwtTokenUtil.getCstmrSnoByToken()));
String dateFormat = "%Y-%m-%d";
BooleanExpression dateExpression = null;

10
pav-server/src/main/java/com/palnet/biz/jpa/repository/flt/FltPlanBasRepository.java

@ -19,11 +19,12 @@ public interface FltPlanBasRepository extends JpaRepository<FltPlanBas, Integer>
List<FltPlanBas> findBySchFltStDtLessThanEqualAndSchFltEndDtGreaterThanEqualAndAprvlYnAndDelYn(Instant schFltEndDt, Instant schFltStDt, String aprvlYn, String delYn);
@Query("select f from FltPlanBas f " +
@Query(value = "select f from FltPlanBas f " +
"where ((SCH_FLT_ST_DT <= :schFltStDt and SCH_FLT_END_DT >= :schFltEndDt)"
+ "or (SCH_FLT_ST_DT >= :schFltStDt and (SCH_FLT_ST_DT <= :schFltEndDt and SCH_FLT_END_DT >= :schFltEndDt ))"
+ "or ((SCH_FLT_ST_DT <= :schFltStDt and SCH_FLT_END_DT >= :schFltStDt) and SCH_FLT_END_DT <= :schFltEndDt)"
+ "or (SCH_FLT_ST_DT >= :schFltStDt and SCH_FLT_END_DT <= :schFltEndDt)) and DEL_YN='N'")
+ "or (SCH_FLT_ST_DT >= :schFltStDt and SCH_FLT_END_DT <= :schFltEndDt)) and DEL_YN='N'"
, nativeQuery = true)
List<FltPlanBas> findByStartEndDate(@Param("schFltStDt") Date schFltStDt, @Param("schFltEndDt") Date schFltEndDt);
@ -57,4 +58,9 @@ public interface FltPlanBasRepository extends JpaRepository<FltPlanBas, Integer>
List<FltPlanBas> findApprovedFlightPlansByApprovalDate(Instant startDate, Instant endDate);
int countByAprvlYnAndAprvlDtBetween(String aprvlYn, Instant startDate, Instant endDate);
int countByAprvlYnAndAprvlDtBetweenAndServiceType(String aprvlYn, Instant startDate, Instant endDate, String serviceType);
int countByAprvlYnAndSchFltStDtLessThanAndSchFltEndDtGreaterThanEqualAndServiceType(String aprvlYn, Instant targetEndDate, Instant targetStDate, String serviceType);
int countByAprvlYnAndSchFltStDtLessThanAndSchFltEndDtGreaterThanEqual(String aprvlYn, Instant targetEndDate, Instant targetStDate);
}

56
pav-server/src/main/java/com/palnet/biz/jpa/repository/flt/FltPlanQueryRepository.java

@ -570,14 +570,16 @@ public class FltPlanQueryRepository {
BooleanBuilder builder = new BooleanBuilder();
DateTemplate<Instant> flightStartDate = Expressions.dateTemplate(
Instant.class, "DATE({0})", fltPlanBas.schFltStDt);
Instant searchDateParam = InstantUtils.fromDateString(searchDate);
DateTemplate<Instant> flightEndDate = Expressions.dateTemplate(
Instant.class, "DATE({0})", fltPlanBas.schFltEndDt);
// DateTemplate<Instant> flightStartDate = Expressions.dateTemplate(
// Instant.class, "DATE({0})", fltPlanBas.schFltStDt);
// DateTemplate<Instant> flightEndDate = Expressions.dateTemplate(
// Instant.class, "DATE({0})", fltPlanBas.schFltEndDt);
builder.and(flightStartDate.loe(DateUtils.stringToDate(searchDate)))
.and(flightEndDate.goe(DateUtils.stringToDate(searchDate)))
builder.and(fltPlanBas.schFltStDt.loe(searchDateParam))
.and(fltPlanBas.schFltEndDt.goe(searchDateParam))
.and(fltPlanBas.aprvlYn.eq("Y"));
List<BasFlightScheduleRs> querys = query.select(
@ -1422,7 +1424,7 @@ public class FltPlanQueryRepository {
* 비행승인 많은 기체 데이터, top 1
* @return
*/
public FlightStcsValueModel getFltPlanAprvnStaticStcs(boolean authCheck, String groupId){
public FlightStcsValueModel getFltPlanAprvnStaticStcs(boolean authCheck, String serviceType){
FlightStcsValueModel result = new FlightStcsValueModel();
QFltPlanArcrft qFltPlanArcrft = QFltPlanArcrft.fltPlanArcrft;
@ -1430,7 +1432,7 @@ public class FltPlanQueryRepository {
BooleanBuilder builder = new BooleanBuilder();
builder.and(qFltPlanBas.aprvlYn.eq("Y"));
if(groupId != null && !(groupId.equals(""))) builder.and(qFltPlanBas.groupId.eq(groupId));
if(serviceType != null && !(serviceType.equals(""))) builder.and(qFltPlanBas.serviceType.eq(serviceType));
if(authCheck) builder.and(qFltPlanBas.cstmrSno.eq(jwtTokenUtil.getCstmrSnoByToken()));
@ -1454,9 +1456,9 @@ public class FltPlanQueryRepository {
if(result.getName().equals("")) result.setName(" ");
String idntfNum = result.getName();
result.setYear(getFltPlanAprvnYear(idntfNum, authCheck, groupId));
result.setMonth(getFltPlanAprvnMonth(idntfNum, authCheck, groupId));
result.setDay(getFltPlanAprvnDay(idntfNum, authCheck, groupId));
result.setYear(getFltPlanAprvnYear(idntfNum, authCheck, serviceType));
result.setMonth(getFltPlanAprvnMonth(idntfNum, authCheck, serviceType));
result.setDay(getFltPlanAprvnDay(idntfNum, authCheck, serviceType));
} else {
FlightStcsValueModel node = new FlightStcsValueModel();
@ -1471,14 +1473,14 @@ public class FltPlanQueryRepository {
return result;
}
private Long getFltPlanAprvnDay(String idntfNum, boolean authCheck, String groupId){
private Long getFltPlanAprvnDay(String idntfNum, boolean authCheck, String serviceType){
QFltPlanArcrft qFltPlanArcrft = QFltPlanArcrft.fltPlanArcrft;
QFltPlanBas qFltPlanBas = QFltPlanBas.fltPlanBas;
String dateFormat = "%Y-%m-%d";
BooleanBuilder builder = new BooleanBuilder();
if(groupId != null && !(groupId.equals(""))) builder.and(qFltPlanBas.groupId.eq(groupId));
if(serviceType != null && !(serviceType.equals(""))) builder.and(qFltPlanBas.serviceType.eq(serviceType));
if(authCheck) builder.and(qFltPlanBas.cstmrSno.eq(jwtTokenUtil.getCstmrSnoByToken()));
builder.and(qFltPlanArcrft.idntfNum.eq(idntfNum));
builder.and(qFltPlanBas.aprvlYn.eq("Y"));
@ -1496,7 +1498,7 @@ public class FltPlanQueryRepository {
.fetchOne();
}
private Long getFltPlanAprvnMonth(String idntfNum, boolean authCheck, String groupId){
private Long getFltPlanAprvnMonth(String idntfNum, boolean authCheck, String serviceType){
QFltPlanArcrft qFltPlanArcrft = QFltPlanArcrft.fltPlanArcrft;
QFltPlanBas qFltPlanBas = QFltPlanBas.fltPlanBas;
@ -1506,7 +1508,7 @@ public class FltPlanQueryRepository {
builder.and(qFltPlanBas.aprvlYn.eq("Y"));
builder.and(qFltPlanBas.createDt.goe(LocalDate.now().minusMonths(1).atStartOfDay().atZone(ZoneId.of("Asia/Seoul")).toInstant()));
builder.and(qFltPlanBas.createDt.loe(LocalDate.now().atStartOfDay().atZone(ZoneId.of("Asia/Seoul")).toInstant()));
if(groupId != null && !(groupId.equals(""))) builder.and(qFltPlanBas.groupId.eq(groupId));
if(serviceType != null && !(serviceType.equals(""))) builder.and(qFltPlanBas.serviceType.eq(serviceType));
if(authCheck) builder.and(qFltPlanBas.cstmrSno.eq(jwtTokenUtil.getCstmrSnoByToken()));
return query
@ -1520,7 +1522,7 @@ public class FltPlanQueryRepository {
.fetchOne();
}
private Long getFltPlanAprvnYear(String idntfNum, boolean authCheck, String groupId){
private Long getFltPlanAprvnYear(String idntfNum, boolean authCheck, String serviceType){
QFltPlanArcrft qFltPlanArcrft = QFltPlanArcrft.fltPlanArcrft;
QFltPlanBas qFltPlanBas = QFltPlanBas.fltPlanBas;
@ -1529,7 +1531,7 @@ public class FltPlanQueryRepository {
builder.and(qFltPlanBas.aprvlYn.eq("Y"));
builder.and(qFltPlanBas.createDt.goe(LocalDate.now().minusYears(1).atStartOfDay().atZone(ZoneId.of("Asia/Seoul")).toInstant()));
builder.and(qFltPlanBas.createDt.loe(LocalDate.now().atStartOfDay().atZone(ZoneId.of("Asia/Seoul")).toInstant()));
if(groupId != null && !(groupId.equals(""))) builder.and(qFltPlanBas.groupId.eq(groupId));
if(serviceType != null && !(serviceType.equals(""))) builder.and(qFltPlanBas.serviceType.eq(serviceType));
if(authCheck) builder.and(qFltPlanBas.cstmrSno.eq(jwtTokenUtil.getCstmrSnoByToken()));
return query
@ -1848,15 +1850,15 @@ public class FltPlanQueryRepository {
/**
* 일일 비행데이터
* @param groupId
* @param serviceType
* @param authCheck
* @param cate
* @return
*/
public List<FltPlanBas> currentFlightStcs(String groupId, boolean authCheck, String cate){
public List<FltPlanBas> currentFlightStcs(String serviceType, String cate){
QFltPlanBas qFltPlanBas = QFltPlanBas.fltPlanBas;
BooleanBuilder builder = getCurrentBooleanBuilder(groupId, authCheck, cate, qFltPlanBas);
BooleanBuilder builder = getCurrentBooleanBuilder(serviceType, cate, qFltPlanBas);
List<FltPlanBas> stcsValues = query
.select(
@ -1873,11 +1875,10 @@ public class FltPlanQueryRepository {
return stcsValues;
}
private BooleanBuilder getCurrentBooleanBuilder(String groupId, boolean authCheck, String cate, QFltPlanBas qFltPlanBas){
private BooleanBuilder getCurrentBooleanBuilder(String serviceType, String cate, QFltPlanBas qFltPlanBas){
BooleanBuilder builder = new BooleanBuilder();
if(groupId != null && !(groupId.equals("")))builder.and(qFltPlanBas.groupId.eq(groupId));
if(authCheck) builder.and(qFltPlanBas.cstmrSno.eq(jwtTokenUtil.getCstmrSnoByToken()));
if (serviceType != null && !serviceType.isEmpty()) builder.and(qFltPlanBas.serviceType.eq(serviceType));
BooleanExpression dateExpression = null;
@ -1991,15 +1992,14 @@ public class FltPlanQueryRepository {
QComIdntfBas cib = QComIdntfBas.comIdntfBas;
QFltPlanArcrft fpa = QFltPlanArcrft.fltPlanArcrft;
QFltPlanBas fpb = QFltPlanBas.fltPlanBas;
QPtyGroupBas pgb = QPtyGroupBas.ptyGroupBas;
// QPtyGroupBas pgb = QPtyGroupBas.ptyGroupBas;
QFltPlanCtrCntrlRel fpccr = QFltPlanCtrCntrlRel.fltPlanCtrCntrlRel;
QCtrCntrlBas ccb = QCtrCntrlBas.ctrCntrlBas;
BooleanBuilder builder = new BooleanBuilder();
if(!cptAuth.equals("KAC")) {
builder.and(pgb.groupNm.eq("cptAuth"));
}
if(!cptAuth.isEmpty()) builder.and(fpb.serviceType.eq(cptAuth));
Instant now = Instant.now();
ZoneId databaseTimeZone = ZoneId.of("Asia/Seoul");
@ -2025,7 +2025,7 @@ public class FltPlanQueryRepository {
)
.from(fpa)
.leftJoin(fpb).on(fpb.planSno.eq(fpa.planSno))
.leftJoin(pgb).on(pgb.groupId.eq(fpb.groupId))
// .leftJoin(pgb).on(pgb.groupId.eq(fpb.groupId))
.leftJoin(cib).on(cib.idntfNum.eq(fpa.idntfNum))
.leftJoin(fpccr).on(fpccr.planSno.eq(fpb.planSno))
.leftJoin(ccb).on(ccb.cntrlId.eq(fpccr.cntrlId))

24
pav-server/src/main/java/com/palnet/biz/jpa/repository/pty/PtyCrtfyhpBasQueryRepository.java

@ -6,7 +6,6 @@ import com.palnet.biz.jpa.entity.QPtyCrtfyhpBas;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import java.time.Instant;
@ -14,26 +13,43 @@ import java.time.temporal.ChronoUnit;
import java.util.List;
@Slf4j
@Repository
@RequiredArgsConstructor
public class PtyCrtfyhpBasQueryRepository {
private final JPAQueryFactory query;
/**
* 휴대폰에 전송된 인증코드가 맞는지 확인하는 SQL기능
* @param hpno
* @param crtfyNo
* @return
*/
public List<PtyCrtfyhpBas> confirmSms(String hpno, String crtfyNo) {
QPtyCrtfyhpBas qEntity = QPtyCrtfyhpBas.ptyCrtfyhpBas;
Instant now = Instant.now();
Instant prevTime = Instant.now().minus(5, ChronoUnit.MINUTES);
BooleanBuilder builder = new BooleanBuilder();
builder.and(qEntity.crtfyhpNo.eq(crtfyNo));
builder.and(qEntity.crtfyhpYn.eq("N"));
builder.and(qEntity.createDt.goe(prevTime));
builder.and(qEntity.createDt.loe(now));
/**
* 휴대폰 번호와 인증번호가 맞는지 확인하는 SQL 입니다.
*
* SELECT
* *
* FROM PTY_CRTFYHP_BAS PCB
* WHERE PCB.CRTFYHP_NO = #{crtfyNo} -- 인증번호
* AND PCB.CRTFYHP_YN = 'N'
* AND PCB.CREATE_DT = DATE_SUB(NOW(), INTERVAL 5 MINUTE)
* AND PCB.CREATE_DT = NOW()
*/
List<PtyCrtfyhpBas> entity =
query.select(qEntity).from(qEntity)
.where(builder)
@ -43,5 +59,5 @@ public class PtyCrtfyhpBasQueryRepository {
return entity;
}
}

180
pav-server/src/main/java/com/palnet/biz/jpa/repository/pty/PtyCstmrQueryRepository.java

@ -26,6 +26,13 @@ public class PtyCstmrQueryRepository {
private final JPAQueryFactory query;
/**
* 입력받은 회원 아이디가 데이터베이스에 있는지 조회하는 SQL기능.
* ID가 있으면 중복되는 , true 반환
* ID가 없으면 중복되지 않는 , false 반환
* @param userId
* @return
*/
public boolean findCstmrByUserId(String userId) {
boolean result = false;
@ -38,6 +45,15 @@ public class PtyCstmrQueryRepository {
builder.and(basEntity.cstmrStatusCd.eq("A")); //활성화 상태
builder.and(basEntity.userId.eq(userId));
/**
* 회원 아이디[USER_ID],
* 회원활성화 여부[CSTMR_STATUS_CD] 값이 조건에 맞으면 회원정보를 가져오는 SQL입니다.
* SELECT
* *
* FROM PTY_CSTMR_BAS PCB
* WHERE PCB.CSTMR_STATUS_CD = 'A'
* AND PCB.USER_ID = #{id}
*/
PtyCstmrBas entity = query.select(basEntity)
.from(basEntity)
.where(builder)
@ -49,24 +65,49 @@ public class PtyCstmrQueryRepository {
return result;
}
/**
* 회원 이름과 휴대폰번호로 데이터 베이스에서 회원정보 찾는 SQL 기능
* @param name
* @param hpno
* @return
*/
public boolean certifNum(String name, String hpno) {
QPtyCstmrDtl dtl = QPtyCstmrDtl.ptyCstmrDtl;
QPtyCstmrDtl dtl = QPtyCstmrDtl.ptyCstmrDtl; // PTY_CSTMR_DTL - 고객 상세 테이블
// 데이터베이스 조건 문을 주는 코드
BooleanBuilder builder = new BooleanBuilder();
builder.and(dtl.hpno.eq(hpno));
builder.and(dtl.memberName.eq(name));
builder.and(dtl.hpno.eq(hpno)); // 휴대폰 번호가 맞는지 조건추가
builder.and(dtl.memberName.eq(name)); // 회원이름이 맞는지 조건추가
/**
* 휴대폰 번호와 이름으로 데이터베이스에서 회원정보를 가져오는 SQL 입니다.
*
* SELECT
* *
* FROM PTY_CSTMR_DTL PCD
* WHERE PCD.HPNO = #{hpno}
* AND PCD.MEMBER_NAME = #{name}
*/
PtyCstmrDtl entity = query.select(dtl)
.from(dtl)
.where(builder)
.fetchFirst();
boolean result = false;
if (entity != null) {
result = true;
}
return result;
}
/**
* 회원명과 암호화된 휴대폰 번호로 ID찾는 SQL 기능
* @param name
* @param hpno
* @return
*/
public String findUserId(String name, String hpno) {
QPtyCstmrBas bas = QPtyCstmrBas.ptyCstmrBas;
QPtyCstmrDtl dtl = QPtyCstmrDtl.ptyCstmrDtl;
@ -75,6 +116,20 @@ public class PtyCstmrQueryRepository {
builder.and(bas.cstmrStatusCd.eq("A"));
builder.and(dtl.hpno.eq(hpno));
builder.and(dtl.memberName.eq(name));
/**
* 회원상태 활성화 여부[CSTMR_STATUS_CD],
* 휴대폰 번호 [HPNO],
* 회원 이름 [MEMBER_NAME] 으로 회원정보를 찾는 SQL 입니다.
* SELECT
* *
* FROM PTY_CSTMR_BAS PCB
* LEFT OUTER JOIN PTY_CSTMR_DTL PCD
* ON PCB.CSTMR_SNO = PCD.CSTMR_SNO
* WHERE PCB.CSTMR_STATUS_CD = 'A'
* AND PCD.HPNO = #{hpno}
* AND PCD.MEMBER_NAME = #{name}
*/
PtyCstmrBas entity = query.select(bas)
.from(bas)
.leftJoin(dtl)
@ -86,6 +141,12 @@ public class PtyCstmrQueryRepository {
return userId;
}
/**
* 회원 ID와 휴대폰번호[hpno] 일치한지 확인하는 SQL기능
* @param id
* @param hpno
* @return
*/
public PtyCstmrBas findUserPw(String id, String hpno) {
QPtyCstmrBas bas = QPtyCstmrBas.ptyCstmrBas;
QPtyCstmrDtl dtl = QPtyCstmrDtl.ptyCstmrDtl;
@ -94,6 +155,20 @@ public class PtyCstmrQueryRepository {
builder.and(bas.cstmrStatusCd.eq("A"));
builder.and(dtl.hpno.eq(hpno));
builder.and(bas.userId.eq(id));
/**
* 회원 아이디[USER_ID],
* 회원활성화 여부[CSTMR_STATUS_CD],
* 휴대폰번호 [HPNO] 값이 조건에 맞으면 회원 정보를 가져오는 SQL입니다.
* SELECT
* *
* FROM PTY_CSTMR_BAS PCB
* LEFT OUTER JOIN PTY_CSTMR_DTL PCD
* ON PCB.CSTMR_SNO = PCD.CSTMR_SNO
* WHERE PCB.CSTMR_STATUS_CD = 'A'
* AND PCD.HPNO = #{hpno}
* AND PCB.USER_ID = #{id}
*/
PtyCstmrBas entity = query.select(bas)
.from(bas)
.leftJoin(dtl)
@ -104,27 +179,44 @@ public class PtyCstmrQueryRepository {
return entity;
}
/**
* 데이터베이스 안에 같은 휴대폰 번호가 있는지 확인
* result가 true 일시 동일한 번호가 존재함
* @param hpno
* @return
*/
public boolean findCstmrByHpno(String hpno) {
boolean result = false;
boolean result = false; // 반환할 값 선언 [default false를 의미함]
QPtyCstmrBas basEntity = QPtyCstmrBas.ptyCstmrBas;
QPtyCstmrDtl dtlEntity = QPtyCstmrDtl.ptyCstmrDtl;
QPtyCstmrBas basEntity = QPtyCstmrBas.ptyCstmrBas;
QPtyCstmrDtl dtlEntity = QPtyCstmrDtl.ptyCstmrDtl;
// 데이터베이스 조건 문을 주는 코드
BooleanBuilder builder = new BooleanBuilder();
builder.and(basEntity.cstmrStatusCd.eq("A")); //활성화 상태
builder.and(dtlEntity.hpno.eq(hpno));
builder.and(basEntity.cstmrStatusCd.eq("A"));
builder.and(dtlEntity.hpno.eq(hpno));
/**
* 휴대폰 번호가 데이터베이스 안에 있는지 확인하는 SQL 입니다.
* SELECT
* *
* FROM PTY_CSTMR_BAS PCB
* LEFT OUTER JOIN PTY_CSTMR_DTL PCD
* ON PCB.CSTMR_SNO = PCD.CSTMR_SNO
* WHERE PCB.CSTMR_STATUS_CD = 'A'
* AND PCD.HPNO = #{hpno}
*/
PtyCstmrBas entity = query.select(basEntity)
.from(basEntity)
.leftJoin(dtlEntity)
.on(basEntity.cstmrSno.eq(dtlEntity.cstmrSno))
.on(basEntity.cstmrSno.eq(dtlEntity.cstmrSno))
.where(builder)
.fetchFirst();
if (entity != null) {
result = true;
}
return result;
}
public JwtUserModel findUserPassword(String userId) {
@ -165,6 +257,7 @@ public class PtyCstmrQueryRepository {
model.setCstmrSno(entity.getCstmrSno());
model.setCstmrStatusCd(entity.getCstmrStatusCd());
model.setUserPswd(entity.getUserPswd());
model.setCptAuthCode(entity.getCptAuthCode());
if (pcgEntityList != null && !pcgEntityList.isEmpty()) {
List<JwtGroupModel> groupModelList = new ArrayList<>();
for (PtyCstmrGroup pcgEntity : pcgEntityList) {
@ -186,6 +279,11 @@ public class PtyCstmrQueryRepository {
}
/**
* cstmrSno 값으로 회원정보를 조회하는 SQL 기능.
* @param cstmrSno
* @return
*/
public JwtProfileRsModel findUserProfile(int cstmrSno) {
QPtyCstmrBas basEntity = QPtyCstmrBas.ptyCstmrBas;
QPtyCstmrDtl dtlEntity = QPtyCstmrDtl.ptyCstmrDtl;
@ -194,12 +292,29 @@ public class PtyCstmrQueryRepository {
builder.and(basEntity.cstmrSno.eq(cstmrSno));
/**
* 회원 고유번호[cstmrSno] 회원의 기본 프로필정보를 데이터베이스에서 조회하는 SQL입니다.
* SELECT
* PCB.CSTMR_SNO,
* PCB.USER_ID ,
* PCB.AUTH_ID ,
* PCB.TRMNL_ID ,
* PCB.SITE_CODE ,
* PCB.USER_ID ,
* PCB.CPT_AUTH_CODE ,
* PCD.MEMBER_NAME
* FROM PTY_CSTMR_BAS PCB
* LEFT OUTER JOIN PTY_CSTMR_DTL PCD
* ON PCB.CSTMR_SNO = PCD.CSTMR_SNO
* WHERE PCB.CSTMR_SNO = #{cstmrSno}
*/
JwtProfileRsModel model = query.select(Projections.bean(JwtProfileRsModel.class,
basEntity.cstmrSno,
basEntity.userId,
basEntity.authId,
basEntity.trmnlId,
basEntity.siteCode,
basEntity.cptAuthCode,
dtlEntity.memberName
))
.from(basEntity)
@ -239,11 +354,24 @@ public class PtyCstmrQueryRepository {
}
/**
* cstmrSno로 기본 회원정보 받아오는 SQL과
* 회원의 인가정보를 조회하여 받는 기능.
* @param cstmrSno
* @return
*/
public JwtUserModel findByIdForrefreshToken(int cstmrSno) {
QPtyCstmrBas basEntity = QPtyCstmrBas.ptyCstmrBas;
BooleanBuilder builder = new BooleanBuilder();
builder.and(basEntity.cstmrSno.eq(cstmrSno));
/**
* 회원 고유번호[cstmrSno] 기본 회원정보 받아오는 SQL 기능입니다.
* SELECT
* *
* FROM PTY_CSTMR_BAS PCB
* WHERE PCB.CSTMR_SNO = #{cstmrSno}
*/
PtyCstmrBas entity = query.select(basEntity)
.from(basEntity)
.where(builder)
@ -262,11 +390,34 @@ public class PtyCstmrQueryRepository {
} else {
return null;
}
}
}
/**
* 회원 고유번호로 데이터베이스에서 회원정보를 조회하는 SQL 기능.
* @param cstmrSno
* @return
*/
public List<AnctCstmerRlModel> list(int cstmrSno) {
QPtyCstmrBas bas = QPtyCstmrBas.ptyCstmrBas;
QPtyCstmrDtl dtl = QPtyCstmrDtl.ptyCstmrDtl;
/**
* 회원 고유번호로 데이터베이스에서 회원정보를 조회하는 SQL 입니다.
* SELECT
* PCD.MEMBER_NAME ,
* PCD.BRTHDY_DATE ,
* PCD.GENDER_CD ,
* PCD.CNTRY_CD ,
* PCD.EMAIL ,
* PCD.HPNO ,
* PCD.UPDATE_DT ,
* PCB.CPT_AUTH_CODE ,
* PCB.USER_ID
* FROM PTY_CSTMR_BAS PCB
* LEFT OUTER JOIN PTY_CSTMR_DTL PCD
* ON PCB.CSTMR_SNO = PCD.CSTMR_SNO
* WHERE PCB.CSTMR_SNO = #{cstmrSno}
*/
List<AnctCstmerRlModel> list = query
.select(Projections.bean(
AnctCstmerRlModel.class,
@ -277,6 +428,7 @@ public class PtyCstmrQueryRepository {
dtl.email,
dtl.hpno,
dtl.updateDt,
bas.cptAuthCode,
bas.userId
))
.from(bas)

28
pav-server/src/main/java/com/palnet/biz/jpa/repository/pty/PtyTermsQueryRepository.java

@ -23,6 +23,11 @@ public class PtyTermsQueryRepository {
private final JPAQueryFactory query;
/**
* 입력받은 값에 따라 약관항목을 데이터베이스에서 가져오는 SQL 기능.
* @param rq
* @return
*/
public List<AcntTermsRsModel> list(AcntTermsRqModel rq) {
QPtyTermsBas basEntity = QPtyTermsBas.ptyTermsBas;
@ -34,7 +39,28 @@ public class PtyTermsQueryRepository {
builder.and(basEntity.siteCd.eq(rq.getSiteCd()));
builder.and(basEntity.termsCtgryCd.eq(rq.getTermsCtgryCd()));
/**
* 최종내역여부[LAST_TXN_YN] 조건,
* 사이트코드[SITE_CD] 조건,
* 약관카테고리[TERMS_CRGRY_CD] 조건이 맞는 약관항목을 데이터베이스에서 조회하는 SQL 입니다.
* SELECT
* PTB.TERMS_SNO ,
* PTB.SITE_CD ,
* PTB.ESTBSH_DATE ,
* PTB.TERMS_CTGRY_CD ,
* PTD.LANG_DIV_CD ,
* PTD.TERMS_TITLE_NM ,
* PTD.TERMS_CN ,
* PTD.SIMPLE_CN
* FROM PTY_TERMS_BAS PTB
* LEFT OUTER JOIN PTY_TERMS_DTL PTD
* ON PTB.TERMS_SNO = PTD.TERMS_SNO
* AND PTD.LANG_DIV_CD = #{langDivCd}
* WHERE PTB.LAST_TXN_YN = 'Y'
* AND PTB.SITE_CD = #{siteCd}
* AND PTB.TERMS_CTGRY_CD = #{termsCtgryCd}
* ORDER BY PTB.UPDATE_DT DESC
*/
List<AcntTermsRsModel> queryList = query.select(Projections.bean(AcntTermsRsModel.class,
basEntity.termsSno,
basEntity.siteCd,

24
pav-server/src/main/java/com/palnet/biz/sample/controller/UtmSampleTestController.java

@ -0,0 +1,24 @@
package com.palnet.biz.sample.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletRequest;
@Slf4j
@RestController
public class UtmSampleTestController {
@PostMapping("/api/v1/utm")
public ResponseEntity<?> utmReciverTest(@RequestBody String body, ServletRequest request) {
log.info("====================================================");
log.info("====================================================");
log.info("====>> /api/v1/utm sample test : {}", body);
log.info("====================================================");
log.info("====================================================");
return ResponseEntity.ok().build();
}
}

87
pav-server/src/main/java/com/palnet/comn/code/ErrorCode.java

@ -1,36 +1,59 @@
package com.palnet.comn.code;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.palnet.biz.jpa.entity.type.FltType;
public enum ErrorCode {
SUCCESS("1", "성공"),
FAIL("-1" , "실패"),
NON_VALID_PARAMETER("VP001", "파라미터가 유효하지 않습니다."),
INTERNAL_SERVER_ERROR("ER500", "내부 시스템 오류"),
NOT_REGIST_ERROR_CODE("ER501", "등록되지 않은 오류 코드"),
DATA_NOTFIND("DT001","데이터 를 찾을수 없습니다."),
DATA_DUPLICATE("DT002","중복 데이터가 존재합니다."),
DATA_NO("DT003", "데이터 미존재"),
DB_ERROR("DB001" , "디비 처리중 오류"),
PLAN_DATA_DUPLICATE("FT500", "이미 등록된 비행계획서의 비행구역과 비행시간이 일치합니다.\n비행시간 또는 비행구역을 수정하여 주십시오."),
ARCRFT_DATA_DUPLICATE("FT501", "해당 기체는 다른 비행계획서에서 이미 등록된 기체입니다.\n비행시간 또는 기체 정보를 확인하여 주십시오."),
PLAN_LAANC_NOT_VALID("FT502", "LAANC를 통과하지 못한 비행계획서입니다."),
EXTERNAL_API_ERROR("EA500", "외부서버 호출에 실패하였습니다.");
private final String code;
private final String message;
private ErrorCode(String code, String message) {
this.code = code;
this.message = message;
}
public String code() {
return code;
}
public String message() {
return message;
}
SUCCESS("1", "성공"),
FAIL("-1", "실패"),
NON_VALID_PARAMETER("VP001", "파라미터가 유효하지 않습니다."),
INTERNAL_SERVER_ERROR("ER500", "내부 시스템 오류"),
NOT_REGIST_ERROR_CODE("ER501", "등록되지 않은 오류 코드"),
DATA_NOTFIND("DT001", "데이터 를 찾을수 없습니다."),
DATA_DUPLICATE("DT002", "중복 데이터가 존재합니다."),
DATA_NOT_CHANGE("DT003", "아직 갱신되지 않았습니다."),
DATA_NO("DT003", "데이터 미존재"),
DB_ERROR("DB001", "디비 처리중 오류"),
PLAN_DATA_DUPLICATE("FT500", "이미 등록된 비행계획서의 비행구역과 비행시간이 일치합니다.\n비행시간 또는 비행구역을 수정하여 주십시오."),
ARCRFT_DATA_DUPLICATE("FT501", "해당 기체는 다른 비행계획서에서 이미 등록된 기체입니다.\n비행시간 또는 기체 정보를 확인하여 주십시오."),
PLAN_LAANC_NOT_VALID("FT502", "LAANC를 통과하지 못한 비행계획서입니다."),
EXTERNAL_API_ERROR("EA500", "외부서버 호출에 실패하였습니다."),
AUTH_NAUTHORIZED("AU001", "권한이 없습니다."),
// TS 연동 ERROR CODE
TS_SUCCESS("TS200", "정상적으로 수신되었습니다."),
TS_PARAM("TS300", "메시지 규격이 다릅니다."), // Json 포멧이 틀린 경우
TS_PARAM_REQUIRED("TS301", "필수 항목이 누락되었습니다."), // 필수 항목이 누락된 경우
TS_TYPE("TS302", "메시지 타입이 맞지 않습니다."), // 메시지내 파라미터의 타입이 잘못된 경우
TS_SERVER_ERROR("TS500", "서버 연결이 되지 않습니다."), // call측 network exception 처리
TS_NT_LAZY("TS501", "네트워크 연결이 지연 됩니다."), // call측 network exception 처리
TS_AUTH_KEY("TS600", "인증키가 유효하지 않습니다."),
TS_ETC("TS700", "기타 오류"); // 기 정의된 내용이 아닌 기타 오류인 경우
private final String code;
private final String message;
private ErrorCode(String code, String message) {
this.code = code;
this.message = message;
}
public String code() {
return code;
}
public String message() {
return message;
}
@JsonCreator
public static ErrorCode fromCode(String code) {
for (ErrorCode errorCode : ErrorCode.values()) {
if (errorCode.code().equals(code)) {
return errorCode;
}
}
return null;
}
}

2
pav-server/src/main/java/com/palnet/comn/utils/AirspaceUtils.java

@ -100,7 +100,7 @@ public class AirspaceUtils {
for (FeatureInfo featureInfo : this.airspaces) {
Geometry airspaceGeometry = featureInfo.getGeometry();
int airspaceHighElev = featureInfo.getHighElev() != null ? featureInfo.getHighElev() : 0;
// 임시로 0~최대고도 기준으로 검증
// 0~최대고도 기준으로 검증
if (airspaceHighElev == 0 || airspaceHighElev < targetHighElev) {
if (airspaceGeometry.intersects(targetGeometry)) {
return false;

5
pav-server/src/main/java/com/palnet/comn/utils/InstantUtils.java

@ -94,6 +94,11 @@ public class InstantUtils {
return localDate.atStartOfDay(ZoneId.of(zone)).toInstant();
}
public static Instant fromDatetimeDouble (double dateDouble){
return Instant.ofEpochSecond((long) dateDouble, (long) ((dateDouble % 1) * 1_000_000_000));
}
// string validate format
public static boolean isValidFormat(String dateString, String format) {
SimpleDateFormat dateFormat = new SimpleDateFormat(format);

4
pav-server/src/main/resources/application-database.yml

@ -41,8 +41,8 @@ spring:
datasource:
control:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
jdbc-url: jdbc:log4jdbc:mysql://palnet.cexpliz30rwl.ap-northeast-2.rds.amazonaws.com:3306/PAV?characterEncoding=UTF-8&autoReconnect=true&useSSL=false
username: pav
jdbc-url: jdbc:log4jdbc:mysql://192.168.100.102:3306/PAV_KAC?characterEncoding=UTF-8&autoReconnect=true&useSSL=false
username: pav-kac
password: palnet!234
minimumidle: 10
maximumpoolsize: 20

1
pav-server/src/main/resources/application.properties

@ -17,6 +17,7 @@ external.sunriseset.key=b/Stm6AMT3EwXc5kOvwnjK/PB57Ay1WzkIGVx5WaMt0MyRt3TEPgcJ/u
### TS ###
external.ts.url=http://121.137.95.45:8170
external.ts.return.uri=/api/external/laanc/vc/callback
### Token key ######
spring.jwt.secret=jwtsecretkey

12
pav-server/src/main/resources/application.yml

@ -70,6 +70,10 @@ url:
file: files/
coord: C:\\Users\\Jaewoo\\Downloads\\pal\\pav\\kac\\coordinate\\CoordinateFolder\\
app:
host: http://localhost:8080
# host: http://211.253.11.189:8080
---
spring:
@ -120,6 +124,10 @@ url:
file: /data/server/files/
coord: /data/coord/coordinateFolder/
app:
host: http://211.253.11.189:8080
---
spring:
@ -179,3 +187,7 @@ url:
file: /data/server/files/
coord: /data/coord/coordinateFolder/
app:
# host: http://211.253.11.189:8080
host: http://121.190.193.50:6081

2
pav-server/src/main/resources/config/log/logback-spring.xml

@ -12,7 +12,7 @@
<property name="LOG_DIR" value="/data/logs/server" />
</springProfile>
<springProfile name="prod">
<property name="LOG_DIR" value="/data/logs/server01/" />
<property name="LOG_DIR" value="/data/logs/server/" />
</springProfile>
<springProfile name="prod2">

572
pav-server/src/main/resources/static/docs/index.html

@ -0,0 +1,572 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.10">
<meta name="author" content="API 문서">
<title>PAV-KAC REST Docs</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<style>
/* Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
/* Uncomment @import statement to use as custom stylesheet */
/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}
audio,video{display:inline-block}
audio:not([controls]){display:none;height:0}
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
a{background:none}
a:focus{outline:thin dotted}
a:active,a:hover{outline:0}
h1{font-size:2em;margin:.67em 0}
abbr[title]{border-bottom:1px dotted}
b,strong{font-weight:bold}
dfn{font-style:italic}
hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
mark{background:#ff0;color:#000}
code,kbd,pre,samp{font-family:monospace;font-size:1em}
pre{white-space:pre-wrap}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
small{font-size:80%}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sup{top:-.5em}
sub{bottom:-.25em}
img{border:0}
svg:not(:root){overflow:hidden}
figure{margin:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
legend{border:0;padding:0}
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
button,input{line-height:normal}
button,select{text-transform:none}
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
textarea{overflow:auto;vertical-align:top}
table{border-collapse:collapse;border-spacing:0}
*,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
html,body{font-size:100%}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
a:hover{cursor:pointer}
img,object,embed{max-width:100%;height:auto}
object,embed{height:100%}
img{-ms-interpolation-mode:bicubic}
.left{float:left!important}
.right{float:right!important}
.text-left{text-align:left!important}
.text-right{text-align:right!important}
.text-center{text-align:center!important}
.text-justify{text-align:justify!important}
.hide{display:none}
img,object,svg{display:inline-block;vertical-align:middle}
textarea{height:auto;min-height:50px}
select{width:100%}
.center{margin-left:auto;margin-right:auto}
.stretch{width:100%}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
a{color:#2156a5;text-decoration:underline;line-height:inherit}
a:hover,a:focus{color:#1d4b8f}
a img{border:0}
p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
h1{font-size:2.125em}
h2{font-size:1.6875em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
h4,h5{font-size:1.125em}
h6{font-size:1em}
hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
em,i{font-style:italic;line-height:inherit}
strong,b{font-weight:bold;line-height:inherit}
small{font-size:60%;line-height:inherit}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
ul,ol{margin-left:1.5em}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ul.square{list-style-type:square}
ul.circle{list-style-type:circle}
ul.disc{list-style-type:disc}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
abbr{text-transform:none}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
blockquote cite::before{content:"\2014 \0020"}
blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
h1{font-size:2.75em}
h2{font-size:2.3125em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
h4{font-size:1.4375em}}
table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
table thead,table tfoot{background:#f7f8f7}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt{background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
.clearfix::after,.float-group::after{clear:both}
:not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
:not(pre)>code.nobreak{word-wrap:normal}
:not(pre)>code.nowrap{white-space:nowrap}
pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed}
pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
pre>code{display:block}
pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
em em{font-style:normal}
strong strong{font-weight:400}
.keyseq{color:rgba(51,51,51,.8)}
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq,.menuref{color:#000}
.menuseq b:not(.caret),.menuref{font-weight:inherit}
.menuseq{word-spacing:-.02em}
.menuseq b.caret{font-size:1.25em;line-height:.8}
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
b.button::before{content:"[";padding:0 3px 0 2px}
b.button::after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
#content{margin-top:1.25em}
#content::before{content:none}
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span::before{content:"\00a0\2013\00a0"}
#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark::before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber::after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
#toc>ul{margin-left:.125em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc li{line-height:1.3334;margin-top:.3334em}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
#toctitle{color:#7a2518;font-size:1.2em}
@media screen and (min-width:768px){#toctitle{font-size:1.375em}
body.toc2{padding-left:15em;padding-right:0}
#toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right{padding-left:0;padding-right:15em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2{width:20em}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2>ul{font-size:.95em}
#toc.toc2 ul ul{padding-left:1.25em}
body.toc2.toc-right{padding-left:0;padding-right:20em}}
#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
#footer{max-width:100%;background:rgba(0,0,0,.8);padding:1.25em}
#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
#content{margin-bottom:.625em}
.sect1{padding-bottom:.625em}
@media screen and (min-width:768px){#content{margin-bottom:1.25em}
.sect1{padding-bottom:1.25em}}
.sect1:last-child{padding-bottom:0}
.sect1+.sect1{border-top:1px solid #e7e7e9}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
details>summary:first-of-type{cursor:pointer;display:list-item;outline:none;margin-bottom:.75em}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
.paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit}
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6)}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
.exampleblock>.content>:first-child{margin-top:0}
.exampleblock>.content>:last-child{margin-bottom:0}
.sidebarblock{border-style:solid;border-width:1px;border-color:#dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;-webkit-border-radius:4px;border-radius:4px}
.sidebarblock>:first-child{margin-top:0}
.sidebarblock>:last-child{margin-bottom:0}
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock>.content>pre{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;overflow-x:auto;padding:1em;font-size:.8125em}
@media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}
@media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}
.literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class="highlight"],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8}
.literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}
.listingblock>.content{position:relative}
.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}
.listingblock:hover code[data-lang]::before{display:block}
.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}
.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
.prettyprint{background:#f7f7f8}
pre.prettyprint .linenums{line-height:1.45;margin-left:2em}
pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}
pre.prettyprint li code[data-lang]::before{opacity:1}
pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}
table.linenotable td.code{padding-left:.75em}
table.linenotable td.linenos{border-right:1px solid currentColor;opacity:.35;padding-right:.5em}
pre.pygments .lineno{border-right:1px solid currentColor;opacity:.35;display:inline-block;margin-right:.75em}
pre.pygments .lineno::before{content:"";margin-right:-.125em}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em}
.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
.verseblock{margin:0 1em 1.25em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
.quoteblock.abstract{margin:0 1em 1.25em;display:block}
.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
.quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
.quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}
.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;text-align:left;margin-right:0}
table.tableblock{max-width:100%;border-collapse:separate}
p.tableblock:last-child{margin-bottom:0}
td.tableblock>.content>:last-child{margin-bottom:-1.25em}
td.tableblock>.content>:last-child.sidebarblock{margin-bottom:0}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0}
table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0}
table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0}
table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px}
table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0}
table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0}
table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0}
table.frame-all{border-width:1px}
table.frame-sides{border-width:0 1px}
table.frame-topbot,table.frame-ends{border-width:1px 0}
table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd),table.stripes-even tr:nth-of-type(even),table.stripes-hover tr:hover{background:#f8f8f7}
th.halign-left,td.halign-left{text-align:left}
th.halign-right,td.halign-right{text-align:right}
th.halign-center,td.halign-center{text-align:center}
th.valign-top,td.valign-top{vertical-align:top}
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
th.valign-middle,td.valign-middle{vertical-align:middle}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
p.tableblock>code:only-child{background:none;padding:0}
p.tableblock{font-size:1em}
ol{margin-left:1.75em}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
ul.unstyled,ol.unstyled{margin-left:0}
ul.checklist{margin-left:.625em}
ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
ul.inline>li{margin-left:1.25em}
.unstyled dl dt{font-weight:400;font-style:normal}
ol.arabic{list-style-type:decimal}
ol.decimal{list-style-type:decimal-leading-zero}
ol.loweralpha{list-style-type:lower-alpha}
ol.upperalpha{list-style-type:upper-alpha}
ol.lowerroman{list-style-type:lower-roman}
ol.upperroman{list-style-type:upper-roman}
ol.lowergreek{list-style-type:lower-greek}
.hdlist>table,.colist>table{border:0;background:none}
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
.colist td:not([class]):first-child img{max-width:none}
.colist td:not([class]):last-child{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
.imageblock.left{margin:.25em .625em 1.25em 0}
.imageblock.right{margin:.25em 0 1.25em .625em}
.imageblock>.title{margin-bottom:0}
.imageblock.thumb,.imageblock.th{border-width:6px}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
.image.left{margin-right:.625em}
.image.right{margin-left:.625em}
a.image{text-decoration:none;display:inline-block}
a.image object{pointer-events:none}
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
sup.footnote a,sup.footnoteref a{text-decoration:none}
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
.gist .file-data>table td.line-data{width:99%}
div.unbreakable{page-break-inside:avoid}
.big{font-size:larger}
.small{font-size:smaller}
.underline{text-decoration:underline}
.overline{text-decoration:overline}
.line-through{text-decoration:line-through}
.aqua{color:#00bfbf}
.aqua-background{background:#00fafa}
.black{color:#000}
.black-background{background:#000}
.blue{color:#0000bf}
.blue-background{background:#0000fa}
.fuchsia{color:#bf00bf}
.fuchsia-background{background:#fa00fa}
.gray{color:#606060}
.gray-background{background:#7d7d7d}
.green{color:#006000}
.green-background{background:#007d00}
.lime{color:#00bf00}
.lime-background{background:#00fa00}
.maroon{color:#600000}
.maroon-background{background:#7d0000}
.navy{color:#000060}
.navy-background{background:#00007d}
.olive{color:#606000}
.olive-background{background:#7d7d00}
.purple{color:#600060}
.purple-background{background:#7d007d}
.red{color:#bf0000}
.red-background{background:#fa0000}
.silver{color:#909090}
.silver-background{background:#bcbcbc}
.teal{color:#006060}
.teal-background{background:#007d7d}
.white{color:#bfbfbf}
.white-background{background:#fafafa}
.yellow{color:#bfbf00}
.yellow-background{background:#fafa00}
span.icon>.fa{cursor:default}
a span.icon>.fa{cursor:inherit}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]+b{display:none}
.conum[data-value]::after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
.conum:not([data-value]):empty{display:none}
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
p{margin-bottom:1.25rem}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.print-only{display:none!important}
@page{margin:1.25cm .75cm}
@media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
html{font-size:80%}
a{color:inherit!important;text-decoration:underline!important}
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]::after{content:" (" attr(title) ")"}
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
thead{display:table-header-group}
svg{max-width:100%}
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span::before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]::before{display:block}
#footer{padding:0 .9375em}
.hide-on-print{display:none!important}
.print-only{display:block!important}
.hide-for-print{display:none!important}
.show-for-print{display:inherit!important}}
@media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem}
.sect1{padding:0!important}
.sect1+.sect1{border:0}
#footer{background:none}
#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body class="book toc2 toc-left">
<div id="header">
<h1>PAV-KAC REST Docs</h1>
<div class="details">
<span id="author" class="author">API 문서</span><br>
<span id="revnumber">version 0.0.1</span>
</div>
<div id="toc" class="toc2">
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#메인통계-API">메인통계 API</a>
<ul class="sectlevel2">
<li><a href="#메인통계">[비행통계 상단 고정데이터]</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div id="content">
<div class="sect1">
<h2 id="메인통계-API"><a class="link" href="#메인통계-API">메인통계 API</a></h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="메인통계"><a class="link" href="#메인통계">[비행통계 상단 고정데이터]</a></h3>
<div class="sect3">
<h4 id="_request"><a class="link" href="#_request">[Request]</a></h4>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight nowrap"><code data-lang="http" class="language-http hljs">GET /api/main/statistics/flight-static HTTP/1.1
Authorization: palnet eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyTm0iOiLtlZzqta3qs7Xtla3qs7XsgqxBIiwic3ViIjoia2FjLWFkbWluIiwiY3N0bXJTbm8iOjEzLCJhdXRoIjoiQURNSU4iLCJjcHRBdXRoQ29kZSI6IktBQyIsImV4cCI6MTcwMTk1OTE5OSwidXNlcklkIjoia2FjLWFkbWluIiwiaWF0IjoxNzAxOTQxMTk5LCJncm91cCI6W3siZ3JvdXBJZCI6IkM4MDdGOSIsImdyb3VwQXV0aENkIjoiTEVBREVSIn1dfQ.xokVPDukL2zY2VK_l8dSfrCptstz_sWxU30nwQt9PyPOVfgtPqcaLGbNjUA12Oin-mRdrdKw9JVDME-hZFYtvg
Host: localhost:8080</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_response"><a class="link" href="#_response">[Response]</a></h4>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight nowrap"><code data-lang="http" class="language-http hljs">HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 344
{
"count" : 3,
"data" : [ {
"name" : "PA0001",
"year" : "07:18:48",
"month" : "07:18:48",
"day" : "00:00:00"
}, {
"name" : "PA0001",
"year" : 264.4089966030238,
"month" : 264.4089966030238,
"day" : 0.0
}, {
"name" : "PA0001",
"value" : 24,
"year" : 24,
"month" : 24,
"day" : 0
} ]
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_responsefields"><a class="link" href="#_responsefields">[ResponseFields]</a></h4>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Path</th>
<th class="tableblock halign-left valign-top">Type</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>count</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Number</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">값의 크기</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>data</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Array</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">비행통계 상단 데이터 리스트</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>data[].name</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">가장 데이터가 많은 기체</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>data[].year</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Varies</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">연 통합 데이터</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>data[].month</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Varies</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">월 통합 데이터</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>data[].day</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Varies</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">일일 통합 데이터</p></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Version 0.0.1<br>
Last updated 2023-12-07 18:22:17 +0900
</div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.6/styles/github.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.6/highlight.min.js"></script>
<script>hljs.initHighlighting()</script>
</body>
</html>

4
pav-server/src/test/java/com/palnet/biz/api/bas/laanc/service/BasLaancAprvServiceTest.java

@ -18,7 +18,7 @@ class BasLaancAprvServiceTest {
@Autowired
private BasLaancAprvService basLaancAprvService;
@Test
// @Test
void getLaancAprvList() {
Page<BasLaancAprvRs> laancAprvList = basLaancAprvService.getLaancAprvList(null, null);
log.info(">>> pageable is null : {}::{}::{}",laancAprvList.getTotalElements(), laancAprvList.getContent().size(), laancAprvList);
@ -27,7 +27,7 @@ class BasLaancAprvServiceTest {
log.info(">>> pageable is not null : {}::{}::{}",laancAprvList1.getTotalElements(), laancAprvList1.getContent().size(), laancAprvList1);
}
@Test
// @Test
void getLaancAprvDetail() {
BasLaancAprvRs rs1 = basLaancAprvService.getLaancAprvDetail("92");
log.info(">>> rs1 : {}", rs1);

2
pav-server/src/test/java/com/palnet/biz/api/comn/file/service/ComnFileServiceTest.java

@ -15,7 +15,7 @@ class ComnFileServiceTest {
@Autowired
private ComnFileService comnFileService;
@Test
// @Test
void makePdf() {
LaancPdfModel model = new LaancPdfModel();
model.setPilotName("TESTER");

3
pav-server/src/test/java/com/palnet/biz/api/comn/sms/service/ComnSmsServiceTest.java

@ -13,7 +13,8 @@ class ComnSmsServiceTest {
@Autowired
private ComnSmsService comnSmsService;
@Test
// @Test
void sendSms() {

4
pav-server/src/test/java/com/palnet/biz/api/external/service/SunRiseSetServiceTest.java vendored

@ -12,12 +12,12 @@ class SunRiseSetServiceTest {
@Autowired
private SunRiseSetService service;
@Test
// @Test
void getSunRiseSet() {
service.callSunRiseSet("20231231", "김포");
}
@Test
// @Test
void setSunRiseSetOnDb() {
service.setSunRiseSetOnDb();
}

2
pav-server/src/test/java/com/palnet/biz/api/external/service/TsServiceTest.java vendored

@ -22,7 +22,7 @@ class TsServiceTest {
private String TS_HOST;
private final String ACCOUNT_VALIDATE_URI = "/api/account/getValidate";
@Test
// @Test
void callAccountValidate() {
PilotValidRq rq = PilotValidRq.builder()
.pilotci("wEi9oYSuekQGxT9MV4rKHG4CO+Zrp+onhLIIuembI8jx/0PLF5Ne3oMBxvUFlN4UmsgjeNErZfmpCVUFHsv8nq==")

116
pav-server/src/test/java/com/palnet/biz/api/main/statistics/StatisticsTests.java

@ -0,0 +1,116 @@
package com.palnet.biz.api.main.statistics;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.modifyUris;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;
import org.springframework.restdocs.RestDocumentationContextProvider;
import org.springframework.restdocs.RestDocumentationExtension;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import com.palnet.biz.api.acnt.jwt.model.JwtRqModel;
import com.palnet.biz.api.acnt.jwt.model.JwtRsModel;
import com.palnet.biz.api.acnt.jwt.service.JwtService;
import lombok.extern.slf4j.Slf4j;
@SpringBootTest
@ExtendWith({RestDocumentationExtension.class})
@ActiveProfiles("local")
@Slf4j
public class StatisticsTests {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@Autowired
private JwtService jwtService;
@BeforeEach
public void setUpAll(RestDocumentationContextProvider restDocumentationContextProvider){
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) // @Autowired로 빈주입 받은 context
.addFilter(new CharacterEncodingFilter("UTF-8", true)) // UTF-8 인코딩 필터
.apply(
MockMvcRestDocumentation.documentationConfiguration(restDocumentationContextProvider)
.operationPreprocessors()
.withRequestDefaults( // (1)
modifyUris().scheme("http").host("localhost").port(8080), prettyPrint() // URL 정보를 넣어주시면 됩니다.
)
.withResponseDefaults(
prettyPrint() // (2)
)
)
.build();
}
@Test
public void fltStcsStaticTest() throws Exception{
String id = "kac-admin";
String pass = "palnet5909!";
JwtRqModel authenticationRequest = new JwtRqModel(id, pass);
JwtRsModel result = (JwtRsModel) jwtService.loginProcess(authenticationRequest).get("result");
log.warn("result => {}", result);
String token = "palnet " + result.getAccessToken();
this.mockMvc.perform(
get("/api/main/statistics/flight-static") // API method와 URL을 적어주시면 됩니다.
.header("Authorization", token)
)
.andDo(print())
.andDo(
document("main/statistics/flight-static", // gradle build를 하게 되면 generated-snippets에 만들어질 폴더이름
preprocessResponse(prettyPrint()
), // 2
requestHeaders(
headerWithName(HttpHeaders.AUTHORIZATION).description("인가 토큰")
),
requestParameters(
parameterWithName("serviceType").description("각 청별 서비스코드").optional()
),
responseFields( // RS필드를 적음
fieldWithPath("count").description("값의 크기"), // fieldWithPath는 컬럼명, description은 설명
subsectionWithPath("data").description("비행통계 상단 데이터 리스트"), // fieldWithPath는 컬럼명, description은 설명
fieldWithPath("data[].name").description("가장 데이터가 많은 기체"),
fieldWithPath("data[].year").description("연 통합 데이터"),
fieldWithPath("data[].month").description("월 통합 데이터"),
fieldWithPath("data[].day").description("일일 통합 데이터")
// fieldWithPath("foodList").description("푸드리스트")
)
))
.andExpect(status().isOk());
}
}

4
pav-server/src/test/java/com/palnet/biz/jpa/repository/flt/FltPlanQueryRepositoryTest.java

@ -23,7 +23,7 @@ class FltPlanQueryRepositoryTest {
@Autowired
private FltPlanQueryRepository fltPlanQueryRepository;
@Test
// @Test
void findAllAprvListBySearch() {
Instant createDate = InstantUtils.fromDateString("2023-10-06");
Instant createStDate = createDate.minus(Duration.ofDays(1));
@ -47,7 +47,7 @@ class FltPlanQueryRepositoryTest {
}
@Test
// @Test
void findAprvById() {
BasLaancAprvRs rs = new BasLaancAprvRs();
}

2
pav-server/src/test/java/com/palnet/biz/scheduler/ctr/service/CtrTrnsLctnServiceTest.java

@ -15,7 +15,7 @@ class CtrTrnsLctnServiceTest {
@Autowired
private CtrTrnsLctnService service;
@Test
// @Test
void convertLatlonToAddress() {
CtrTrnsLctnModel ctrTrnsLctnModel = service.convertLatlonToAddress(37.5666805, 126.9784147);
log.info(">>> {}", ctrTrnsLctnModel);

3
pav-server/src/test/java/com/palnet/exec/TempAdmDistrictServiceTest.java

@ -11,7 +11,8 @@ class TempAdmDistrictServiceTest {
@Autowired
private TempAdmDistrictService service;
@Test
// @Test
void readAdmDistrictCode() {
service.readAdmDistrictCode();
}

43
pav-socket/src/main/java/com/palnet/comn/collection/GPCollection.java

@ -32,7 +32,7 @@ public class GPCollection {
}
public static Map<String, List<GPModel>> getAll() {
if (gpMap.keySet().size() < 1) {
if (gpMap.keySet().isEmpty()) {
return null;
}
return gpMap;
@ -74,7 +74,7 @@ public class GPCollection {
public static Map<String, List<GPModel>> sendAll() {
log.info("sendAll start - GPMap size : {}", gpMap.size());
if(gpMap.keySet().size() < 1) {
if(gpMap.keySet().isEmpty()) {
return null;
}
Map<String, List<GPModel>> map = gpMap;
@ -83,13 +83,50 @@ public class GPCollection {
return map;
}
public static List<GPModel> sendAllUtm() {
log.info("sendAllUtm start - GPMap size : {}", gpMap.size());
if(gpMap.keySet().isEmpty()) {
return null;
}
List<GPModel> list = new ArrayList<>();
for (String key : gpMap.keySet()) {
List<GPModel> temp = gpMap.get(key);
if (temp == null || temp.isEmpty()) {
continue;
}
GPModel model = temp.get(temp.size() - 1);
if(!model.isSendUtm()){
list.add(model);
}
}
log.info("sendAllUtm end - GPMap size : {}", gpMap.size());
return list;
}
public static void sendAllUtmSuccess(List<GPModel> successGPModel) {
if(successGPModel == null || successGPModel.isEmpty()) return;
for (GPModel model : successGPModel) {
if (model == null || model.getObjectId() == null || model.getObjectId().isEmpty()) {
continue;
}
List<GPModel> list = gpMap.get(model.getObjectId());
if (list == null) return;
list.stream().filter(gpModel -> {
if(gpModel == null || gpModel.getRegDt() == null) return false;
return gpModel.getRegDt().equals(model.getRegDt());
}).findFirst().ifPresent(gpModel -> {
gpModel.setSendUtm(true);
});
}
}
// 1분마다 데이터 삭제
@Scheduled(fixedDelay = 1000 * 60)
public void removeSchedule() {
log.info("removeSchedule start - GPMap size : {}", gpMap.size());
for (String key : gpMap.keySet()) {
List<GPModel> list = gpMap.get(key);
if (list == null || list.size() == 0) {
if (list == null || list.isEmpty()) {
continue;
}
GPModel model = list.get(list.size() - 1);

4
pav-socket/src/main/java/com/palnet/comn/model/GPModel.java

@ -72,5 +72,7 @@ public class GPModel {
// 큐가 Socket서버에 도착한 시간
private Instant regDt;
// 큐가 Socket서버에 도착한 시간
private boolean sendUtm; // 불법드론 전송 여부
}

37
pav-socket/src/main/java/com/palnet/comn/model/UtmModel.java

@ -0,0 +1,37 @@
package com.palnet.comn.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UtmModel {
@JsonProperty("GPSime")
private String GPSime; // 시간 yyyyMMddHHmmss
@JsonProperty("droneInfo")
private List<DronInfo> dronInfo;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class DronInfo {
@JsonProperty("Id")
private String id;
@JsonProperty("Latitude")
private String latitude;
@JsonProperty("Longitude")
private String longitude;
@JsonProperty("Height")
private String height;
}
}

83
pav-socket/src/main/java/com/palnet/server/task/server/service/TaskServerService.java

@ -2,6 +2,7 @@ package com.palnet.server.task.server.service;
import com.palnet.comn.collection.GPCollection;
import com.palnet.comn.model.GPModel;
import com.palnet.comn.model.UtmModel;
import com.palnet.comn.utils.JsonUtils;
import io.netty.channel.ChannelOption;
import lombok.RequiredArgsConstructor;
@ -19,9 +20,14 @@ import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
* packageName : com.palnet.server.task.wb.service
@ -129,4 +135,81 @@ public class TaskServerService {
.bodyToMono(Void.class).subscribe();
}
@Scheduled(fixedDelay = 1000 * 2)
public void sendDataAllUtm() {
List<GPModel> modelList = GPCollection.sendAllUtm();
if (modelList == null) {
return;
}
// 가공
List<UtmModel.DronInfo> dronInfoList = modelList.stream().map(model -> {
UtmModel.DronInfo dronInfo = UtmModel.DronInfo.builder()
.id(model.getObjectId())
.latitude(model.getLat().toString())
.longitude(model.getLng().toString())
.height(model.getElev().toString())
.build();
return dronInfo;
}).collect(Collectors.toList());
if(dronInfoList.isEmpty()) return;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss")
.withZone(ZoneId.of("Asia/Seoul"));
String dateStr = formatter.format(Instant.now());
UtmModel utmModel = UtmModel.builder()
.GPSime(dateStr)
.dronInfo(dronInfoList)
.build();
// 임시 하드코딩
final String UTM_HOST = "http://192.168.0.133:9000";
final String UTM_REALTIME_URI = "/api/v1/utm";
WebClient client = WebClient.builder()
.baseUrl(UTM_HOST)
.defaultHeader("Content-Type", "application/json")
.build();
client.post()
.uri(UTM_REALTIME_URI)
.body(Mono.just(utmModel), UtmModel.class)
.retrieve()
.bodyToMono(Void.class).subscribe();
// 전송 완료시 true 처리
GPCollection.sendAllUtmSuccess(modelList);
}
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss")
.withZone(ZoneId.of("Asia/Seoul"));
String dateStr = formatter.format(Instant.now());
Double lat = 37.123456;
Double lon = 127.123456;
Double elev = 100.0;
UtmModel.DronInfo dronInfo = UtmModel.DronInfo.builder()
.id("objectId")
.latitude(lat.toString())
.longitude(lon.toString())
.height(elev.toString())
.build();
List<UtmModel.DronInfo> dronInfoList = List.of(dronInfo);
UtmModel utmModel = UtmModel.builder()
.GPSime(dateStr)
.dronInfo(dronInfoList)
.build();
String json = JsonUtils.toJson(utmModel);
System.out.println(json);
}
}

6
pav-socket/src/main/resources/application.yml

@ -86,12 +86,14 @@ logging:
console: '%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n'
file: '%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n'
file:
name: /data/logs/data.log
name: /data/logs/socket/data.log
level:
com.palnet: info
app:
host: http://127.0.0.1:8080
# host: http://121.190.193.50:8080
web-socket:
host: http://127.0.0.1:8081
host: http://127.0.0.1:8181
# host: http://121.190.193.50:8181

4
pav-websocket/src/main/java/com/palnet/server/controller/SocketReceiverController.java

@ -36,7 +36,7 @@ public class SocketReceiverController {
@PostMapping("/receiver")
public ResponseEntity<?> receiver(@RequestBody GPModel model) {
log.info("websocket message : {}", model);
log.info("websocket message receiver : {}", model);
// GPModel model = null;
// try {
// model = objectMapper.readValue(message, GPModel.class);
@ -56,7 +56,7 @@ public class SocketReceiverController {
@PostMapping("/receiver/async")
public Callable<String> asyncReceiver(@RequestBody GPModel model) {
return () -> {
log.info("websocket message : {}", model);
log.info("websocket message receiver async: {}", model);
CtrCntrlModel history = service.modelConvert(model);
// DRON의 대한 식별정보만 이력 관리
historyShareContext.putHistory(model.getObjectId(), history);

1
pav-websocket/src/main/resources/application.yml

@ -70,3 +70,4 @@ logging:
app:
host: http://127.0.0.1:8080/
# host: http://121.190.193.50:8080/

Loading…
Cancel
Save