Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ dependencies {
// OpenCSV
implementation 'com.opencsv:opencsv:5.7.1'

// Cache
implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation 'com.github.ben-manes.caffeine:caffeine'

// Servlet API
//compileOnly 'jakarta.servlet:jakarta.servlet-api:6.0.0'

Expand All @@ -74,6 +78,9 @@ dependencies {
testImplementation 'org.testcontainers:junit-jupiter' // 어노테이션 담당
testImplementation 'org.testcontainers:postgresql'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// GraphHopper
implementation 'com.graphhopper:graphhopper-core:9.0'
}

tasks.named('test') {
Expand Down
14 changes: 12 additions & 2 deletions backend/src/main/java/_team/onmyway/service/ImageService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import _team.onmyway.entity.Photos;
import _team.onmyway.entity.Place;
import _team.onmyway.repository.PhotosRepository;
import com.github.benmanes.caffeine.cache.Cache;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
Expand All @@ -18,15 +20,17 @@ public class ImageService {

private final WebClient webClient;
private final PhotosRepository photosRepository;
private final Cache<Long, String> placePhotoCache;

@Value("${naver.api.clientId}")
private String naverClientId;

@Value("${naver.api.clientSecret}")
private String naverClientSecret;

public ImageService(PhotosRepository photosRepository) {
public ImageService(PhotosRepository photosRepository, Cache<Long, String> placePhotoCache) {
this.photosRepository = photosRepository;
this.placePhotoCache = placePhotoCache;
this.webClient = WebClient.builder()
.baseUrl("https://openapi.naver.com")
.build();
Expand All @@ -37,8 +41,14 @@ public Mono<String> getImageURL(Place p) {
if (hasPhoto) {
return Mono.just(photosRepository.findFirstByPlaceId(p.getId()).get().getPhotoURL());
} else {
String distinct = p.getAddress().split(" ")[2];
String cacheURL = placePhotoCache.getIfPresent(p.getId());
if (cacheURL != null) {
return Mono.just(cacheURL);
}

String distinct = p.getAddress();
String name = p.getName();

return webClient.get()
.uri(uri -> uri
.path("/v1/search/image")
Expand Down
68 changes: 64 additions & 4 deletions backend/src/main/java/_team/onmyway/service/RouteService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@
import _team.onmyway.dto.RouteResponseDTO;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.graphhopper.GraphHopper;
import com.graphhopper.routing.util.EdgeFilter;
import com.graphhopper.storage.BaseGraph;
import com.graphhopper.storage.NodeAccess;
import com.graphhopper.storage.index.LocationIndex;
import com.graphhopper.storage.index.Snap;
import com.graphhopper.util.EdgeExplorer;
import com.graphhopper.util.shapes.GHPoint;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.edgegraph.EdgeGraph;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
Expand All @@ -19,15 +28,15 @@
import reactor.core.publisher.Mono;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.*;

@Service
@Slf4j
@RequiredArgsConstructor
public class RouteService {

private final ObjectMapper objectMapper;
private final GraphHopper graphHopper;

@Value("${tmap.api.key}")
private String tmapAPIKey;
Expand Down Expand Up @@ -144,10 +153,61 @@ private PositionDTO makeStopOver(PositionDTO start, PositionDTO end) {

Double d = 0.0011;

double lat, lon;
if (gradation > 0) {
return new PositionDTO(positionLat-unitLon*d, positionLon+unitLat*d); // 시계방향 회전
lat = positionLat-unitLon*d;
lon = positionLon-unitLat*d; // 시계방향 회전
} else {
return new PositionDTO(positionLat+unitLon*d, positionLon-unitLat*d); // 반시계방향 회전
lat = positionLat+unitLon*d;
lon = positionLon-unitLat*d; // 반시계방향 회전
}
return nearestIntersection(lat, lon);
}

public PositionDTO nearestIntersection(double lat, double lon) {
BaseGraph baseGraph = graphHopper.getBaseGraph();
NodeAccess nodeAccess = baseGraph.getNodeAccess();
EdgeExplorer edgeExplorer = baseGraph.createEdgeExplorer();

LocationIndex locationIndex = graphHopper.getLocationIndex();

Snap closest = locationIndex.findClosest(lat, lon, EdgeFilter.ALL_EDGES);

int closestNodeId = closest.getClosestNode();
int intersectionId = findNearestIntersectionBFS(closestNodeId, baseGraph, edgeExplorer);

return new PositionDTO(nodeAccess.getLat(intersectionId), nodeAccess.getLon(intersectionId));
}

private int findNearestIntersectionBFS(int startNodeId, BaseGraph baseGraph, EdgeExplorer explorer) {
Queue<Integer> queue = new LinkedList<>();
Set<Integer> visited = new HashSet<>();

queue.add(startNodeId);
visited.add(startNodeId);

while (!queue.isEmpty()) {
int curr = queue.poll();

int edgeCount = 0;
var edgeIterator = explorer.setBaseNode(curr);
while (edgeIterator.next()) {
edgeCount += 1;
}

if (edgeCount >= 3) {
return curr;
}

edgeIterator = explorer.setBaseNode(curr);
while (edgeIterator.next()) {
int nextId = edgeIterator.getAdjNode();
if (!visited.contains(nextId)) {
visited.add(nextId);
queue.add(nextId);
}
}
}
return -1;
}
}
2 changes: 1 addition & 1 deletion backend/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ jwt.refresh-expiration=${REFRESH_TOKEN_EXPIRATION}
#Tmap api
tmap.api.key=${TMAP_API_KEY}

#Naver api
# Naver api
naver.api.clientId=${NAVER_CLIENT_ID}
naver.api.clientSecret=${NAVER_CLIENT_SECRET}