Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@

@Schema(description = "대중교통 길찾기 응답 DTO")
public record TransportationResponseDto(
List<Step> routes,
List<Route> routes,
PageInfo pageInfo
) {
public record Route(
Integer routeIndex, // 경로 인덱스
List<Step> steps // 해당 경로의 단계들
) {}

public record Step(
DirectionType mode, // 예: START, WALK, SUBWAY, BUS, FINISH
@Nullable List<MoveInfo> moveInfo, // 같은 Step으로 이동한 정류장(Node) 정보 (중간 정류장만)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class TransportationService {
private static final int ORIGIN_DESTINATION_WALK_DISTANCE = 1000; // 출발지/도착지에서 정류장까지 도보 연결 가능 거리 (m)
private static final int MAX_NEARBY_NODES = 5; // 출발지/도착지 주변에서 고려할 최대 정류장 수
private static final int MAX_DIJKSTRA_VISITS = 5000; // 다익스트라 알고리즘에서 방문할 수 있는 최대 노드 수 (무한 루프 방지)
private static final int MAX_ROUTES = 5; // 찾을 최대 경로 수

public TransportationResponseDto findRoutes(TransportationRequestDto request){

Expand All @@ -54,27 +55,39 @@ public TransportationResponseDto findRoutes(TransportationRequestDto request){
Node start = Node.createNode(-1L, origin.name(), DirectionType.FROM_WAYPOINT ,origin.latitude(), origin.longitude());
Node end = Node.createNode(-2L, destination.name(), DirectionType.TO_WAYPOINT,destination.latitude(), destination.longitude());

// 3. 경로 찾기
List<TransportationResponseDto.Step> steps = findTransportationRoute(start, end);
// 3. 여러 경로 찾기
List<List<TransportationResponseDto.Step>> allRoutes = findMultipleTransportationRoutes(start, end);

// 4. 페이징 처리
int startIndex = (request.cursor() != null) ? request.cursor() : 0;
int pageSize = request.size() != null ? request.size() : steps.size();
int endIndex = Math.min(startIndex + pageSize, steps.size());
boolean hasNext = endIndex < steps.size();
int pageSize = (request.size() != null) ? request.size() : 5; // 기본값 5로 설정
int endIndex = Math.min(startIndex + pageSize, allRoutes.size());
boolean hasNext = endIndex < allRoutes.size();
Integer nextCursor = hasNext ? endIndex : null;
TransportationResponseDto.PageInfo pageInfo = new TransportationResponseDto.PageInfo(nextCursor, hasNext);

// 경로를 찾지 못한 경우 처리
if (steps.isEmpty()) {
if (allRoutes.isEmpty()) {
throw new ApplicationException(PATH_NOT_FOUND);
}

return new TransportationResponseDto(steps, pageInfo);
// 페이징된 경로들을 Route 객체로 변환
List<TransportationResponseDto.Route> routeList = new ArrayList<>();
List<List<TransportationResponseDto.Step>> pagedRoutes = allRoutes.subList(startIndex, endIndex);
for (int i = 0; i < pagedRoutes.size(); i++) {
List<TransportationResponseDto.Step> route = pagedRoutes.get(i);
TransportationResponseDto.Route routeObj = createRoute(route, startIndex + i + 1);
routeList.add(routeObj);
}

return new TransportationResponseDto(routeList, pageInfo);
}

private TransportationResponseDto.Route createRoute(List<TransportationResponseDto.Step> steps, int routeIndex) {
return new TransportationResponseDto.Route(routeIndex, steps);
}

private List<TransportationResponseDto.Step> findTransportationRoute(Node startTmp, Node endTmp){
private List<List<TransportationResponseDto.Step>> findMultipleTransportationRoutes(Node startTmp, Node endTmp){
// 1. 데이터 로드
List<Node> nodes = new ArrayList<>(nodeRepository.findAll());
List<Edge> edges = new ArrayList<>(edgeRepository.findAllWithNodesAndRoute());
Expand All @@ -91,13 +104,12 @@ private List<TransportationResponseDto.Step> findTransportationRoute(Node startT
nodes.add(startTmp);
nodes.add(endTmp);

// 4. 그래프 빌드 및 최적 경로 찾기
// 4. 그래프 빌드 및 여러 경로 찾기
TransportationGraphDto graphData = buildGraph(nodes, edges, startTmp, endTmp);
return findOptimalRoute(graphData.graph(), startTmp, endTmp, graphData.weightMap(), nodes, nearestToStart, nearestToEnd);
return findMultipleOptimalRoutes(graphData.graph(), startTmp, endTmp, graphData.weightMap(), nodes, nearestToStart, nearestToEnd);
}


private List<TransportationResponseDto.Step> findOptimalRoute(
private List<List<TransportationResponseDto.Step>> findMultipleOptimalRoutes(
Map<Long, List<Edge>> graph,
Node startTmp,
Node endTmp,
Expand All @@ -121,26 +133,179 @@ private List<TransportationResponseDto.Step> findOptimalRoute(
return new ArrayList<>();
}

// 2. 다익스트라 알고리즘으로 최적 경로 찾기
List<TransportationResponseDto.Step> route = runDijkstra(graph, startNode, endNode, weightMap, nodes);
// 2. 여러 경로 찾기
List<List<TransportationResponseDto.Step>> allRoutes = findMultipleRoutes(graph, startNode, endNode, weightMap, nodes);

// 3. 경로 필터링 및 정렬
return filterAndSortRoutes(allRoutes);
}

private List<List<TransportationResponseDto.Step>> findMultipleRoutes(
Map<Long, List<Edge>> graph,
Node start,
Node end,
Map<Pair<Long, Long>, Integer> weightMap,
List<Node> nodes) {

List<List<TransportationResponseDto.Step>> routes = new ArrayList<>();

// 1. 기본 다익스트라로 첫 번째 경로 찾기
List<TransportationResponseDto.Step> firstRoute = runDijkstra(graph, start, end, weightMap, nodes);
if (!firstRoute.isEmpty()) {
routes.add(firstRoute);
}

// 2. 효율적인 다중 경로 찾기 - 한 번의 탐색으로 여러 경로 생성
if (!firstRoute.isEmpty()) {
List<List<TransportationResponseDto.Step>> alternativeRoutes = findAlternativeRoutesEfficiently(
graph, start, end, weightMap, nodes, firstRoute
);
routes.addAll(alternativeRoutes);
}

if (!route.isEmpty()) {
// 3. 대중교통 포함 여부 확인
boolean hasPublicTransport = route.stream()
.anyMatch(step -> step.mode() == DirectionType.BUS || step.mode() == DirectionType.SUBWAY);
return routes;
}

private List<List<TransportationResponseDto.Step>> findAlternativeRoutesEfficiently(
Map<Long, List<Edge>> graph,
Node start,
Node end,
Map<Pair<Long, Long>, Integer> weightMap,
List<Node> nodes,
List<TransportationResponseDto.Step> firstRoute) {

List<List<TransportationResponseDto.Step>> alternativeRoutes = new ArrayList<>();

// 첫 번째 경로에서 실제 사용된 엣지들을 추출
Set<Pair<Long, Long>> usedEdges = extractActualEdgesFromRoute(firstRoute, graph);

// 최대 4개의 추가 경로 찾기
for (int i = 0; i < 4 && alternativeRoutes.size() < MAX_ROUTES - 1; i++) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

대체 경로 생성 루프의 종료 조건 개선 필요

현재 루프가 4회 고정 반복인데, MAX_ROUTES - 1개의 대체 경로를 찾으면 조기 종료하도록 되어 있습니다. 이는 불필요한 반복을 유발할 수 있습니다.

-        for (int i = 0; i < 4 && alternativeRoutes.size() < MAX_ROUTES - 1; i++) {
+        for (int i = 0; alternativeRoutes.size() < MAX_ROUTES - 1 && i < MAX_ROUTES - 1; i++) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (int i = 0; i < 4 && alternativeRoutes.size() < MAX_ROUTES - 1; i++) {
for (int i = 0; alternativeRoutes.size() < MAX_ROUTES - 1 && i < MAX_ROUTES - 1; i++) {
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/direction/service/TransportationService.java
around line 183, replace the fixed-count for-loop with a loop that stops
immediately when the desired number of alternative routes is reached: introduce
an attempts counter (e.g., attempts = 0) and use while (alternativeRoutes.size()
< MAX_ROUTES - 1 && attempts < 4) { ...; attempts++; } so the loop checks the
current alternativeRoutes.size() each iteration and exits as soon as MAX_ROUTES
- 1 is met, avoiding unnecessary extra iterations.

// 실제 사용된 엣지들에만 패널티를 적용한 가중치 맵 생성
Map<Pair<Long, Long>, Integer> penalizedWeightMap = createActualEdgePenalizedWeightMap(weightMap, usedEdges, i + 1);

// 다익스트라로 새로운 경로 찾기
List<TransportationResponseDto.Step> newRoute = runDijkstra(graph, start, end, penalizedWeightMap, nodes);

if (!hasPublicTransport) {
return new ArrayList<>();
if (newRoute.isEmpty()) {
break;
}

// 4. 환승 횟수 검증 (4회 이상 제외)
int transferCount = calculateTransferCount(route);
if (transferCount >= 4) {
return new ArrayList<>();
// 첫 번째 경로와 동일한지 확인
if (areRoutesIdentical(newRoute, firstRoute)) {
continue;
}

// 새로운 경로에서 사용된 엣지들도 추가
Set<Pair<Long, Long>> newUsedEdges = extractActualEdgesFromRoute(newRoute, graph);
usedEdges.addAll(newUsedEdges);

alternativeRoutes.add(newRoute);
}

return route;
return alternativeRoutes;
}





private Set<Pair<Long, Long>> extractActualEdgesFromRoute(List<TransportationResponseDto.Step> route, Map<Long, List<Edge>> graph) {
Set<Pair<Long, Long>> usedEdges = new HashSet<>();

for (TransportationResponseDto.Step step : route) {
String fromName = step.from();
String toName = step.to();

for (Map.Entry<Long, List<Edge>> entry : graph.entrySet()) {
Long nodeId = entry.getKey();
List<Edge> edges = entry.getValue();

for (Edge edge : edges) {
Node fromNode = edge.getStartNode();
Node toNode = edge.getEndNode();

if ((fromNode.getStationName().equals(fromName) && toNode.getStationName().equals(toName)) ||
(fromNode.getStationName().equals(toName) && toNode.getStationName().equals(fromName))) {
usedEdges.add(Pair.of(fromNode.getId(), toNode.getId()));
usedEdges.add(Pair.of(toNode.getId(), fromNode.getId()));
}
}
}
}

return usedEdges;
}
Comment on lines +213 to +238
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

extractActualEdgesFromRoute 메서드의 성능 최적화 필요

이 메서드는 O(n * m * k) 복잡도를 가지고 있습니다 (n: route 크기, m: graph 엔트리 수, k: 각 노드의 엣지 수). 대규모 그래프에서는 성능 문제가 발생할 수 있습니다.

노드 이름을 키로 하는 맵을 미리 구성하여 검색 성능을 개선할 수 있습니다:

 private Set<Pair<Long, Long>> extractActualEdgesFromRoute(List<TransportationResponseDto.Step> route, Map<Long, List<Edge>> graph) {
     Set<Pair<Long, Long>> usedEdges = new HashSet<>();
+    
+    // 노드 이름으로 엣지를 빠르게 찾기 위한 맵 구성
+    Map<String, List<Edge>> edgesByNodeName = new HashMap<>();
+    for (List<Edge> edges : graph.values()) {
+        for (Edge edge : edges) {
+            if (edge.getStartNode() != null) {
+                edgesByNodeName.computeIfAbsent(edge.getStartNode().getStationName(), k -> new ArrayList<>()).add(edge);
+            }
+        }
+    }
     
     for (TransportationResponseDto.Step step : route) {
         String fromName = step.from();
         String toName = step.to();
         
-        for (Map.Entry<Long, List<Edge>> entry : graph.entrySet()) {
-            Long nodeId = entry.getKey();
-            List<Edge> edges = entry.getValue();
-            
-            for (Edge edge : edges) {
-                Node fromNode = edge.getStartNode();
-                Node toNode = edge.getEndNode();
-                
-                if ((fromNode.getStationName().equals(fromName) && toNode.getStationName().equals(toName)) ||
-                    (fromNode.getStationName().equals(toName) && toNode.getStationName().equals(fromName))) {
-                    usedEdges.add(Pair.of(fromNode.getId(), toNode.getId()));
-                    usedEdges.add(Pair.of(toNode.getId(), fromNode.getId()));
-                }
+        List<Edge> candidateEdges = edgesByNodeName.getOrDefault(fromName, new ArrayList<>());
+        for (Edge edge : candidateEdges) {
+            Node toNode = edge.getEndNode();
+            if (toNode != null && toNode.getStationName().equals(toName)) {
+                usedEdges.add(Pair.of(edge.getStartNode().getId(), toNode.getId()));
+                usedEdges.add(Pair.of(toNode.getId(), edge.getStartNode().getId()));
             }
         }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private Set<Pair<Long, Long>> extractActualEdgesFromRoute(List<TransportationResponseDto.Step> route, Map<Long, List<Edge>> graph) {
Set<Pair<Long, Long>> usedEdges = new HashSet<>();
for (TransportationResponseDto.Step step : route) {
String fromName = step.from();
String toName = step.to();
for (Map.Entry<Long, List<Edge>> entry : graph.entrySet()) {
Long nodeId = entry.getKey();
List<Edge> edges = entry.getValue();
for (Edge edge : edges) {
Node fromNode = edge.getStartNode();
Node toNode = edge.getEndNode();
if ((fromNode.getStationName().equals(fromName) && toNode.getStationName().equals(toName)) ||
(fromNode.getStationName().equals(toName) && toNode.getStationName().equals(fromName))) {
usedEdges.add(Pair.of(fromNode.getId(), toNode.getId()));
usedEdges.add(Pair.of(toNode.getId(), fromNode.getId()));
}
}
}
}
return usedEdges;
}
private Set<Pair<Long, Long>> extractActualEdgesFromRoute(List<TransportationResponseDto.Step> route, Map<Long, List<Edge>> graph) {
Set<Pair<Long, Long>> usedEdges = new HashSet<>();
// 노드 이름으로 엣지를 빠르게 찾기 위한 맵 구성
Map<String, List<Edge>> edgesByNodeName = new HashMap<>();
for (List<Edge> edges : graph.values()) {
for (Edge edge : edges) {
if (edge.getStartNode() != null) {
edgesByNodeName.computeIfAbsent(edge.getStartNode().getStationName(), k -> new ArrayList<>()).add(edge);
}
}
}
for (TransportationResponseDto.Step step : route) {
String fromName = step.from();
String toName = step.to();
List<Edge> candidateEdges = edgesByNodeName.getOrDefault(fromName, new ArrayList<>());
for (Edge edge : candidateEdges) {
Node toNode = edge.getEndNode();
if (toNode != null && toNode.getStationName().equals(toName)) {
usedEdges.add(Pair.of(edge.getStartNode().getId(), toNode.getId()));
usedEdges.add(Pair.of(toNode.getId(), edge.getStartNode().getId()));
}
}
}
return usedEdges;
}


private Map<Pair<Long, Long>, Integer> createActualEdgePenalizedWeightMap(Map<Pair<Long, Long>, Integer> originalWeightMap, Set<Pair<Long, Long>> usedEdges, int routeIndex) {
Map<Pair<Long, Long>, Integer> penalizedWeightMap = new HashMap<>();

for (Map.Entry<Pair<Long, Long>, Integer> entry : originalWeightMap.entrySet()) {
Pair<Long, Long> edge = entry.getKey();
int weight = entry.getValue();

if (usedEdges.contains(edge)) {
int penalty = routeIndex * 100000;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

패널티 계산에 매직 넘버 사용

routeIndex * 100000에서 100000이라는 매직 넘버가 사용되고 있습니다. 이 값을 상수로 정의하여 코드의 가독성과 유지보수성을 향상시키는 것이 좋습니다.

+ private static final int ROUTE_PENALTY_MULTIPLIER = 100000; // 경로별 패널티 가중치

 private Map<Pair<Long, Long>, Integer> createActualEdgePenalizedWeightMap(Map<Pair<Long, Long>, Integer> originalWeightMap, Set<Pair<Long, Long>> usedEdges, int routeIndex) {
     Map<Pair<Long, Long>, Integer> penalizedWeightMap = new HashMap<>();
     
     for (Map.Entry<Pair<Long, Long>, Integer> entry : originalWeightMap.entrySet()) {
         Pair<Long, Long> edge = entry.getKey();
         int weight = entry.getValue();
         
         if (usedEdges.contains(edge)) {
-            int penalty = routeIndex * 100000;
+            int penalty = routeIndex * ROUTE_PENALTY_MULTIPLIER;
             penalizedWeightMap.put(edge, weight + penalty);
         } else {
             penalizedWeightMap.put(edge, weight);
         }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
int penalty = routeIndex * 100000;
private static final int ROUTE_PENALTY_MULTIPLIER = 100000; // 경로별 패널티 가중치
private Map<Pair<Long, Long>, Integer> createActualEdgePenalizedWeightMap(Map<Pair<Long, Long>, Integer> originalWeightMap, Set<Pair<Long, Long>> usedEdges, int routeIndex) {
Map<Pair<Long, Long>, Integer> penalizedWeightMap = new HashMap<>();
for (Map.Entry<Pair<Long, Long>, Integer> entry : originalWeightMap.entrySet()) {
Pair<Long, Long> edge = entry.getKey();
int weight = entry.getValue();
if (usedEdges.contains(edge)) {
int penalty = routeIndex * ROUTE_PENALTY_MULTIPLIER;
penalizedWeightMap.put(edge, weight + penalty);
} else {
penalizedWeightMap.put(edge, weight);
}
}
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/direction/service/TransportationService.java
around line 248, the penalty calculation uses a magic number ("routeIndex *
100000"); replace the literal with a clearly named constant (e.g.,
PENALTY_PER_ROUTE or ROUTE_PENALTY_MULTIPLIER) declared at the top of the class
(private static final int) and use that constant in the multiplication to
improve readability and maintainability.

penalizedWeightMap.put(edge, weight + penalty);
} else {
penalizedWeightMap.put(edge, weight);
}
}

return penalizedWeightMap;
}

private boolean areRoutesIdentical(List<TransportationResponseDto.Step> route1, List<TransportationResponseDto.Step> route2) {
// 두 경로가 완전히 동일한지 확인
if (route1.size() != route2.size()) {
return false;
}

for (int i = 0; i < route1.size(); i++) {
TransportationResponseDto.Step step1 = route1.get(i);
TransportationResponseDto.Step step2 = route2.get(i);

if (step1.mode() != step2.mode() ||
!Objects.equals(step1.from(), step2.from()) ||
!Objects.equals(step1.to(), step2.to()) ||
!Objects.equals(step1.routeName(), step2.routeName())) {
return false;
}
}

return true;
}

private List<List<TransportationResponseDto.Step>> filterAndSortRoutes(List<List<TransportationResponseDto.Step>> routes) {
return routes.stream()
.filter(route -> {
// 대중교통 포함 여부 확인
boolean hasPublicTransport = route.stream()
.anyMatch(step -> step.mode() == DirectionType.BUS || step.mode() == DirectionType.SUBWAY);

if (!hasPublicTransport) {
return false;
}

// 환승 횟수 검증 (4회 이상 제외)
int transferCount = calculateTransferCount(route);
return transferCount < 4;
Comment on lines +290 to +292
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

환승 횟수 제한이 하드코딩됨

환승 횟수 제한이 4회로 하드코딩되어 있습니다. 이를 상수로 정의하여 설정 가능하도록 하는 것이 좋습니다.

+ private static final int MAX_TRANSFER_COUNT = 4; // 최대 환승 횟수

 // 환승 횟수 검증 (4회 이상 제외)
 int transferCount = calculateTransferCount(route);
- return transferCount < 4;
+ return transferCount < MAX_TRANSFER_COUNT;

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/direction/service/TransportationService.java
around lines 290 to 292 the transfer limit is hardcoded as 4; replace the magic
number with a named constant (e.g., MAX_TRANSFER_COUNT) declared at the top of
the class (or as a configurable property if preferred) and use that constant in
the comparison; ensure the constant is documented and, if made configurable,
loaded from application properties with a sensible default and validated before
use.

})
.sorted(Comparator
.<List<TransportationResponseDto.Step>>comparingInt(this::calculateTransferCount)
.thenComparingInt(this::calculateWalkDistance))
.limit(MAX_ROUTES)
.collect(Collectors.toList());
}

private int calculateWalkDistance(List<TransportationResponseDto.Step> route) {
return route.stream()
.filter(step -> step.mode() == DirectionType.WALK)
.mapToInt(step -> {
// 간단한 도보 거리 추정 (실제로는 정확한 거리 계산 필요)
return 500; // 기본값
})
.sum();
}
Comment on lines +301 to 309
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

도보 거리 계산이 하드코딩된 값 사용

calculateWalkDistance 메서드가 실제 거리를 계산하지 않고 모든 WALK 단계에 대해 500이라는 고정값을 반환하고 있습니다. 이는 경로 정렬 시 부정확한 결과를 초래할 수 있습니다.

실제 거리 계산 로직을 구현해야 합니다. 각 Step의 from과 to 좌표를 사용하여 haversine 함수로 실제 거리를 계산하는 구현이 필요합니다. 이 기능을 구현한 코드를 제공해드릴까요?

🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/direction/service/TransportationService.java
around lines 301 to 309, replace the hardcoded 500-per-WALK-step with a real
distance calculation: for each Step with mode == DirectionType.WALK, extract the
from and to coordinates (lat/lon), compute the great-circle distance using a
haversine helper (use Math.sin/Math.cos/Math.asin/Math.sqrt) and return the
distance in meters, sum those distances and return the total as an int; include
null/empty-coordinate guards and a small helper method signature like
haversine(lat1, lon1, lat2, lon2) -> double (meters) to keep code clean.


private TransportationGraphDto buildGraph(List<Node> nodes, List<Edge> edges, Node startTmp, Node endTmp) {
Expand Down Expand Up @@ -457,9 +622,9 @@ private List<TransportationResponseDto.Step> mergeConsecutiveRoutes(List<Edge> p
return new ArrayList<>();
}
}
} catch (Exception e) {
} catch (Exception e) {
log.info("버스 정보 조회 실패: {}", e.getMessage());
}
}
} else if (currentType == DirectionType.SUBWAY) {
try {
if (currentEdge.getStartNode() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ public CommonResponse<List<WaybleZoneDistrictResponseDto>> findMostLikesWaybleZo
));
}

@GetMapping("/validate")
public CommonResponse<WaybleZoneSearchResponseDto> findIsValidWaybleZone(
@Valid @ModelAttribute WaybleZoneSearchConditionDto conditionDto
)
{
return CommonResponse.success(waybleZoneSearchService.isValidWaybleZone(conditionDto));
}
Comment on lines +70 to +76
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

유사 존 미발견 시의 HTTP 응답을 명확히 처리하세요.

현재 서비스가 null을 반환할 수 있으나 컨트롤러는 그대로 200 OK + null data를 반환합니다. API 계약을 명확히 하기 위해 미발견 시 404(Not Found) 또는 204(No Content)로 응답하는 것을 권장합니다. 공통 응답 규약(CommonResponse)에 맞춰 에러/빈 응답 처리가 있으면 그 방식을 사용하세요.

간단한 404 처리 예시:

     @GetMapping("/validate")
     public CommonResponse<WaybleZoneSearchResponseDto> findIsValidWaybleZone(
             @Valid @ModelAttribute WaybleZoneSearchConditionDto conditionDto
     )
     {
-        return CommonResponse.success(waybleZoneSearchService.isValidWaybleZone(conditionDto));
+        WaybleZoneSearchResponseDto result = waybleZoneSearchService.isValidWaybleZone(conditionDto);
+        if (result == null) {
+            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "30m 이내에서 유사한 웨이블존을 찾지 못했습니다.");
+        }
+        return CommonResponse.success(result);
     }

추가 import:

import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
🤖 Prompt for AI Agents
In
src/main/java/com/wayble/server/explore/controller/WaybleZoneSearchController.java
around lines 70 to 76, the controller currently returns 200 OK with null data
when the service finds no matching zone; change it to handle "not found"
explicitly by checking the service result before wrapping it in CommonResponse
and either (a) throw a ResponseStatusException(HttpStatus.NOT_FOUND, "Wayble
zone not found") when the service returns null, or (b) if your CommonResponse
has a standard empty/404 helper, use that helper to return the correct response;
also add the necessary imports for org.springframework.http.HttpStatus and
org.springframework.web.server.ResponseStatusException if you choose the
exception approach.


@PostMapping("")
public CommonResponse<String> registerDocumentFromDto(@RequestBody WaybleZoneRegisterDto registerDto) {
waybleZoneDocumentService.saveDocumentFromDto(registerDto);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public record WaybleZoneSearchConditionDto(
@NotNull(message = "경도 입력은 필수입니다.")
Double longitude,

@DecimalMin(value = "0.1", message = "검색 반경은 100미터 이상이어야 합니다.")
Double radiusKm,

@Size(min = 2, message = "zoneName은 최소 2글자 이상이어야 합니다.")
Expand Down
Loading
Loading