-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* [feat] : 엔티티 생성 정적 메서드 추가 * [rename] : 파일명 변경 및 경로 수정 * [chore] : querydsl 라이브러리 추가 * [fix] : reference null 예외 해결 * [feat] query repository 추가 * [refactor] 생성자 대신 builder 사용 * [test] : 카테고리 필터 테스트 코드 작성 * [feat] : respository support class 추가 * [feat] 검색 필터링 추가 * [test] : 검색 필터링 테스트 추가 * [feat] : 키워드 검색 필터링 추가 * [test] : 키워드 검색 필터링 테스트 추가 * [feat] : 정렬 기능 구현 * [feat] : pageResponse 추가 * [refactor] : 엔티티 builder 수정 * [feat] : dto 통합 및 request builder 삭제 * [feat] : 정렬 기능 추가 * [feat] : 검색 API 추가 * [test] : 서비스 테스트 추가 * [style] : 함수명 수정 * [test] : 검색 통합 테스트 작성 * [style] : 코드 리포멧팅 * [fix] : request 정적 팩토리 메서드 추가
- Loading branch information
Showing
39 changed files
with
927 additions
and
286 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
48 changes: 48 additions & 0 deletions
48
api/src/main/java/dev/handsup/auction/controller/AuctionApiController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package dev.handsup.auction.controller; | ||
|
||
import org.springframework.data.domain.Pageable; | ||
import org.springframework.http.ResponseEntity; | ||
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.RestController; | ||
|
||
import dev.handsup.auction.dto.request.AuctionSearchCondition; | ||
import dev.handsup.auction.dto.request.RegisterAuctionRequest; | ||
import dev.handsup.auction.dto.response.AuctionResponse; | ||
import dev.handsup.auction.service.AuctionService; | ||
import dev.handsup.auth.annotation.NoAuth; | ||
import dev.handsup.common.dto.PageResponse; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Tag(name = "경매 API") | ||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api/auctions") | ||
public class AuctionApiController { | ||
|
||
private final AuctionService auctionService; | ||
|
||
@NoAuth | ||
@Operation(summary = "경매 등록 API", description = "경매를 등록한다") | ||
@ApiResponse(useReturnTypeSchema = true) | ||
@PostMapping | ||
public ResponseEntity<AuctionResponse> registerAuction(@Valid @RequestBody RegisterAuctionRequest request) { | ||
AuctionResponse response = auctionService.registerAuction(request); | ||
return ResponseEntity.ok(response); | ||
} | ||
|
||
@NoAuth | ||
@Operation(summary = "경매 검색 API", description = "경매를 검색한다") | ||
@ApiResponse(useReturnTypeSchema = true) | ||
@PostMapping("/search") | ||
public ResponseEntity<PageResponse<AuctionResponse>> searchAuctions(@RequestBody AuctionSearchCondition condition, | ||
Pageable pageable) { | ||
PageResponse<AuctionResponse> response = auctionService.searchAuctions(condition, pageable); | ||
return ResponseEntity.ok(response); | ||
} | ||
} |
37 changes: 0 additions & 37 deletions
37
api/src/main/java/dev/handsup/auction/controller/AuctionController.java
This file was deleted.
Oops, something went wrong.
25 changes: 0 additions & 25 deletions
25
api/src/main/java/dev/handsup/auction/dto/ApiAuctionMapper.java
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
180 changes: 180 additions & 0 deletions
180
api/src/test/java/dev/handsup/auction/controller/AuctionApiControllerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
package dev.handsup.auction.controller; | ||
|
||
import static org.springframework.http.MediaType.*; | ||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; | ||
|
||
import java.time.LocalDate; | ||
import java.util.List; | ||
|
||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.test.util.ReflectionTestUtils; | ||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers; | ||
|
||
import dev.handsup.auction.domain.Auction; | ||
import dev.handsup.auction.domain.auction_field.PurchaseTime; | ||
import dev.handsup.auction.domain.auction_field.TradeMethod; | ||
import dev.handsup.auction.domain.product.ProductStatus; | ||
import dev.handsup.auction.domain.product.product_category.ProductCategory; | ||
import dev.handsup.auction.dto.request.AuctionSearchCondition; | ||
import dev.handsup.auction.dto.request.RegisterAuctionRequest; | ||
import dev.handsup.auction.repository.auction.AuctionRepository; | ||
import dev.handsup.auction.repository.product.ProductCategoryRepository; | ||
import dev.handsup.common.support.ApiTestSupport; | ||
import dev.handsup.fixture.AuctionFixture; | ||
import dev.handsup.fixture.ProductFixture; | ||
|
||
class AuctionApiControllerTest extends ApiTestSupport { | ||
|
||
private final String DIGITAL_DEVICE = "디지털 기기"; | ||
private ProductCategory productCategory; | ||
|
||
@Autowired | ||
private AuctionRepository auctionRepository; | ||
@Autowired | ||
private ProductCategoryRepository productCategoryRepository; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
productCategory = ProductFixture.productCategory(DIGITAL_DEVICE); | ||
productCategoryRepository.save(productCategory); | ||
} | ||
|
||
@DisplayName("[경매를 등록할 수 있다.]") | ||
@Test | ||
void registerAuction() throws Exception { | ||
RegisterAuctionRequest request = RegisterAuctionRequest.of( | ||
"거의 새상품 버즈 팔아요", | ||
DIGITAL_DEVICE, | ||
10000, | ||
LocalDate.parse("2022-10-18"), | ||
ProductStatus.NEW.getLabel(), | ||
PurchaseTime.UNDER_ONE_MONTH.getLabel(), | ||
"거의 새상품이에요", | ||
TradeMethod.DELIVER.getLabel() | ||
); | ||
|
||
mockMvc.perform(post("/api/auctions") | ||
.contentType(APPLICATION_JSON) | ||
.content(toJson(request))) | ||
.andExpect(status().isOk()) | ||
.andExpect(jsonPath("$.title").value(request.title())) | ||
.andExpect(jsonPath("$.description").value(request.description())) | ||
.andExpect(jsonPath("$.productStatus").value(request.productStatus())) | ||
.andExpect(jsonPath("$.tradeMethod").value(request.tradeMethod())) | ||
.andExpect(jsonPath("$.endDate").value(request.endDate().toString())) | ||
.andExpect(jsonPath("$.initPrice").value(request.initPrice())) | ||
.andExpect(jsonPath("$.purchaseTime").value(request.purchaseTime())) | ||
.andExpect(jsonPath("$.productCategory").value(request.productCategory())) | ||
.andExpect(jsonPath("$.si").isEmpty()) | ||
.andExpect(jsonPath("$.gu").isEmpty()) | ||
.andExpect(jsonPath("$.dong").isEmpty()); | ||
} | ||
|
||
@DisplayName("[경매를 등록 시 상품 카테고리가 DB에 없으면 예외가 발생한다.]") | ||
@Test | ||
void registerAuctionFails() throws Exception { | ||
final String NOT_EXIST_CATEGORY = "아"; | ||
RegisterAuctionRequest request = RegisterAuctionRequest.of( | ||
"거의 새상품 버즈 팔아요", | ||
NOT_EXIST_CATEGORY, | ||
10000, | ||
LocalDate.parse("2022-10-18"), | ||
ProductStatus.NEW.getLabel(), | ||
PurchaseTime.UNDER_ONE_MONTH.getLabel(), | ||
"거의 새상품이에요", | ||
TradeMethod.DELIVER.getLabel(), | ||
"서울시", | ||
"성북구", | ||
"동선동" | ||
); | ||
|
||
mockMvc.perform(post("/api/auctions") | ||
.contentType(APPLICATION_JSON) | ||
.content(toJson(request))) | ||
.andExpect(status().isBadRequest()) | ||
.andExpect(jsonPath("$.message").value("존재하지 않는 상품 카테고리입니다.")) | ||
.andExpect(jsonPath("$.code").value("AU_004")); | ||
} | ||
|
||
@DisplayName("[경매를 검색해서 조회할 수 있다. 정렬 조건이 없을 경우 최신순으로 정렬한다.]") | ||
@Test | ||
void searchAuction() throws Exception { | ||
Auction auction1 = AuctionFixture.auction(productCategory, "버즈 이어폰 팔아요"); | ||
Auction auction2 = AuctionFixture.auction(productCategory, "에버어즈팟"); | ||
Auction auction3 = AuctionFixture.auction(productCategory, "버즈 이어폰 팔아요"); | ||
AuctionSearchCondition condition = AuctionSearchCondition.builder() | ||
.keyword("버즈").build(); | ||
auctionRepository.saveAll(List.of(auction1, auction2, auction3)); | ||
|
||
mockMvc.perform(post("/api/auctions/search") | ||
.contentType(APPLICATION_JSON) | ||
.content(toJson(condition))) | ||
.andDo(MockMvcResultHandlers.print()) | ||
.andExpect(status().isOk()) | ||
.andExpect(jsonPath("$.content[0].title").value(auction1.getTitle())) | ||
.andExpect(jsonPath("$.content[0].description").value(auction1.getProduct().getDescription())) | ||
.andExpect(jsonPath("$.content[0].productStatus").value(auction1.getProduct().getStatus().getLabel())) | ||
.andExpect(jsonPath("$.content[0].tradeMethod").value(auction1.getTradeMethod().getLabel())) | ||
.andExpect(jsonPath("$.content[0].endDate").value(auction1.getEndDate().toString())) | ||
.andExpect(jsonPath("$.content[0].initPrice").value(auction1.getInitPrice())) | ||
.andExpect(jsonPath("$.content[0].purchaseTime").value(auction1.getProduct().getPurchaseTime().getLabel())) | ||
.andExpect(jsonPath("$.content[0].productCategory").value( | ||
auction1.getProduct().getProductCategory().getCategoryValue())) | ||
.andExpect(jsonPath("$.content[0].si").value(auction1.getTradingLocation().getSi())) | ||
.andExpect(jsonPath("$.content[0].gu").value(auction1.getTradingLocation().getGu())) | ||
.andExpect(jsonPath("$.content[0].dong").value(auction1.getTradingLocation().getDong())) | ||
.andExpect(jsonPath("$.content[1].title").value(auction3.getTitle())); | ||
} | ||
|
||
@DisplayName("[경매를 북마크 순으로 정렬할 수 있다.]") | ||
@Test | ||
void searchAuctionSort() throws Exception { | ||
Auction auction1 = AuctionFixture.auction(productCategory); | ||
Auction auction2 = AuctionFixture.auction(productCategory); | ||
Auction auction3 = AuctionFixture.auction(productCategory); | ||
ReflectionTestUtils.setField(auction2, "bookmarkCount", 5); | ||
ReflectionTestUtils.setField(auction3, "bookmarkCount", 3); | ||
auctionRepository.saveAll(List.of(auction1, auction2, auction3)); | ||
AuctionSearchCondition condition = AuctionSearchCondition.builder() | ||
.keyword(null).build(); | ||
|
||
mockMvc.perform(post("/api/auctions/search") | ||
.content(toJson(condition)) | ||
.contentType(APPLICATION_JSON) | ||
.param("sort", "bookmarkCount,desc")) | ||
.andDo(MockMvcResultHandlers.print()) | ||
.andExpect(status().isOk()) | ||
.andExpect(jsonPath("$.size").value(3)) | ||
.andExpect(jsonPath("$.content[0].auctionId").value(auction2.getId())) | ||
.andExpect(jsonPath("$.content[1].auctionId").value(auction3.getId())) | ||
.andExpect(jsonPath("$.content[2].auctionId").value(auction1.getId())); | ||
} | ||
|
||
@DisplayName("[검색된 경매를 필터링할 수 있다.]") | ||
@Test | ||
void searchAuctionFilter() throws Exception { | ||
Auction auction1 = AuctionFixture.auction(productCategory, "버즈", 15000); | ||
Auction auction2 = AuctionFixture.auction(productCategory, "에어팟", 15000); | ||
Auction auction3 = AuctionFixture.auction(productCategory, "버즈 팔아요", 25000); | ||
ReflectionTestUtils.setField(auction2, "bookmarkCount", 5); | ||
ReflectionTestUtils.setField(auction3, "bookmarkCount", 3); | ||
auctionRepository.saveAll(List.of(auction1, auction2, auction3)); | ||
AuctionSearchCondition condition = AuctionSearchCondition.builder() | ||
.keyword("버즈") | ||
.minPrice(10000) | ||
.maxPrice(20000) | ||
.build(); | ||
|
||
mockMvc.perform(post("/api/auctions/search") | ||
.content(toJson(condition)) | ||
.contentType(APPLICATION_JSON)) | ||
.andDo(MockMvcResultHandlers.print()) | ||
.andExpect(status().isOk()) | ||
.andExpect(jsonPath("$.size").value(1)) | ||
.andExpect(jsonPath("$.content[0].auctionId").value(auction1.getId())); | ||
} | ||
} |
Oops, something went wrong.