From 34767770f5801922c087637441f365dddebd1a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?lkd9125=28=EC=9D=B4=EA=B2=BD=EB=8F=84=29?= Date: Thu, 12 Sep 2024 10:43:37 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=ED=86=B5=EA=B3=84=20=EA=B8=B0?= =?UTF-8?q?=EC=B4=88=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/StatisticsDosController.java | 40 +++++++++++++ .../biz/api/bas/dos/model/AllStatDataRS.java | 27 +++++++++ .../biz/api/bas/dos/model/CptStatRQ.java | 15 +++++ .../biz/api/bas/dos/model/CptStatRS.java | 35 +++++++++++ .../bas/dos/service/StatisticsDosService.java | 60 +++++++++++++++++++ 5 files changed, 177 insertions(+) create mode 100644 pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java create mode 100644 pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java create mode 100644 pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRQ.java create mode 100644 pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRS.java create mode 100644 pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java new file mode 100644 index 00000000..e6b5fe97 --- /dev/null +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java @@ -0,0 +1,40 @@ +package com.palnet.biz.api.bas.dos.controller; + +import com.palnet.biz.api.bas.dos.model.AllStatDataRS; +import com.palnet.biz.api.bas.dos.model.CptStatRQ; +import com.palnet.biz.api.bas.dos.model.CptStatRS; +import com.palnet.biz.api.bas.dos.service.StatisticsDosService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@Slf4j +@RequestMapping("/api/statistics/dos") +@RequiredArgsConstructor +public class StatisticsDosController { + + private final StatisticsDosService statisticsDosService; + + @GetMapping("/all-data") + public ResponseEntity allData(){ + log.info("allData"); + + AllStatDataRS result = statisticsDosService.allData(); + + return ResponseEntity.ok().body(result); + } + + @GetMapping("/table-data") + public ResponseEntity tableData(@RequestParam CptStatRQ rq){ + + CptStatRS result = statisticsDosService.cptStatData(rq); + + return ResponseEntity.ok().body(null); + } + + + + +} diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java new file mode 100644 index 00000000..8f4a8b2f --- /dev/null +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java @@ -0,0 +1,27 @@ +package com.palnet.biz.api.bas.dos.model; + +import lombok.Data; + +@Data +public class AllStatDataRS { + + private GroupModel fullApproval; + + private GroupModel controlApproval; + + private GroupModel nonControlApproval; + + @Data + public static class GroupModel{ + + private String groupName; + + private Long all; + + private Long year; + + private Long month; + + private Long day; + } +} diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRQ.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRQ.java new file mode 100644 index 00000000..2587be04 --- /dev/null +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRQ.java @@ -0,0 +1,15 @@ +package com.palnet.biz.api.bas.dos.model; + +import lombok.Data; + +import java.time.LocalDate; + +@Data +public class CptStatRQ { + + private String category; + + private LocalDate startDt; + + private LocalDate endDt; +} diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRS.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRS.java new file mode 100644 index 00000000..7b60b88f --- /dev/null +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRS.java @@ -0,0 +1,35 @@ +package com.palnet.biz.api.bas.dos.model; + +import lombok.Data; + +import java.util.List; + +@Data +public class CptStatRS { + + private List cptList; + + + + @Data + public static class CptStat{ + + private String cptName; // 관할청 이름 + + private Long count; // 총 카운트 + + private List coordinateModels; // 중심좌표 + + } + + @Data + public static class CoordinateModel{ + + private Double lat; // 위도 36.. ~~ + + private Double lon; // 경도 126.. ~~ + + } + + +} diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java new file mode 100644 index 00000000..3690ad01 --- /dev/null +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java @@ -0,0 +1,60 @@ +package com.palnet.biz.api.bas.dos.service; + +import com.palnet.biz.api.bas.dos.model.AllStatDataRS; +import com.palnet.biz.api.bas.dos.model.CptStatRQ; +import com.palnet.biz.api.bas.dos.model.CptStatRS; +import com.palnet.biz.jpa.repository.dos.DosFltPlanAreaRepository; +import com.palnet.biz.jpa.repository.dos.DosFltPlanBasRepository; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +@RequiredArgsConstructor +public class StatisticsDosService { + + private final DosFltPlanBasRepository dosFltPlanBasRepository; + + private final DosFltPlanAreaRepository dosFltPlanAreaRepository; + + public AllStatDataRS allData() { + + + AllStatDataRS result = new AllStatDataRS(); + + return result; + } + + + public CptStatRS cptStatData(CptStatRQ rq) { + + CptStatRS result = new CptStatRS(); + + return result; + } + + @Getter + @RequiredArgsConstructor + private enum Auth{ + + + F0001("서울지방항공청(항공운항과)"), + F0002("김포항공관리사무소(안전운항과)"), + F0003("양양공항출장소"), + F0004("원주공항출장소"), + F0005("청주공항출장소"), + F0006("군산공항출장소"), + F0007("부산지방항공청(항공운항과)"), + F0008("제주지방항공청(안전운항과)"), + F0009("정석비행장"), + F0010("울진공항출장소"), + ; + + private final String desc; + + } + + +} From 79814eecd8a69bd3e2b2f589873a13010909a358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?lkd9125=28=EC=9D=B4=EA=B2=BD=EB=8F=84=29?= Date: Thu, 12 Sep 2024 16:23:24 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20CPT=5FCD=20=EC=A0=81=EC=9A=A9X,=20?= =?UTF-8?q?=ED=86=B5=EA=B3=84=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/StatisticsDosController.java | 4 +- .../biz/api/bas/dos/model/AllStatDataRS.java | 1 + .../biz/api/bas/dos/model/CptStatRS.java | 11 +- .../bas/dos/service/StatisticsDosService.java | 30 +++- .../dos/DosFltPlanAreaQueryRepository.java | 160 ++++++++++++++++++ 5 files changed, 193 insertions(+), 13 deletions(-) create mode 100644 pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java index e6b5fe97..e51888c8 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java @@ -27,11 +27,11 @@ public class StatisticsDosController { } @GetMapping("/table-data") - public ResponseEntity tableData(@RequestParam CptStatRQ rq){ + public ResponseEntity tableData(CptStatRQ rq){ CptStatRS result = statisticsDosService.cptStatData(rq); - return ResponseEntity.ok().body(null); + return ResponseEntity.ok().body(result); } diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java index 8f4a8b2f..38e641d5 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java @@ -23,5 +23,6 @@ public class AllStatDataRS { private Long month; private Long day; + } } diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRS.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRS.java index 7b60b88f..e3f84d38 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRS.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRS.java @@ -16,10 +16,17 @@ public class CptStatRS { private String cptName; // 관할청 이름 - private Long count; // 총 카운트 + private List countModel; // 카운트 private List coordinateModels; // 중심좌표 - + + } + + @Data + public static class DateCountModel{ + private String date; + + private Long count; } @Data diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java index 3690ad01..055607db 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java @@ -3,6 +3,7 @@ package com.palnet.biz.api.bas.dos.service; import com.palnet.biz.api.bas.dos.model.AllStatDataRS; import com.palnet.biz.api.bas.dos.model.CptStatRQ; import com.palnet.biz.api.bas.dos.model.CptStatRS; +import com.palnet.biz.jpa.repository.dos.DosFltPlanAreaQueryRepository; import com.palnet.biz.jpa.repository.dos.DosFltPlanAreaRepository; import com.palnet.biz.jpa.repository.dos.DosFltPlanBasRepository; import lombok.Getter; @@ -10,6 +11,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import java.util.List; + @Service @Slf4j @RequiredArgsConstructor @@ -19,10 +22,16 @@ public class StatisticsDosService { private final DosFltPlanAreaRepository dosFltPlanAreaRepository; + private final DosFltPlanAreaQueryRepository dosFltPlanAreaQueryRepository; + public AllStatDataRS allData() { - + + + + AllStatDataRS.GroupModel fullApproval = dosFltPlanAreaQueryRepository.allApplyData(); AllStatDataRS result = new AllStatDataRS(); + result.setFullApproval(fullApproval); return result; } @@ -30,26 +39,29 @@ public class StatisticsDosService { public CptStatRS cptStatData(CptStatRQ rq) { + + List cptList = dosFltPlanAreaQueryRepository.cptStatData(rq); + CptStatRS result = new CptStatRS(); + result.setCptList(cptList); return result; } @Getter @RequiredArgsConstructor - private enum Auth{ - + public enum CompetentAgency{ - F0001("서울지방항공청(항공운항과)"), - F0002("김포항공관리사무소(안전운항과)"), + F0002("김포항공관리사무소"), + F0001("서울지방항공청"), F0003("양양공항출장소"), F0004("원주공항출장소"), - F0005("청주공항출장소"), F0006("군산공항출장소"), - F0007("부산지방항공청(항공운항과)"), - F0008("제주지방항공청(안전운항과)"), - F0009("정석비행장"), + F0007("부산지방항공청"), F0010("울진공항출장소"), + C0001("울산공항출장소"), + C0002("여수공항출장소"), + C0003("무안공항출장소"), ; private final String desc; diff --git a/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java b/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java new file mode 100644 index 00000000..f30ab6d2 --- /dev/null +++ b/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java @@ -0,0 +1,160 @@ +package com.palnet.biz.jpa.repository.dos; + +import com.palnet.biz.api.bas.dos.model.AllStatDataRS; +import com.palnet.biz.api.bas.dos.model.CptStatRQ; +import com.palnet.biz.api.bas.dos.model.CptStatRS; +import com.palnet.biz.api.bas.dos.service.StatisticsDosService; +import com.palnet.biz.jpa.entity.QDosFltPlanArea; +import com.palnet.biz.jpa.entity.QDosFltPlanBas; +import com.palnet.comn.code.ErrorCode; +import com.palnet.comn.exception.CustomException; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.core.types.dsl.NumberTemplate; +import com.querydsl.core.types.dsl.StringTemplate; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Repository; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +@Repository +@Slf4j +@RequiredArgsConstructor +public class DosFltPlanAreaQueryRepository { + + private final JPAQueryFactory query; + + + public AllStatDataRS.GroupModel allApplyData() { + + QDosFltPlanArea qDosFltPlanArea = QDosFltPlanArea.dosFltPlanArea; + QDosFltPlanBas qDosFltPlanBas = QDosFltPlanBas.dosFltPlanBas; + + // TODO :: CPT_CD가 추가 되면 사용할 것, 가장 신청이 많은 항공청 코드를 가져와야함 +// String cptCd = ""; + + Integer year = LocalDate.now().getYear(); + Integer month = LocalDate.now().getMonth().getValue(); + + NumberTemplate yearTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN YEAR({0}) = {1} THEN 1 END)", qDosFltPlanBas.applyDt, year); + NumberTemplate monthTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN YEAR({0}) = {1} AND MONTH({2}) = {3} THEN 1 END)", qDosFltPlanBas.applyDt, year, qDosFltPlanBas.applyDt, month); + NumberTemplate todayTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN DATE({0}) = CURDATE() THEN 1 END)", qDosFltPlanBas.applyDt); + + BooleanBuilder builder = new BooleanBuilder(); +// builder.and(qDosFltPlanArea.cptCd.eq(cptCd)); + + AllStatDataRS.GroupModel groupModel = query + .select( + Projections.bean( + AllStatDataRS.GroupModel.class, + qDosFltPlanArea.count().as("all"), + yearTemplate.as("year"), + monthTemplate.as("month"), + todayTemplate.as("day") + ) + ) + .from(qDosFltPlanArea) + .leftJoin(qDosFltPlanBas) + .on(qDosFltPlanArea.planSno.eq(qDosFltPlanBas.planSno)) + .fetchOne(); + +// groupModel.setGroupName(cptCd); + + return groupModel; + } + + + public List cptStatData(CptStatRQ rq) { + + QDosFltPlanArea qDosFltPlanArea = QDosFltPlanArea.dosFltPlanArea; + QDosFltPlanBas qDosFltPlanBas = QDosFltPlanBas.dosFltPlanBas; + + StatisticsDosService.CompetentAgency[] constants = StatisticsDosService.CompetentAgency.values(); + + List cptStatList = new ArrayList<>(); + + for(StatisticsDosService.CompetentAgency competnetAgency : constants){ + + String cptCd = competnetAgency.name(); + + String format = this.getFormat(rq.getCategory()); + StringTemplate formattedDate = Expressions.stringTemplate("DATE_FORMAT({0},{1})", qDosFltPlanBas.applyDt , format); + + BooleanBuilder builder = new BooleanBuilder(); + + if(!rq.getCategory().equals("year")){ + builder.and(qDosFltPlanBas.applyDt.goe(rq.getStartDt())); + builder.and(qDosFltPlanBas.applyDt.loe(rq.getEndDt())); + } + + List countModel = query + .select( + Projections.bean( + CptStatRS.DateCountModel.class, + formattedDate.as("date"), + qDosFltPlanArea.count().as("count") + ) + ) + .from(qDosFltPlanArea) + .leftJoin(qDosFltPlanBas) + .on(qDosFltPlanArea.planSno.eq(qDosFltPlanBas.planSno)) + .where(builder) + .groupBy(formattedDate) + .fetch(); + + List coordinateModels = query + .select( + Projections.bean( + CptStatRS.CoordinateModel.class, + qDosFltPlanArea.lat.as("lat"), + qDosFltPlanArea.lon.as("lon") + ) + ) + .from(qDosFltPlanArea) + .leftJoin(qDosFltPlanBas) + .on(qDosFltPlanArea.planSno.eq(qDosFltPlanBas.planSno)) + .where(builder) + .fetch(); + + + CptStatRS.CptStat cptStatModel = new CptStatRS.CptStat(); + cptStatModel.setCptName(competnetAgency.getDesc()); + + // TODO :: CPT_CD 나오기전 임시 코드 + if(cptCd.equals("F0002")){ + cptStatModel.setCountModel(countModel); + cptStatModel.setCoordinateModels(coordinateModels); + } + + cptStatList.add(cptStatModel); + } + + return cptStatList; + } + + private String getFormat(String category){ + String format = null; + + switch (category){ + case "year": + format = "%Y"; + break; + case "month": + format = "%Y-%m"; + break; + case "day": + format = "%Y-%m-%d"; + break; + default: + throw new CustomException(ErrorCode.NON_VALID_PARAMETER); + } + + return format; + } + +} From e46a819b4c66e68c81683b1014f82278e57d06d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?lkd9125=28=EC=9D=B4=EA=B2=BD=EB=8F=84=29?= Date: Thu, 12 Sep 2024 18:36:52 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20=ED=86=B5=EA=B3=84=20=EC=83=81?= =?UTF-8?q?=EB=8B=A8=20API=20CPT=5FCD=20=EA=B5=AC=EB=B6=84=EC=9E=90=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=20=EC=B6=94=EA=B0=80,=20=ED=86=B5=EA=B3=84?= =?UTF-8?q?=20=ED=95=98=EB=8B=A8=20CPT=5FCD=20=EC=BB=AC=EB=9F=BC=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../biz/api/bas/dos/model/AllStatDataRS.java | 8 +++ .../biz/api/bas/dos/model/CptStatRS.java | 2 + .../ctr/CtrCntrlQueryRepository.java | 3 +- .../dos/DosFltPlanAreaQueryRepository.java | 61 ++++++++++++++++--- 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java index 38e641d5..979bd9ac 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java @@ -25,4 +25,12 @@ public class AllStatDataRS { private Long day; } + + @Data + public static class CptCountModel{ + private String cptName; + + private Long count; + } + } diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRS.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRS.java index e3f84d38..97807758 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRS.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRS.java @@ -16,6 +16,8 @@ public class CptStatRS { private String cptName; // 관할청 이름 + private String cptCd; + private List countModel; // 카운트 private List coordinateModels; // 중심좌표 diff --git a/pav-server/src/main/java/com/palnet/biz/jpa/repository/ctr/CtrCntrlQueryRepository.java b/pav-server/src/main/java/com/palnet/biz/jpa/repository/ctr/CtrCntrlQueryRepository.java index 1a9fa43b..056cd475 100644 --- a/pav-server/src/main/java/com/palnet/biz/jpa/repository/ctr/CtrCntrlQueryRepository.java +++ b/pav-server/src/main/java/com/palnet/biz/jpa/repository/ctr/CtrCntrlQueryRepository.java @@ -1361,7 +1361,8 @@ public class CtrCntrlQueryRepository{ .from(qCntrlBasEntity) .leftJoin(qCtrCntrHstry) .on(qCntrlBasEntity.cntrlId.eq(qCtrCntrHstry.cntrlId)) - .where(builder) .orderBy(qCtrCntrHstry.hstrySno.asc()) + .where(builder) + .orderBy(qCtrCntrHstry.hstrySno.asc()) .fetch(); return result; diff --git a/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java b/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java index f30ab6d2..554e4d6f 100644 --- a/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java +++ b/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java @@ -20,7 +20,10 @@ import org.springframework.stereotype.Repository; import java.time.LocalDate; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Repository @Slf4j @@ -35,8 +38,53 @@ public class DosFltPlanAreaQueryRepository { QDosFltPlanArea qDosFltPlanArea = QDosFltPlanArea.dosFltPlanArea; QDosFltPlanBas qDosFltPlanBas = QDosFltPlanBas.dosFltPlanBas; - // TODO :: CPT_CD가 추가 되면 사용할 것, 가장 신청이 많은 항공청 코드를 가져와야함 -// String cptCd = ""; + + + // TODO :: CPT_CD의 데이터가 없음으로 임시 F0002처리 + StringTemplate ifTemplate = Expressions.stringTemplate("CASE WHEN {0} IS NULL THEN 'F0002' ELSE {0} END", qDosFltPlanArea.cptCd); + + Map cptCountModels = query + .select( + Projections.bean( + AllStatDataRS.CptCountModel.class, + ifTemplate.as("cptName"), + qDosFltPlanArea.count().as("count") + ) + ) + .from(qDosFltPlanArea) + .groupBy(qDosFltPlanArea.cptCd) + .fetch() + .stream() + .collect(Collectors.toMap( + AllStatDataRS.CptCountModel::getCptName, + AllStatDataRS.CptCountModel::getCount + )); + + for(Map.Entry entry : cptCountModels.entrySet()){ + + String[] cptCdArray = entry.getKey().split(","); + + if(cptCdArray.length > 1) continue; + + for(String cptCd : cptCdArray){ + Long newCount = cptCountModels.get(cptCd) + entry.getValue(); + cptCountModels.put(cptCd, newCount); + } + } + + // 정렬 + Long max = -1000L; + String cptCd = ""; + + for(Map.Entry entry : cptCountModels.entrySet()){ + Long value = entry.getValue(); + + if(value > max){ + max = value; + cptCd = entry.getKey(); + } + } + Integer year = LocalDate.now().getYear(); Integer month = LocalDate.now().getMonth().getValue(); @@ -46,7 +94,7 @@ public class DosFltPlanAreaQueryRepository { NumberTemplate todayTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN DATE({0}) = CURDATE() THEN 1 END)", qDosFltPlanBas.applyDt); BooleanBuilder builder = new BooleanBuilder(); -// builder.and(qDosFltPlanArea.cptCd.eq(cptCd)); + builder.and(qDosFltPlanArea.cptCd.contains(cptCd)); AllStatDataRS.GroupModel groupModel = query .select( @@ -63,7 +111,7 @@ public class DosFltPlanAreaQueryRepository { .on(qDosFltPlanArea.planSno.eq(qDosFltPlanBas.planSno)) .fetchOne(); -// groupModel.setGroupName(cptCd); + groupModel.setGroupName(cptCd); return groupModel; } @@ -80,8 +128,6 @@ public class DosFltPlanAreaQueryRepository { for(StatisticsDosService.CompetentAgency competnetAgency : constants){ - String cptCd = competnetAgency.name(); - String format = this.getFormat(rq.getCategory()); StringTemplate formattedDate = Expressions.stringTemplate("DATE_FORMAT({0},{1})", qDosFltPlanBas.applyDt , format); @@ -124,9 +170,10 @@ public class DosFltPlanAreaQueryRepository { CptStatRS.CptStat cptStatModel = new CptStatRS.CptStat(); cptStatModel.setCptName(competnetAgency.getDesc()); + cptStatModel.setCptCd(competnetAgency.name()); // TODO :: CPT_CD 나오기전 임시 코드 - if(cptCd.equals("F0002")){ + if(competnetAgency.name().equals("F0002")){ cptStatModel.setCountModel(countModel); cptStatModel.setCoordinateModels(coordinateModels); } From ada61e90a0b4e587ae0b8d9340f75d2564764275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?lkd9125=28=EC=9D=B4=EA=B2=BD=EB=8F=84=29?= Date: Thu, 19 Sep 2024 15:02:02 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20=ED=86=B5=EA=B3=84=20=EC=83=81?= =?UTF-8?q?=EB=8B=A8,=20=ED=95=98=EB=8B=A8=20API=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/StatisticsDosController.java | 71 +++++- .../biz/api/bas/dos/model/AllStatDataRS.java | 19 +- .../biz/api/bas/dos/model/CptStatRQ.java | 4 + .../bas/dos/service/StatisticsDosService.java | 13 +- .../dos/DosFltPlanAreaQueryRepository.java | 208 +++++++++++++----- 5 files changed, 245 insertions(+), 70 deletions(-) diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java index e51888c8..b364824b 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/StatisticsDosController.java @@ -4,32 +4,95 @@ import com.palnet.biz.api.bas.dos.model.AllStatDataRS; import com.palnet.biz.api.bas.dos.model.CptStatRQ; import com.palnet.biz.api.bas.dos.model.CptStatRS; import com.palnet.biz.api.bas.dos.service.StatisticsDosService; +import com.palnet.biz.api.comn.response.ErrorResponse; +import com.palnet.biz.api.comn.response.SuccessResponse; +import com.palnet.comn.code.ErrorCode; +import com.palnet.comn.exception.CustomException; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.HashMap; +import java.util.Map; + @RestController @Slf4j @RequestMapping("/api/statistics/dos") @RequiredArgsConstructor +@Tag(name = "드론 원스톱 통계 컨트롤러", description = "드론원스톱 통계 관련 API") public class StatisticsDosController { private final StatisticsDosService statisticsDosService; - @GetMapping("/all-data") + @GetMapping("/top-data") + @Operation(summary = "통계 페이지 상단 데이터 조회", description = "가장 많은 비행승인 데이터가 들어온 관할기관 데이터를 조회합니다.") public ResponseEntity allData(){ - log.info("allData"); - AllStatDataRS result = statisticsDosService.allData(); + AllStatDataRS result = null; + + try { + result = statisticsDosService.allData(); + } catch(CustomException e){ + ErrorCode errorCode = ErrorCode.fromCode(e.getSourceErrorCode()); + String paramMessage = (String) e.getParamArray()[0]; + + Map resultMap = new HashMap<>(); + log.error("IGNORE : ", e); + resultMap.put("result", false); + resultMap.put("errorCode", errorCode.code()); + resultMap.put("errorMessage", errorCode.message()); + resultMap.put("errorDesc", paramMessage); + return ResponseEntity.ok().body(new SuccessResponse<>(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")); + } + return ResponseEntity.ok().body(result); } @GetMapping("/table-data") + @Operation(summary = "통계 페이지 테이블 데이터 조회", description = "관할 기관 별 날짜별로 데이터 건수를 조회합니다.") public ResponseEntity tableData(CptStatRQ rq){ - CptStatRS result = statisticsDosService.cptStatData(rq); + CptStatRS result = null; + + try { + result = statisticsDosService.cptStatData(rq); + } catch(CustomException e){ + ErrorCode errorCode = ErrorCode.fromCode(e.getSourceErrorCode()); + String paramMessage = (String) e.getParamArray()[0]; + + Map resultMap = new HashMap<>(); + log.error("IGNORE : ", e); + resultMap.put("result", false); + resultMap.put("errorCode", errorCode.code()); + resultMap.put("errorMessage", errorCode.message()); + resultMap.put("errorDesc", paramMessage); + return ResponseEntity.ok().body(new SuccessResponse<>(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")); + } return ResponseEntity.ok().body(result); } diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java index 979bd9ac..f72a346b 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/AllStatDataRS.java @@ -2,19 +2,22 @@ package com.palnet.biz.api.bas.dos.model; import lombok.Data; +import java.util.ArrayList; +import java.util.List; + @Data public class AllStatDataRS { - private GroupModel fullApproval; + private List fullApproval; - private GroupModel controlApproval; + private List controlApproval; - private GroupModel nonControlApproval; + private List nonControlApproval; @Data public static class GroupModel{ - private String groupName; + private List groupName; private Long all; @@ -24,13 +27,11 @@ public class AllStatDataRS { private Long day; - } + public GroupModel(){ + this.groupName = new ArrayList<>(); + } - @Data - public static class CptCountModel{ - private String cptName; - private Long count; } } diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRQ.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRQ.java index 2587be04..1e9dcd83 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRQ.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/CptStatRQ.java @@ -1,5 +1,6 @@ package com.palnet.biz.api.bas.dos.model; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.time.LocalDate; @@ -7,9 +8,12 @@ import java.time.LocalDate; @Data public class CptStatRQ { + @Schema(description = "[ year: 연도별, month: 월별, day: 일일 ] 카테고리 선택 컬럼" , example = "month") private String category; + @Schema(description = "검색 시작일자" , example = "2024-03-01") private LocalDate startDt; + @Schema(description = "검색 종료일자" , example = "2024-12-31") private LocalDate endDt; } diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java index 055607db..10cce123 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/StatisticsDosService.java @@ -18,20 +18,18 @@ import java.util.List; @RequiredArgsConstructor public class StatisticsDosService { - private final DosFltPlanBasRepository dosFltPlanBasRepository; - - private final DosFltPlanAreaRepository dosFltPlanAreaRepository; - private final DosFltPlanAreaQueryRepository dosFltPlanAreaQueryRepository; public AllStatDataRS allData() { - - - AllStatDataRS.GroupModel fullApproval = dosFltPlanAreaQueryRepository.allApplyData(); + List fullApproval = dosFltPlanAreaQueryRepository.allApplyTopData(); + List controlApproval = dosFltPlanAreaQueryRepository.controlApplyTopData(true); + List nonControlApproval = dosFltPlanAreaQueryRepository.controlApplyTopData(false); AllStatDataRS result = new AllStatDataRS(); result.setFullApproval(fullApproval); + result.setControlApproval(controlApproval); + result.setNonControlApproval(nonControlApproval); return result; } @@ -68,5 +66,4 @@ public class StatisticsDosService { } - } diff --git a/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java b/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java index 554e4d6f..c3df98a8 100644 --- a/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java +++ b/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanAreaQueryRepository.java @@ -10,19 +10,15 @@ import com.palnet.comn.code.ErrorCode; import com.palnet.comn.exception.CustomException; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.types.Projections; -import com.querydsl.core.types.dsl.Expressions; -import com.querydsl.core.types.dsl.NumberTemplate; -import com.querydsl.core.types.dsl.StringTemplate; +import com.querydsl.core.types.dsl.*; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Repository; import java.time.LocalDate; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @Repository @@ -33,58 +29,73 @@ public class DosFltPlanAreaQueryRepository { private final JPAQueryFactory query; - public AllStatDataRS.GroupModel allApplyData() { + /** + * 총 데이터 조회 + * @return + */ + public List allApplyTopData() { QDosFltPlanArea qDosFltPlanArea = QDosFltPlanArea.dosFltPlanArea; QDosFltPlanBas qDosFltPlanBas = QDosFltPlanBas.dosFltPlanBas; + Integer year = LocalDate.now().getYear(); + Integer month = LocalDate.now().getMonth().getValue(); + NumberTemplate yearTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN YEAR({0}) = {1} THEN 1 END)", qDosFltPlanBas.applyDt, year); + NumberTemplate monthTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN YEAR({0}) = {1} AND MONTH({2}) = {3} THEN 1 END)", qDosFltPlanBas.applyDt, year, qDosFltPlanBas.applyDt, month); + NumberTemplate todayTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN DATE({0}) = CURDATE() THEN 1 END)", qDosFltPlanBas.applyDt); - // TODO :: CPT_CD의 데이터가 없음으로 임시 F0002처리 - StringTemplate ifTemplate = Expressions.stringTemplate("CASE WHEN {0} IS NULL THEN 'F0002' ELSE {0} END", qDosFltPlanArea.cptCd); + BooleanBuilder builder = new BooleanBuilder(); + builder.and(Expressions.booleanTemplate("{0} IS NOT NULL", qDosFltPlanArea.cptCd)); - Map cptCountModels = query + Map groupModel = query .select( - Projections.bean( - AllStatDataRS.CptCountModel.class, - ifTemplate.as("cptName"), - qDosFltPlanArea.count().as("count") - ) + Projections.bean( + AllStatDataRS.GroupModel.class, + qDosFltPlanArea.cptCd.as("groupName"), + qDosFltPlanArea.count().as("all"), + yearTemplate.as("year"), + monthTemplate.as("month"), + todayTemplate.as("day") + ) ) .from(qDosFltPlanArea) + .leftJoin(qDosFltPlanBas) + .on(qDosFltPlanArea.planSno.eq(qDosFltPlanBas.planSno)) + .where(builder) .groupBy(qDosFltPlanArea.cptCd) .fetch() .stream() .collect(Collectors.toMap( - AllStatDataRS.CptCountModel::getCptName, - AllStatDataRS.CptCountModel::getCount - )); - - for(Map.Entry entry : cptCountModels.entrySet()){ + key -> { - String[] cptCdArray = entry.getKey().split(","); + if(key.getGroupName() == null) return ""; - if(cptCdArray.length > 1) continue; + StringBuilder result = new StringBuilder(); - for(String cptCd : cptCdArray){ - Long newCount = cptCountModels.get(cptCd) + entry.getValue(); - cptCountModels.put(cptCd, newCount); - } - } + key.getGroupName().forEach(node -> { + result.append(node); + result.append(","); + }); - // 정렬 - Long max = -1000L; - String cptCd = ""; + result.deleteCharAt(result.length() - 1); - for(Map.Entry entry : cptCountModels.entrySet()){ - Long value = entry.getValue(); + return result.toString(); + }, + value -> value + )); - if(value > max){ - max = value; - cptCd = entry.getKey(); - } - } + return this.topDataParsing(groupModel); + } + /** + * 관제, 비관제 데이터 조회 + * @param controlFlag TRUE : 관제권 조회, FALSE : 비 관제권 조회 + * @return + */ + public List controlApplyTopData(Boolean controlFlag) { + QDosFltPlanArea qDosFltPlanArea = QDosFltPlanArea.dosFltPlanArea; + QDosFltPlanBas qDosFltPlanBas = QDosFltPlanBas.dosFltPlanBas; Integer year = LocalDate.now().getYear(); Integer month = LocalDate.now().getMonth().getValue(); @@ -93,13 +104,23 @@ public class DosFltPlanAreaQueryRepository { NumberTemplate monthTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN YEAR({0}) = {1} AND MONTH({2}) = {3} THEN 1 END)", qDosFltPlanBas.applyDt, year, qDosFltPlanBas.applyDt, month); NumberTemplate todayTemplate = Expressions.numberTemplate(Long.class, "COUNT(CASE WHEN DATE({0}) = CURDATE() THEN 1 END)", qDosFltPlanBas.applyDt); + ListPath groupingColumn = null; BooleanBuilder builder = new BooleanBuilder(); - builder.and(qDosFltPlanArea.cptCd.contains(cptCd)); + builder.and(Expressions.booleanTemplate("{0} IS NOT NULL", qDosFltPlanArea.cptCd)); + + if(controlFlag){ + builder.and(Expressions.booleanTemplate("{0} IS NOT NULL", qDosFltPlanArea.innerCptCd)); + groupingColumn = qDosFltPlanArea.innerCptCd; + } else { + builder.and(Expressions.booleanTemplate("{0} IS NULL", qDosFltPlanArea.innerCptCd)); + groupingColumn = qDosFltPlanArea.cptCd; + } - AllStatDataRS.GroupModel groupModel = query + Map groupModel = query .select( Projections.bean( AllStatDataRS.GroupModel.class, + groupingColumn.as("groupName"), qDosFltPlanArea.count().as("all"), yearTemplate.as("year"), monthTemplate.as("month"), @@ -109,14 +130,37 @@ public class DosFltPlanAreaQueryRepository { .from(qDosFltPlanArea) .leftJoin(qDosFltPlanBas) .on(qDosFltPlanArea.planSno.eq(qDosFltPlanBas.planSno)) - .fetchOne(); + .where(builder) + .groupBy(groupingColumn) + .fetch() + .stream() + .collect(Collectors.toMap( + key -> { + if(key.getGroupName() == null) return ""; + + StringBuilder result = new StringBuilder(); + + key.getGroupName().forEach(node -> { + result.append(node); + result.append(","); + }); + + result.deleteCharAt(result.length() - 1); - groupModel.setGroupName(cptCd); + return result.toString(); + }, + value -> value + )); - return groupModel; + return this.topDataParsing(groupModel); } + /** + * 공항별 데이터 통계 + * @param rq + * @return + */ public List cptStatData(CptStatRQ rq) { QDosFltPlanArea qDosFltPlanArea = QDosFltPlanArea.dosFltPlanArea; @@ -131,7 +175,10 @@ public class DosFltPlanAreaQueryRepository { String format = this.getFormat(rq.getCategory()); StringTemplate formattedDate = Expressions.stringTemplate("DATE_FORMAT({0},{1})", qDosFltPlanBas.applyDt , format); + String cptCd = competnetAgency.name(); + BooleanBuilder builder = new BooleanBuilder(); + builder.and(Expressions.booleanTemplate("{0} LIKE CONCAT('%', {1}, '%')", qDosFltPlanArea.cptCd, cptCd)); if(!rq.getCategory().equals("year")){ builder.and(qDosFltPlanBas.applyDt.goe(rq.getStartDt())); @@ -171,12 +218,8 @@ public class DosFltPlanAreaQueryRepository { CptStatRS.CptStat cptStatModel = new CptStatRS.CptStat(); cptStatModel.setCptName(competnetAgency.getDesc()); cptStatModel.setCptCd(competnetAgency.name()); - - // TODO :: CPT_CD 나오기전 임시 코드 - if(competnetAgency.name().equals("F0002")){ - cptStatModel.setCountModel(countModel); - cptStatModel.setCoordinateModels(coordinateModels); - } + cptStatModel.setCountModel(countModel); + cptStatModel.setCoordinateModels(coordinateModels); cptStatList.add(cptStatModel); } @@ -184,6 +227,72 @@ public class DosFltPlanAreaQueryRepository { return cptStatList; } + + private List topDataParsing(Map groupModel){ + Map currentMap = new ConcurrentHashMap<>(groupModel); + + // CptCd가 한 개가 아닌 값들에 대한 로직 + for(Map.Entry entry : currentMap.entrySet()){ + + String[] cptCdArray = entry.getKey().split(","); + + // CptCd가 1개일 경우 continue + if(cptCdArray.length <= 1) continue; + + for(String cptCd : cptCdArray){ + + // 기존 Map에 없는 값일 경우 CptCd를 Key로 새로 만들어 put + if(currentMap.get(cptCd) == null){ + AllStatDataRS.GroupModel node = new AllStatDataRS.GroupModel(); + node.setGroupName(Collections.singletonList(cptCd)); + node.setAll(entry.getValue().getAll()); + node.setYear(entry.getValue().getYear()); + node.setMonth(entry.getValue().getMonth()); + node.setDay(entry.getValue().getDay()); + + currentMap.put(cptCd, node); + continue; + } + + // 기존 값이 있을 경우 객체를 새로운 메모리에 할당하여 put + AllStatDataRS.GroupModel node = new AllStatDataRS.GroupModel(); + node.setGroupName(Collections.singletonList(cptCd)); + node.setAll(currentMap.get(cptCd).getAll() + entry.getValue().getAll()); + node.setYear(currentMap.get(cptCd).getYear() + entry.getValue().getYear()); + node.setMonth(currentMap.get(cptCd).getMonth() + entry.getValue().getMonth()); + node.setDay(currentMap.get(cptCd).getDay() + entry.getValue().getDay()); + + currentMap.put(cptCd, node); + } + + currentMap.remove(entry.getKey()); + } + + // Key의 맞는 GroupName Set + currentMap.forEach((key, value) -> { + value.setGroupName(Collections.singletonList(key)); + }); + + // 총 카운트가 가장많은 값 추출 + Long max = currentMap.values().stream() + .mapToLong(AllStatDataRS.GroupModel::getAll) + .max() + .orElse(0); + + List result = new ArrayList<>(); + + // 가장 많은 값만 반환 리스트에 ADD + for(Map.Entry entry : currentMap.entrySet()){ + if(entry.getValue().getAll().equals(max)){ + result.add(entry.getValue()); + } + } + + if(result.isEmpty()) result.add(new AllStatDataRS.GroupModel()); + + return result; + } + private String getFormat(String category){ String format = null; @@ -204,4 +313,5 @@ public class DosFltPlanAreaQueryRepository { return format; } + }