diff --git a/src/main/kotlin/mara/server/config/pageable/PageableConfig.kt b/src/main/kotlin/mara/server/config/pageable/PageableConfig.kt deleted file mode 100644 index bf5a46f..0000000 --- a/src/main/kotlin/mara/server/config/pageable/PageableConfig.kt +++ /dev/null @@ -1,20 +0,0 @@ -package mara.server.config.pageable - -import org.springframework.beans.factory.annotation.Qualifier -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.data.domain.PageRequest -import org.springframework.data.domain.Pageable -import org.springframework.data.domain.Sort - -@Configuration -class PageableConfig { - - @Bean - @Qualifier("userPageable") - fun userPageable(): Pageable = PageRequest.of(0, 5, Sort.Direction.DESC, "ingredientAddDate") - - @Bean - @Qualifier("ingredientPageable") - fun ingredientPageable(): Pageable = PageRequest.of(0, 4, Sort.Direction.DESC, "addDate") -} diff --git a/src/main/kotlin/mara/server/config/querydsl/QueryDslConfig.kt b/src/main/kotlin/mara/server/config/querydsl/QueryDslConfig.kt new file mode 100644 index 0000000..d761983 --- /dev/null +++ b/src/main/kotlin/mara/server/config/querydsl/QueryDslConfig.kt @@ -0,0 +1,17 @@ +package mara.server.config.querydsl + +import com.querydsl.jpa.impl.JPAQueryFactory +import jakarta.persistence.EntityManager +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class QueryDslConfig( + private val em: EntityManager +) { + + @Bean + fun jpaQueryFactory(): JPAQueryFactory { + return JPAQueryFactory(em) + } +} diff --git a/src/main/kotlin/mara/server/domain/friend/FriendRefrigeratorController.kt b/src/main/kotlin/mara/server/domain/friend/FriendRefrigeratorController.kt index cbc9cce..8c1388b 100644 --- a/src/main/kotlin/mara/server/domain/friend/FriendRefrigeratorController.kt +++ b/src/main/kotlin/mara/server/domain/friend/FriendRefrigeratorController.kt @@ -1,27 +1,22 @@ package mara.server.domain.friend +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag import mara.server.common.CommonResponse import mara.server.common.success -import org.springframework.beans.factory.annotation.Qualifier -import org.springframework.data.domain.Page -import org.springframework.data.domain.Pageable import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/friend-refrigs") +@Tag(name = "친구 냉장고", description = "친구 냉장고 API") class FriendRefrigeratorController( private val friendRefrigeratorService: FriendRefrigeratorService ) { - @GetMapping("/recent") - fun getRecentFriendRefrigeratorList( - @Qualifier("userPageable") - userPageable: Pageable, - @Qualifier("ingredientPageable") - ingredientPageable: Pageable, - ): CommonResponse> { - return success(friendRefrigeratorService.getRecentFriendRefrigeratorList(userPageable, ingredientPageable)) + @Operation(summary = "친구 냉장고 최신 근황 조회 API") + fun getRecentFriendRefrigeratorList(): CommonResponse> { + return success(friendRefrigeratorService.getRecentFriendRefrigeratorList()) } } diff --git a/src/main/kotlin/mara/server/domain/friend/FriendRefrigeratorDto.kt b/src/main/kotlin/mara/server/domain/friend/FriendRefrigeratorDto.kt index cd650a8..0a867ec 100644 --- a/src/main/kotlin/mara/server/domain/friend/FriendRefrigeratorDto.kt +++ b/src/main/kotlin/mara/server/domain/friend/FriendRefrigeratorDto.kt @@ -3,14 +3,13 @@ package mara.server.domain.friend import mara.server.domain.ingredient.Ingredient import mara.server.domain.refrigerator.Refrigerator import mara.server.domain.user.User -import org.springframework.data.domain.Page data class FriendRefrigeratorResponse( val nickname: String, val refrigeratorId: Long, - val friendRefrigeratorIngredientGroupList: Page + val friendRefrigeratorIngredientGroupList: List ) { - constructor(user: User, refrigerator: Refrigerator, ingredientList: Page) : this( + constructor(user: User, refrigerator: Refrigerator, ingredientList: List) : this( nickname = user.nickName, refrigeratorId = refrigerator.refrigeratorId, friendRefrigeratorIngredientGroupList = ingredientList.map { FriendRefrigeratorIngredient(it) } diff --git a/src/main/kotlin/mara/server/domain/friend/FriendRefrigeratorService.kt b/src/main/kotlin/mara/server/domain/friend/FriendRefrigeratorService.kt index 7f36634..8736664 100644 --- a/src/main/kotlin/mara/server/domain/friend/FriendRefrigeratorService.kt +++ b/src/main/kotlin/mara/server/domain/friend/FriendRefrigeratorService.kt @@ -3,8 +3,6 @@ package mara.server.domain.friend import mara.server.domain.ingredient.IngredientDetailRepository import mara.server.domain.refrigerator.RefrigeratorRepository import mara.server.domain.user.UserService -import org.springframework.data.domain.Page -import org.springframework.data.domain.Pageable import org.springframework.stereotype.Service @Service @@ -15,17 +13,17 @@ class FriendRefrigeratorService( private val ingredientDetailRepository: IngredientDetailRepository ) { - fun getRecentFriendRefrigeratorList(userPageable: Pageable, ingredientPageable: Pageable): Page { + fun getRecentFriendRefrigeratorList(): List { val currentLoginUser = userService.getCurrentLoginUser() - val friendshipList = friendshipRepository.findAllByFromUser(currentLoginUser) + val friendshipList = friendshipRepository.findByFromUser(currentLoginUser) .orElseThrow { NoSuchElementException("친구 관계가 존재하지 않습니다.") } val userList = friendshipList.map { it.toUser } - val refrigeratorList = refrigeratorRepository.findRefrigeratorByUserIn(userList, userPageable) + val refrigeratorList = refrigeratorRepository.findByUserList(userList, 5) val friendRefrigeratorResponseList = refrigeratorList.map { refrig -> - val ingredientDetailList = ingredientDetailRepository - .findByRefrigeratorAndIsDeletedIsFalse(refrig, ingredientPageable) + val ingredientDetailList = + ingredientDetailRepository.findByRefrigerator(refrig, 4) val ingredientList = ingredientDetailList.map { it.ingredient } FriendRefrigeratorResponse(refrig.user, refrig, ingredientList) } diff --git a/src/main/kotlin/mara/server/domain/friend/FriendshipController.kt b/src/main/kotlin/mara/server/domain/friend/FriendshipController.kt index 3046852..cdcdc3f 100644 --- a/src/main/kotlin/mara/server/domain/friend/FriendshipController.kt +++ b/src/main/kotlin/mara/server/domain/friend/FriendshipController.kt @@ -1,8 +1,13 @@ package mara.server.domain.friend +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag import mara.server.common.CommonResponse import mara.server.common.success import mara.server.domain.user.UserFriendResponse +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.web.PageableDefault import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody @@ -11,26 +16,36 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/friendship") +@Tag(name = "친구", description = "친구 API") class FriendshipController( private val friendshipService: FriendshipService ) { @PostMapping + @Operation(summary = "친구 맺기 API") fun createFriendship(@RequestBody friendshipRequest: FriendshipRequest): CommonResponse { return success(friendshipService.createFriendship(friendshipRequest)) } @GetMapping - fun getFriendshipList(): CommonResponse> { - return success(friendshipService.getFriendshipList()) + @Operation(summary = "친구 조회 API") + fun getFriendshipList( + @PageableDefault( + size = 10 + ) + pageable: Pageable + ): CommonResponse> { + return success(friendshipService.getFriendshipList(pageable)) } @GetMapping("/count") + @Operation(summary = "친구 수 조회 API") fun getFriendshipCount(): CommonResponse { return success(friendshipService.getFriendshipCount()) } @PostMapping("/delete") + @Operation(summary = "친구 삭제 API") fun deleteFriendship(@RequestBody friendshipDeleteRequestList: List): CommonResponse { return success(friendshipService.deleteFriendship(friendshipDeleteRequestList)) } diff --git a/src/main/kotlin/mara/server/domain/friend/FriendshipRepository.kt b/src/main/kotlin/mara/server/domain/friend/FriendshipRepository.kt index fc9cb95..36a1874 100644 --- a/src/main/kotlin/mara/server/domain/friend/FriendshipRepository.kt +++ b/src/main/kotlin/mara/server/domain/friend/FriendshipRepository.kt @@ -1,26 +1,50 @@ package mara.server.domain.friend +import com.querydsl.jpa.impl.JPAQueryFactory +import mara.server.domain.friend.QFriendship.friendship import mara.server.domain.user.User +import org.springframework.data.domain.Page +import org.springframework.data.domain.PageImpl +import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.data.jpa.repository.Query -import org.springframework.stereotype.Repository import java.util.Optional -@Repository -interface FriendshipRepository : JpaRepository { - - @Query("select f from Friendship f where f.fromUser = ?1") - fun findAllByFromUser( - user: User +interface FriendshipRepository : JpaRepository, CustomFriendshipRepository { + fun findByFromUser( + user: User, ): Optional> fun countByFromUser( user: User ): Long +} - @Query("select f from Friendship f where (f.fromUser = ?1 and f.toUser = ?2) or (f.fromUser = ?2 and f.toUser = ?1)") - fun findAllByFromUserAndToUser( - fromUser: User, - toUser: User - ): Optional> +interface CustomFriendshipRepository { + + fun findByFromUserPage(user: User, pageable: Pageable): Page + + fun findByFromUserAndToUser(fromUser: User, toUser: User): List +} + +class CustomFriendshipRepositoryImpl( + private val queryFactory: JPAQueryFactory +) : CustomFriendshipRepository { + + override fun findByFromUserPage(user: User, pageable: Pageable): Page { + val results = queryFactory.select(friendship).from(friendship).where(friendship.fromUser.eq(user)) + .offset(pageable.offset).limit(pageable.pageSize.toLong()).fetch() + + val count = queryFactory.select(friendship.count()).from(friendship) + .where(friendship.fromUser.eq(user)) + .offset(pageable.offset).limit(pageable.pageSize.toLong()).orderBy(friendship.createdAt.asc()).fetchOne() ?: 0 + + return PageImpl(results, pageable, count) + } + + override fun findByFromUserAndToUser(fromUser: User, toUser: User): List { + return queryFactory.selectFrom(friendship).where( + friendship.fromUser.eq(fromUser).and(friendship.toUser.eq(toUser)) + .or(friendship.fromUser.eq(toUser).and(friendship.toUser.eq(fromUser))) + ).fetch() + } } diff --git a/src/main/kotlin/mara/server/domain/friend/FriendshipService.kt b/src/main/kotlin/mara/server/domain/friend/FriendshipService.kt index 20cdede..fb5a8e5 100644 --- a/src/main/kotlin/mara/server/domain/friend/FriendshipService.kt +++ b/src/main/kotlin/mara/server/domain/friend/FriendshipService.kt @@ -4,6 +4,8 @@ import mara.server.domain.user.User import mara.server.domain.user.UserFriendResponse import mara.server.domain.user.UserRepository import mara.server.domain.user.UserService +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -31,12 +33,10 @@ class FriendshipService( return ok } - fun getFriendshipList(): List { + fun getFriendshipList(pageable: Pageable): Page { val currentLoginUser = userService.getCurrentLoginUser() - val friendshipList = friendshipRepository.findAllByFromUser(currentLoginUser) - .orElseThrow { NoSuchElementException("친구 관계가 존재하지 않습니다.") } - - val userFriendResponseList: List = friendshipList.map { friendship -> + val friendshipList = friendshipRepository.findByFromUserPage(currentLoginUser, pageable) + val userFriendResponseList = friendshipList.map { friendship -> val userId = friendship.toUser.userId val user = userRepository.findById(userId).orElseThrow { NoSuchElementException("해당 유저가 존재하지 않습니다. ID: $userId") } @@ -59,9 +59,7 @@ class FriendshipService( val targetUser = userRepository.findById(friendshipDeleteRequest.friendId) .orElseThrow { NoSuchElementException("해당 유저가 존재하지 않습니다. ID: ${friendshipDeleteRequest.friendId}") } - val friendshipList = friendshipRepository.findAllByFromUserAndToUser(currentLoginUser, targetUser) - .orElseThrow { NoSuchElementException("친구 관계가 존재하지 않습니다.") } - + val friendshipList = friendshipRepository.findByFromUserAndToUser(currentLoginUser, targetUser) friendshipList.forEach { friendshipRepository.delete(it) } } diff --git a/src/main/kotlin/mara/server/domain/ingredient/IngredientController.kt b/src/main/kotlin/mara/server/domain/ingredient/IngredientController.kt index b6edad7..dab58f8 100644 --- a/src/main/kotlin/mara/server/domain/ingredient/IngredientController.kt +++ b/src/main/kotlin/mara/server/domain/ingredient/IngredientController.kt @@ -1,5 +1,7 @@ package mara.server.domain.ingredient +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag import mara.server.common.CommonResponse import mara.server.common.success import org.springframework.web.bind.annotation.DeleteMapping @@ -13,31 +15,37 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/ingrs") +@Tag(name = "식자재", description = "식자재 API") class IngredientController( private val ingredientService: IngredientService ) { @PostMapping + @Operation(summary = "식자재 생성 API") fun createIngredient(@RequestBody ingredientRequest: IngredientRequest): CommonResponse { return success(ingredientService.createIngredient(ingredientRequest)) } @GetMapping("/{id}") + @Operation(summary = "식자재 조회 API") fun getIngredient(@PathVariable(name = "id") id: Long): CommonResponse { return success(ingredientService.getIngredient(id)) } @GetMapping + @Operation(summary = "식자재 리스트 조회 API") fun getIngredientList(): CommonResponse> { return success(ingredientService.getIngredientList()) } @GetMapping("/category") + @Operation(summary = "카테고리별 식자재 리스트 조회 API") fun getIngredientGroupListByCategory(): CommonResponse> { return success(ingredientService.getIngredientListByCategory()) } @PutMapping("/{id}") + @Operation(summary = "식자재 업데이트 API") fun updateIngredient( @PathVariable(name = "id") id: Long, @RequestBody ingredientRequest: IngredientRequest @@ -46,6 +54,7 @@ class IngredientController( } @DeleteMapping("/{id}") + @Operation(summary = "식자재 삭제 조회 API") fun deleteIngredient(@PathVariable(name = "id") id: Long): CommonResponse { return success(ingredientService.deleteIngredient(id)) } diff --git a/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailController.kt b/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailController.kt index 7990fd4..3646f02 100644 --- a/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailController.kt +++ b/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailController.kt @@ -1,10 +1,11 @@ package mara.server.domain.ingredient +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag import mara.server.common.CommonResponse import mara.server.common.success import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable -import org.springframework.data.domain.Sort import org.springframework.data.web.PageableDefault import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.GetMapping @@ -18,24 +19,28 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/ingrs/detail") +@Tag(name = "식자재 상세", description = "식자재 상세 API") class IngredientDetailController( private val ingredientDetailService: IngredientDetailService ) { @PostMapping + @Operation(summary = "식자재 상세 생성 API") fun createIngredientDetail(@RequestBody ingredientDetailRequest: IngredientDetailRequest): CommonResponse { return success(ingredientDetailService.createIngredientDetail(ingredientDetailRequest)) } @GetMapping("/{id}") + @Operation(summary = "식자재 상세 조회 API") fun getIngredientDetail(@PathVariable(name = "id") id: Long): CommonResponse { return success(ingredientDetailService.getIngredientDetail(id)) } @GetMapping("/refrig/{id}") + @Operation(summary = "특정 냉장고 식자재 상세 리스트 조회 API") fun getIngredientDetailList( @PageableDefault( - size = 5 + size = 10 ) pageable: Pageable, @PathVariable(name = "id") refrigeratorId: Long @@ -44,21 +49,19 @@ class IngredientDetailController( } @GetMapping("/count") + @Operation(summary = "소비기한내 식자재 상세 수 조회 API") fun getIngredientDetailCount(@RequestParam("day") days: Long): CommonResponse { return success(ingredientDetailService.getIngredientDetailCount(days)) } @GetMapping("/recent") - fun getIngredientDetailRecent( - @PageableDefault( - size = 4, sort = ["expirationDate"], direction = Sort.Direction.ASC - ) - pageable: Pageable, - ): CommonResponse> { - return success(ingredientDetailService.getIngredientDetailRecent(pageable)) + @Operation(summary = "소비기한 만료일 기준 정렬 식자재 상세 조회 API") + fun getIngredientDetailRecent(): CommonResponse> { + return success(ingredientDetailService.getIngredientDetailRecent()) } @PutMapping("/{id}") + @Operation(summary = "식자재 상세 업데이트 API") fun updateIngredientDetail( @PathVariable(name = "id") id: Long, @RequestBody ingredientDetailUpdateRequest: IngredientDetailUpdateRequest @@ -67,6 +70,7 @@ class IngredientDetailController( } @DeleteMapping("/{id}") + @Operation(summary = "식자재 상세 삭제 API") fun deleteIngredient(@PathVariable(name = "id") id: Long): CommonResponse { return success(ingredientDetailService.deleteIngredientDetail(id)) } diff --git a/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailDto.kt b/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailDto.kt index 2f72c00..19b05e1 100644 --- a/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailDto.kt +++ b/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailDto.kt @@ -51,3 +51,7 @@ data class IngredientDetailResponse( fun Page.toIngredientDetailResponseListPage(): Page { return this.map { IngredientDetailResponse(it) } } + +fun List.toIngredientDetailResponseList(): List { + return this.map { IngredientDetailResponse(it) } +} diff --git a/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailRepository.kt b/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailRepository.kt index ee55026..4b1ca49 100644 --- a/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailRepository.kt +++ b/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailRepository.kt @@ -1,22 +1,80 @@ package mara.server.domain.ingredient +import com.querydsl.jpa.impl.JPAQueryFactory +import mara.server.domain.ingredient.QIngredientDetail.ingredientDetail import mara.server.domain.refrigerator.Refrigerator import org.springframework.data.domain.Page +import org.springframework.data.domain.PageImpl import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.data.jpa.repository.Query -import org.springframework.data.repository.query.Param -import org.springframework.stereotype.Repository import java.time.LocalDateTime -@Repository -interface IngredientDetailRepository : JpaRepository { +interface IngredientDetailRepository : JpaRepository, CustomIngredientDetailRepository - fun findByRefrigeratorAndIsDeletedIsFalse(refrigerator: Refrigerator, pageable: Pageable): Page +interface CustomIngredientDetailRepository { - @Query("SELECT count(i) from IngredientDetail i where i.refrigerator in (?1) and i.expirationDate between now() and ?2") - fun findIngredientDetailCountByRefrigeratorAndExpirationDate(refrigerator: List, expirationDay: LocalDateTime): Long + fun findByRefrigerator( + refrigerator: Refrigerator, + limit: Long + ): List - @Query("SELECT i from IngredientDetail i where i.refrigerator in (?1)") - fun findByRefrigerators(@Param("refrigerators")refrigerators: List, pageable: Pageable): Page + fun findByRefrigerator( + refrigerator: Refrigerator, + pageable: Pageable + ): Page + + fun findByRefrigeratorList( + refrigeratorList: List, + limit: Long + ): List + + fun countByRefrigeratorListAndExpirationDay( + refrigeratorList: List, + expirationDay: LocalDateTime + ): Long +} + +class CustomIngredientDetailRepositoryImpl( + private val queryFactory: JPAQueryFactory +) : CustomIngredientDetailRepository { + + override fun findByRefrigerator(refrigerator: Refrigerator, limit: Long): List { + return queryFactory.selectFrom(ingredientDetail) + .where(ingredientDetail.refrigerator.eq(refrigerator).and(ingredientDetail.isDeleted.isFalse)).orderBy( + ingredientDetail.addDate.desc() + ).limit(limit) + .fetch() + } + + override fun findByRefrigerator(refrigerator: Refrigerator, pageable: Pageable): Page { + val results = queryFactory.selectFrom(ingredientDetail) + .where(ingredientDetail.refrigerator.eq(refrigerator).and(ingredientDetail.isDeleted.isFalse)) + .offset(pageable.offset).limit(pageable.pageSize.toLong()).fetch() + + val count = queryFactory.select(ingredientDetail.count()).from(ingredientDetail) + .where(ingredientDetail.refrigerator.eq(refrigerator).and(ingredientDetail.isDeleted.isFalse)) + .offset(pageable.offset).limit(pageable.pageSize.toLong()).fetchOne() ?: 0 + + return PageImpl(results, pageable, count) + } + + override fun findByRefrigeratorList(refrigeratorList: List, limit: Long): List { + return queryFactory.selectFrom(ingredientDetail) + .where(ingredientDetail.refrigerator.`in`(refrigeratorList).and(ingredientDetail.isDeleted.isFalse)) + .orderBy(ingredientDetail.expirationDate.desc()).limit(limit).fetch() + } + + override fun countByRefrigeratorListAndExpirationDay( + refrigeratorList: List, + expirationDay: LocalDateTime + ): Long { + val now = LocalDateTime.now() + val count = queryFactory.select(ingredientDetail.count()).from(ingredientDetail).where( + ingredientDetail.refrigerator.`in`(refrigeratorList) + .and(ingredientDetail.expirationDate.between(now, expirationDay)) + .and(ingredientDetail.isDeleted.isFalse) + ).fetchOne() + + return count ?: 0 + } } diff --git a/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailService.kt b/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailService.kt index fc60940..c4eac94 100644 --- a/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailService.kt +++ b/src/main/kotlin/mara/server/domain/ingredient/IngredientDetailService.kt @@ -1,7 +1,7 @@ package mara.server.domain.ingredient import mara.server.domain.refrigerator.RefrigeratorRepository -import mara.server.domain.user.UserService +import mara.server.domain.refrigerator.RefrigeratorService import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import org.springframework.stereotype.Service @@ -10,10 +10,11 @@ import java.time.LocalDateTime @Service class IngredientDetailService( - private val ingredientDetailRepository: IngredientDetailRepository, + private val refrigeratorService: RefrigeratorService, private val refrigeratorRepository: RefrigeratorRepository, private val ingredientRepository: IngredientRepository, - private val userService: UserService + private val ingredientDetailRepository: IngredientDetailRepository + ) { private val deleted = "deleted" @@ -56,28 +57,26 @@ class IngredientDetailService( val refrigerator = refrigeratorRepository.findById(refrigeratorId) .orElseThrow { NoSuchElementException("해당 냉장고가 존재하지 않습니다. ID: $refrigeratorId") } val ingredientDetailList = - ingredientDetailRepository.findByRefrigeratorAndIsDeletedIsFalse(refrigerator, pageable) + ingredientDetailRepository.findByRefrigerator(refrigerator, pageable) return ingredientDetailList.toIngredientDetailResponseListPage() } fun getIngredientDetailCount(days: Long): Long { - val user = userService.getCurrentLoginUser() - val refrigeratorList = refrigeratorRepository.findRefrigeratorsByUser(user) + val refrigeratorList = refrigeratorService.getCurrentLoginUserRefrigeratorList() val expirationDate = LocalDateTime.now().plusDays(days) - return ingredientDetailRepository.findIngredientDetailCountByRefrigeratorAndExpirationDate( + return ingredientDetailRepository.countByRefrigeratorListAndExpirationDay( refrigeratorList, expirationDate ) } - fun getIngredientDetailRecent(pageable: Pageable): Page { - val user = userService.getCurrentLoginUser() - val refrigeratorList = refrigeratorRepository.findRefrigeratorsByUser(user) + fun getIngredientDetailRecent(): List { + val refrigeratorList = refrigeratorService.getCurrentLoginUserRefrigeratorList() val ingredientDetailRecentList = - ingredientDetailRepository.findByRefrigerators(refrigeratorList, pageable) + ingredientDetailRepository.findByRefrigeratorList(refrigeratorList, 4) - return ingredientDetailRecentList.toIngredientDetailResponseListPage() + return ingredientDetailRecentList.toIngredientDetailResponseList() } @Transactional diff --git a/src/main/kotlin/mara/server/domain/ingredient/IngredientRepository.kt b/src/main/kotlin/mara/server/domain/ingredient/IngredientRepository.kt index 8af6f7d..5c905d4 100644 --- a/src/main/kotlin/mara/server/domain/ingredient/IngredientRepository.kt +++ b/src/main/kotlin/mara/server/domain/ingredient/IngredientRepository.kt @@ -1,7 +1,5 @@ package mara.server.domain.ingredient import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.stereotype.Repository -@Repository interface IngredientRepository : JpaRepository diff --git a/src/main/kotlin/mara/server/domain/refrigerator/Refrigerator.kt b/src/main/kotlin/mara/server/domain/refrigerator/Refrigerator.kt index 3550a60..49d28d7 100644 --- a/src/main/kotlin/mara/server/domain/refrigerator/Refrigerator.kt +++ b/src/main/kotlin/mara/server/domain/refrigerator/Refrigerator.kt @@ -14,6 +14,7 @@ import java.time.LocalDateTime @Entity class Refrigerator( + @Column(length = 30) var name: String, var ingredientAddDate: LocalDateTime?, @ManyToOne(fetch = FetchType.LAZY) diff --git a/src/main/kotlin/mara/server/domain/refrigerator/RefrigeratorController.kt b/src/main/kotlin/mara/server/domain/refrigerator/RefrigeratorController.kt index 381d15f..ff6f99c 100644 --- a/src/main/kotlin/mara/server/domain/refrigerator/RefrigeratorController.kt +++ b/src/main/kotlin/mara/server/domain/refrigerator/RefrigeratorController.kt @@ -1,5 +1,7 @@ package mara.server.domain.refrigerator +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag import mara.server.common.CommonResponse import mara.server.common.success import org.springframework.web.bind.annotation.DeleteMapping @@ -13,30 +15,37 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/refrigs") +@Tag(name = "냉장고", description = "냉장고 API") class RefrigeratorController( private val refrigeratorService: RefrigeratorService ) { + @PostMapping + @Operation(summary = "냉장고 생성 API") fun createRefrigerator(@RequestBody refrigeratorRequest: RefrigeratorRequest): CommonResponse { return success(refrigeratorService.createRefrigerator(refrigeratorRequest)) } - @GetMapping("/{id}") - fun getRefrigerator(@PathVariable(name = "id") id: Long): CommonResponse { - return success(refrigeratorService.getRefrigerator((id))) - } +// TODO : FE API 연동 테스트 이후 삭제 예정 +// @GetMapping("/{id}") +// fun getRefrigerator(@PathVariable(name = "id") id: Long): CommonResponse { +// return success(refrigeratorService.getRefrigerator((id))) +// } @GetMapping("/users/{user-id}") + @Operation(summary = "다른 사용자 냉장고 리스트 조회 API") fun getRefrigeratorList(@PathVariable(name = "user-id") userId: Long): CommonResponse> { return success(refrigeratorService.getRefrigeratorList((userId))) } @GetMapping("/my") + @Operation(summary = "현 로그인 사용자 냉장고 리스트 조회 API") fun getMyRefrigeratorList(): CommonResponse> { return success(refrigeratorService.getMyRefrigeratorList()) } @PutMapping("/{id}") + @Operation(summary = "냉장고 업데이트 API") fun updateRefrigerator( @PathVariable(name = "id") id: Long, @RequestBody refrigeratorRequest: RefrigeratorRequest @@ -45,7 +54,8 @@ class RefrigeratorController( } @DeleteMapping("/{id}") - fun updateRefrigerator(@PathVariable(name = "id") id: Long): CommonResponse { + @Operation(summary = "냉장고 삭제 API", description = "냉장고 id와 냉장고 ") + fun deleteRefrigerator(@PathVariable(name = "id") id: Long): CommonResponse { return success(refrigeratorService.deleteRefrigerator(id)) } } diff --git a/src/main/kotlin/mara/server/domain/refrigerator/RefrigeratorRepository.kt b/src/main/kotlin/mara/server/domain/refrigerator/RefrigeratorRepository.kt index 63a61cd..6624536 100644 --- a/src/main/kotlin/mara/server/domain/refrigerator/RefrigeratorRepository.kt +++ b/src/main/kotlin/mara/server/domain/refrigerator/RefrigeratorRepository.kt @@ -1,14 +1,24 @@ package mara.server.domain.refrigerator +import com.querydsl.jpa.impl.JPAQueryFactory +import mara.server.domain.refrigerator.QRefrigerator.refrigerator import mara.server.domain.user.User -import org.springframework.data.domain.Page -import org.springframework.data.domain.Pageable import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.stereotype.Repository -@Repository -interface RefrigeratorRepository : JpaRepository { - fun findRefrigeratorsByUser(user: User): List +interface RefrigeratorRepository : JpaRepository, CustomRefrigeratorRepository { + fun findByUser(user: User): List +} + +interface CustomRefrigeratorRepository { + + fun findByUserList(userList: List, limit: Long): List +} + +class CustomRefrigeratorRepositoryImpl( + private val queryFactory: JPAQueryFactory +) : CustomRefrigeratorRepository { - fun findRefrigeratorByUserIn(user: List, pageable: Pageable): Page + override fun findByUserList(userList: List, limit: Long): List { + return queryFactory.selectFrom(refrigerator).where(refrigerator.user.`in`(userList)).orderBy(refrigerator.ingredientAddDate.desc()).limit(limit).fetch() + } } diff --git a/src/main/kotlin/mara/server/domain/refrigerator/RefrigeratorService.kt b/src/main/kotlin/mara/server/domain/refrigerator/RefrigeratorService.kt index 35e80cf..8c62349 100644 --- a/src/main/kotlin/mara/server/domain/refrigerator/RefrigeratorService.kt +++ b/src/main/kotlin/mara/server/domain/refrigerator/RefrigeratorService.kt @@ -1,15 +1,21 @@ package mara.server.domain.refrigerator +import mara.server.domain.user.UserRepository import mara.server.domain.user.UserService import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional @Service class RefrigeratorService( private val refrigeratorRepository: RefrigeratorRepository, - private val userService: UserService + private val userService: UserService, + private val userRepository: UserRepository ) { private val deleted = "deleted" + fun getCurrentLoginUserRefrigeratorList(): List = refrigeratorRepository.findByUser(userService.getCurrentLoginUser()) + + @Transactional fun createRefrigerator(refrigeratorRequest: RefrigeratorRequest): Long { val user = userService.getCurrentLoginUser() val refrigerator = Refrigerator( @@ -20,24 +26,25 @@ class RefrigeratorService( return refrigeratorRepository.save(refrigerator).refrigeratorId } - fun getRefrigerator(id: Long): RefrigeratorResponse { - val refrigerator = - refrigeratorRepository.findById(id).orElseThrow { NoSuchElementException("해당 냉장고가 존재하지 않습니다. ID: $id") } - return RefrigeratorResponse(refrigerator) - } +// TODO : FE API 연동 테스트 이후 삭제 예정 +// fun getRefrigerator(id: Long): RefrigeratorResponse { +// val refrigerator = +// refrigeratorRepository.findById(id).orElseThrow { NoSuchElementException("해당 냉장고가 존재하지 않습니다. ID: $id") } +// return RefrigeratorResponse(refrigerator) +// } fun getRefrigeratorList(userId: Long): List { - val user = userService.getCurrentLoginUser() - val refrigeratorList = refrigeratorRepository.findRefrigeratorsByUser(user) + val user = userRepository.findById(userId).orElseThrow { NoSuchElementException("해당 유저가 존재하지 않습니다. ID: $userId") } + val refrigeratorList = refrigeratorRepository.findByUser(user) return refrigeratorList.toRefrigeratorResponseList() } fun getMyRefrigeratorList(): List { - val user = userService.getCurrentLoginUser() - val refrigeratorList = refrigeratorRepository.findRefrigeratorsByUser(user) + val refrigeratorList = getCurrentLoginUserRefrigeratorList() return refrigeratorList.toRefrigeratorResponseList() } + @Transactional fun updateRefrigerator(id: Long, refrigeratorRequest: RefrigeratorRequest): RefrigeratorResponse { val refrigerator = refrigeratorRepository.findById(id).orElseThrow { NoSuchElementException("해당 냉장고가 존재하지 않습니다. ID: $id") } @@ -45,6 +52,7 @@ class RefrigeratorService( return RefrigeratorResponse(refrigeratorRepository.save(refrigerator)) } + @Transactional fun deleteRefrigerator(id: Long): String { refrigeratorRepository.deleteById(id) return deleted diff --git a/src/main/kotlin/mara/server/domain/s3/S3Controller.kt b/src/main/kotlin/mara/server/domain/s3/S3Controller.kt index d55d18b..e9ffced 100644 --- a/src/main/kotlin/mara/server/domain/s3/S3Controller.kt +++ b/src/main/kotlin/mara/server/domain/s3/S3Controller.kt @@ -1,5 +1,7 @@ package mara.server.domain.s3 +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag import mara.server.common.CommonResponse import mara.server.common.success import org.springframework.http.MediaType @@ -11,11 +13,13 @@ import org.springframework.web.multipart.MultipartFile @RequestMapping("/s3") @RestController +@Tag(name = "AWS S3", description = "AWS S3 API") class S3Controller( private val s3Service: S3Service ) { @PostMapping("/upload", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) + @Operation(summary = "S3 파일 업로드 API") fun fileUpload( @RequestParam("image") multipartFile: MultipartFile, @RequestParam("dir", required = false) customDir: String? diff --git a/src/main/kotlin/mara/server/domain/s3/S3Service.kt b/src/main/kotlin/mara/server/domain/s3/S3Service.kt index 1949988..a660980 100644 --- a/src/main/kotlin/mara/server/domain/s3/S3Service.kt +++ b/src/main/kotlin/mara/server/domain/s3/S3Service.kt @@ -7,6 +7,7 @@ import com.amazonaws.services.s3.model.PutObjectRequest import com.amazonaws.util.IOUtils import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional import org.springframework.web.multipart.MultipartFile import java.io.ByteArrayInputStream import java.util.UUID @@ -19,6 +20,7 @@ class S3Service( @Value("\${cloud.aws.s3.dir}") private val dir: String ) { + @Transactional fun upload(file: MultipartFile, customDir: String? = dir): String { val fileName = UUID.randomUUID().toString() + "-" + file.originalFilename val objMeta = ObjectMetadata() diff --git a/src/main/kotlin/mara/server/domain/user/UserRepository.kt b/src/main/kotlin/mara/server/domain/user/UserRepository.kt index eeedbc0..e7f412d 100644 --- a/src/main/kotlin/mara/server/domain/user/UserRepository.kt +++ b/src/main/kotlin/mara/server/domain/user/UserRepository.kt @@ -1,14 +1,28 @@ package mara.server.domain.user +import com.querydsl.jpa.impl.JPAQueryFactory +import mara.server.domain.user.QUser.user import org.springframework.data.jpa.repository.JpaRepository -import org.springframework.stereotype.Repository import java.util.Optional -@Repository -interface UserRepository : JpaRepository { +interface UserRepository : JpaRepository, CustomUserRepository { fun findByKakaoId(id: Long): User? fun findByGoogleEmail(email: String): User? fun findByInviteCode(inviteCode: String): Optional fun existsByNickName(nickName: String): Boolean } + +interface CustomUserRepository { + + fun findByIdPage(userId: Long): List +} + +class CustomUserRepositoryImpl( + private val queryFactory: JPAQueryFactory +) : CustomUserRepository { + + override fun findByIdPage(userId: Long): List { + return queryFactory.selectFrom(user).where(user.userId.eq(userId)).fetch() + } +}