-
Notifications
You must be signed in to change notification settings - Fork 1
지도 관련 API 3개 구현 #44
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
지도 관련 API 3개 구현 #44
Changes from all commits
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,131 @@ | ||
| package busanVibe.busan.domain.place.service | ||
|
|
||
| import busanVibe.busan.domain.place.domain.Place | ||
| import busanVibe.busan.domain.place.domain.PlaceImage | ||
| import busanVibe.busan.domain.place.dto.PlaceMapResponseDTO | ||
| import busanVibe.busan.domain.place.enums.PlaceType | ||
| import busanVibe.busan.domain.place.repository.PlaceRepository | ||
| import busanVibe.busan.domain.review.domain.Review | ||
| import busanVibe.busan.domain.review.domain.repository.ReviewRepository | ||
| import busanVibe.busan.global.apiPayload.code.status.ErrorStatus | ||
| import busanVibe.busan.global.apiPayload.exception.handler.ExceptionHandler | ||
| import org.slf4j.LoggerFactory | ||
| import org.springframework.stereotype.Service | ||
| import org.springframework.transaction.annotation.Transactional | ||
| import java.math.BigDecimal | ||
| import java.math.RoundingMode | ||
| import java.time.LocalDateTime | ||
|
|
||
| @Service | ||
| class PlaceCongestionQueryService( | ||
| private val placeRepository: PlaceRepository, | ||
| private val placeRedisUtil: PlaceRedisUtil, | ||
| private val reviewRepository: ReviewRepository, | ||
| ) { | ||
|
|
||
| private val latitudeRange: Double = 0.05 | ||
| private val longitudeRange: Double = 0.05 | ||
|
|
||
| private val log = LoggerFactory.getLogger(PlaceCongestionQueryService::class.java) | ||
|
|
||
| @Transactional(readOnly = true) | ||
| fun getMap(type: PlaceType?, latitude: Double, longitude: Double): PlaceMapResponseDTO.MapListDto{ | ||
|
|
||
| // Place -> name, type, latitude, longitude | ||
| // Redis -> congestion level | ||
|
|
||
| // Place 목록 조회 | ||
| val placeList = placeRepository.findPlacesByLocationAndType( | ||
| BigDecimal(latitude - latitudeRange).setScale(6, RoundingMode.HALF_UP), | ||
| BigDecimal(latitude + latitudeRange).setScale(6, RoundingMode.HALF_UP), | ||
| BigDecimal(longitude - longitudeRange).setScale(6, RoundingMode.HALF_UP), | ||
| BigDecimal(longitude + longitudeRange).setScale(6, RoundingMode.HALF_UP), | ||
| type | ||
| ) | ||
|
|
||
| // DTO 변환 | ||
| val placeDtoList :List<PlaceMapResponseDTO.PlaceMapInfoDto> = placeList.map { | ||
| PlaceMapResponseDTO.PlaceMapInfoDto( | ||
| placeId = it.id, | ||
| name = it.name, | ||
| type = it.type.capitalEnglish, | ||
| latitude = it.latitude, | ||
| longitude = it.longitude, | ||
| congestionLevel = placeRedisUtil.getRedisCongestion(it.id) | ||
| ) | ||
| } | ||
|
Comment on lines
+47
to
+56
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. 🛠️ Refactor suggestion Potential N+1 performance issue with Redis calls The current implementation makes individual Redis calls for each place when fetching congestion levels. For large result sets, this could impact performance. Consider implementing a batch fetch method in // In PlaceRedisUtil
fun getRedisCongestionBatch(placeIds: List<Long>): Map<Long, Int> {
val keys = placeIds.map { "place:congestion:$it" }
val values = redisTemplate.opsForValue().multiGet(keys)
return placeIds.zip(values ?: emptyList()).associate { (id, value) ->
id to (value?.toIntOrNull() ?: generateAndStoreCongestion(id))
}
}Then update the mapping: + val congestionMap = placeRedisUtil.getRedisCongestionBatch(placeList.map { it.id })
val placeDtoList :List<PlaceMapResponseDTO.PlaceMapInfoDto> = placeList.map {
PlaceMapResponseDTO.PlaceMapInfoDto(
placeId = it.id,
name = it.name,
type = it.type.capitalEnglish,
latitude = it.latitude,
longitude = it.longitude,
- congestionLevel = placeRedisUtil.getRedisCongestion(it.id)
+ congestionLevel = congestionMap[it.id] ?: 0
)
}🤖 Prompt for AI Agents |
||
|
|
||
| return PlaceMapResponseDTO.MapListDto(placeDtoList) | ||
| } | ||
|
|
||
| @Transactional(readOnly = true) | ||
| fun getPlaceDefault(placeId: Long): PlaceMapResponseDTO.PlaceDefaultInfoDto{ | ||
|
|
||
| // Place -> name, imageList, address, openTime | ||
| // Review -> grade, count | ||
| // Image -> list | ||
| // Redis -> congestion | ||
|
|
||
| // 명소 조회 | ||
| val place: Place? = placeRepository.findByIdWithReviewAndImage(placeId) | ||
| place?: throw ExceptionHandler(ErrorStatus.PLACE_NOT_FOUND) | ||
|
|
||
| // 이미지 조회 | ||
| val placeImageSet: Set<PlaceImage> = place.placeImages | ||
| val placeImageList = placeImageSet.toList() | ||
| .sortedBy { it.createdAt } | ||
| .map { it.imgUrl } | ||
|
|
||
| // 리뷰 조회 | ||
| val reviewSet: Set<Review> = reviewRepository.findByPlace(place).toSet() | ||
| val grade = if (reviewSet.isEmpty()) 0f | ||
| else reviewSet.map { it.score }.average().toFloat() | ||
|
|
||
| return PlaceMapResponseDTO.PlaceDefaultInfoDto( | ||
| id = place.id, | ||
| name = place.name, | ||
| congestionLevel = placeRedisUtil.getRedisCongestion(place.id), | ||
| grade = grade, | ||
| reviewAmount = reviewSet.size, | ||
| latitude = place.latitude, | ||
| longitude = place.longitude, | ||
| address = place.address, | ||
| isOpen = true, | ||
|
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. Hardcoded isOpen value doesn't reflect actual status The Consider implementing actual open/closed logic based on the place's open times: isOpen = determineIfOpen(place.openTimes, LocalDateTime.now())🤖 Prompt for AI Agents |
||
| imgList = placeImageList | ||
| ) | ||
| } | ||
|
|
||
| @Transactional(readOnly = true) | ||
| fun getCongestion(placeId: Long): PlaceMapResponseDTO.PlaceCongestionDto { | ||
|
|
||
| val current = LocalDateTime.now() | ||
| log.info("현재 시간: ${current}시") | ||
|
|
||
| val roundedBase = (current.hour / 3) * 3 | ||
|
|
||
| // 최근 6개 3시간 단위 시간 생성 (기준시간 포함 총 7개) | ||
| val hours = (6 downTo 0).map { i -> (roundedBase - i * 3 + 24) % 24 } | ||
|
|
||
| log.info("배열 담기 시작") | ||
|
|
||
| val byTimePercent: List<Float> = hours.map { hour -> | ||
| val adjustedDateTime = current.withHour(hour) | ||
| .withMinute(0).withSecond(0).withNano(0) | ||
| .let { | ||
| if (hour > current.hour) it.minusDays(1) else it | ||
| } | ||
| placeRedisUtil.getTimeCongestion(placeId, adjustedDateTime) | ||
| } | ||
|
|
||
| log.info("배열 담기 끝") | ||
|
|
||
| return PlaceMapResponseDTO.PlaceCongestionDto( | ||
| standardTime = roundedBase, | ||
| realTimeCongestionLevel = placeRedisUtil.getTimeCongestion(placeId, current).toInt(), | ||
| byTimePercent = byTimePercent | ||
| ) | ||
| } | ||
|
|
||
|
|
||
|
|
||
| } | ||
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.
Fix parameter name typo
There's a typo in the parameter name:
longtitudeshould belongitude.Also update the service call:
📝 Committable suggestion
🤖 Prompt for AI Agents