Skip to content

Commit

Permalink
Merge pull request #27 from ClothingStoreService/feature/product-pagi…
Browse files Browse the repository at this point in the history
…nation

Feature/product pagination
  • Loading branch information
Ogu1208 authored Aug 17, 2024
2 parents abc53d1 + 1a3506d commit aca383a
Show file tree
Hide file tree
Showing 23 changed files with 699 additions and 143 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package org.store.clothstar.category.controller

import io.swagger.v3.oas.annotations.Operation
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.domain.Slice
import org.springframework.data.web.PageableDefault
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.validation.annotation.Validated
Expand All @@ -11,21 +15,53 @@ import org.store.clothstar.category.dto.response.CategoryResponse
import org.store.clothstar.category.service.CategoryService
import org.store.clothstar.common.dto.MessageDTO
import org.store.clothstar.common.util.URIBuilder
import org.store.clothstar.product.dto.response.ProductListResponse
import org.store.clothstar.product.service.ProductService

@RestController
@RequestMapping("/v1/categories")
class CategoryController(
private val categoryService: CategoryService,
// private val productLineService: ProductLineService
private val productService: ProductService
) {

@Operation(summary = "전체 카테고리 조회", description = "모든 카테고리를 조회한다.")
@GetMapping
fun getAllCategories(): ResponseEntity<List<CategoryResponse>> {
val categoryResponses = categoryService.getAllCategories()
return ResponseEntity.ok(categoryResponses)
}


@Operation(
summary = "카테고리별 상품 조회 (Offset Paging)",
description = "카테고리 ID로 해당 카테고리에 속하는 모든 상품을 Offset Paging을 통해 조회한다."
)
@GetMapping("/{categoryId}/products/offset")
fun getProductLinesByCategory(
@PathVariable categoryId: Long,
@PageableDefault(size = 18) pageable: Pageable,
@RequestParam(required = false) keyword: String?
): ResponseEntity<Page<ProductListResponse>> {
val productResponses: Page<ProductListResponse> =
productService.getProductLinesByCategoryWithOffsetPaging(categoryId, pageable, keyword)
return ResponseEntity.ok().body<Page<ProductListResponse>>(productResponses)
}

@Operation(
summary = "카테고리별 상품 조회 (Slice Paging)",
description = "카테고리 ID로 해당 카테고리에 속하는 모든 상품을 Slice Paging을 통해 조회한다."
)
@GetMapping("/{categoryId}/products/slice")
fun getProductLinesByCategorySlice(
@PathVariable categoryId: Long,
@PageableDefault(size = 18) pageable: Pageable,
@RequestParam(required = false) keyword: String?
): ResponseEntity<Slice<ProductListResponse>> {
val productResponses: Slice<ProductListResponse> =
productService.getProductLinesByCategoryWithSlicePaging(categoryId, pageable, keyword)
return ResponseEntity.ok().body<Slice<ProductListResponse>>(productResponses)
}

@Operation(summary = "카테고리 상세 조회", description = "id로 카테고리 한개를 상세 조회한다.")
@GetMapping("/{categoryId}")
fun getCategory(@PathVariable categoryId: Long): ResponseEntity<CategoryResponse> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ package org.store.clothstar.common.config

import com.querydsl.jpa.impl.JPAQueryFactory
import jakarta.persistence.EntityManager
import jakarta.persistence.PersistenceContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration
class JpaQueryFactoryConfig {

@PersistenceContext
private lateinit var entityManager: EntityManager

class JpaQueryFactoryConfig(
private val em: EntityManager,
) {
@Bean
fun jpaQueryFactory() = JPAQueryFactory(entityManager)
fun jpaQueryFactory(): JPAQueryFactory {
return JPAQueryFactory(em)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class SecurityConfiguration(
"/v1/members/login", "/signup", "/v1/members/email/**", "/v1/access",
"/v1/categories/**", "/v1/products/**", "/v1/productLines/**", "/v2/productLines/**",
"/productLinePagingSlice", "/productLinePagingOffset",
"/v3/products/**",
"/v3/products/**", "v3/sellers/products/**",
"/v1/orderdetails", "/v1/orders", "membersPagingOffset", "membersPagingSlice",
"/v1/orderdetails", "/v1/orders", "/v2/orders", "/v3/orders", "/v1/orders/list",
"/v1/orders/list", "/ordersPagingOffset", "/ordersPagingSlice", "/v2/orders/list",
Expand Down
7 changes: 7 additions & 0 deletions src/main/kotlin/org/store/clothstar/common/error/ErrorCode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ enum class ErrorCode(
INVALID_REFRESH_TOKEN(HttpStatus.BAD_REQUEST, "refresh 토큰이 만료되었거나 유효하지 않습니다."),
INVALID_AUTH_CERTIFY_NUM(HttpStatus.BAD_REQUEST, "인증번호가 잘못 되었습니다."),

INVALID_ROLE(HttpStatus.BAD_REQUEST, "계정 ID: %d - 이 계정은 요청된 권한(%s)을 가지고 있지 않습니다."),

// Order 관련 에러코드
NOT_FOUND_ORDER(HttpStatus.NOT_FOUND, "존재하지 않는 주문번호입니다."),
INVALID_ORDER_STATUS_CONFIRMED(HttpStatus.BAD_REQUEST, "주문이 '입금확인' 상태가 아니므로 요청을 처리할 수 없습니다."),
Expand All @@ -35,4 +37,9 @@ enum class ErrorCode(
this.status = status
this.message = message
}

fun withDynamicMessage(vararg args: Any): ErrorCode {
this.message = String.format(this.message, *args)
return this
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import org.springframework.http.HttpStatus
import org.store.clothstar.common.error.ErrorCode

class BadRequestException(
val code: ErrorCode
val code: ErrorCode,
vararg args: Any
) : RuntimeException(code.message) {

val httpStatus: HttpStatus
get() = code.status

Expand Down
19 changes: 19 additions & 0 deletions src/main/kotlin/org/store/clothstar/member/AccountValidateUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.store.clothstar.member

import org.springframework.stereotype.Component
import org.store.clothstar.common.error.ErrorCode
import org.store.clothstar.common.error.exception.order.BadRequestException
import org.store.clothstar.member.domain.Account
import org.store.clothstar.member.domain.MemberRole

@Component
class AccountValidateUtil (

) {

// fun validateRole(accout: Account, memberRole: MemberRole) {
// if (!accout.role.equals(memberRole)) {
//// throw BadRequestException(ErrorCode.INVALID_ROLE, accout.accountId, memberRole)
// }
// }
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
package org.store.clothstar.member.dto.response

import org.store.clothstar.member.domain.Seller

class SellerSimpleResponse(
var memberId: Long,
val brandName: String,
val bizNo: String,
)
) {
companion object {
fun getSellerSimpleResponseBySeller(seller: Seller): SellerSimpleResponse {
return SellerSimpleResponse(
memberId = seller.memberId,
bizNo = seller.bizNo,
brandName = seller.brandName,
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ package org.store.clothstar.product.controller

import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.domain.Slice
import org.springframework.data.web.PageableDefault
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
import org.store.clothstar.common.dto.MessageDTO
import org.store.clothstar.product.dto.request.ProductCreateRequest
import org.store.clothstar.product.dto.request.UpdateDisplayStatusRequest
import org.store.clothstar.product.dto.response.ProductListResponse
import org.store.clothstar.product.dto.response.ProductResponse
import org.store.clothstar.product.service.ProductApplicationService

Expand All @@ -19,62 +23,33 @@ import org.store.clothstar.product.service.ProductApplicationService
private class ProductController(
private val productApplicationService: ProductApplicationService,
) {
@PostMapping
@Operation(
summary = "상품 등록",
description = "카테고리 아이디, 상품 이름, 내용, 가격, 상태를 입력하여 상품을 신규 등록한다."
)
fun createProduct(
@RequestPart(value = "mainImage", required = false) mainImage: MultipartFile,
@RequestPart(value = "subImages", required = false) subImages: List<MultipartFile>?,
@RequestPart(value = "dto") @Validated productCreateRequest: ProductCreateRequest
): ResponseEntity<MessageDTO> {
// 상품 등록
productApplicationService.createProduct(mainImage, subImages, productCreateRequest);

val messageDTO = MessageDTO(
HttpStatus.CREATED.value(),
"상품 생성이 정상적으로 처리됐습니다."
)
// 상품 전체 Offset 페이징 조회
@GetMapping("/offset")
@Operation(summary = "상품 전체 Offset 페이징 조회", description = "상품 전체 리스트를 Offset 페이징 형식으로 조회한다.")
fun getAllProductsOffsetPaging(
@PageableDefault(size = 18) pageable: Pageable,
@RequestParam(required = false) keyword: String?
): ResponseEntity<Page<ProductListResponse>> {
val productPages = productApplicationService.getAllProductsOffsetPaging(pageable, keyword)
return ResponseEntity.ok().body(productPages)
}

return ResponseEntity(messageDTO, HttpStatus.CREATED)
// 상품 전체 Slice 페이징 조회
@GetMapping("/slice")
@Operation(summary = "상품 전체 Slice 페이징 조회", description = "상품 전체 리스트를 Slice 페이징 형식으로 조회한다.")
fun getAllProductsSlicePaging(
@PageableDefault(size = 18) pageable: Pageable,
@RequestParam(required = false) keyword: String?
): ResponseEntity<Slice<ProductListResponse>> {
val productPages = productApplicationService.getAllProductsSlicePaging(pageable, keyword)
return ResponseEntity.ok().body(productPages)
}

@GetMapping("/{productId}")
@Operation(summary = "상품 상세 조회", description = "상품 ID를 사용하여 특정 상품의 상세 정보를 조회한다.")
fun getProductDetails(@PathVariable productId: Long): ResponseEntity<ProductResponse> {
val productResponse = productApplicationService.getProductDetails(productId)
val productResponse = productApplicationService.getProductDetails(productId, false)
return ResponseEntity(productResponse, HttpStatus.OK)
}

@PatchMapping("/{productId}/displayStatus")
@Operation(summary = "상품 진열 상태 변경", description = "상품 ID를 사용하여 해당 상품의 진열 상태를 변경합니다.")
fun updateProductDisplayStatus(
@PathVariable productId: Long,
@RequestBody request: UpdateDisplayStatusRequest
): ResponseEntity<MessageDTO> {
productApplicationService.updateProductDisplayStatus(productId, request.displayStatus)

val messageDTO = MessageDTO(
HttpStatus.OK.value(),
"상품 진열 상태가 성공적으로 변경되었습니다."
)
return ResponseEntity(messageDTO, HttpStatus.OK)
}

@PatchMapping("/{productId}/items/{itemId}/displayStatus")
@Operation(summary = "아이템 진열 상태 변경", description = "상품 ID와 아이템 ID를 사용하여 해당 아이템의 진열 상태를 변경합니다.")
fun updateItemDisplayStatus(
@PathVariable productId: Long,
@PathVariable itemId: Long,
@RequestBody request: UpdateDisplayStatusRequest
): ResponseEntity<MessageDTO> {
productApplicationService.updateItemDisplayStatus(productId, itemId, request.displayStatus)

val messageDTO = MessageDTO(
HttpStatus.OK.value(),
"아이템 진열 상태가 성공적으로 변경되었습니다."
)
return ResponseEntity(messageDTO, HttpStatus.OK)
}
}
Loading

0 comments on commit aca383a

Please sign in to comment.