Skip to content

Commit

Permalink
Merge pull request #96 from Route-Box/feature/#93
Browse files Browse the repository at this point in the history
feat: #93 홈화면 로직 구현
  • Loading branch information
suyeoniii authored Sep 18, 2024
2 parents 42e4406 + 1073704 commit 5153e26
Show file tree
Hide file tree
Showing 16 changed files with 253 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.routebox.routebox.application.popular_route

import com.routebox.routebox.application.popular_route.dto.PopularRouteDto
import com.routebox.routebox.domain.popular_route.PopularRouteService
import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Transactional

@Component
class GetPopularRoutesUseCase(
private val popularRouteService: PopularRouteService,
) {
@Transactional(readOnly = true)
operator fun invoke(): List<PopularRouteDto> {
return popularRouteService.getPopularRoutes()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.routebox.routebox.application.popular_route.dto

data class PopularRouteDto(
val id: Long,
val name: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.routebox.routebox.application.recommended_route

import com.routebox.routebox.application.recommended_route.dto.RecommendedRouteDto
import com.routebox.routebox.domain.recommended_route.RecommendedRouteService
import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Transactional

@Component
class GetRecommendedRoutesUseCase(
private val recommendedRouteService: RecommendedRouteService,
) {
@Transactional(readOnly = true)
operator fun invoke(): List<RecommendedRouteDto> {
return recommendedRouteService.getRecommendRoutes()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.routebox.routebox.application.recommended_route.dto
data class RecommendedRouteDto(
val id: Long,
val name: String,
val description: String?,
val commonComment: String?,
val routeImageUrl: String?,
)
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.routebox.routebox.controller.route

import com.routebox.routebox.controller.route.dto.GetPopularRoutesResponse
import com.routebox.routebox.controller.route.dto.GetRecommendedRoutesResponse
import com.routebox.routebox.controller.route.dto.PopularRouteDto
import com.routebox.routebox.controller.route.dto.RecommendRouteDto
import com.routebox.routebox.application.popular_route.GetPopularRoutesUseCase
import com.routebox.routebox.application.recommended_route.GetRecommendedRoutesUseCase
import com.routebox.routebox.controller.route.dto.home.GetPopularRoutesResponse
import com.routebox.routebox.controller.route.dto.home.GetRecommendedRoutesResponse
import com.routebox.routebox.controller.route.dto.home.PopularRouteDto
import com.routebox.routebox.controller.route.dto.home.RecommendedRouteDto
import com.routebox.routebox.security.UserPrincipal
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import io.swagger.v3.oas.annotations.security.SecurityRequirement
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
Expand All @@ -17,39 +20,48 @@ import org.springframework.web.bind.annotation.RestController
@RestController
@Validated
@RequestMapping("/api")
class RouteHomeController {
class RouteHomeController(
private val getRecommendedRoutesUseCase: GetRecommendedRoutesUseCase,
private val getPopularRoutesUseCase: GetPopularRoutesUseCase,
) {
@Operation(
summary = "추천 루트 조회",
description = "추천 루트 조회",
)
@ApiResponses(
ApiResponse(responseCode = "200"),
security = [SecurityRequirement(name = "access-token")],
)
@GetMapping("/v1/routes/recommend")
fun getRecommendedRoutes(): GetRecommendedRoutesResponse {
val comment = "8월엔 여기로 여행 어때요?"
val mockData = listOf(
RecommendRouteDto.from(1, "경주 200% 즐기는 법", "경주 200% 즐기는 법", "https://routebox-resources.s3.ap-northeast-2.amazonaws.com/image/1.jpg"),
RecommendRouteDto.from(2, "대구 먹방 여행", "대구 200% 즐기는 법", "https://routebox-resources.s3.ap-northeast-2.amazonaws.com/image/2.jpg"),
RecommendRouteDto.from(3, "대전 빵 여행", "대전 200% 즐기는 법", "https://routebox-resources.s3.ap-northeast-2.amazonaws.com/image/3.jpg"),
fun getRecommendedRoutes(
@AuthenticationPrincipal userPrincipal: UserPrincipal,
): GetRecommendedRoutesResponse {
val routes = getRecommendedRoutesUseCase()
return GetRecommendedRoutesResponse.from(
comment = routes.firstOrNull()?.commonComment,
routes = routes.map {
RecommendedRouteDto.from(
it.id,
it.name,
it.description,
it.routeImageUrl,
)
},
)
return GetRecommendedRoutesResponse.from(comment, mockData)
}

@Operation(
summary = "인기 루트 조회",
description = "인기 루트 조회",
)
@ApiResponses(
ApiResponse(responseCode = "200"),
security = [SecurityRequirement(name = "access-token")],
)
@GetMapping("/v1/routes/popular")
fun getPopularRoutes(): GetPopularRoutesResponse {
val mockData = listOf(
PopularRouteDto(1, "8월에 꼭 가야하는 장소"),
PopularRouteDto(2, "여자친구에게 칭찬 왕창 받은 데이트 코스"),
PopularRouteDto(3, "친구들과 함께 떠나고 싶은 여행지"),
)
return GetPopularRoutesResponse.from(mockData)
fun getPopularRoutes(
@AuthenticationPrincipal userPrincipal: UserPrincipal,
): GetPopularRoutesResponse {
val routes = getPopularRoutesUseCase().map {
PopularRouteDto.from(
it.id,
it.name,
)
}
return GetPopularRoutesResponse.from(routes)
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.routebox.routebox.controller.route.dto
package com.routebox.routebox.controller.route.dto.home

import io.swagger.v3.oas.annotations.media.Schema

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package com.routebox.routebox.controller.route.dto
package com.routebox.routebox.controller.route.dto.home

import io.swagger.v3.oas.annotations.media.Schema

data class GetRecommendedRoutesResponse(
@Schema(description = "오늘의 추천루트 문구")
val comment: String,
val comment: String?,

@Schema(description = "추천 루트 목록")
val routes: List<RecommendRouteDto>,
val routes: List<RecommendedRouteDto>,
) {
companion object {
fun from(comment: String, routes: List<RecommendRouteDto>): GetRecommendedRoutesResponse = GetRecommendedRoutesResponse(
fun from(comment: String?, routes: List<RecommendedRouteDto>): GetRecommendedRoutesResponse = GetRecommendedRoutesResponse(
comment = comment,
routes = routes,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.routebox.routebox.controller.route.dto
package com.routebox.routebox.controller.route.dto.home

import io.swagger.v3.oas.annotations.media.Schema

Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
package com.routebox.routebox.controller.route.dto
package com.routebox.routebox.controller.route.dto.home

import io.swagger.v3.oas.annotations.media.Schema

data class RecommendRouteDto(
data class RecommendedRouteDto(
@Schema(description = "루트 ID")
val id: Long,

@Schema(description = "루트 이름")
val routeName: String,

@Schema(description = "루트 설명")
val routeDescription: String,
val routeDescription: String?,

@Schema(description = "루트 대표 이미지")
val routeImageUrl: String,
val routeImageUrl: String?,
) {
companion object {
fun from(id: Long, routeName: String, routeDescription: String, routeImageUrl: String): RecommendRouteDto = RecommendRouteDto(
fun from(id: Long, routeName: String, routeDescription: String?, routeImageUrl: String?): RecommendedRouteDto = RecommendedRouteDto(
id = id,
routeName = routeName,
routeDescription = routeDescription,
routeImageUrl = routeImageUrl,
routeImageUrl = if (routeImageUrl.isNullOrEmpty()) null else routeImageUrl,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.routebox.routebox.domain.popular_route

import com.routebox.routebox.domain.common.TimeTrackedBaseEntity
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.Table

@Table(name = "popular_routes")
@Entity
class PopularRoute(
id: Long = 0,
routeId: Long,
) : TimeTrackedBaseEntity() {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "popular_route_id")
val id: Long = id

val routeId: Long = routeId
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.routebox.routebox.domain.popular_route

import com.routebox.routebox.application.popular_route.dto.PopularRouteDto
import com.routebox.routebox.infrastructure.popular_route.PopularRouteRepository
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class PopularRouteService(
private val popularRouteRepository: PopularRouteRepository,
) {

/**
* 인기 루트 조회
*/
@Transactional(readOnly = true)
fun getPopularRoutes(): List<PopularRouteDto> {
return popularRouteRepository.findAllPopularRoutes()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.routebox.routebox.domain.recommended_route

import com.routebox.routebox.domain.common.TimeTrackedBaseEntity
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.Table
import java.time.LocalDateTime

@Table(name = "recommended_routes")
@Entity
class RecommendedRoute(
id: Long = 0,
routeId: Long,
showFrom: LocalDateTime,
commonComment: String? = null,
) : TimeTrackedBaseEntity() {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "recommended_route_id")
val id: Long = id

val routeId: Long = routeId

val showFrom: LocalDateTime = showFrom

val commonComment: String? = commonComment
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.routebox.routebox.domain.recommended_route

import com.routebox.routebox.application.recommended_route.dto.RecommendedRouteDto
import com.routebox.routebox.infrastructure.recommended_route.RecommendedRouteRepository
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class RecommendedRouteService(
private val recommendedRouteRepository: RecommendedRouteRepository,
) {

/**
* 추천 루트 조회
*/
@Transactional(readOnly = true)
fun getRecommendRoutes(): List<RecommendedRouteDto> {
return recommendedRouteRepository.findAllRecommendedRoutes()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.routebox.routebox.infrastructure.popular_route

import com.routebox.routebox.application.popular_route.dto.PopularRouteDto
import com.routebox.routebox.domain.popular_route.PopularRoute
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query

interface PopularRouteRepository : JpaRepository<PopularRoute, Long> {
@Query(
"""
SELECT NEW com.routebox.routebox.application.popular_route.dto.PopularRouteDto(r.id, r.name)
FROM PopularRoute pr
JOIN Route r ON pr.routeId = r.id
WHERE r.isPublic = true
""",
)
fun findAllPopularRoutes(): List<PopularRouteDto>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.routebox.routebox.infrastructure.recommended_route

import com.routebox.routebox.application.recommended_route.dto.RecommendedRouteDto
import com.routebox.routebox.domain.recommended_route.RecommendedRoute
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query

interface RecommendedRouteRepository : JpaRepository<RecommendedRoute, Long> {
@Query(
"""
SELECT NEW com.routebox.routebox.application.recommended_route.dto.RecommendedRouteDto(
r.id, r.name, r.description, rr.commonComment,
CASE WHEN rai.fileUrl IS NOT NULL THEN rai.fileUrl ELSE "" END
)
FROM RecommendedRoute rr
JOIN Route r ON rr.routeId = r.id
LEFT JOIN RouteActivity ra ON ra.route = r
LEFT JOIN RouteActivityImage rai ON rai.activity = ra
WHERE r.isPublic = true AND rr.showFrom <= CURRENT_TIMESTAMP
GROUP BY r.id
""",
)
fun findAllRecommendedRoutes(): List<RecommendedRouteDto>
}
19 changes: 19 additions & 0 deletions src/main/resources/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,22 @@ CREATE TABLE withdrawal_histories
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '생성 시간',
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '업데이트 시간'
);

CREATE TABLE popular_routes
(
popular_route_id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '인기 루트 ID',
route_id BIGINT NOT NULL COMMENT '루트 ID',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '생성 시간',
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '업데이트 시간'
);

CREATE TABLE recommended_routes
(
recommended_route_id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '추천 루트 ID',
route_id BIGINT NOT NULL COMMENT '루트 ID',
show_from DATETIME NOT NULL COMMENT '표시 시작 시간',
common_comment VARCHAR(255) NULL COMMENT '추천 루트 상단에 나오는 공통 코멘트, 가장 앞쪽 데이터의 코멘트가 노출됨',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '생성 시간',
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '업데이트 시간'
);

0 comments on commit 5153e26

Please sign in to comment.