Skip to content

Commit f0e8c84

Browse files
committed
✨ feat : 근처 가게 위치 목록 조회 API 구현
1 parent fd1831e commit f0e8c84

File tree

5 files changed

+115
-0
lines changed

5 files changed

+115
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,30 @@
11
package com.example.Centralthon.domain.store.repository;
22

3+
import com.example.Centralthon.domain.menu.entity.Menu;
34
import com.example.Centralthon.domain.store.entity.Store;
45
import org.springframework.data.jpa.repository.JpaRepository;
6+
import org.springframework.data.jpa.repository.Query;
57
import org.springframework.stereotype.Repository;
68

9+
import java.time.LocalDateTime;
10+
import java.util.List;
11+
712
@Repository
813
public interface StoreRepository extends JpaRepository<Store, Long> {
14+
@Query(value = "SELECT s.* FROM stores s " +
15+
"WHERE s.latitude BETWEEN :minLat AND :maxLat AND s.longitude BETWEEN :minLng AND :maxLng " +
16+
"AND ST_Distance_Sphere(POINT(s.longitude, s.latitude), POINT(:lng, :lat)) <= 2000 " +
17+
"AND EXISTS ( " +
18+
" SELECT 1 FROM menus m " +
19+
" WHERE m.store_id = s.store_id AND m.quantity > 0 AND m.deadline > NOW())"
20+
, nativeQuery = true)
21+
List<Store> findNearbyStores(
22+
double lat,
23+
double lng,
24+
LocalDateTime now,
25+
double minLat,
26+
double maxLat,
27+
double minLng,
28+
double maxLng
29+
);
930
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.example.Centralthon.domain.store.service;
2+
3+
import com.example.Centralthon.domain.store.web.dto.NearbyStoresRes;
4+
5+
import java.util.List;
6+
7+
public interface StoreService {
8+
List<NearbyStoresRes> nearbyStores(double lat, double lng);
9+
10+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.example.Centralthon.domain.store.service;
2+
3+
import com.example.Centralthon.domain.store.entity.Store;
4+
import com.example.Centralthon.domain.store.repository.StoreRepository;
5+
import com.example.Centralthon.domain.store.web.dto.NearbyStoresRes;
6+
import com.example.Centralthon.global.util.geo.BoundingBox;
7+
import lombok.RequiredArgsConstructor;
8+
import org.springframework.stereotype.Service;
9+
import org.springframework.transaction.annotation.Transactional;
10+
11+
import java.time.LocalDateTime;
12+
import java.util.List;
13+
14+
import static com.example.Centralthon.global.util.geo.GeoUtils.calculateBoundingBox;
15+
16+
@Service
17+
@RequiredArgsConstructor
18+
public class StoreServiceImpl implements StoreService {
19+
private final StoreRepository storeRepository;
20+
21+
@Override
22+
@Transactional(readOnly = true)
23+
public List<NearbyStoresRes> nearbyStores(double lat, double lng) {
24+
LocalDateTime now = LocalDateTime.now();
25+
26+
// 사용자 위치를 기반으로 2km 반경의 Bounding Box 계산
27+
BoundingBox bbox = calculateBoundingBox(lat, lng, 2.0);
28+
29+
List<Store> stores = storeRepository.findNearbyStores(lat, lng, now,
30+
bbox.minLat(), bbox.maxLat(), bbox.minLng(), bbox.maxLng());
31+
32+
return stores.stream()
33+
.map(store -> NearbyStoresRes.from(store))
34+
.toList();
35+
}
36+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.example.Centralthon.domain.store.web.controller;
2+
3+
import com.example.Centralthon.domain.store.service.StoreService;
4+
import com.example.Centralthon.domain.store.web.dto.NearbyStoresRes;
5+
import com.example.Centralthon.global.response.SuccessResponse;
6+
import lombok.RequiredArgsConstructor;
7+
import org.springframework.http.HttpStatus;
8+
import org.springframework.http.ResponseEntity;
9+
import org.springframework.web.bind.annotation.GetMapping;
10+
import org.springframework.web.bind.annotation.RequestMapping;
11+
import org.springframework.web.bind.annotation.RequestParam;
12+
import org.springframework.web.bind.annotation.RestController;
13+
import java.util.List;
14+
15+
@RestController
16+
@RequestMapping("/api/stores")
17+
@RequiredArgsConstructor
18+
public class StoreController {
19+
private final StoreService storeService;
20+
21+
// 근처 가게 위치 목록 조회
22+
@GetMapping("")
23+
public ResponseEntity<SuccessResponse<List<NearbyStoresRes>>> nearbyStores(
24+
@RequestParam("lat") Double lat,
25+
@RequestParam("lng") Double lng){
26+
27+
List<NearbyStoresRes> stores = storeService.nearbyStores(lat, lng);
28+
29+
return ResponseEntity.status(HttpStatus.OK).body(SuccessResponse.from(stores));
30+
}
31+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.example.Centralthon.domain.store.web.dto;
2+
3+
import com.example.Centralthon.domain.store.entity.Store;
4+
5+
public record NearbyStoresRes(
6+
Long storeId,
7+
Double lat,
8+
Double lng
9+
) {
10+
public static NearbyStoresRes from(Store store){
11+
return new NearbyStoresRes(
12+
store.getId(),
13+
store.getLatitude(),
14+
store.getLongitude()
15+
);
16+
}
17+
}

0 commit comments

Comments
 (0)