diff --git a/build.gradle b/build.gradle index 7786006..187dec7 100644 --- a/build.gradle +++ b/build.gradle @@ -79,9 +79,6 @@ dependencies { // xml implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.0") - implementation 'org.springframework.boot:spring-boot-starter-webflux' - - } diff --git a/src/main/kotlin/busanVibe/busan/domain/chat/controller/ChatRestController.kt b/src/main/kotlin/busanVibe/busan/domain/chat/controller/ChatRestController.kt index e03a02e..8ad7433 100644 --- a/src/main/kotlin/busanVibe/busan/domain/chat/controller/ChatRestController.kt +++ b/src/main/kotlin/busanVibe/busan/domain/chat/controller/ChatRestController.kt @@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController @Tag(name = "채팅 관련 API") @@ -30,9 +31,15 @@ class ChatRestController( } @GetMapping("/history") - @Operation(summary = "채팅 조회 API", description = "채팅 목록을 조회합니다.") - fun getHistory(): ApiResponse { - val chatList = chatMongoService.getChatHistory() + @Operation(summary = "채팅 조회 API", + description = """ + 채팅 목록을 조회합니다. + - cursor 페이지네이션 처리를 합니다. + 처음 조회할 때는 cursor-id에 null이 들어가고, 이후에는 cursor-id에 응답받은 cursor_id를 넣어 요청하세요. + - page-size의 기본값은 30이며 최대값은 30입니다. + """) + fun getHistory(@RequestParam("cursor-id", required = false) cursorId: String?, @RequestParam("page-size", required = false, defaultValue = "30") size: Int): ApiResponse { + val chatList = chatMongoService.getChatHistory(cursorId, size) return ApiResponse.onSuccess(chatList) } diff --git a/src/main/kotlin/busanVibe/busan/domain/chat/dto/websocket/ChatMessageResponseDTO.kt b/src/main/kotlin/busanVibe/busan/domain/chat/dto/websocket/ChatMessageResponseDTO.kt index 3551768..ff15f18 100644 --- a/src/main/kotlin/busanVibe/busan/domain/chat/dto/websocket/ChatMessageResponseDTO.kt +++ b/src/main/kotlin/busanVibe/busan/domain/chat/dto/websocket/ChatMessageResponseDTO.kt @@ -9,12 +9,13 @@ class ChatMessageResponseDTO { @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) data class ListDto( - val chatList: List + val chatList: List, + val nextCursor: String? = null ) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) data class ChatInfoDto( - val userName: String, + val userName: String?, val userImage: String?, val content: String, val dateTime: LocalDateTime?, diff --git a/src/main/kotlin/busanVibe/busan/domain/chat/dto/websocket/ChatMessageSendDTO.kt b/src/main/kotlin/busanVibe/busan/domain/chat/dto/websocket/ChatMessageSendDTO.kt index b1a74b6..ed0f39d 100644 --- a/src/main/kotlin/busanVibe/busan/domain/chat/dto/websocket/ChatMessageSendDTO.kt +++ b/src/main/kotlin/busanVibe/busan/domain/chat/dto/websocket/ChatMessageSendDTO.kt @@ -10,7 +10,7 @@ data class ChatMessageSendDTO( // var userId: Long? = null, var type: MessageType? = null, // 메시지 타입 var message: String? = null, // 메시지 - var time: LocalDateTime? = null, // 전송 시간 +// var time: LocalDateTime? = null, // 전송 시간 ){ } \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/chat/repository/ChatMongoRepository.kt b/src/main/kotlin/busanVibe/busan/domain/chat/repository/ChatMongoRepository.kt index 15d22e1..64f2b7e 100644 --- a/src/main/kotlin/busanVibe/busan/domain/chat/repository/ChatMongoRepository.kt +++ b/src/main/kotlin/busanVibe/busan/domain/chat/repository/ChatMongoRepository.kt @@ -1,8 +1,10 @@ package busanVibe.busan.domain.chat.repository import busanVibe.busan.domain.chat.domain.ChatMessage +import org.springframework.data.domain.Pageable import org.springframework.data.mongodb.repository.MongoRepository interface ChatMongoRepository: MongoRepository { - fun findAllByOrderByTime(): List + fun findAllByOrderByTimeDesc(pageable: Pageable): List + fun findByIdLessThanOrderByTimeDesc(id: String, pageable: Pageable): List } \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/chat/service/ChatMongoService.kt b/src/main/kotlin/busanVibe/busan/domain/chat/service/ChatMongoService.kt index bf8e20d..8fb015a 100644 --- a/src/main/kotlin/busanVibe/busan/domain/chat/service/ChatMongoService.kt +++ b/src/main/kotlin/busanVibe/busan/domain/chat/service/ChatMongoService.kt @@ -6,10 +6,13 @@ import busanVibe.busan.domain.chat.dto.websocket.ChatMessageResponseDTO import busanVibe.busan.domain.chat.dto.websocket.ChatMessageSendDTO import busanVibe.busan.domain.chat.enums.MessageType import busanVibe.busan.domain.chat.repository.ChatMongoRepository +import busanVibe.busan.domain.user.data.User import busanVibe.busan.domain.user.repository.UserRepository import busanVibe.busan.domain.user.service.login.AuthService import busanVibe.busan.global.apiPayload.code.ErrorReasonDTO import busanVibe.busan.global.apiPayload.code.status.ErrorStatus +import busanVibe.busan.global.apiPayload.exception.GeneralException +import org.springframework.data.domain.Pageable import org.springframework.data.redis.listener.ChannelTopic import org.springframework.http.HttpStatus import org.springframework.messaging.simp.SimpMessagingTemplate @@ -50,7 +53,7 @@ class ChatMongoService( type = chatMessage.type?: MessageType.CHAT, userId = currentUser.id, message = chatMessage.message?:"", - time = chatMessage.time?: LocalDateTime.now(), + time = LocalDateTime.now(), ) // 채팅 저장 @@ -68,26 +71,45 @@ class ChatMongoService( redisPublisher.publish(topic, receiveDto) } - fun getChatHistory(): ChatMessageResponseDTO.ListDto { + fun getChatHistory(cursorId: String?, pageSize: Int = 15): ChatMessageResponseDTO.ListDto { + + if(pageSize < 0){ + throw GeneralException(ErrorStatus.INVALID_PAGE_SIZE_MINUS) + }else if (pageSize > 30) { + throw GeneralException(ErrorStatus.INVALID_PAGE_SIZE_BIG) + } + + // 현재 로그인한 유저 조회 val currentUser = AuthService().getCurrentUser() - val chatHistory = chatMongoRepository.findAllByOrderByTime() + // 조회 -> List 변수 선언 및 초기화 + val chatHistory: List = if (cursorId != null) { // 처음이면 cursorId 없이 조회 + chatMongoRepository.findByIdLessThanOrderByTimeDesc(cursorId, Pageable.ofSize(pageSize)) + } else { // 처음 아니면 cursorId로 조회 + chatMongoRepository.findAllByOrderByTimeDesc(Pageable.ofSize(pageSize)) + } - val dtoList = chatHistory.mapNotNull { chat -> - val user = chat.userId?.let { userRepository.findById(it).orElse(null) } + // userId List 저장. 바로 뒤에 userId로 User 정보들을 먼저 찾고, 그 뒤에 DTO 변환 + val userIdList: List = chatHistory.mapNotNull { it -> it.userId }.toList() - if (user == null) return@mapNotNull null + // -> Map로 저장 + val userMap: Map = userRepository.findUsersByIdIn(userIdList).associateBy { it.id as Long } + // DTO 변환 + val dtoList = chatHistory.map { chat -> + val user: User? = userMap[chat.userId ?: -1] ChatMessageResponseDTO.ChatInfoDto( - userName = user.nickname, - userImage = user.profileImageUrl, - content = chat.message, + userName = user?.nickname ?: "알 수 없음", + userImage = user?.profileImageUrl, dateTime = chat.time, - isMy = user.id == currentUser.id + content = chat.message, + isMy = user?.id == currentUser.id ) } - return ChatMessageResponseDTO.ListDto(dtoList) + val nextCursor = chatHistory.lastOrNull()?.id + + return ChatMessageResponseDTO.ListDto(dtoList, nextCursor) } diff --git a/src/main/kotlin/busanVibe/busan/domain/common/dto/InfoType.kt b/src/main/kotlin/busanVibe/busan/domain/common/dto/InfoType.kt index f2da98d..a394f2b 100644 --- a/src/main/kotlin/busanVibe/busan/domain/common/dto/InfoType.kt +++ b/src/main/kotlin/busanVibe/busan/domain/common/dto/InfoType.kt @@ -1,14 +1,18 @@ package busanVibe.busan.domain.common.dto +import busanVibe.busan.domain.place.enums.PlaceType + enum class InfoType( val kr: String, val en: String, + val placeType: PlaceType? = null ) { - ALL("전체", "ALL"), + ALL("전체", "ALL", PlaceType.ALL), // 명소 - SIGHT("명소", "SIGHT"), - RESTAURANT("식당", "RESTAURANT"), - CAFE("카페", "CAFE"), + SIGHT("명소", "SIGHT", PlaceType.SIGHT), + RESTAURANT("식당", "RESTAURANT", PlaceType.RESTAURANT), + CAFE("카페", "CAFE", PlaceType.CAFE), + CULTURE("문화시설", "CULTURE", PlaceType.CULTURE), // 축제 FESTIVAL("축제", "FESTIVAL"), ; diff --git a/src/main/kotlin/busanVibe/busan/domain/festival/repository/FestivalLikesRepository.kt b/src/main/kotlin/busanVibe/busan/domain/festival/repository/FestivalLikesRepository.kt index 4e5d989..2eb2f59 100644 --- a/src/main/kotlin/busanVibe/busan/domain/festival/repository/FestivalLikesRepository.kt +++ b/src/main/kotlin/busanVibe/busan/domain/festival/repository/FestivalLikesRepository.kt @@ -3,11 +3,15 @@ package busanVibe.busan.domain.festival.repository import busanVibe.busan.domain.festival.domain.Festival import busanVibe.busan.domain.festival.domain.FestivalLike import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.query.Param interface FestivalLikesRepository: JpaRepository { fun findAllByFestivalIn(festivalList: List): List fun findAllByFestivalIn(festivalList: Set): List + @Query("SELECT fl FROM FestivalLike fl WHERE fl.festival IN :festivals") + fun findLikeByFestival(@Param("festivals") festivalList: List): List } \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/festival/repository/FestivalRepository.kt b/src/main/kotlin/busanVibe/busan/domain/festival/repository/FestivalRepository.kt index 114f309..858a308 100644 --- a/src/main/kotlin/busanVibe/busan/domain/festival/repository/FestivalRepository.kt +++ b/src/main/kotlin/busanVibe/busan/domain/festival/repository/FestivalRepository.kt @@ -2,6 +2,7 @@ package busanVibe.busan.domain.festival.repository import busanVibe.busan.domain.festival.domain.Festival import busanVibe.busan.domain.festival.enums.FestivalStatus +import busanVibe.busan.domain.user.data.User import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.query.Param @@ -33,4 +34,15 @@ interface FestivalRepository: JpaRepository { ) fun findAllWithFetch(): List + @Query( + """ + SELECT f FROM Festival f + LEFT JOIN FETCH f.festivalImages + LEFT JOIN FETCH f.festivalLikes fl + LEFT JOIN FETCH fl.user + WHERE fl.user = :user + """ + ) + fun findLikeFestivals(@Param("user") user: User): List + } \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/place/controller/PlaceCongestionController.kt b/src/main/kotlin/busanVibe/busan/domain/place/controller/PlaceCongestionController.kt index 4096e1a..cb1df41 100644 --- a/src/main/kotlin/busanVibe/busan/domain/place/controller/PlaceCongestionController.kt +++ b/src/main/kotlin/busanVibe/busan/domain/place/controller/PlaceCongestionController.kt @@ -20,13 +20,25 @@ class PlaceCongestionController ( ){ @GetMapping - @Operation(summary = "지도 조회") + @Operation(summary = "지도 조회", + description = + """ + 지도에 띄울 장소를 조회합니다. + 좌측 상단의 좌표와 우측 하단의 위경도를 요청 파라미터로 포함하세요. + 좌측상단 ( lat1, lng1 ), 우측하단 ( lat2, lng2 ) + lat1 > lat2 + lng1 < lng2 + """ + ) fun map( @RequestParam("type", required = false, defaultValue = "ALL") type: PlaceType, - @RequestParam("latitude")latitude: Double, - @RequestParam("longitude")longitude: Double): ApiResponse{ + @RequestParam("lat1")lat1: Double, + @RequestParam("lng1")lng1: Double, + @RequestParam("lat2")lat2: Double, + @RequestParam("lng2")lng2: Double + ): ApiResponse{ - val places = placeCongestionQueryService.getMap(type, latitude, longitude) + val places = placeCongestionQueryService.getMap(type, lat1, lng1, lat2, lng2) return ApiResponse.onSuccess(places); } diff --git a/src/main/kotlin/busanVibe/busan/domain/place/repository/PlaceLikeRepository.kt b/src/main/kotlin/busanVibe/busan/domain/place/repository/PlaceLikeRepository.kt index aa85f8e..78091ff 100644 --- a/src/main/kotlin/busanVibe/busan/domain/place/repository/PlaceLikeRepository.kt +++ b/src/main/kotlin/busanVibe/busan/domain/place/repository/PlaceLikeRepository.kt @@ -3,8 +3,14 @@ package busanVibe.busan.domain.place.repository import busanVibe.busan.domain.place.domain.Place import busanVibe.busan.domain.place.domain.PlaceLike import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.query.Param interface PlaceLikeRepository: JpaRepository { fun findAllByPlaceIn(placeList: List): List fun findByPlace(place: Place): List + + @Query("SELECT pl FROM PlaceLike pl WHERE pl.place IN :places") + fun findLikeByPlace(@Param("places") placeList: List): List + } \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/place/repository/PlaceRepository.kt b/src/main/kotlin/busanVibe/busan/domain/place/repository/PlaceRepository.kt index b0d9827..70b6100 100644 --- a/src/main/kotlin/busanVibe/busan/domain/place/repository/PlaceRepository.kt +++ b/src/main/kotlin/busanVibe/busan/domain/place/repository/PlaceRepository.kt @@ -2,6 +2,7 @@ package busanVibe.busan.domain.place.repository import busanVibe.busan.domain.place.domain.Place import busanVibe.busan.domain.place.enums.PlaceType +import busanVibe.busan.domain.user.data.User import org.springframework.data.jpa.repository.EntityGraph import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query @@ -102,4 +103,28 @@ interface PlaceRepository: JpaRepository { ) fun findAllWithFetch(): List + @Query( + """ + SELECT DISTINCT p FROM Place p + LEFT JOIN FETCH p.placeLikes pl + LEFT JOIN FETCH p.placeImages + LEFT JOIN FETCH p.openTime + LEFT JOIN FETCH pl.user + WHERE pl.user = :user + """ + ) + fun findLikePlace(@Param("user") user: User): List + + @Query( + """ + SELECT DISTINCT p FROM Place p + LEFT JOIN FETCH p.placeLikes pl + LEFT JOIN FETCH p.placeImages + LEFT JOIN FETCH p.openTime + LEFT JOIN FETCH pl.user + WHERE p.type = :type AND pl.user = :user + """ + ) + fun findLikePlaceByType(@Param("type") type: PlaceType, @Param("user") user: User): List + } \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/place/service/PlaceCongestionQueryService.kt b/src/main/kotlin/busanVibe/busan/domain/place/service/PlaceCongestionQueryService.kt index 9ed6fe7..c60a64c 100644 --- a/src/main/kotlin/busanVibe/busan/domain/place/service/PlaceCongestionQueryService.kt +++ b/src/main/kotlin/busanVibe/busan/domain/place/service/PlaceCongestionQueryService.kt @@ -11,6 +11,7 @@ import busanVibe.busan.domain.place.util.PlaceRedisUtil 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.GeneralException import busanVibe.busan.global.apiPayload.exception.handler.ExceptionHandler import org.slf4j.LoggerFactory import org.springframework.stereotype.Service @@ -32,18 +33,33 @@ class PlaceCongestionQueryService( private val log = LoggerFactory.getLogger(PlaceCongestionQueryService::class.java) + /** + * 두 좌표를 받아 계산 및 조회 후 반환 + * 좌측상단 좌표 ( lat1, ln1 ), 우측하단 좌표 ( lat2, lng2 ) + * lat1 > lat2 + * lng1 < lng2 + */ @Transactional(readOnly = true) - fun getMap(type: PlaceType?, latitude: Double, longitude: Double): PlaceMapResponseDTO.MapListDto{ + fun getMap(type: PlaceType?, lat1: Double, lng1: Double, lat2: Double, lng2: Double): PlaceMapResponseDTO.MapListDto{ // Place -> name, type, latitude, longitude // Redis -> congestion level + if (lat1 !in -90.0..90.0 || lat2 !in -90.0..90.0) + throw GeneralException(ErrorStatus.MAP_LATITUDE_OUT_OF_RANGE) + + if (lng1 !in -180.0..180.0 || lng2 !in -180.0..180.0) + throw GeneralException(ErrorStatus.MAP_LONGITUDE_OUT_OF_RANGE) + + if (lat1 <= lat2 || lng1 >= lng2) + throw GeneralException(ErrorStatus.MAP_INVALID_COORDINATE_ORDER) + // 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), + BigDecimal(lat2).setScale(6, RoundingMode.HALF_UP), + BigDecimal(lat1).setScale(6, RoundingMode.HALF_UP), + BigDecimal(lng1).setScale(6, RoundingMode.HALF_UP), + BigDecimal(lng2).setScale(6, RoundingMode.HALF_UP), type ) diff --git a/src/main/kotlin/busanVibe/busan/domain/search/dto/SearchResultDTO.kt b/src/main/kotlin/busanVibe/busan/domain/search/dto/SearchResultDTO.kt index 7f9b03d..19e6d50 100644 --- a/src/main/kotlin/busanVibe/busan/domain/search/dto/SearchResultDTO.kt +++ b/src/main/kotlin/busanVibe/busan/domain/search/dto/SearchResultDTO.kt @@ -8,6 +8,7 @@ class SearchResultDTO { @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) data class ListDto( + val sort: String, val resultList: List ) @@ -26,7 +27,8 @@ class SearchResultDTO { val startDate: String? = null, val endDate: String? = null, @get:JsonProperty("is_end") - val isEnd: Boolean? + val isEnd: Boolean?, + val likeCount: Int = 0 ) } \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/search/service/SearchQueryService.kt b/src/main/kotlin/busanVibe/busan/domain/search/service/SearchQueryService.kt index 45e323f..45bea9a 100644 --- a/src/main/kotlin/busanVibe/busan/domain/search/service/SearchQueryService.kt +++ b/src/main/kotlin/busanVibe/busan/domain/search/service/SearchQueryService.kt @@ -1,12 +1,14 @@ package busanVibe.busan.domain.search.service import busanVibe.busan.domain.common.dto.InfoType +import busanVibe.busan.domain.festival.repository.FestivalLikesRepository import busanVibe.busan.domain.festival.repository.FestivalRepository import busanVibe.busan.domain.place.enums.PlaceType +import busanVibe.busan.domain.place.repository.PlaceLikeRepository import busanVibe.busan.domain.place.repository.PlaceRepository -import busanVibe.busan.domain.place.util.PlaceRedisUtil import busanVibe.busan.domain.search.dto.SearchResultDTO import busanVibe.busan.domain.search.enums.GeneralSortType +import busanVibe.busan.domain.search.util.SearchUtil import busanVibe.busan.domain.user.service.login.AuthService import busanVibe.busan.global.apiPayload.code.status.ErrorStatus import busanVibe.busan.global.apiPayload.exception.handler.ExceptionHandler @@ -17,7 +19,9 @@ import org.springframework.transaction.annotation.Transactional class SearchQueryService( private val placeRepository: PlaceRepository, private val festivalRepository: FestivalRepository, - private val placeRedisUtil: PlaceRedisUtil + private val placeLikeRepository: PlaceLikeRepository, + private val festivalLikeRepository: FestivalLikesRepository, + private val searchUtil: SearchUtil, ) { @Transactional(readOnly = true) @@ -44,68 +48,13 @@ class SearchQueryService( else -> emptyList() } - // 축제 List -> dto List 변환 - val festivalDtoList = festivals.map { festival -> - SearchResultDTO.InfoDto( - typeKr = InfoType.FESTIVAL.kr, - typeEn = InfoType.FESTIVAL.en, - id = festival.id, - name = festival.name, - address = festival.place, - isLiked = festival.festivalLikes.any { it.user == currentUser }, - startDate = festival.startDate.toString(), - endDate = festival.endDate.toString(), - isEnd = festival.endDate.before(java.util.Date()) - ) - } - - // 혼잡도 List -> dto List 변환 - val placeDtoList = places.map { place -> - SearchResultDTO.InfoDto( - typeKr = place.type.korean, - typeEn = place.type.capitalEnglish, - id = place.id, - name = place.name, - latitude = place.latitude?.toDouble(), - longitude = place.longitude?.toDouble(), - address = place.address, - congestionLevel = placeRedisUtil.getRedisCongestion(place.id), - isLiked = place.placeLikes.any { it.user == currentUser }, - startDate = null, - endDate = null, - isEnd = null - ) - } - - // 정렬 기준에 따라 처리 - val resultList: List = when (sort) { - GeneralSortType.LIKE -> { - (placeDtoList + festivalDtoList).sortedByDescending { item -> - // 좋아요 수 기준 정렬 - when (item.typeEn) { - InfoType.FESTIVAL.en -> festivals.find { it.id == item.id }?.festivalLikes?.size ?: 0 - else -> places.find { it.id == item.id }?.placeLikes?.size ?: 0 - } - } - } + val placeLikeList = placeLikeRepository.findLikeByPlace(places) + val festivalLikeList = festivalLikeRepository.findLikeByFestival(festivals) - GeneralSortType.CONGESTION -> { - // 혼잡도 정렬은 명소만 해당 - placeDtoList - .filter { it.congestionLevel != null } - .sortedBy { it.congestionLevel } - } + // 엔티티 List로 DTO List 반환 + val resultList = searchUtil.listToSearchDTO(places, festivals, sort, currentUser, placeLikeList, festivalLikeList) - GeneralSortType.DEFAULT -> { - // 기본 정렬은 그대로 - placeDtoList + festivalDtoList - } - } - - // 반환 - return SearchResultDTO.ListDto(resultList) + return SearchResultDTO.ListDto(sort.name, resultList) } - - } \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/search/util/SearchUtil.kt b/src/main/kotlin/busanVibe/busan/domain/search/util/SearchUtil.kt new file mode 100644 index 0000000..13c4535 --- /dev/null +++ b/src/main/kotlin/busanVibe/busan/domain/search/util/SearchUtil.kt @@ -0,0 +1,80 @@ +package busanVibe.busan.domain.search.util + +import busanVibe.busan.domain.common.dto.InfoType +import busanVibe.busan.domain.festival.domain.Festival +import busanVibe.busan.domain.festival.domain.FestivalLike +import busanVibe.busan.domain.place.domain.Place +import busanVibe.busan.domain.place.domain.PlaceLike +import busanVibe.busan.domain.place.util.PlaceRedisUtil +import busanVibe.busan.domain.search.dto.SearchResultDTO +import busanVibe.busan.domain.search.enums.GeneralSortType +import busanVibe.busan.domain.user.data.User +import org.springframework.stereotype.Component + +@Component +class SearchUtil( + private val placeRedisUtil: PlaceRedisUtil +) { + + /** + * List와 List로 정렬 조건에 맞는 List 반환 + */ + fun listToSearchDTO(places: List, festivals: List, sort: GeneralSortType, currentUser: User, placeLikeList: List, festivalLikeList: List): List { + + // 축제 List -> dto List 변환 + val festivalDtoList = festivals.map { festival -> + + val festivalLikeCount = festivalLikeList.filter { it.festival == festival }.size + + SearchResultDTO.InfoDto( + typeKr = InfoType.FESTIVAL.kr, + typeEn = InfoType.FESTIVAL.en, + id = festival.id, + name = festival.name, + address = festival.place, + isLiked = festival.festivalLikes.any { it.user == currentUser }, + startDate = festival.startDate.toString(), + endDate = festival.endDate.toString(), + isEnd = festival.endDate.before(java.util.Date()), + likeCount = festivalLikeCount + ) + } + + // 혼잡도 List -> dto List 변환 + val placeDtoList = places.map { place -> + + val placeLikeCount = placeLikeList.filter { it.place == place }.size + + SearchResultDTO.InfoDto( + typeKr = place.type.korean, + typeEn = place.type.capitalEnglish, + id = place.id, + name = place.name, + latitude = place.latitude?.toDouble(), + longitude = place.longitude?.toDouble(), + address = place.address, + congestionLevel = placeRedisUtil.getRedisCongestion(place.id), + isLiked = place.placeLikes.any { it.user == currentUser }, + startDate = null, + endDate = null, + isEnd = null, + likeCount = placeLikeCount + ) + } + + + val dtoList = placeDtoList + festivalDtoList + + // 정렬 기준에 따라 처리 + return when (sort) { + GeneralSortType.LIKE -> dtoList.sortedByDescending { it.likeCount } + GeneralSortType.CONGESTION -> placeDtoList + .filter { it.congestionLevel != null } + .sortedBy { it.congestionLevel } + GeneralSortType.DEFAULT -> dtoList.shuffled() + } + + + } + +} \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/user/controller/UserAuthController.kt b/src/main/kotlin/busanVibe/busan/domain/user/controller/UserAuthController.kt new file mode 100644 index 0000000..7373423 --- /dev/null +++ b/src/main/kotlin/busanVibe/busan/domain/user/controller/UserAuthController.kt @@ -0,0 +1,41 @@ +package busanVibe.busan.domain.user.controller + +import busanVibe.busan.domain.user.data.dto.login.TokenResponseDto +import busanVibe.busan.domain.user.data.dto.login.UserLoginResponseDTO +import busanVibe.busan.domain.user.service.UserCommandService +import busanVibe.busan.domain.user.util.LoginRedirectUtil +import busanVibe.busan.global.apiPayload.exception.ApiResponse +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController + +@Tag(name = "로그인 관련 API", description = "로그인과 분리할수도 있습니다") +@RestController +@RequestMapping("/users") +class UserAuthController ( + private val userCommandService: UserCommandService, + private val loginRedirectUtil: LoginRedirectUtil +){ + + @GetMapping("/oauth/kakao") + fun callBack(@RequestParam("code") code: String): ResponseEntity { + val userResponse: UserLoginResponseDTO.LoginDto = userCommandService.loginOrRegisterByKakao(code) + val redirectHeader = loginRedirectUtil.getRedirectHeader(userResponse) + return ResponseEntity.status(HttpStatus.FOUND).headers(redirectHeader).build() + } + + @PostMapping("/guest/login") + @Operation(summary = "게스트 로그인 API", description = "1회용 계정 로그인입니다. 재로그인이 불가능합니다.") + fun guestLogin(): ApiResponse{ + val userResponse: UserLoginResponseDTO.LoginDto = userCommandService.guestLogin() + return ApiResponse.onSuccess(userResponse.tokenResponseDTO) + } + + +} \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/user/controller/UserController.kt b/src/main/kotlin/busanVibe/busan/domain/user/controller/UserController.kt index e34be67..52ceb80 100644 --- a/src/main/kotlin/busanVibe/busan/domain/user/controller/UserController.kt +++ b/src/main/kotlin/busanVibe/busan/domain/user/controller/UserController.kt @@ -1,40 +1,45 @@ package busanVibe.busan.domain.user.controller -import busanVibe.busan.domain.user.data.dto.TokenResponseDto +import busanVibe.busan.domain.common.dto.InfoType +import busanVibe.busan.domain.search.dto.SearchResultDTO +import busanVibe.busan.domain.search.enums.GeneralSortType import busanVibe.busan.domain.user.data.dto.UserResponseDTO -import busanVibe.busan.domain.user.service.UserCommandService -import busanVibe.busan.domain.user.util.LoginRedirectUtil +import busanVibe.busan.domain.user.service.UserQueryService import busanVibe.busan.global.apiPayload.exception.ApiResponse import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag -import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController -@Tag(name = "유저 관련 API", description = "로그인과 분리할수도 있습니다") +@Tag(name = "마이페이지 API") @RestController -@RequestMapping("/users") -class UserController ( - private val userCommandService: UserCommandService, - private val loginRedirectUtil: LoginRedirectUtil -){ - - @GetMapping("/oauth/kakao") - fun callBack(@RequestParam("code") code: String): ResponseEntity { - val userResponse: UserResponseDTO.LoginDto = userCommandService.loginOrRegisterByKakao(code) - val redirectHeader = loginRedirectUtil.getRedirectHeader(userResponse) - return ResponseEntity.status(HttpStatus.FOUND).headers(redirectHeader).build() +@RequestMapping("/api/users") +class UserController( + private val userQueryService: UserQueryService +) { + + @GetMapping("/mypage") + @Operation(summary = "마이페이지 조회 API", description = "it is what it is") + fun myPage(): ApiResponse { + val myPageInfo = userQueryService.getMyPageInfo() + return ApiResponse.onSuccess(myPageInfo) } - @PostMapping("/guest/login") - @Operation(summary = "게스트 로그인 API", description = "1회용 계정 로그인입니다. 재로그인이 불가능합니다.") - fun guestLogin(): ApiResponse{ - val userResponse: UserResponseDTO.LoginDto = userCommandService.guestLogin() - return ApiResponse.onSuccess(userResponse.tokenResponseDTO) + @GetMapping("/likes") + @Operation(summary = "좋아요 목록 조회 API", + description = """ + 내가 좋아요 누른 정보 조회 API + CONGESTION(혼잡도) 정렬조건은 지원하지 않습니다. + """) + fun likes(@RequestParam("option", defaultValue = "ALL") infoType: InfoType, + @RequestParam("sort", defaultValue = "DEFAULT") sort: GeneralSortType + ): ApiResponse { + + val likeInfo = userQueryService.getMyLikes(infoType, sort) + return ApiResponse.onSuccess(likeInfo) + } diff --git a/src/main/kotlin/busanVibe/busan/domain/user/converter/UserConverter.kt b/src/main/kotlin/busanVibe/busan/domain/user/converter/UserConverter.kt index ffb1b76..b9ed5f7 100644 --- a/src/main/kotlin/busanVibe/busan/domain/user/converter/UserConverter.kt +++ b/src/main/kotlin/busanVibe/busan/domain/user/converter/UserConverter.kt @@ -1,8 +1,8 @@ package busanVibe.busan.domain.user.converter import busanVibe.busan.domain.user.data.User -import busanVibe.busan.domain.user.data.dto.TokenResponseDto -import busanVibe.busan.domain.user.data.dto.UserResponseDTO +import busanVibe.busan.domain.user.data.dto.login.TokenResponseDto +import busanVibe.busan.domain.user.data.dto.login.UserLoginResponseDTO import org.springframework.stereotype.Component @Component @@ -10,8 +10,8 @@ class UserConverter { fun toLoginDto( user: User, isNewUser: Boolean, tokenResponseDto: TokenResponseDto - ): UserResponseDTO.LoginDto { - return UserResponseDTO.LoginDto( + ): UserLoginResponseDTO.LoginDto { + return UserLoginResponseDTO.LoginDto( user.id, tokenResponseDto, user.email, isNewUser ) } diff --git a/src/main/kotlin/busanVibe/busan/domain/user/data/User.kt b/src/main/kotlin/busanVibe/busan/domain/user/data/User.kt index 819e0cc..691481d 100644 --- a/src/main/kotlin/busanVibe/busan/domain/user/data/User.kt +++ b/src/main/kotlin/busanVibe/busan/domain/user/data/User.kt @@ -27,7 +27,7 @@ class User( val id: Long? = null, @Column(nullable = false, unique = true) - var email: String?, + var email: String, @Column(nullable = false, length = 50) var nickname: String, diff --git a/src/main/kotlin/busanVibe/busan/domain/user/data/dto/UserLikesDTO.kt b/src/main/kotlin/busanVibe/busan/domain/user/data/dto/UserLikesDTO.kt new file mode 100644 index 0000000..0dae9f8 --- /dev/null +++ b/src/main/kotlin/busanVibe/busan/domain/user/data/dto/UserLikesDTO.kt @@ -0,0 +1,28 @@ +package busanVibe.busan.domain.user.data.dto + +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.annotation.JsonNaming + +class UserLikesDTO { + + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) + data class ListDto( + val resultList: List + ) + + data class LikesInfoDto( + val typeKr: String, + val typeEn: String, + val id: Long? = null, + val name: String, + val address: String, + @get:JsonProperty("is_liked") + val isLiked: Boolean, +// val startDate: String? = null, +// val endDate: String? = null, + @get:JsonProperty("is_end") + val isEnd: Boolean? + ) + +} \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/user/data/dto/UserResponseDTO.kt b/src/main/kotlin/busanVibe/busan/domain/user/data/dto/UserResponseDTO.kt index 69e78b2..2719ee6 100644 --- a/src/main/kotlin/busanVibe/busan/domain/user/data/dto/UserResponseDTO.kt +++ b/src/main/kotlin/busanVibe/busan/domain/user/data/dto/UserResponseDTO.kt @@ -1,13 +1,15 @@ package busanVibe.busan.domain.user.data.dto +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.annotation.JsonNaming + class UserResponseDTO { - companion object class LoginDto( - val id: Long?, - val tokenResponseDTO: TokenResponseDto, - val email: String?, - val isNewUser: Boolean + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) + data class MyPageDto( + val nickname: String, + val email: String, + val userImageUrl: String? = null ) - } \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/user/data/dto/KakaoTokenResponseDTO.kt b/src/main/kotlin/busanVibe/busan/domain/user/data/dto/login/KakaoTokenResponseDTO.kt similarity index 93% rename from src/main/kotlin/busanVibe/busan/domain/user/data/dto/KakaoTokenResponseDTO.kt rename to src/main/kotlin/busanVibe/busan/domain/user/data/dto/login/KakaoTokenResponseDTO.kt index 92d345a..6b1cebe 100644 --- a/src/main/kotlin/busanVibe/busan/domain/user/data/dto/KakaoTokenResponseDTO.kt +++ b/src/main/kotlin/busanVibe/busan/domain/user/data/dto/login/KakaoTokenResponseDTO.kt @@ -1,4 +1,4 @@ -package busanVibe.busan.domain.user.data.dto +package busanVibe.busan.domain.user.data.dto.login import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonProperty diff --git a/src/main/kotlin/busanVibe/busan/domain/user/data/dto/KakaoUserInfoResponse.kt b/src/main/kotlin/busanVibe/busan/domain/user/data/dto/login/KakaoUserInfoResponse.kt similarity index 94% rename from src/main/kotlin/busanVibe/busan/domain/user/data/dto/KakaoUserInfoResponse.kt rename to src/main/kotlin/busanVibe/busan/domain/user/data/dto/login/KakaoUserInfoResponse.kt index cc4a786..cd6bbf2 100644 --- a/src/main/kotlin/busanVibe/busan/domain/user/data/dto/KakaoUserInfoResponse.kt +++ b/src/main/kotlin/busanVibe/busan/domain/user/data/dto/login/KakaoUserInfoResponse.kt @@ -1,4 +1,4 @@ -package busanVibe.busan.domain.user.data.dto +package busanVibe.busan.domain.user.data.dto.login import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonProperty diff --git a/src/main/kotlin/busanVibe/busan/domain/user/data/dto/TokenResponseDto.kt b/src/main/kotlin/busanVibe/busan/domain/user/data/dto/login/TokenResponseDto.kt similarity index 87% rename from src/main/kotlin/busanVibe/busan/domain/user/data/dto/TokenResponseDto.kt rename to src/main/kotlin/busanVibe/busan/domain/user/data/dto/login/TokenResponseDto.kt index be5f687..0e4285f 100644 --- a/src/main/kotlin/busanVibe/busan/domain/user/data/dto/TokenResponseDto.kt +++ b/src/main/kotlin/busanVibe/busan/domain/user/data/dto/login/TokenResponseDto.kt @@ -1,4 +1,4 @@ -package busanVibe.busan.domain.user.data.dto +package busanVibe.busan.domain.user.data.dto.login import com.fasterxml.jackson.annotation.JsonInclude diff --git a/src/main/kotlin/busanVibe/busan/domain/user/data/dto/login/UserLoginResponseDTO.kt b/src/main/kotlin/busanVibe/busan/domain/user/data/dto/login/UserLoginResponseDTO.kt new file mode 100644 index 0000000..da074df --- /dev/null +++ b/src/main/kotlin/busanVibe/busan/domain/user/data/dto/login/UserLoginResponseDTO.kt @@ -0,0 +1,13 @@ +package busanVibe.busan.domain.user.data.dto.login + +class UserLoginResponseDTO { + + companion object class LoginDto( + val id: Long?, + val tokenResponseDTO: TokenResponseDto, + val email: String?, + val isNewUser: Boolean + ) + + +} \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/user/repository/UserRepository.kt b/src/main/kotlin/busanVibe/busan/domain/user/repository/UserRepository.kt index 2de0d41..5bbaec6 100644 --- a/src/main/kotlin/busanVibe/busan/domain/user/repository/UserRepository.kt +++ b/src/main/kotlin/busanVibe/busan/domain/user/repository/UserRepository.kt @@ -6,4 +6,6 @@ import java.util.Optional interface UserRepository : JpaRepository { fun findByEmail(email: String?): Optional + + fun findUsersByIdIn(ids: List): List } \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/user/service/UserCommandService.kt b/src/main/kotlin/busanVibe/busan/domain/user/service/UserCommandService.kt index e85324f..b3236cf 100644 --- a/src/main/kotlin/busanVibe/busan/domain/user/service/UserCommandService.kt +++ b/src/main/kotlin/busanVibe/busan/domain/user/service/UserCommandService.kt @@ -2,10 +2,12 @@ package busanVibe.busan.domain.user.service import busanVibe.busan.domain.user.converter.UserConverter import busanVibe.busan.domain.user.data.User -import busanVibe.busan.domain.user.data.dto.KaKaoUserInfoResponseDTO -import busanVibe.busan.domain.user.data.dto.KakaoTokenResponseDTO -import busanVibe.busan.domain.user.data.dto.UserResponseDTO +import busanVibe.busan.domain.user.data.dto.login.KaKaoUserInfoResponseDTO +import busanVibe.busan.domain.user.data.dto.login.KakaoTokenResponseDTO +import busanVibe.busan.domain.user.data.dto.login.UserLoginResponseDTO import busanVibe.busan.domain.user.repository.UserRepository +import busanVibe.busan.global.apiPayload.code.status.ErrorStatus +import busanVibe.busan.global.apiPayload.exception.GeneralException import busanVibe.busan.global.config.security.JwtTokenProvider import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Qualifier @@ -38,7 +40,7 @@ class UserCommandService( private val log = LoggerFactory.getLogger(this::class.java) - fun guestLogin(): UserResponseDTO.LoginDto { + fun guestLogin(): UserLoginResponseDTO.LoginDto { val email = UUID.randomUUID().toString().substring(0,7) + "@busanvibe.com" val nickname = UUID.randomUUID().toString().substring(0, 7) @@ -48,13 +50,13 @@ class UserCommandService( } - fun loginOrRegisterByKakao(code: String): UserResponseDTO.LoginDto { + fun loginOrRegisterByKakao(code: String): UserLoginResponseDTO.LoginDto { val token: KakaoTokenResponseDTO = getKakaoToken(code) val userInfo = getUserInfo(token.accessToken) - val email = userInfo.kakaoAccount?.email - val nickname = userInfo.kakaoAccount?.profile?.nickName ?: "\uCE74\uCE74\uC624 \uC0AC\uC6A9\uC790" - val profileImageUrl = userInfo.kakaoAccount?.profile?.profileImageUrl ?: "" + val email = userInfo.kakaoAccount?.email ?: throw GeneralException(ErrorStatus.USER_NOT_FOUND) + val nickname = userInfo.kakaoAccount.profile?.nickName ?: "\uCE74\uCE74\uC624 \uC0AC\uC6A9\uC790" + val profileImageUrl = userInfo.kakaoAccount.profile?.profileImageUrl ?: "" return isNewUser(email, nickname, profileImageUrl) } @@ -97,10 +99,10 @@ class UserCommandService( } private fun isNewUser( - email: String?, + email: String, nickname: String, profileImageUrl: String?, - ): UserResponseDTO.LoginDto { + ): UserLoginResponseDTO.LoginDto { val user = userRepository.findByEmail(email) return user.map { diff --git a/src/main/kotlin/busanVibe/busan/domain/user/service/UserQueryService.kt b/src/main/kotlin/busanVibe/busan/domain/user/service/UserQueryService.kt new file mode 100644 index 0000000..20d5a12 --- /dev/null +++ b/src/main/kotlin/busanVibe/busan/domain/user/service/UserQueryService.kt @@ -0,0 +1,74 @@ +package busanVibe.busan.domain.user.service + +import busanVibe.busan.domain.common.dto.InfoType +import busanVibe.busan.domain.festival.repository.FestivalLikesRepository +import busanVibe.busan.domain.festival.repository.FestivalRepository +import busanVibe.busan.domain.place.repository.PlaceLikeRepository +import busanVibe.busan.domain.place.repository.PlaceRepository +import busanVibe.busan.domain.search.dto.SearchResultDTO +import busanVibe.busan.domain.search.enums.GeneralSortType +import busanVibe.busan.domain.search.util.SearchUtil +import busanVibe.busan.domain.user.data.dto.UserResponseDTO +import busanVibe.busan.domain.user.service.login.AuthService +import busanVibe.busan.global.apiPayload.code.status.ErrorStatus +import busanVibe.busan.global.apiPayload.exception.GeneralException +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class UserQueryService( + private val placeRepository: PlaceRepository, + private val festivalRepository: FestivalRepository, + private val placeLikeRepository: PlaceLikeRepository, + private val festivalLikeRepository: FestivalLikesRepository, + private val searchUtil: SearchUtil, +) { + + // 마이페이지 기본 정보 조회 + @Transactional(readOnly = true) + fun getMyPageInfo(): UserResponseDTO.MyPageDto{ + val user = AuthService().getCurrentUser() + return UserResponseDTO.MyPageDto( + nickname = user.nickname, + email = user.email, + userImageUrl = user.profileImageUrl + ) + } + + // 유저 좋아요 목록 정보 조회 + @Transactional(readOnly = true) + fun getMyLikes(infoType: InfoType, sort: GeneralSortType): SearchResultDTO.ListDto{ + + val user = AuthService().getCurrentUser() + + // 검색조건 검사 + if(sort == GeneralSortType.CONGESTION){ // 좋아요 정보 조회에서는 혼잡도 정렬은 제외 + throw GeneralException(ErrorStatus.SEARCH_INVALID_CONDITION) + } + + // 명소 조회 + val places = when(infoType){ + InfoType.ALL -> placeRepository.findLikePlace(user) + InfoType.RESTAURANT, InfoType.SIGHT, InfoType.CAFE -> placeRepository.findLikePlaceByType( + infoType.placeType?: throw GeneralException(ErrorStatus.SEARCH_INVALID_CONDITION), + user + ) + else -> emptyList() + } + + // 축제 조회 + val festivals = when (infoType){ + InfoType.ALL, InfoType.FESTIVAL -> festivalRepository.findLikeFestivals(user) + else -> emptyList() + } + + val placeLikeList = placeLikeRepository.findLikeByPlace(places) + val festivalLikeList = festivalLikeRepository.findLikeByFestival(festivals) + + // 엔티티 List로 DTO List 반환 + val resultList = searchUtil.listToSearchDTO(places, festivals, sort, user, placeLikeList, festivalLikeList) + + return SearchResultDTO.ListDto(sort.name, resultList) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/busanVibe/busan/domain/user/util/LoginRedirectUtil.kt b/src/main/kotlin/busanVibe/busan/domain/user/util/LoginRedirectUtil.kt index 5a4f061..ce4f08f 100644 --- a/src/main/kotlin/busanVibe/busan/domain/user/util/LoginRedirectUtil.kt +++ b/src/main/kotlin/busanVibe/busan/domain/user/util/LoginRedirectUtil.kt @@ -1,6 +1,6 @@ package busanVibe.busan.domain.user.util -import busanVibe.busan.domain.user.data.dto.UserResponseDTO +import busanVibe.busan.domain.user.data.dto.login.UserLoginResponseDTO import org.springframework.beans.factory.annotation.Value import org.springframework.http.HttpHeaders import org.springframework.stereotype.Component @@ -13,7 +13,7 @@ class LoginRedirectUtil( private val deepLink: String ){ - fun getRedirectHeader(userResponse: UserResponseDTO.LoginDto): HttpHeaders{ + fun getRedirectHeader(userResponse: UserLoginResponseDTO.LoginDto): HttpHeaders{ val accessTokenEncoded = URLEncoder.encode(userResponse.tokenResponseDTO.accessToken, "UTF-8") val refreshTokenEncoded = URLEncoder.encode(userResponse.tokenResponseDTO.refreshToken, "UTF-8") diff --git a/src/main/kotlin/busanVibe/busan/global/apiPayload/code/status/ErrorStatus.kt b/src/main/kotlin/busanVibe/busan/global/apiPayload/code/status/ErrorStatus.kt index 22c3500..171357a 100644 --- a/src/main/kotlin/busanVibe/busan/global/apiPayload/code/status/ErrorStatus.kt +++ b/src/main/kotlin/busanVibe/busan/global/apiPayload/code/status/ErrorStatus.kt @@ -35,6 +35,14 @@ enum class ErrorStatus( // 채팅 관련 에러 CHAT_INVALID_LENGTH(HttpStatus.BAD_REQUEST, "CHAT4001", "글자 수는 200자로 제한됩니다."), + INVALID_PAGE_SIZE_MINUS(HttpStatus.BAD_REQUEST, "CHAT4002", "페이지 크기는 음수일 수 없습니다."), + INVALID_PAGE_SIZE_BIG(HttpStatus.BAD_REQUEST, "CHAT4003", "페이지 크기는 30을 넘을 수 없습니다."), + CHAT_USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "CHAT4004", "채팅에 해당하는 유저를 찾을 수 없습니다."), + + // 지도 관련 에러 + MAP_LATITUDE_OUT_OF_RANGE(HttpStatus.BAD_REQUEST, "MAP4001", "위도는 -90~90 사이여야 합니다."), + MAP_LONGITUDE_OUT_OF_RANGE(HttpStatus.BAD_REQUEST, "MAP4002", "경도는 -180~180 사이여야 합니다."), + MAP_INVALID_COORDINATE_ORDER(HttpStatus.BAD_REQUEST, "MAP4003", "좌측상단 좌표가 우측하단 좌표보다 위/왼쪽에 있어야 합니다."), ; diff --git a/src/main/kotlin/busanVibe/busan/global/config/security/JwtTokenProvider.kt b/src/main/kotlin/busanVibe/busan/global/config/security/JwtTokenProvider.kt index 6e6d878..bfebcd5 100644 --- a/src/main/kotlin/busanVibe/busan/global/config/security/JwtTokenProvider.kt +++ b/src/main/kotlin/busanVibe/busan/global/config/security/JwtTokenProvider.kt @@ -1,7 +1,7 @@ package busanVibe.busan.global.config.security import busanVibe.busan.domain.user.data.User -import busanVibe.busan.domain.user.data.dto.TokenResponseDto +import busanVibe.busan.domain.user.data.dto.login.TokenResponseDto import busanVibe.busan.domain.user.repository.RefreshTokenRepository import busanVibe.busan.domain.user.repository.UserRepository import busanVibe.busan.global.apiPayload.code.status.ErrorStatus