-
Notifications
You must be signed in to change notification settings - Fork 1
[feat] 현재까지 변경사항 main으로 병합 #88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d6c3570
0c6d677
917b95c
fce8d5e
e677432
e73cef2
8428d40
b87ea14
d0d7d56
75d5029
47c6082
f348bc6
a9902b3
b1b037b
fe29920
5d056da
d865a8e
13d89e8
28fdfa3
62caa26
3bb249a
14e5403
1a87492
db99290
c327e27
5a9475f
111d37d
b1c6711
4bf2c83
3a3bbc5
d8bef71
2eae9b1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| package com.wayble.server.common.converter; | ||
|
|
||
| import com.fasterxml.jackson.core.type.TypeReference; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import jakarta.persistence.AttributeConverter; | ||
| import jakarta.persistence.Converter; | ||
| import lombok.extern.slf4j.Slf4j; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.List; | ||
|
|
||
| @Slf4j | ||
| @Converter | ||
| public class StringListConverter implements AttributeConverter<List<String>, String> { | ||
| private static final ObjectMapper objectMapper = new ObjectMapper(); | ||
|
|
||
| @Override | ||
| public String convertToDatabaseColumn(List<String> list) { | ||
| try { | ||
| return list == null ? "[]" : objectMapper.writeValueAsString(list); | ||
| } catch (Exception e) { | ||
| log.warn("Failed to convert list to JSON string: {}", list, e); | ||
| return "[]"; | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public List<String> convertToEntityAttribute(String json) { | ||
| try { | ||
| if (json == null || json.isBlank()) return Collections.emptyList(); | ||
| return objectMapper.readValue(json, new TypeReference<List<String>>() {}); | ||
| } catch (Exception e) { | ||
| log.warn("Failed to convert JSON string to list: {}", json, e); | ||
| return Collections.emptyList(); | ||
| } | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| package com.wayble.server.direction.dto.response; | ||
|
|
||
| import com.wayble.server.direction.entity.type.Type; | ||
| import io.swagger.v3.oas.annotations.media.Schema; | ||
| import lombok.Builder; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @Builder | ||
| @Schema(description = "웨이블 추천 경로 API") | ||
| public record WayblePathResponse( | ||
|
|
||
| @Schema(description = "총 거리", example = "1365") | ||
| int distance, | ||
|
|
||
| @Schema(description = "총 소요 시간", example = "909") | ||
| int time, | ||
|
|
||
| @Schema(description = "위치", example = "[{\"lat\":37.4941736,\"lon\":127.0247425,\"type\":\"RAMP\"}]") | ||
| List<WayblePoint> points, | ||
|
|
||
| @Schema(description = "좌표 리스트", example = "[[127.0247425,37.4941736],[127.0249966,37.4942539]]") | ||
| List<double[]> polyline | ||
| ) { | ||
| public record WayblePoint( | ||
| @Schema(description = "위도", example = "37.4941736") | ||
| double lat, | ||
|
|
||
| @Schema(description = "경도", example = "127.0247425") | ||
| double lon, | ||
|
|
||
| @Schema(description = "웨이블 마커 타입", example = "RAMP") | ||
| Type type | ||
| ) {} | ||
|
|
||
| public static WayblePathResponse of( | ||
| int distance, | ||
| int time, | ||
| List<WayblePoint> points, | ||
| List<double[]> polyline | ||
| ) { | ||
| return WayblePathResponse.builder() | ||
| .distance(distance) | ||
| .time(time) | ||
| .points(points) | ||
| .polyline(polyline) | ||
| .build(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.wayble.server.direction.entity; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public record Edge( | ||
| long from, | ||
| long to, | ||
| double length, | ||
| List<double[]> geometry | ||
| ) { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.wayble.server.direction.entity; | ||
|
|
||
| public record Node( | ||
| Long id, | ||
| double lat, | ||
| double lon | ||
| ) { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.wayble.server.direction.entity; | ||
|
|
||
| import com.wayble.server.direction.entity.type.Type; | ||
|
|
||
| public record WaybleMarker( | ||
| Long id, | ||
| double lat, | ||
| double lon, | ||
| Type type | ||
| ) { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package com.wayble.server.direction.entity.type; | ||
|
|
||
| import lombok.Getter; | ||
|
|
||
| @Getter | ||
| public enum Type { | ||
| WHEELCHAIR_CHARGER("휠체어 충전소"), | ||
| NO_THRESHOLD("문턱 없음"), | ||
| RAMP("경사로"), | ||
| TABLE_SEAT("테이블석"), | ||
| ELEVATOR("엘리베이터"), | ||
| FIRST_FLOOR("1층"), | ||
| ACCESSIBLE_TOILET("장애인 화장실"), | ||
| WHEELCHAIR_LIFT("휠체어 리프트"), | ||
| NONE("해당없음"); | ||
|
|
||
| private final String description; | ||
|
|
||
| Type(String description) { | ||
| this.description = description; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,109 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package com.wayble.server.direction.init; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.fasterxml.jackson.core.type.TypeReference; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.fasterxml.jackson.databind.JsonNode; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.wayble.server.common.exception.ApplicationException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.wayble.server.direction.entity.Edge; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.wayble.server.direction.entity.Node; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.wayble.server.direction.entity.WaybleMarker; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.wayble.server.direction.entity.type.Type; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.wayble.server.direction.exception.WalkingErrorCase; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.wayble.server.direction.service.util.HaversineUtil; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import jakarta.annotation.PostConstruct; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import lombok.extern.slf4j.Slf4j; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.stereotype.Component; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.io.IOException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.io.InputStream; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.*; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.stream.Collectors; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Slf4j | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Component | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class GraphInit { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private List<Node> nodes; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private List<Edge> edges; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private List<WaybleMarker> markers; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Map<Long, List<Edge>> adjacencyList; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Map<Long, Node> nodeMap; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Map<Long, Type> markerMap; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @PostConstruct | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public void init() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ObjectMapper objectMapper = new ObjectMapper(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 그래프 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try (InputStream graphStream = getClass().getResourceAsStream("/seocho_pedestrian.json")) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (graphStream == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new ApplicationException(WalkingErrorCase.GRAPH_FILE_NOT_FOUND); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| JsonNode root = objectMapper.readTree(graphStream); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nodes = Arrays.asList(objectMapper.convertValue(root.get("nodes"), Node[].class)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| edges = Arrays.asList(objectMapper.convertValue(root.get("edges"), Edge[].class)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| nodeMap = nodes.stream().collect(Collectors.toMap(Node::id, node -> node)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 웨이블 마커 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try (InputStream markerStream = getClass().getResourceAsStream("/wayble_markers.json")) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| markers = markerStream != null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? objectMapper.readValue(markerStream, new TypeReference<>() {}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : new ArrayList<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| markerMap = findWaybleMarkers(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| adjacencyList = buildAdjacencyList(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (IOException e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.error("🚨 그래프 초기화 실패: {}", e.getMessage()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new ApplicationException(WalkingErrorCase.GRAPH_INIT_FAILED); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Map<Long, List<Edge>> buildAdjacencyList() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Map<Long, List<Edge>> adjacencyList = new HashMap<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (Edge edge : edges) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| boolean isWaybleMarker = markerMap.containsKey(edge.from()) || markerMap.containsKey(edge.to()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| double distance = isWaybleMarker ? edge.length() * 0.5 : edge.length(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 양방향 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| adjacencyList.computeIfAbsent(edge.from(), k -> new ArrayList<>()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .add(new Edge(edge.from(), edge.to(), distance, edge.geometry())); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| adjacencyList.computeIfAbsent(edge.to(), k -> new ArrayList<>()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .add(new Edge(edge.to(), edge.from(), distance, edge.geometry())); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return adjacencyList; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private Map<Long, Type> findWaybleMarkers() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Map<Long, Type> waybleMarkers = new HashMap<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (WaybleMarker marker : markers) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| long nearNode = nodes.stream() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .min(Comparator.comparingDouble( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| n -> HaversineUtil.haversine(marker.lat(), marker.lon(), n.lat(), n.lon()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .map(Node::id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .orElse(marker.id()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (nearNode != marker.id()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| waybleMarkers.put(nearNode, marker.type()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return waybleMarkers; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+80
to
+96
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 마커와 노드 ID 비교 로직에 문제가 있습니다.
다음과 같이 수정하세요: - .orElse(marker.id());
+ .orElseThrow(() -> new ApplicationException(WalkingErrorCase.NODE_NOT_FOUND));
- if (nearNode != marker.id()) {
- waybleMarkers.put(nearNode, marker.type());
- }
+ waybleMarkers.put(nearNode, marker.type());또는 거리 임계값을 설정하여 너무 먼 노드는 제외하는 로직을 추가하는 것도 고려해보세요. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public Map<Long, Node> getNodeMap() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Collections.unmodifiableMap(nodeMap); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public Map<Long, Type> getMarkerMap() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Collections.unmodifiableMap(markerMap); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public Map<Long, List<Edge>> getGraph() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Collections.unmodifiableMap(adjacencyList); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
초기화 시 데이터 검증을 추가하세요.
그래프 데이터 로드 후 다음과 같은 검증을 추가하면 런타임 오류를 방지할 수 있습니다:
markerMap = findWaybleMarkers(); adjacencyList = buildAdjacencyList(); + + // 데이터 검증 + if (nodes.isEmpty() || edges.isEmpty()) { + log.error("🚨 그래프 데이터가 비어있습니다"); + throw new ApplicationException(WalkingErrorCase.GRAPH_INIT_FAILED); + } + + log.info("✅ 그래프 초기화 완료: 노드 {}, 엣지 {}, 마커 {}", + nodes.size(), edges.size(), markers.size());📝 Committable suggestion
🤖 Prompt for AI Agents