diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/BasDosController.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/BasDosController.java index 08f573f0..08ef2eb4 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/BasDosController.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/controller/BasDosController.java @@ -2,6 +2,7 @@ package com.palnet.biz.api.bas.dos.controller; import com.palnet.biz.api.bas.dos.model.*; import com.palnet.biz.api.bas.dos.service.BasDosService; +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.tags.Tag; @@ -10,7 +11,9 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Slf4j @RequiredArgsConstructor @@ -25,7 +28,7 @@ public class BasDosController { /** * 비행계획 조회 * - * @param rq + * @param rq 비행승인 계획 요청 RQ, 승인날짜 범위, 지역이름 등.. * @return */ @GetMapping("/plan") @@ -34,6 +37,33 @@ public class BasDosController { return ResponseEntity.ok(rs); } + /** + * 비행계획 조회 [페이징] + * + * @param rq + * @return + */ + @GetMapping("/plan/paging") + public ResponseEntity getPagingDosPlan(SearchBasDosPlanRQ rq) { + SearchBasDosPlanRS rs = null; + try { + rs = basDosService.getPagingDosPlan(rq, PlanSelectType.LIST); + } 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)); + } + + return ResponseEntity.ok(rs); + } + /** * 비행계획 수정 * diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/BasDosPlanDroneRs.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/BasDosPlanDroneRs.java index 1925b5cd..cdf446e8 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/BasDosPlanDroneRs.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/BasDosPlanDroneRs.java @@ -1,5 +1,6 @@ package com.palnet.biz.api.bas.dos.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -22,4 +23,7 @@ public class BasDosPlanDroneRs { private String weightNm; // 가입여부 private String insrncJoinYn; + // planSno + @JsonIgnore + private Long planSno; } diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/BasDosPlanPilotRs.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/BasDosPlanPilotRs.java index 02f8340c..9e470026 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/BasDosPlanPilotRs.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/BasDosPlanPilotRs.java @@ -1,5 +1,6 @@ package com.palnet.biz.api.bas.dos.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -18,4 +19,7 @@ public class BasDosPlanPilotRs { private String birthDate; // 조종사 자격번호 private String crtfctNo; + + @JsonIgnore + private Long planSno; } diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/Pagination.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/Pagination.java new file mode 100644 index 00000000..57982399 --- /dev/null +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/Pagination.java @@ -0,0 +1,13 @@ +package com.palnet.biz.api.bas.dos.model; + +import lombok.Data; + +@Data +public class Pagination { + private Long totalDataCount; // 전체데이터 + private Long totalPages; // 나올 수 있는 페이지 갯수 + private Long currentPage; // 현재 페이지 [RQ로 수급] + private Long pageDataSize; // 페이지당 데이터 갯수 [RQ로 수급] + private Boolean isFirst; // 첫번째 페이지인지 여부 + private Boolean isLast; // 마지막 페이지인지 여부 +} diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/SearchBasDosPlanRQ.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/SearchBasDosPlanRQ.java new file mode 100644 index 00000000..f0be4fae --- /dev/null +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/SearchBasDosPlanRQ.java @@ -0,0 +1,47 @@ +package com.palnet.biz.api.bas.dos.model; + +import com.palnet.biz.jpa.entity.type.ReviewedProcType; +import com.palnet.biz.jpa.entity.type.ReviewedType; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDate; + +@Data +public class SearchBasDosPlanRQ { + @Schema(description = "검색시작일자", example = "2024-06-01", implementation = LocalDate.class) + private LocalDate searchStDt; + + @Schema(description = "검색끝일자", example = "2024-06-30", implementation = LocalDate.class) + private LocalDate searchEndDt; + + @Schema(description = "문서번호", example = "201118-1010", implementation = String.class) + private String applyNo; + + @Schema(description = "승인코드", example = "S", implementation = String.class) + private String approvalCd; + + @Schema(description = "바운더리", example = "GIMPO", implementation = String.class) + private String selectZone; + + @Schema(description = "시/구 주소", example = "인천광역시", implementation = String.class) + private String ctprvn; + + @Schema(description = "시/군/구 주소", example = "남동구", implementation = String.class) + private String sig; + + @Schema(description = "상세주소", example = "만수동", implementation = String.class) + private String address; + + @Schema(description = "검토유형(운항과)", example = "W", implementation = ReviewedType.class) + private ReviewedType reviewedType; + + @Schema(description = "검토유형(관제과)", example = "W", implementation = ReviewedProcType.class) + private ReviewedProcType reviewedProcType; + + @Schema(description = "페이지번호 [Default : 1]", example = "1", implementation = Integer.class) + private Long page = 1L; + + @Schema(description = "페이지당 데이터 갯수 [Default : 10]", example = "10", implementation = Integer.class) + private Long pageDataSize = 10L; +} diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/SearchBasDosPlanRS.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/SearchBasDosPlanRS.java new file mode 100644 index 00000000..90de82d2 --- /dev/null +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/model/SearchBasDosPlanRS.java @@ -0,0 +1,14 @@ +package com.palnet.biz.api.bas.dos.model; + +import lombok.Data; + +import java.util.List; + +@Data +public class SearchBasDosPlanRS { + + private List content; + + private Pagination pagination; + +} diff --git a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/BasDosService.java b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/BasDosService.java index 63c00df8..909c02ca 100644 --- a/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/BasDosService.java +++ b/pav-server/src/main/java/com/palnet/biz/api/bas/dos/service/BasDosService.java @@ -15,6 +15,7 @@ import com.palnet.biz.api.external.model.DosApprovalResult; import com.palnet.biz.api.external.service.DronOneStopService; import com.palnet.biz.jpa.entity.DosFltPlanArea; import com.palnet.biz.jpa.entity.DosFltPlanBas; +import com.palnet.biz.jpa.entity.DosFltPlanDrone; import com.palnet.biz.jpa.entity.DosFltPlanResult; import com.palnet.biz.jpa.entity.type.ReviewedProcType; import com.palnet.biz.jpa.entity.type.ReviewedType; @@ -53,6 +54,7 @@ import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletResponse; import java.io.*; +import java.lang.reflect.Field; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.time.Instant; @@ -129,9 +131,10 @@ public class BasDosService { } - + // 비행지역 List areaRsList = new ArrayList<>(); + // area 객체를 for (DosFltPlanArea area : areaList) { if (area.getPlanSno().equals(planSno)) { Optional first = resultList.stream().filter(result -> result.getPlanAreaSno().equals(area.getPlanAreaSno())).findFirst(); @@ -143,6 +146,11 @@ public class BasDosService { fltElevMax = dosFltPlanResult.getFltElevMax(); } + /** + * 1. 요청코드가 있을경우 [검색조건] + * 2. 조회할 area의 승인코드 있을경우 + * 3. 요청코드와 조회한 area의 승인코드가 맞지 않을경우 continue + */ if (rq.getApprovalCd() != null && approvalCd != null && !rq.getApprovalCd().equals(approvalCd.getCode())) { continue; } @@ -175,6 +183,7 @@ public class BasDosService { }); if (!isContain) continue; } else if ("DF0002-1".equals(cptAuthCode)) { + // 운항과는 전체건수 조회 /* // TODO 운항과(김항소 관리 전역) if(boundary == null) { @@ -204,12 +213,15 @@ public class BasDosService { .geometry(rqGeometry) .build(); boolean isDuplicatedAirspace = airspaceUtils.isDuplicatedAirspace(targetfeatureInfo, AirspaceUtils.AirspaceType.GIMPO); + + // 지역과 공역이 중복되지 않는다면 continue if (!isDuplicatedAirspace) { continue; } } bufferCoordList = coordBuffers.stream().map(coord -> Map.of("lat", coord.y, "lon", coord.x)).collect(Collectors.toList()); if (area.getReqRadius() != null && area.getReqRadius() > 0) { + // 승인요청 지역 바운더리 좌표 List reqCoordBuffers = areaUtils.createCircle(new Coordinate(area.getLon(), area.getLat()), area.getReqRadius()); reqBufferCoordList = reqCoordBuffers.stream().map(coord -> Map.of("lat", coord.y, "lon", coord.x)).collect(Collectors.toList()); } @@ -959,4 +971,364 @@ public class BasDosService { } } + /** + * 페이징처리 + * @param rq + * @param type + * @return + */ + @Transactional(readOnly = true) + public SearchBasDosPlanRS getPagingDosPlan(SearchBasDosPlanRQ rq, PlanSelectType type){ + List planBasList = dosFltPlanQueryRepository.findPlanByBasSearch(rq); + + if (planBasList.isEmpty()) { + return null; + } + + List planSnoList = planBasList.stream().map(DosFltPlanBas::getPlanSno).collect(Collectors.toList()); + + Long totalDataCount = dosFltPlanQueryRepository.countByPlanSnoInAndSearchOrderByZoneNoAsc(planSnoList, rq); + Long totalPages = totalDataCount / rq.getPageDataSize(); + + if(totalDataCount % rq.getPageDataSize() > 0) totalPages ++; + + if(rq.getPage() > totalPages || rq.getPage() < 1) throw new CustomException(ErrorCode.NON_VALID_PARAMETER, String.format("페이지는 [ %s ] page 부터 [ %s ] page 까지입니다.", 1, totalPages)); + + Boolean isFirst = rq.getPage() == 1; + Boolean isLast = rq.getPage().equals(totalPages); + + Pagination pagination = new Pagination(); + pagination.setTotalDataCount(totalDataCount); + pagination.setTotalPages(totalPages); + pagination.setCurrentPage(rq.getPage()); + pagination.setPageDataSize(rq.getPageDataSize()); + pagination.setIsFirst(isFirst); + pagination.setIsLast(isLast); + + Map fltPlanBasMap = this.getConvertMap(planBasList, "planSno", Long.class); + Map> fltDroneBasMap = dosFltPlanDroneRepository.findByPlanSnoIn(planSnoList).stream() + .map(drone -> { + String weightCd = drone.getWeightCd(); + WeightCdType weightCdType = WeightCdType.fromCode(weightCd); + return BasDosPlanDroneRs.builder() + .planDroneSno(drone.getPlanDroneSno()) + .fbctnNo(drone.getFbctnNo()) + .benefit(drone.getBenefit()) + .weightCd(drone.getWeightCd()) + .weightNm(weightCdType != null ? weightCdType.getMessage() : null) + .insrncJoinYn(drone.getInsrncJoinYn()) + .planSno(drone.getPlanSno()) + .build(); + }) + .collect(Collectors.groupingBy(BasDosPlanDroneRs::getPlanSno));; + + Map> fltPliotBasMap = dosFltPlanPilotRepository.findByPlanSnoIn(planSnoList).stream() + .map(pilot -> { + return BasDosPlanPilotRs.builder() + .planPilotSno(pilot.getPlanPilotSno()) + .pilotNm(pilot.getPilotNm()) + .birthDate(pilot.getBirthDate()) + .crtfctNo(pilot.getCrtfctNo()) + .planSno(pilot.getPlanPilotSno()) + .build(); + }) + .collect(Collectors.groupingBy(BasDosPlanPilotRs::getPlanSno)); + + List areaList = dosFltPlanQueryRepository.findByPlanSnoInAndSearchOrderByZoneNoAsc(planSnoList, rq); + List resultList = dosFltPlanResultRepository.findByPlanSnoIn(planSnoList); + + Set areaPlanSno = areaList.stream().map(DosFltPlanArea::getPlanSno).collect(Collectors.toSet()); + Set removePlanSnoSet = new HashSet<>(planSnoList); + removePlanSnoSet.removeAll(areaPlanSno); + + List removeList = new ArrayList<>(removePlanSnoSet); + for(Long removePlanSno : removeList){ + fltPlanBasMap.remove(removePlanSno); + } + + List rs = new ArrayList<>(); + List boundary = null; + + Map sortedMap = fltPlanBasMap.entrySet().stream() + .sorted((e1, e2) -> { + int cmp = e2.getValue().getApplyDt().compareTo(e1.getValue().getApplyDt()); + if (cmp == 0) { + return e2.getValue().getApplyNo().compareTo(e1.getValue().getApplyNo()); + } + return cmp; + }) + .collect(Collectors.toMap( + Map.Entry::getKey, + Map.Entry::getValue, + (e1, e2) -> e1, + LinkedHashMap::new + )); + + for(Map.Entry entry : sortedMap.entrySet()){ + Long planSno = entry.getKey(); + DosFltPlanBas bas = entry.getValue(); + + String applyNo = bas.getApplyNo(); + + // 신청일시 분할 + LocalDate applyDt = bas.getApplyDt(); + String applyDtMonth = String.valueOf(applyDt.getMonthValue()); + String applyDtDay = String.valueOf(applyDt.getDayOfMonth()); + + // 비행목적 - 비행목적은 레저비행, 사진/영상촬영을 제외한 나머지 목적은 기타 로 표현 + String purpose = "기타"; + String[] purposeTexts = {"레저비행", "사진/영상촬영"}; + + if (StringUtils.hasText(bas.getPurpose())) { + purpose = Arrays.asList(purposeTexts).contains(bas.getPurpose()) ? bas.getPurpose() : "기타"; + } + + List areaRsList = new ArrayList<>(); + + for (int i = 0; i < areaList.size(); i ++) { + + DosFltPlanArea area = areaList.get(i); + +// TOOD :: 추후 리스트를 삭제하며 돌 수 있도록 수정 필요 +// Boolean addResult = false; + + if (area.getPlanSno().equals(planSno)) { + Optional first = resultList.stream().filter(result -> result.getPlanAreaSno().equals(area.getPlanAreaSno())).findFirst(); + ApprovalCd approvalCd = null; + Double fltElevMax = null; + if (first.isPresent()) { + DosFltPlanResult dosFltPlanResult = first.get(); + approvalCd = ApprovalCd.fromCode(dosFltPlanResult.getApprovalCd()); + fltElevMax = dosFltPlanResult.getFltElevMax(); + } + + /** + * 1. 요청코드가 있을경우 [검색조건] + * 2. 조회할 area의 승인코드 있을경우 + * 3. 요청코드와 조회한 area의 승인코드가 맞지 않을경우 continue + */ + if (rq.getApprovalCd() != null && approvalCd != null && !rq.getApprovalCd().equals(approvalCd.getCode())) { + continue; + } + + // ReviewedType이 UNNECESSARY(불필요)인 경우 ApprovalCd가 UNTARGETED_AREA(비대상)인 경우만 조회 + if (rq.getReviewedType() == ReviewedType.UNNECESSARY) { + if (approvalCd != ApprovalCd.UNTARGETED_AREA) { + continue; + } + } + + // 사용자 부서에 따른 필터 관제과(DF0002), 운항과(DF0002-1) + String cptAuthCode = jwtTokenUtil.getCptAuthCodeByToken(); + if (cptAuthCode != null) { + Coordinate centerPoint = new Coordinate(area.getLon(), area.getLat()); + if ("DF0002".equals(cptAuthCode)) { + // 관제과와 관련된 내용으로만 필터링 reviewedProcType이 null이 아니라면 표출 + if (area.getReviewedProcType() == null) { + continue; + } + + // 관제과(9.3km) + AirspaceUtils airspaceUtils = AirspaceUtils.getInstance(); + List airspaces = airspaceUtils.getAirspaces(AirspaceUtils.AirspaceType.GIMPO); + GeometryFactory geometryFactory = new GeometryFactory(); + Point point = geometryFactory.createPoint(centerPoint); + boolean isContain = airspaces.stream().anyMatch(airspace -> { + Geometry airspaceGeometry = airspace.getGeometry(); + return airspaceGeometry.contains(point); + }); + if (!isContain) continue; + } else if ("DF0002-1".equals(cptAuthCode)) { + // 운항과는 전체건수 조회 + /* + // TODO 운항과(김항소 관리 전역) + if(boundary == null) { + boundary = comnCoordinateService.getDeptGeometry("F0002"); + } + // log.info("boundary : {}", boundary); + GeometryFactory geometryFactory = new GeometryFactory(); + Point point = geometryFactory.createPoint(centerPoint); + boolean isContain = boundary.stream().anyMatch(geometry -> geometry.contains(point)); + if(!isContain) continue; + */ + + } + } + + List> bufferCoordList = null; + List> reqBufferCoordList = null; + if (type == PlanSelectType.LIST) { + List coordBuffers = areaUtils.createCircle(new Coordinate(area.getLon(), area.getLat()), area.getBufferZone()); + if ("GIMPO".equalsIgnoreCase(rq.getSelectZone())) { + AirspaceUtils airspaceUtils = AirspaceUtils.getInstance(); + Geometry rqGeometry = airspaceUtils.createGeometryByCoordinate(coordBuffers); + + AirspaceUtils.FeatureInfo targetfeatureInfo = AirspaceUtils.FeatureInfo.builder() + .lowElev(0D) + .highElev(area.getFltElev()) + .geometry(rqGeometry) + .build(); + boolean isDuplicatedAirspace = airspaceUtils.isDuplicatedAirspace(targetfeatureInfo, AirspaceUtils.AirspaceType.GIMPO); + + // 지역과 공역이 중복되지 않는다면 continue + if (!isDuplicatedAirspace) { + continue; + } + } + bufferCoordList = coordBuffers.stream().map(coord -> Map.of("lat", coord.y, "lon", coord.x)).collect(Collectors.toList()); + if (area.getReqRadius() != null && area.getReqRadius() > 0) { + // 승인요청 지역 바운더리 좌표 + List reqCoordBuffers = areaUtils.createCircle(new Coordinate(area.getLon(), area.getLat()), area.getReqRadius()); + reqBufferCoordList = reqCoordBuffers.stream().map(coord -> Map.of("lat", coord.y, "lon", coord.x)).collect(Collectors.toList()); + } + + + } + + // TODO 추후 Utils 생성 + // 주소 분할 - 임시 순서대로 split + String addr = area.getAddr() != null ? area.getAddr() : ""; + String[] addrArr = addr.split(" "); + String addr1 = ""; + String addr2 = ""; + StringBuilder addrRest = new StringBuilder(); + for (int j = 0; j < addrArr.length; j++) { + switch (j) { + case 0: + addr1 = addrArr[j]; + break; + case 1: + addr2 = addrArr[j]; + break; + case 2: + addrRest.append(addrArr[j]); + break; + default: + addrRest.append(" ").append(addrArr[j]); + break; + } + } + + String addr3 = addrRest.toString(); + String limitZone = area.getLimitZone(); + LimitZoneType limitZoneType = LimitZoneType.fromCode(limitZone); + + ReviewedType reviewedType = area.getReviewedType(); + if (reviewedType == null) { + reviewedType = approvalCd == ApprovalCd.UNTARGETED_AREA ? ReviewedType.UNNECESSARY : ReviewedType.WAIT; + } + + + BasDosPlanAreaRs areaRs = BasDosPlanAreaRs.builder() + .planAreaSno(area.getPlanAreaSno()) + .planSno(area.getPlanSno()) + .applyNo(applyNo) + .applyDt(applyDt) + .applyDtMonth(applyDtMonth) + .applyDtDay(applyDtDay) + .zoneNo(area.getZoneNo()) + .bufferZone(area.getBufferZone()) + .fltElev(area.getFltElev()) + .lat(area.getLat()) + .lon(area.getLon()) + .addr(addr) + .addr1(addr1) + .addr2(addr2) + .addr3(addr3) + .approvalCd(approvalCd != null ? approvalCd.getCode() : null) + .fltElevMax(fltElevMax) + .reqElev(area.getReqElev()) + .dtl(area.getDtl()) + .era(area.getEra()) + .rm(area.getRm()) + .reviewedType(reviewedType) + .reviewedReason(area.getReviewedReason()) + .reviewedProcType(area.getReviewedProcType()) + .reqRadius(area.getReqRadius()) + .allowRadius(area.getAllowRadius()) + .limitZoneCd(area.getLimitZone()) + .limitZoneNm(limitZoneType != null ? limitZoneType.getMessage() : null) + .bufferCoordList(bufferCoordList) + .reqBufferCoordList(reqBufferCoordList) + .build(); +// addResult = + areaRsList.add(areaRs); + } +// if(addResult) areaList.remove(i); + } + + // TODO :: 속도이슈 걸리는 곳.. [paging 하면 완화됨] + List droneList = null; + List pilotList = null; + if (type == PlanSelectType.LIST) { + droneList = fltDroneBasMap.get(planSno); + pilotList = fltPliotBasMap.get(planSno); + } + + + BasDosPlanRs basRs = BasDosPlanRs.builder() + .planSno(bas.getPlanSno()) + .applyNo(bas.getApplyNo()) + .applyDt(applyDt) + .applyDtMonth(applyDtMonth) + .applyDtDay(applyDtDay) + .applyNm(bas.getApplyNm()) + .schFltStDt(bas.getSchFltStDt()) + .schFltEndDt(bas.getSchFltEndDt()) + .purpose(purpose) + .updateDt(bas.getUpdateDt()) + .createDt(bas.getCreateDt()) + .areaList(areaRsList) + .droneList(droneList) + .pilotList(pilotList) + .build(); + rs.add(basRs); + + } + + int count = 0; + + for(int i = 0; i < rs.size(); i ++){ + BasDosPlanRs rsNode = rs.get(i); + + count += rsNode.getAreaList().size(); + } + + SearchBasDosPlanRS result = new SearchBasDosPlanRS(); + result.setContent(rs); + result.setPagination(pagination); + + return result; + } + + /** + * List 노드객체의 컬럼중 하나를 Key값으로 잡아 Map을 만듬 + * EX -> PlanBas의 planSno를 키값으로 잡아 Map 형태로 변환 + * @param list Map으로 바꿀 리스트 + * @param fieldName Map의 key가 될 컬럼 이름 + * @param keyType Map의 key가 될 클래스 타입 + * @return + * @param

+ * @param + * @param + */ + private , C> Map getConvertMap(B list, String fieldName, Class

keyType) { + Map result = new HashMap<>(); + + try { + for (C node : list) { + Field field = node.getClass().getDeclaredField(fieldName); + field.setAccessible(true); // private 필드 접근 허용 + + P key = keyType.cast(field.get(node)); + + result.put(key, node); + } + } catch (IllegalAccessException | NoSuchFieldException | SecurityException e) { + log.error("", e); + } + + return result; + } + } diff --git a/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanDroneRepository.java b/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanDroneRepository.java index 72bf8867..02d10f07 100644 --- a/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanDroneRepository.java +++ b/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanDroneRepository.java @@ -9,4 +9,6 @@ import java.util.List; @Repository public interface DosFltPlanDroneRepository extends JpaRepository { List findByPlanSno(Long planSno); + + List findByPlanSnoIn(List planSnot); } diff --git a/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanPilotRepository.java b/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanPilotRepository.java index f93dfb8d..c95721ae 100644 --- a/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanPilotRepository.java +++ b/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanPilotRepository.java @@ -9,4 +9,6 @@ import java.util.List; @Repository public interface DosFltPlanPilotRepository extends JpaRepository { List findByPlanSno(Long planSno); + + List findByPlanSnoIn (List planSno); } diff --git a/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanQueryRepository.java b/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanQueryRepository.java index 73c9b689..cc8c5dfe 100644 --- a/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanQueryRepository.java +++ b/pav-server/src/main/java/com/palnet/biz/jpa/repository/dos/DosFltPlanQueryRepository.java @@ -1,6 +1,7 @@ package com.palnet.biz.jpa.repository.dos; import com.palnet.biz.api.bas.dos.model.BasDosPlanRq; +import com.palnet.biz.api.bas.dos.model.SearchBasDosPlanRQ; import com.palnet.biz.jpa.entity.DosFltPlanArea; import com.palnet.biz.jpa.entity.DosFltPlanBas; import com.palnet.biz.jpa.entity.QDosFltPlanArea; @@ -12,6 +13,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Repository; import org.springframework.util.StringUtils; +import java.util.LinkedList; import java.util.List; @Slf4j @@ -105,4 +107,129 @@ public class DosFltPlanQueryRepository { .fetch(); } + + public List findByPlanSnoInAndSearchOrderByZoneNoAsc(List planSno, SearchBasDosPlanRQ rq) { + QDosFltPlanBas qDosFltPlanBas = QDosFltPlanBas.dosFltPlanBas; + QDosFltPlanArea qDosFltPlanArea = QDosFltPlanArea.dosFltPlanArea; + short idx = 0; + + long offset = (rq.getPage() - 1) * rq.getPageDataSize(); + long limit = rq.getPageDataSize(); + + StringBuilder districtAddr = new StringBuilder(); + if (rq.getCtprvn() != null && !rq.getCtprvn().isBlank()) { + districtAddr.append(rq.getCtprvn()); + idx++; + } + if (rq.getSig() != null && !rq.getSig().isBlank()) { + if (idx > 0) districtAddr.append(" "); + districtAddr.append(rq.getSig()); + } + + BooleanBuilder builder = new BooleanBuilder(); + builder.and(qDosFltPlanArea.planSno.in(planSno)); + + if (!districtAddr.toString().isBlank()) { + builder.and(qDosFltPlanArea.addr.like("%" + districtAddr.toString() + "%")); + } + if (rq.getAddress() != null && !rq.getAddress().isEmpty()) { + builder.and(qDosFltPlanArea.addr.like("%" + rq.getAddress() + "%")); + } + + // 검토 결과 - W일 경우 W, null 모두 조회(null == W) + if (rq.getReviewedType() != null) { + builder.and(qDosFltPlanArea.reviewedType.eq(rq.getReviewedType()).or(qDosFltPlanArea.reviewedType.isNull())); + } + + return new LinkedList<>(query + .select(qDosFltPlanArea) + .from(qDosFltPlanArea) + .leftJoin(qDosFltPlanBas) + .on(qDosFltPlanBas.planSno.eq(qDosFltPlanArea.planSno)) + .where(builder) + .orderBy(qDosFltPlanBas.applyDt.desc(), qDosFltPlanBas.applyNo.desc(), qDosFltPlanArea.zoneNo.asc()) + .limit(limit) + .offset(offset) + .fetch()); + } + + public Long countByPlanSnoInAndSearchOrderByZoneNoAsc(List planSno, SearchBasDosPlanRQ rq) { + QDosFltPlanArea qDosFltPlanArea = QDosFltPlanArea.dosFltPlanArea; + short idx = 0; + + StringBuilder districtAddr = new StringBuilder(); + if (rq.getCtprvn() != null && !rq.getCtprvn().isBlank()) { + districtAddr.append(rq.getCtprvn()); + idx++; + } + if (rq.getSig() != null && !rq.getSig().isBlank()) { + if (idx > 0) districtAddr.append(" "); + districtAddr.append(rq.getSig()); + } + + BooleanBuilder builder = new BooleanBuilder(); + builder.and(qDosFltPlanArea.planSno.in(planSno)); + + if (!districtAddr.toString().isBlank()) { + builder.and(qDosFltPlanArea.addr.like("%" + districtAddr.toString() + "%")); + } + if (rq.getAddress() != null && !rq.getAddress().isEmpty()) { + builder.and(qDosFltPlanArea.addr.like("%" + rq.getAddress() + "%")); + } + + // 검토 결과 - W일 경우 W, null 모두 조회(null == W) + if (rq.getReviewedType() != null) { + builder.and(qDosFltPlanArea.reviewedType.eq(rq.getReviewedType()).or(qDosFltPlanArea.reviewedType.isNull())); + } + + return query + .select(qDosFltPlanArea.count()) + .from(qDosFltPlanArea) + .where(builder) + .fetchOne(); + + } + + public List findPlanByBasSearch(SearchBasDosPlanRQ rq) { + QDosFltPlanBas bas = QDosFltPlanBas.dosFltPlanBas; + QDosFltPlanArea qDosFltPlanArea = QDosFltPlanArea.dosFltPlanArea; + + short idx = 0; + + StringBuilder districtAddr = new StringBuilder(); + if (rq.getCtprvn() != null && !rq.getCtprvn().isBlank()) { + districtAddr.append(rq.getCtprvn()); + idx++; + } + if (rq.getSig() != null && !rq.getSig().isBlank()) { + if (idx > 0) districtAddr.append(" "); + districtAddr.append(rq.getSig()); + } + + BooleanBuilder builder = new BooleanBuilder(); + + if (rq.getSearchStDt() != null) { + builder.and(bas.applyDt.goe(rq.getSearchStDt())); + } + if (rq.getSearchEndDt() != null) { + builder.and(bas.applyDt.loe(rq.getSearchEndDt())); + } + if (StringUtils.hasText(rq.getApplyNo())) { + builder.and(bas.applyNo.eq(rq.getApplyNo())); + } + if (!districtAddr.toString().isBlank()) { + builder.and(qDosFltPlanArea.addr.like("%" + districtAddr.toString() + "%")); + } + if (rq.getAddress() != null && !rq.getAddress().isEmpty()) { + builder.and(qDosFltPlanArea.addr.like("%" + rq.getAddress() + "%")); + } + + return query.selectFrom(bas) + .leftJoin(qDosFltPlanArea) + .on(bas.planSno.eq(qDosFltPlanArea.planSno)) + .where(builder) + .orderBy(bas.applyDt.desc(), bas.applyNo.desc()) + .groupBy(bas.planSno) + .fetch(); + } } diff --git a/pav-server/src/main/java/com/palnet/comn/exception/CustomException.java b/pav-server/src/main/java/com/palnet/comn/exception/CustomException.java index 3e3308f3..dcd83c48 100644 --- a/pav-server/src/main/java/com/palnet/comn/exception/CustomException.java +++ b/pav-server/src/main/java/com/palnet/comn/exception/CustomException.java @@ -70,7 +70,7 @@ public class CustomException extends RuntimeException { // } public CustomException(Throwable th, ErrorCode erorCode, String sourceErrorMessage) { - this(th, Level.WARN, ErrorCode.INTERNAL_SERVER_ERROR, (Object[])null); + this(th, Level.WARN, ErrorCode.INTERNAL_SERVER_ERROR,new Object[]{(Object) sourceErrorMessage}); this.sourceErrorCode = erorCode.code(); this.sourceErrorMessage = errorCode.message(); }