From f99b77647dcadc2645a174b7ab6ad28acc0a36b6 Mon Sep 17 00:00:00 2001 From: chaechaen Date: Wed, 4 Sep 2024 13:04:33 +0900 Subject: [PATCH 1/7] =?UTF-8?q?refactor:=20ResponseDTO=EC=97=90=20from=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/MarketPostService.java | 58 +++++-------------- .../marketPost/dto/MarketPostResponseDTO.java | 23 ++++++++ .../scrap/application/ScrapService.java | 47 ++------------- .../domain/scrap/dto/ScrapResponseDTO.java | 9 +++ 4 files changed, 51 insertions(+), 86 deletions(-) diff --git a/src/main/java/com/on/server/domain/marketPost/application/MarketPostService.java b/src/main/java/com/on/server/domain/marketPost/application/MarketPostService.java index 76df891a..e115023d 100644 --- a/src/main/java/com/on/server/domain/marketPost/application/MarketPostService.java +++ b/src/main/java/com/on/server/domain/marketPost/application/MarketPostService.java @@ -29,12 +29,11 @@ public class MarketPostService { private final MarketPostRepository marketPostRepository; private final UserRepository userRepository; private final UuidFileService uuidFileService; - private final UuidFileRepository uuidFileRepository; // 1. 모든 물품글 조회 public List getAllMarketPosts() { return marketPostRepository.findAllByOrderByCreatedAtDesc().stream() - .map(this::mapToMarketPostResponseDTO) + .map(MarketPostResponseDTO::from) .collect(Collectors.toList()); } @@ -42,14 +41,12 @@ public List getAllMarketPosts() { public MarketPostResponseDTO getMarketPostById(Long marketPostId) { MarketPost marketPost = marketPostRepository.findById(marketPostId) .orElseThrow(() -> new RuntimeException("게시글을 찾을 수 없습니다. ID: " + marketPostId)); - return mapToMarketPostResponseDTO(marketPost); + return MarketPostResponseDTO.from(marketPost); } // 3. 새로운 물품글 작성 @Transactional - public MarketPostResponseDTO createMarketPost(MarketPostRequestDTO requestDTO, List imageFiles) { - User user = userRepository.findById(requestDTO.getUserId()) - .orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다. ID: " + requestDTO.getUserId())); + public MarketPostResponseDTO createMarketPost(User user, MarketPostRequestDTO requestDTO, List imageFiles) { // 이미지 파일 처리 List uploadedImages = new ArrayList<>(); @@ -74,28 +71,23 @@ public MarketPostResponseDTO createMarketPost(MarketPostRequestDTO requestDTO, L marketPost = marketPostRepository.save(marketPost); - return mapToMarketPostResponseDTO(marketPost); + return MarketPostResponseDTO.from(marketPost); } // 4. 특정 사용자가 작성한 모든 물품글 조회 - public List getMarketPostsByUserId(Long userId) { - User user = userRepository.findById(userId) - .orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다. ID: " + userId)); - + public List getMarketPostsByUser(User user) { return marketPostRepository.findByUserOrderByCreatedAtDesc(user).stream() - .map(this::mapToMarketPostResponseDTO) + .map(MarketPostResponseDTO::from) .collect(Collectors.toList()); } // 5. 특정 게시글 삭제 @Transactional - public void deleteMarketPost(Long userId, Long marketPostId) { - User user = userRepository.findById(userId) - .orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다. ID: " + userId)); + public void deleteMarketPost(User user, Long marketPostId) { MarketPost marketPost = marketPostRepository.findById(marketPostId) .orElseThrow(() -> new RuntimeException("게시글을 찾을 수 없습니다. ID: " + marketPostId)); - if (!marketPost.getUser().getId().equals(userId)) { + if (!marketPost.getUser().getId().equals(user.getId())) { throw new RuntimeException("삭제 권한이 없습니다."); } @@ -111,27 +103,24 @@ public MarketPostResponseDTO updateMarketPostStatus(Long marketPostId, DealStatu MarketPost marketPost = marketPostRepository.findById(marketPostId) .orElseThrow(() -> new RuntimeException("게시글을 찾을 수 없습니다. ID: " + marketPostId)); - if (marketPost.getDealStatus() != DealStatus.AWAIT) { - throw new RuntimeException("거래 상태가 AWAIT인 경우에만 COMPLETE로 업데이트할 수 있습니다."); - } + marketPost.completeDeal(); // 상태 업데이트 - marketPost.setDealStatus(DealStatus.COMPLETE); // 상태 업데이트 MarketPost updatedMarketPost = marketPostRepository.save(marketPost); // 저장 - return mapToMarketPostResponseDTO(updatedMarketPost); + return MarketPostResponseDTO.from(updatedMarketPost); } // 필터링: 거래형식, 국가, 거래상태 필터링 public List getFilteredMarketPosts(DealType dealType, String currentCountry, DealStatus dealStatus) { return marketPostRepository.findFilteredMarketPosts(dealType, currentCountry, dealStatus).stream() - .map(this::mapToMarketPostResponseDTO) + .map(MarketPostResponseDTO::from) .collect(Collectors.toList()); } // 필터링: 거래 가능 물품만 보기 public List getAvailableMarketPosts() { return marketPostRepository.findFilteredMarketPosts(null, null, DealStatus.AWAIT).stream() - .map(this::mapToMarketPostResponseDTO) + .map(MarketPostResponseDTO::from) .collect(Collectors.toList()); } @@ -139,7 +128,7 @@ public List getAvailableMarketPosts() { public List searchMarketPosts(String keyword) { List marketPosts = marketPostRepository.searchMarketPosts(keyword); return marketPosts.stream() - .map(this::mapToMarketPostResponseDTO) + .map(MarketPostResponseDTO::from) .collect(Collectors.toList()); } @@ -148,26 +137,7 @@ public List searchMarketPosts(String keyword) { public List getNearbyMarketPosts(String currentCountry, Long marketPostId) { List nearbyPosts = marketPostRepository.findTop3ByCurrentCountryAndAwaitingOrder(currentCountry, marketPostId); return nearbyPosts.stream() - .map(this::mapToMarketPostResponseDTO) + .map(MarketPostResponseDTO::from) .collect(Collectors.toList()); } - - // MarketPost 엔티티를 MarketPostResponseDto로 매핑하는 메서드 - private MarketPostResponseDTO mapToMarketPostResponseDTO(MarketPost marketPost) { - return MarketPostResponseDTO.builder() - .marketPostId(marketPost.getId()) - .userId(marketPost.getUser().getId()) - .nickname(marketPost.getUser().getNickname()) - .currentCountry(marketPost.getCurrentCountry()) - .currentLocation(marketPost.getCurrentLocation()) - .title(marketPost.getTitle()) - .cost(marketPost.getCost()) - .isShare(marketPost.isShare()) - .dealType(marketPost.getDealType()) - .dealStatus(marketPost.getDealStatus()) - .content(marketPost.getContent()) - .createdAt(marketPost.getCreatedAt()) - .imageUrls(marketPost.getImages().stream().map(UuidFile::getFileUrl).collect(Collectors.toList())) // 이미지 URL 리스트 - .build(); - } } diff --git a/src/main/java/com/on/server/domain/marketPost/dto/MarketPostResponseDTO.java b/src/main/java/com/on/server/domain/marketPost/dto/MarketPostResponseDTO.java index 2c9ed1bc..792960e5 100644 --- a/src/main/java/com/on/server/domain/marketPost/dto/MarketPostResponseDTO.java +++ b/src/main/java/com/on/server/domain/marketPost/dto/MarketPostResponseDTO.java @@ -3,6 +3,7 @@ import com.on.server.domain.marketPost.domain.DealStatus; import com.on.server.domain.marketPost.domain.DealType; import com.on.server.domain.marketPost.domain.MarketPost; +import com.on.server.global.aws.s3.uuidFile.domain.UuidFile; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -10,6 +11,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.stream.Collectors; @Getter @Builder @@ -56,4 +58,25 @@ public class MarketPostResponseDTO { // 작성 시간 private LocalDateTime createdAt; + // MarketPost 엔티티를 MarketPostResponseDTO로 매핑하는 메서드 + public static MarketPostResponseDTO from(MarketPost marketPost) { + return MarketPostResponseDTO.builder() + .marketPostId(marketPost.getId()) + .userId(marketPost.getUser().getId()) + .nickname(marketPost.getUser().getNickname()) + .currentCountry(marketPost.getCurrentCountry()) + .currentLocation(marketPost.getCurrentLocation()) + .title(marketPost.getTitle()) + .cost(marketPost.getCost()) + .isShare(marketPost.isShare()) + .dealType(marketPost.getDealType()) + .dealStatus(marketPost.getDealStatus()) + .content(marketPost.getContent()) + .createdAt(marketPost.getCreatedAt()) + .imageUrls(marketPost.getImages().stream() + .map(UuidFile::getFileUrl) + .collect(Collectors.toList())) // 이미지 URL 리스트 + .build(); + } + } diff --git a/src/main/java/com/on/server/domain/scrap/application/ScrapService.java b/src/main/java/com/on/server/domain/scrap/application/ScrapService.java index 10aaa4bf..73c8244a 100644 --- a/src/main/java/com/on/server/domain/scrap/application/ScrapService.java +++ b/src/main/java/com/on/server/domain/scrap/application/ScrapService.java @@ -23,13 +23,10 @@ public class ScrapService { private final ScrapRepository scrapRepository; - private final UserRepository userRepository; private final MarketPostRepository marketPostRepository; // 1. 특정 물품글 스크랩 - public void scrapMarketPost(ScrapRequestDTO scrapRequestDTO) { - User user = userRepository.findById(scrapRequestDTO.getUserId()) - .orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다. ID: " + scrapRequestDTO.getUserId())); + public void scrapMarketPost(User user, ScrapRequestDTO scrapRequestDTO) { MarketPost marketPost = marketPostRepository.findById(scrapRequestDTO.getMarketPostId()) .orElseThrow(() -> new RuntimeException("게시글을 찾을 수 없습니다. ID: " + scrapRequestDTO.getMarketPostId())); @@ -50,54 +47,20 @@ public void scrapMarketPost(ScrapRequestDTO scrapRequestDTO) { // 2. 스크랩한 모든 물품글 조회 @Transactional(readOnly = true) - public List getScrappedMarketPosts(Long userId) { - User user = userRepository.findById(userId) - .orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다. ID: " + userId)); - - // 스크랩한 물품글 목록을 가져오고, 이를 ScrapResponseDTO로 변환 + public List getScrappedMarketPosts(User user) { return scrapRepository.findByUser(user).stream() - .map(this::mapToScrapResponseDTO) // Scrap 객체를 ScrapResponseDTO로 매핑 + .map(ScrapResponseDTO::from) // Scrap 객체를 ScrapResponseDTO로 매핑 .collect(Collectors.toList()); } // 3. 스크랩 목록에서 자기가 작성한 특정 물품글 스크랩 취소 (삭제) - public void deleteMarketPost(Long userId, Long marketPostId) { - User user = userRepository.findById(userId) - .orElseThrow(() -> new RuntimeException("사용자를 찾을 수 없습니다. ID: " + userId)); + public void deleteMarketPost(User user, Long marketPostId) { MarketPost marketPost = marketPostRepository.findById(marketPostId) .orElseThrow(() -> new RuntimeException("게시글을 찾을 수 없습니다. ID: " + marketPostId)); + Scrap scrap = scrapRepository.findByUserAndMarketPost(user, marketPost) .orElseThrow(() -> new RuntimeException("스크랩을 찾을 수 없습니다.")); scrapRepository.delete(scrap); } - - // Scrap 엔티티를 ScrapResponseDto로 매핑하는 메서드 - private ScrapResponseDTO mapToScrapResponseDTO(Scrap scrap) { - return ScrapResponseDTO.builder() - .scrapId(scrap.getId()) - .userId(scrap.getUser().getId()) - .marketPost(mapToMarketPostResponseDTO(scrap.getMarketPost())) - .build(); - } - - // MarketPost 엔티티를 MarketPostResponseDTO로 매핑하는 메서드 - private MarketPostResponseDTO mapToMarketPostResponseDTO(MarketPost marketPost) { - return MarketPostResponseDTO.builder() - .marketPostId(marketPost.getId()) - .userId(marketPost.getUser().getId()) - .currentCountry(marketPost.getCurrentCountry()) - .currentLocation(marketPost.getCurrentLocation()) - .title(marketPost.getTitle()) - .cost(marketPost.getCost()) - .isShare(marketPost.isShare()) - .dealType(marketPost.getDealType()) - .dealStatus(marketPost.getDealStatus()) - .content(marketPost.getContent()) - .imageUrls(marketPost.getImages().stream() - .map(UuidFile::getFileUrl) // 이미지 URL 리스트를 가져오는 로직 - .collect(Collectors.toList())) - .createdAt(marketPost.getCreatedAt()) - .build(); - } } diff --git a/src/main/java/com/on/server/domain/scrap/dto/ScrapResponseDTO.java b/src/main/java/com/on/server/domain/scrap/dto/ScrapResponseDTO.java index 8f39ae54..cfaec518 100644 --- a/src/main/java/com/on/server/domain/scrap/dto/ScrapResponseDTO.java +++ b/src/main/java/com/on/server/domain/scrap/dto/ScrapResponseDTO.java @@ -1,6 +1,7 @@ package com.on.server.domain.scrap.dto; import com.on.server.domain.marketPost.dto.MarketPostResponseDTO; +import com.on.server.domain.scrap.domain.Scrap; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -19,4 +20,12 @@ public class ScrapResponseDTO { // 물품거래글에 대한 정보 private MarketPostResponseDTO marketPost; // 물품거래글 작성자의 ID + + public static ScrapResponseDTO from(Scrap scrap) { + return ScrapResponseDTO.builder() + .scrapId(scrap.getId()) + .userId(scrap.getUser().getId()) + .marketPost(MarketPostResponseDTO.from(scrap.getMarketPost())) // MarketPostResponseDTO의 from 메서드를 사용 + .build(); + } } \ No newline at end of file From 0e1a838d2eec923544ccaec81fb192abce01fc52 Mon Sep 17 00:00:00 2001 From: chaechaen Date: Wed, 4 Sep 2024 13:05:30 +0900 Subject: [PATCH 2/7] =?UTF-8?q?refactor:=20UserDetails=EC=97=90=EC=84=9C?= =?UTF-8?q?=20User=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EA=B0=80=EC=A0=B8?= =?UTF-8?q?=EC=98=A4=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95,=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20ok=EB=A1=9C=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/MarketPostController.java | 50 ++++++++++--------- .../scrap/presentation/ScrapController.java | 40 ++++++++++----- 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/on/server/domain/marketPost/presentation/MarketPostController.java b/src/main/java/com/on/server/domain/marketPost/presentation/MarketPostController.java index 69104216..98f37b78 100644 --- a/src/main/java/com/on/server/domain/marketPost/presentation/MarketPostController.java +++ b/src/main/java/com/on/server/domain/marketPost/presentation/MarketPostController.java @@ -7,6 +7,7 @@ import com.on.server.domain.marketPost.dto.MarketPostResponseDTO; import com.on.server.domain.scrap.application.ScrapService; import com.on.server.domain.user.domain.User; +import com.on.server.global.security.SecurityService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; @@ -28,13 +29,13 @@ public class MarketPostController { private final MarketPostService marketPostService; - private final ScrapService scrapService; + private final SecurityService securityService; // 1. 모든 물품글 조회 @Operation(summary = "모든 물품거래글 조회") @PreAuthorize("@securityService.isNotTemporaryUser()") @GetMapping - public ResponseEntity> getAllMarketPosts(@AuthenticationPrincipal UserDetails userDetails) { + public ResponseEntity> getAllMarketPosts() { List posts = marketPostService.getAllMarketPosts(); return ResponseEntity.ok(posts); } @@ -43,7 +44,7 @@ public ResponseEntity> getAllMarketPosts(@Authentica @Operation(summary = "특정 물품거래글 조회") @PreAuthorize("@securityService.isNotTemporaryUser()") @GetMapping("/{marketPostId}") - public ResponseEntity getMarketPostById(@PathVariable Long marketPostId, @AuthenticationPrincipal UserDetails userDetails) { + public ResponseEntity getMarketPostById(@PathVariable Long marketPostId) { MarketPostResponseDTO post = marketPostService.getMarketPostById(marketPostId); return ResponseEntity.ok(post); } @@ -53,33 +54,35 @@ public ResponseEntity getMarketPostById(@PathVariable Lon @PreAuthorize("@securityService.isNotTemporaryUser()") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity createMarketPost(@RequestPart("requestDTO") MarketPostRequestDTO requestDTO, - @RequestPart(value = "imageFiles", required = false) List imageFiles, @AuthenticationPrincipal UserDetails userDetails) { - // 현재 인증된 사용자의 ID를 DTO에 설정 - if (userDetails instanceof User) { - User user = (User) userDetails; - requestDTO.setUserId(user.getId()); - } - - MarketPostResponseDTO createdPost = marketPostService.createMarketPost(requestDTO, imageFiles); - return ResponseEntity.status(HttpStatus.CREATED).body(createdPost); + @RequestPart(value = "imageFiles", required = false) List imageFiles, + @AuthenticationPrincipal UserDetails userDetails) { + + User user = securityService.getUserByUserDetails(userDetails); + + MarketPostResponseDTO createdPost = marketPostService.createMarketPost(user, requestDTO, imageFiles); + return ResponseEntity.ok(createdPost); } // 4. 마이페이지에서 자기가 작성한 모든 물품글 조회 @Operation(summary = "자기가 작성한 모든 물품거래글 조회") @PreAuthorize("@securityService.isNotTemporaryUser()") - @GetMapping("/user/{userId}") - public ResponseEntity> getMarketPostsByUserId(@PathVariable Long userId, @AuthenticationPrincipal UserDetails userDetails) { - List posts = marketPostService.getMarketPostsByUserId(userId); + @GetMapping("/user") + public ResponseEntity> getMarketPostsByUser(@AuthenticationPrincipal UserDetails userDetails) { + User user = securityService.getUserByUserDetails(userDetails); + + List posts = marketPostService.getMarketPostsByUser(user); return ResponseEntity.ok(posts); } // 5. 마이페이지에서 자기가 작성한 특정 게시글 삭제 - @Operation(summary = "자기가 작성한 특정 동행구하기 게시글 삭제") + @Operation(summary = "자기가 작성한 물품거래 게시글 삭제") @PreAuthorize("@securityService.isNotTemporaryUser()") - @DeleteMapping("/user/{userId}/{marketPostId}") - public ResponseEntity deleteMarketPost(@PathVariable Long userId, @PathVariable Long marketPostId, @AuthenticationPrincipal UserDetails userDetails) { - marketPostService.deleteMarketPost(userId, marketPostId); - return ResponseEntity.noContent().build(); + @DeleteMapping("/user/{marketPostId}") + public ResponseEntity deleteMarketPost(@PathVariable Long marketPostId, @AuthenticationPrincipal UserDetails userDetails) { + User user = securityService.getUserByUserDetails(userDetails); + + marketPostService.deleteMarketPost(user, marketPostId); + return ResponseEntity.ok().build(); } // 6. 필터링된 물품글 조회 (국가와 거래 유형에 따라 필터링) @@ -89,8 +92,7 @@ public ResponseEntity deleteMarketPost(@PathVariable Long userId, @PathVar public ResponseEntity> getFilteredMarketPosts( @RequestParam(required = false) DealType dealType, @RequestParam(required = false) String currentCountry, - @RequestParam(required = false) DealStatus dealStatus, - @AuthenticationPrincipal UserDetails userDetails) { + @RequestParam(required = false) DealStatus dealStatus) { List filteredPosts = marketPostService.getFilteredMarketPosts(dealType, currentCountry, dealStatus); return ResponseEntity.ok(filteredPosts); @@ -100,7 +102,7 @@ public ResponseEntity> getFilteredMarketPosts( @Operation(summary = "거래 가능 물품만 보기") @PreAuthorize("@securityService.isNotTemporaryUser()") @GetMapping("/available") - public ResponseEntity> getAvailableMarketPosts(@AuthenticationPrincipal UserDetails userDetails) { + public ResponseEntity> getAvailableMarketPosts() { // DealStatus를 AWAIT으로 고정하여 필터링 List availablePosts = marketPostService.getAvailableMarketPosts(); @@ -111,7 +113,7 @@ public ResponseEntity> getAvailableMarketPosts(@Auth @Operation(summary = "거래 상태 업데이트") @PutMapping("/{marketPostId}/status") @PreAuthorize("@securityService.isNotTemporaryUser()") - public ResponseEntity updateMarketPostStatus(@PathVariable Long marketPostId, @AuthenticationPrincipal UserDetails userDetails) { + public ResponseEntity updateMarketPostStatus(@PathVariable Long marketPostId) { MarketPostResponseDTO updatedPost = marketPostService.updateMarketPostStatus(marketPostId, DealStatus.COMPLETE); return ResponseEntity.ok(updatedPost); diff --git a/src/main/java/com/on/server/domain/scrap/presentation/ScrapController.java b/src/main/java/com/on/server/domain/scrap/presentation/ScrapController.java index ab42e5a7..36080c60 100644 --- a/src/main/java/com/on/server/domain/scrap/presentation/ScrapController.java +++ b/src/main/java/com/on/server/domain/scrap/presentation/ScrapController.java @@ -3,12 +3,15 @@ import com.on.server.domain.scrap.application.ScrapService; import com.on.server.domain.scrap.dto.ScrapRequestDTO; import com.on.server.domain.scrap.dto.ScrapResponseDTO; +import com.on.server.domain.user.domain.User; +import com.on.server.global.security.SecurityService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -20,28 +23,41 @@ public class ScrapController { private final ScrapService scrapService; + private final SecurityService securityService; // 1. 특정 물품글 스크랩 @Operation(summary = "특정 물품거래글 스크랩") @PostMapping - public ResponseEntity scrapMarketPost(@RequestBody ScrapRequestDTO scrapRequestDTO) { - scrapService.scrapMarketPost(scrapRequestDTO); - return ResponseEntity.status(HttpStatus.CREATED).build(); + @PreAuthorize("@securityService.isNotTemporaryUser()") + public ResponseEntity scrapMarketPost(@RequestBody ScrapRequestDTO scrapRequestDTO, @AuthenticationPrincipal UserDetails userDetails) { + + User user = securityService.getUserByUserDetails(userDetails); + + scrapService.scrapMarketPost(user, scrapRequestDTO); + return ResponseEntity.ok().build(); } // 2. 스크랩한 모든 물품글 조회 @Operation(summary = "스크랩한 모든 물품거래글 조회") - @GetMapping("/{userId}") - public ResponseEntity> getScrappedMarketPosts(@PathVariable Long userId) { - List posts = scrapService.getScrappedMarketPosts(userId); + @GetMapping + @PreAuthorize("@securityService.isNotTemporaryUser()") + public ResponseEntity> getScrappedMarketPosts(@AuthenticationPrincipal UserDetails userDetails) { + + User user = securityService.getUserByUserDetails(userDetails); + + List posts = scrapService.getScrappedMarketPosts(user); return ResponseEntity.ok(posts); } // 3. 스크랩 목록에서 특정 물품글 스크랩 취소 (삭제) @Operation(summary = "스크랩 목록에서 특정 물품글 스크랩 취소") - @DeleteMapping("/{userId}/{marketPostId}") - public ResponseEntity deleteScrap(@PathVariable Long userId, @PathVariable Long marketPostId) { - scrapService.deleteMarketPost(userId, marketPostId); - return ResponseEntity.noContent().build(); + @DeleteMapping("/{marketPostId}") + @PreAuthorize("@securityService.isNotTemporaryUser()") + public ResponseEntity deleteScrap(@PathVariable Long marketPostId, @AuthenticationPrincipal UserDetails userDetails) { + + User user = securityService.getUserByUserDetails(userDetails); + + scrapService.deleteMarketPost(user, marketPostId); + return ResponseEntity.ok().build(); } } \ No newline at end of file From ab525be90440272e38872cba10fc146aa38152f7 Mon Sep 17 00:00:00 2001 From: chaechaen Date: Wed, 4 Sep 2024 13:05:40 +0900 Subject: [PATCH 3/7] =?UTF-8?q?refactor:=20setter=20=EC=96=B4=EB=85=B8?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=A0=9C=EC=99=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../on/server/domain/marketPost/domain/MarketPost.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/on/server/domain/marketPost/domain/MarketPost.java b/src/main/java/com/on/server/domain/marketPost/domain/MarketPost.java index 103c3000..8e009978 100644 --- a/src/main/java/com/on/server/domain/marketPost/domain/MarketPost.java +++ b/src/main/java/com/on/server/domain/marketPost/domain/MarketPost.java @@ -11,7 +11,6 @@ import java.util.List; @Getter -@Setter @Builder @AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PROTECTED) @@ -55,6 +54,13 @@ public class MarketPost extends BaseEntity { @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "market_post_id") private List images = new ArrayList<>(); // 이미지 리스트 필드 추가 + + public void completeDeal() { + if (this.dealStatus != DealStatus.AWAIT) { + throw new IllegalStateException("거래 상태가 AWAIT인 경우에만 COMPLETE로 업데이트할 수 있습니다."); + } + this.dealStatus = DealStatus.COMPLETE; + } } From 3568e07766ed5fff29aeb0a022fa41a72e7f2f82 Mon Sep 17 00:00:00 2001 From: chaechaen Date: Wed, 4 Sep 2024 13:05:49 +0900 Subject: [PATCH 4/7] =?UTF-8?q?refactor:=20request=20body=EC=97=90?= =?UTF-8?q?=EC=84=9C=20userId=20=EC=A0=9C=EC=99=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/on/server/domain/scrap/dto/ScrapRequestDTO.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/on/server/domain/scrap/dto/ScrapRequestDTO.java b/src/main/java/com/on/server/domain/scrap/dto/ScrapRequestDTO.java index 22a78e2a..d9d05516 100644 --- a/src/main/java/com/on/server/domain/scrap/dto/ScrapRequestDTO.java +++ b/src/main/java/com/on/server/domain/scrap/dto/ScrapRequestDTO.java @@ -8,7 +8,4 @@ public class ScrapRequestDTO { //마켓글 ID private Long marketPostId; - - //유저 ID - private Long userId; } From 91bd384a637877850e5f802ac3d9c55c615c0bf7 Mon Sep 17 00:00:00 2001 From: chaechaen Date: Fri, 6 Sep 2024 14:12:28 +0900 Subject: [PATCH 5/7] =?UTF-8?q?refactor:=20GlobalExceptionHandler=EB=A1=9C?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../marketPost/application/MarketPostService.java | 14 +++++++------- .../domain/scrap/application/ScrapService.java | 13 ++++++------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/on/server/domain/marketPost/application/MarketPostService.java b/src/main/java/com/on/server/domain/marketPost/application/MarketPostService.java index e115023d..e0c082e0 100644 --- a/src/main/java/com/on/server/domain/marketPost/application/MarketPostService.java +++ b/src/main/java/com/on/server/domain/marketPost/application/MarketPostService.java @@ -7,11 +7,12 @@ import com.on.server.domain.marketPost.dto.MarketPostRequestDTO; import com.on.server.domain.marketPost.dto.MarketPostResponseDTO; import com.on.server.domain.user.domain.User; -import com.on.server.domain.user.domain.repository.UserRepository; import com.on.server.global.aws.s3.uuidFile.application.UuidFileService; import com.on.server.global.aws.s3.uuidFile.domain.FilePath; import com.on.server.global.aws.s3.uuidFile.domain.UuidFile; -import com.on.server.global.aws.s3.uuidFile.domain.repository.UuidFileRepository; +import com.on.server.global.common.ResponseCode; +import com.on.server.global.common.exceptions.BadRequestException; +import com.on.server.global.common.exceptions.UnauthorizedException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -27,7 +28,6 @@ public class MarketPostService { private final MarketPostRepository marketPostRepository; - private final UserRepository userRepository; private final UuidFileService uuidFileService; // 1. 모든 물품글 조회 @@ -40,7 +40,7 @@ public List getAllMarketPosts() { // 2. 특정 물품글 조회 public MarketPostResponseDTO getMarketPostById(Long marketPostId) { MarketPost marketPost = marketPostRepository.findById(marketPostId) - .orElseThrow(() -> new RuntimeException("게시글을 찾을 수 없습니다. ID: " + marketPostId)); + .orElseThrow(() -> new BadRequestException(ResponseCode.ROW_DOES_NOT_EXIST, "게시글을 찾을 수 없습니다. ID: " + marketPostId)); return MarketPostResponseDTO.from(marketPost); } @@ -85,10 +85,10 @@ public List getMarketPostsByUser(User user) { @Transactional public void deleteMarketPost(User user, Long marketPostId) { MarketPost marketPost = marketPostRepository.findById(marketPostId) - .orElseThrow(() -> new RuntimeException("게시글을 찾을 수 없습니다. ID: " + marketPostId)); + .orElseThrow(() -> new BadRequestException(ResponseCode.ROW_DOES_NOT_EXIST, "게시글을 찾을 수 없습니다. ID: " + marketPostId)); if (!marketPost.getUser().getId().equals(user.getId())) { - throw new RuntimeException("삭제 권한이 없습니다."); + throw new UnauthorizedException(ResponseCode.GRANT_ROLE_NOT_ALLOWED, "삭제 권한이 없습니다."); } // 연관된 이미지 삭제 @@ -101,7 +101,7 @@ public void deleteMarketPost(User user, Long marketPostId) { @Transactional public MarketPostResponseDTO updateMarketPostStatus(Long marketPostId, DealStatus status) { MarketPost marketPost = marketPostRepository.findById(marketPostId) - .orElseThrow(() -> new RuntimeException("게시글을 찾을 수 없습니다. ID: " + marketPostId)); + .orElseThrow(() -> new BadRequestException(ResponseCode.ROW_DOES_NOT_EXIST, "게시글을 찾을 수 없습니다. ID: " + marketPostId)); marketPost.completeDeal(); // 상태 업데이트 diff --git a/src/main/java/com/on/server/domain/scrap/application/ScrapService.java b/src/main/java/com/on/server/domain/scrap/application/ScrapService.java index 73c8244a..6b8988bd 100644 --- a/src/main/java/com/on/server/domain/scrap/application/ScrapService.java +++ b/src/main/java/com/on/server/domain/scrap/application/ScrapService.java @@ -2,14 +2,13 @@ import com.on.server.domain.marketPost.domain.MarketPost; import com.on.server.domain.marketPost.domain.repository.MarketPostRepository; -import com.on.server.domain.marketPost.dto.MarketPostResponseDTO; import com.on.server.domain.scrap.domain.Scrap; import com.on.server.domain.scrap.domain.repository.ScrapRepository; import com.on.server.domain.scrap.dto.ScrapRequestDTO; import com.on.server.domain.scrap.dto.ScrapResponseDTO; import com.on.server.domain.user.domain.User; -import com.on.server.domain.user.domain.repository.UserRepository; -import com.on.server.global.aws.s3.uuidFile.domain.UuidFile; +import com.on.server.global.common.ResponseCode; +import com.on.server.global.common.exceptions.BadRequestException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -28,12 +27,12 @@ public class ScrapService { // 1. 특정 물품글 스크랩 public void scrapMarketPost(User user, ScrapRequestDTO scrapRequestDTO) { MarketPost marketPost = marketPostRepository.findById(scrapRequestDTO.getMarketPostId()) - .orElseThrow(() -> new RuntimeException("게시글을 찾을 수 없습니다. ID: " + scrapRequestDTO.getMarketPostId())); + .orElseThrow(() -> new BadRequestException(ResponseCode.ROW_DOES_NOT_EXIST, "게시글을 찾을 수 없습니다. ID: " + scrapRequestDTO.getMarketPostId())); // 중복 스크랩 방지하기 boolean alreadyScrapped = scrapRepository.findByUserAndMarketPost(user, marketPost).isPresent(); if (alreadyScrapped) { - throw new RuntimeException("이미 스크랩된 게시글입니다."); + throw new BadRequestException(ResponseCode.ROW_ALREADY_EXIST, "이미 스크랩된 게시글입니다."); } // 스크랩 로직 구현 @@ -56,10 +55,10 @@ public List getScrappedMarketPosts(User user) { // 3. 스크랩 목록에서 자기가 작성한 특정 물품글 스크랩 취소 (삭제) public void deleteMarketPost(User user, Long marketPostId) { MarketPost marketPost = marketPostRepository.findById(marketPostId) - .orElseThrow(() -> new RuntimeException("게시글을 찾을 수 없습니다. ID: " + marketPostId)); + .orElseThrow(() -> new BadRequestException(ResponseCode.ROW_DOES_NOT_EXIST, "게시글을 찾을 수 없습니다. ID: " + marketPostId)); Scrap scrap = scrapRepository.findByUserAndMarketPost(user, marketPost) - .orElseThrow(() -> new RuntimeException("스크랩을 찾을 수 없습니다.")); + .orElseThrow(() -> new BadRequestException(ResponseCode.ROW_DOES_NOT_EXIST, "스크랩을 찾을 수 없습니다.")); scrapRepository.delete(scrap); } From 510e68030d45f6b2ea532249257de816b2060be0 Mon Sep 17 00:00:00 2001 From: chaechaen Date: Fri, 6 Sep 2024 23:50:10 +0900 Subject: [PATCH 6/7] =?UTF-8?q?refactor:=20=EB=AC=BC=ED=92=88=EA=B1=B0?= =?UTF-8?q?=EB=9E=98=EA=B8=80=20=EB=B0=8F=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20?= =?UTF-8?q?paging=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/MarketPostService.java | 40 +++++++++---------- .../repository/MarketPostRepository.java | 15 +++---- .../presentation/MarketPostController.java | 34 +++++++++------- .../scrap/application/ScrapService.java | 12 +++--- .../domain/repository/ScrapRepository.java | 9 +++-- .../scrap/presentation/ScrapController.java | 15 ++++--- 6 files changed, 65 insertions(+), 60 deletions(-) diff --git a/src/main/java/com/on/server/domain/marketPost/application/MarketPostService.java b/src/main/java/com/on/server/domain/marketPost/application/MarketPostService.java index e0c082e0..2259f17b 100644 --- a/src/main/java/com/on/server/domain/marketPost/application/MarketPostService.java +++ b/src/main/java/com/on/server/domain/marketPost/application/MarketPostService.java @@ -14,6 +14,8 @@ import com.on.server.global.common.exceptions.BadRequestException; import com.on.server.global.common.exceptions.UnauthorizedException; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -31,10 +33,9 @@ public class MarketPostService { private final UuidFileService uuidFileService; // 1. 모든 물품글 조회 - public List getAllMarketPosts() { - return marketPostRepository.findAllByOrderByCreatedAtDesc().stream() - .map(MarketPostResponseDTO::from) - .collect(Collectors.toList()); + public Page getAllMarketPosts(Pageable pageable) { + return marketPostRepository.findAllByOrderByCreatedAtDesc(pageable) + .map(MarketPostResponseDTO::from); } // 2. 특정 물품글 조회 @@ -75,10 +76,9 @@ public MarketPostResponseDTO createMarketPost(User user, MarketPostRequestDTO re } // 4. 특정 사용자가 작성한 모든 물품글 조회 - public List getMarketPostsByUser(User user) { - return marketPostRepository.findByUserOrderByCreatedAtDesc(user).stream() - .map(MarketPostResponseDTO::from) - .collect(Collectors.toList()); + public Page getMarketPostsByUser(User user, Pageable pageable) { + return marketPostRepository.findByUserOrderByCreatedAtDesc(user, pageable) + .map(MarketPostResponseDTO::from); } // 5. 특정 게시글 삭제 @@ -99,7 +99,7 @@ public void deleteMarketPost(User user, Long marketPostId) { // 6. 거래 상태 업데이트 @Transactional - public MarketPostResponseDTO updateMarketPostStatus(Long marketPostId, DealStatus status) { + public MarketPostResponseDTO updateMarketPostStatus(Long marketPostId) { MarketPost marketPost = marketPostRepository.findById(marketPostId) .orElseThrow(() -> new BadRequestException(ResponseCode.ROW_DOES_NOT_EXIST, "게시글을 찾을 수 없습니다. ID: " + marketPostId)); @@ -111,25 +111,21 @@ public MarketPostResponseDTO updateMarketPostStatus(Long marketPostId, DealStatu } // 필터링: 거래형식, 국가, 거래상태 필터링 - public List getFilteredMarketPosts(DealType dealType, String currentCountry, DealStatus dealStatus) { - return marketPostRepository.findFilteredMarketPosts(dealType, currentCountry, dealStatus).stream() - .map(MarketPostResponseDTO::from) - .collect(Collectors.toList()); + public Page getFilteredMarketPosts(DealType dealType, String currentCountry, DealStatus dealStatus, Pageable pageable) { + return marketPostRepository.findFilteredMarketPosts(dealType, currentCountry, dealStatus, pageable) + .map(MarketPostResponseDTO::from); } // 필터링: 거래 가능 물품만 보기 - public List getAvailableMarketPosts() { - return marketPostRepository.findFilteredMarketPosts(null, null, DealStatus.AWAIT).stream() - .map(MarketPostResponseDTO::from) - .collect(Collectors.toList()); + public Page getAvailableMarketPosts(Pageable pageable) { + return marketPostRepository.findFilteredMarketPosts(null, null, DealStatus.AWAIT, pageable) + .map(MarketPostResponseDTO::from); } // 검색 기능 - public List searchMarketPosts(String keyword) { - List marketPosts = marketPostRepository.searchMarketPosts(keyword); - return marketPosts.stream() - .map(MarketPostResponseDTO::from) - .collect(Collectors.toList()); + public Page searchMarketPosts(String keyword, Pageable pageable) { + return marketPostRepository.searchMarketPosts(keyword, pageable) + .map(MarketPostResponseDTO::from); } // 내 주변 물품거래글 diff --git a/src/main/java/com/on/server/domain/marketPost/domain/repository/MarketPostRepository.java b/src/main/java/com/on/server/domain/marketPost/domain/repository/MarketPostRepository.java index 0e31a3cf..ee94e199 100644 --- a/src/main/java/com/on/server/domain/marketPost/domain/repository/MarketPostRepository.java +++ b/src/main/java/com/on/server/domain/marketPost/domain/repository/MarketPostRepository.java @@ -4,6 +4,8 @@ import com.on.server.domain.marketPost.domain.DealType; import com.on.server.domain.marketPost.domain.MarketPost; import com.on.server.domain.user.domain.User; +import org.springframework.data.domain.Page; +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; @@ -14,18 +16,17 @@ @Repository public interface MarketPostRepository extends JpaRepository { - List findByUser(User user); - // 필터링 @Query("SELECT mp FROM MarketPost mp WHERE (:dealType IS NULL OR mp.dealType = :dealType) " + "AND (:currentCountry IS NULL OR mp.currentCountry = :currentCountry) " + "AND (:dealStatus IS NULL OR mp.dealStatus = :dealStatus)"+ "ORDER BY mp.createdAt DESC") - List findFilteredMarketPosts( + Page findFilteredMarketPosts( @Param("dealType") DealType dealType, @Param("currentCountry") String currentCountry, - @Param("dealStatus") DealStatus dealStatus); + @Param("dealStatus") DealStatus dealStatus, + Pageable pageable); // 검색: 국가와 물품에 대한 제목 또는 내용을 검색하는 메서드 @Query("SELECT mp FROM MarketPost mp WHERE " + @@ -33,7 +34,7 @@ List findFilteredMarketPosts( "mp.title LIKE %:keyword% OR " + "mp.content LIKE %:keyword% " + "ORDER BY mp.createdAt DESC") - List searchMarketPosts(@Param("keyword") String keyword); + Page searchMarketPosts(@Param("keyword") String keyword, Pageable pageable); // 내 주변 물품거래글: 특정 국가에서 거래 상태가 AWAIT인 최신순 3개의 게시글 조회 @Query("SELECT mp FROM MarketPost mp WHERE mp.currentCountry = :currentCountry " + @@ -43,6 +44,6 @@ List findFilteredMarketPosts( List findTop3ByCurrentCountryAndAwaitingOrder(@Param("currentCountry") String currentCountry, @Param("marketPostId") Long marketPostId); // 최신순 정렬 - List findAllByOrderByCreatedAtDesc(); - List findByUserOrderByCreatedAtDesc(User user); + Page findAllByOrderByCreatedAtDesc(Pageable pageable); + Page findByUserOrderByCreatedAtDesc(User user, Pageable pageable); } \ No newline at end of file diff --git a/src/main/java/com/on/server/domain/marketPost/presentation/MarketPostController.java b/src/main/java/com/on/server/domain/marketPost/presentation/MarketPostController.java index 98f37b78..4195501e 100644 --- a/src/main/java/com/on/server/domain/marketPost/presentation/MarketPostController.java +++ b/src/main/java/com/on/server/domain/marketPost/presentation/MarketPostController.java @@ -5,13 +5,13 @@ import com.on.server.domain.marketPost.domain.DealType; import com.on.server.domain.marketPost.dto.MarketPostRequestDTO; import com.on.server.domain.marketPost.dto.MarketPostResponseDTO; -import com.on.server.domain.scrap.application.ScrapService; import com.on.server.domain.user.domain.User; import com.on.server.global.security.SecurityService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; @@ -35,8 +35,8 @@ public class MarketPostController { @Operation(summary = "모든 물품거래글 조회") @PreAuthorize("@securityService.isNotTemporaryUser()") @GetMapping - public ResponseEntity> getAllMarketPosts() { - List posts = marketPostService.getAllMarketPosts(); + public ResponseEntity> getAllMarketPosts(Pageable pageable) { + Page posts = marketPostService.getAllMarketPosts(pageable); return ResponseEntity.ok(posts); } @@ -67,10 +67,11 @@ public ResponseEntity createMarketPost(@RequestPart("requ @Operation(summary = "자기가 작성한 모든 물품거래글 조회") @PreAuthorize("@securityService.isNotTemporaryUser()") @GetMapping("/user") - public ResponseEntity> getMarketPostsByUser(@AuthenticationPrincipal UserDetails userDetails) { + public ResponseEntity> getMarketPostsByUser(@AuthenticationPrincipal UserDetails userDetails, + Pageable pageable) { User user = securityService.getUserByUserDetails(userDetails); - List posts = marketPostService.getMarketPostsByUser(user); + Page posts = marketPostService.getMarketPostsByUser(user, pageable); return ResponseEntity.ok(posts); } @@ -78,7 +79,8 @@ public ResponseEntity> getMarketPostsByUser(@Authent @Operation(summary = "자기가 작성한 물품거래 게시글 삭제") @PreAuthorize("@securityService.isNotTemporaryUser()") @DeleteMapping("/user/{marketPostId}") - public ResponseEntity deleteMarketPost(@PathVariable Long marketPostId, @AuthenticationPrincipal UserDetails userDetails) { + public ResponseEntity deleteMarketPost(@PathVariable Long marketPostId, + @AuthenticationPrincipal UserDetails userDetails) { User user = securityService.getUserByUserDetails(userDetails); marketPostService.deleteMarketPost(user, marketPostId); @@ -89,12 +91,13 @@ public ResponseEntity deleteMarketPost(@PathVariable Long marketPostId, @A @Operation(summary = "필터링된 물품거래글 조회") @PreAuthorize("@securityService.isNotTemporaryUser()") @GetMapping("/filter") - public ResponseEntity> getFilteredMarketPosts( + public ResponseEntity> getFilteredMarketPosts( @RequestParam(required = false) DealType dealType, @RequestParam(required = false) String currentCountry, - @RequestParam(required = false) DealStatus dealStatus) { + @RequestParam(required = false) DealStatus dealStatus, + Pageable pageable) { - List filteredPosts = marketPostService.getFilteredMarketPosts(dealType, currentCountry, dealStatus); + Page filteredPosts = marketPostService.getFilteredMarketPosts(dealType, currentCountry, dealStatus, pageable); return ResponseEntity.ok(filteredPosts); } @@ -102,10 +105,10 @@ public ResponseEntity> getFilteredMarketPosts( @Operation(summary = "거래 가능 물품만 보기") @PreAuthorize("@securityService.isNotTemporaryUser()") @GetMapping("/available") - public ResponseEntity> getAvailableMarketPosts() { + public ResponseEntity> getAvailableMarketPosts(Pageable pageable) { // DealStatus를 AWAIT으로 고정하여 필터링 - List availablePosts = marketPostService.getAvailableMarketPosts(); + Page availablePosts = marketPostService.getAvailableMarketPosts(pageable); return ResponseEntity.ok(availablePosts); } @@ -115,7 +118,7 @@ public ResponseEntity> getAvailableMarketPosts() { @PreAuthorize("@securityService.isNotTemporaryUser()") public ResponseEntity updateMarketPostStatus(@PathVariable Long marketPostId) { - MarketPostResponseDTO updatedPost = marketPostService.updateMarketPostStatus(marketPostId, DealStatus.COMPLETE); + MarketPostResponseDTO updatedPost = marketPostService.updateMarketPostStatus(marketPostId); return ResponseEntity.ok(updatedPost); } @@ -123,8 +126,9 @@ public ResponseEntity updateMarketPostStatus(@PathVariabl @Operation(summary = "검색") @PreAuthorize("@securityService.isNotTemporaryUser()") @GetMapping("/search") - public ResponseEntity> searchMarketPosts(@RequestParam String keyword, @AuthenticationPrincipal UserDetails userDetails) { - List searchResults = marketPostService.searchMarketPosts(keyword); + public ResponseEntity> searchMarketPosts(@RequestParam String keyword, + Pageable pageable) { + Page searchResults = marketPostService.searchMarketPosts(keyword, pageable); return ResponseEntity.ok(searchResults); } diff --git a/src/main/java/com/on/server/domain/scrap/application/ScrapService.java b/src/main/java/com/on/server/domain/scrap/application/ScrapService.java index 6b8988bd..df8b2f45 100644 --- a/src/main/java/com/on/server/domain/scrap/application/ScrapService.java +++ b/src/main/java/com/on/server/domain/scrap/application/ScrapService.java @@ -10,12 +10,11 @@ import com.on.server.global.common.ResponseCode; import com.on.server.global.common.exceptions.BadRequestException; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.stream.Collectors; - @RequiredArgsConstructor @Service @Transactional @@ -46,10 +45,9 @@ public void scrapMarketPost(User user, ScrapRequestDTO scrapRequestDTO) { // 2. 스크랩한 모든 물품글 조회 @Transactional(readOnly = true) - public List getScrappedMarketPosts(User user) { - return scrapRepository.findByUser(user).stream() - .map(ScrapResponseDTO::from) // Scrap 객체를 ScrapResponseDTO로 매핑 - .collect(Collectors.toList()); + public Page getScrappedMarketPosts(User user, Pageable pageable) { + return scrapRepository.findByUser(user, pageable) + .map(ScrapResponseDTO::from); } // 3. 스크랩 목록에서 자기가 작성한 특정 물품글 스크랩 취소 (삭제) diff --git a/src/main/java/com/on/server/domain/scrap/domain/repository/ScrapRepository.java b/src/main/java/com/on/server/domain/scrap/domain/repository/ScrapRepository.java index c578de2a..26ea3ed9 100644 --- a/src/main/java/com/on/server/domain/scrap/domain/repository/ScrapRepository.java +++ b/src/main/java/com/on/server/domain/scrap/domain/repository/ScrapRepository.java @@ -3,16 +3,19 @@ import com.on.server.domain.marketPost.domain.MarketPost; import com.on.server.domain.scrap.domain.Scrap; import com.on.server.domain.user.domain.User; +import org.springframework.data.domain.Page; +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.util.List; import java.util.Optional; @Repository public interface ScrapRepository extends JpaRepository { - List findByUser(User user); + @Query("SELECT s FROM Scrap s WHERE s.user = :user ORDER BY s.createdAt DESC") + Page findByUser(@Param("user") User user, Pageable pageable); Optional findByUserAndMarketPost(User user, MarketPost marketPost); } \ No newline at end of file diff --git a/src/main/java/com/on/server/domain/scrap/presentation/ScrapController.java b/src/main/java/com/on/server/domain/scrap/presentation/ScrapController.java index 36080c60..e917f393 100644 --- a/src/main/java/com/on/server/domain/scrap/presentation/ScrapController.java +++ b/src/main/java/com/on/server/domain/scrap/presentation/ScrapController.java @@ -8,14 +8,14 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.*; -import java.util.List; - @Tag(name = "물품거래글 스크랩") @RequiredArgsConstructor @RestController @@ -29,7 +29,8 @@ public class ScrapController { @Operation(summary = "특정 물품거래글 스크랩") @PostMapping @PreAuthorize("@securityService.isNotTemporaryUser()") - public ResponseEntity scrapMarketPost(@RequestBody ScrapRequestDTO scrapRequestDTO, @AuthenticationPrincipal UserDetails userDetails) { + public ResponseEntity scrapMarketPost(@RequestBody ScrapRequestDTO scrapRequestDTO, + @AuthenticationPrincipal UserDetails userDetails) { User user = securityService.getUserByUserDetails(userDetails); @@ -41,11 +42,12 @@ public ResponseEntity scrapMarketPost(@RequestBody ScrapRequestDTO scrapRe @Operation(summary = "스크랩한 모든 물품거래글 조회") @GetMapping @PreAuthorize("@securityService.isNotTemporaryUser()") - public ResponseEntity> getScrappedMarketPosts(@AuthenticationPrincipal UserDetails userDetails) { + public ResponseEntity> getScrappedMarketPosts(@AuthenticationPrincipal UserDetails userDetails, + Pageable pageable) { User user = securityService.getUserByUserDetails(userDetails); - List posts = scrapService.getScrappedMarketPosts(user); + Page posts = scrapService.getScrappedMarketPosts(user, pageable); return ResponseEntity.ok(posts); } @@ -53,7 +55,8 @@ public ResponseEntity> getScrappedMarketPosts(@Authentica @Operation(summary = "스크랩 목록에서 특정 물품글 스크랩 취소") @DeleteMapping("/{marketPostId}") @PreAuthorize("@securityService.isNotTemporaryUser()") - public ResponseEntity deleteScrap(@PathVariable Long marketPostId, @AuthenticationPrincipal UserDetails userDetails) { + public ResponseEntity deleteScrap(@PathVariable Long marketPostId, + @AuthenticationPrincipal UserDetails userDetails) { User user = securityService.getUserByUserDetails(userDetails); From 3904ef658ad5dc83d4b3f3de9d6b52acb606190f Mon Sep 17 00:00:00 2001 From: chaechaen Date: Wed, 18 Sep 2024 00:30:14 +0900 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20Pageable=20=ED=8C=8C=EB=9D=BC?= =?UTF-8?q?=EB=AF=B8=ED=84=B0=EC=97=90=20@ParameterObject=20=EC=96=B4?= =?UTF-8?q?=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../marketPost/presentation/MarketPostController.java | 11 ++++++----- .../domain/scrap/presentation/ScrapController.java | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/on/server/domain/marketPost/presentation/MarketPostController.java b/src/main/java/com/on/server/domain/marketPost/presentation/MarketPostController.java index 4195501e..c87dc142 100644 --- a/src/main/java/com/on/server/domain/marketPost/presentation/MarketPostController.java +++ b/src/main/java/com/on/server/domain/marketPost/presentation/MarketPostController.java @@ -10,6 +10,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.MediaType; @@ -35,7 +36,7 @@ public class MarketPostController { @Operation(summary = "모든 물품거래글 조회") @PreAuthorize("@securityService.isNotTemporaryUser()") @GetMapping - public ResponseEntity> getAllMarketPosts(Pageable pageable) { + public ResponseEntity> getAllMarketPosts(@ParameterObject Pageable pageable) { Page posts = marketPostService.getAllMarketPosts(pageable); return ResponseEntity.ok(posts); } @@ -68,7 +69,7 @@ public ResponseEntity createMarketPost(@RequestPart("requ @PreAuthorize("@securityService.isNotTemporaryUser()") @GetMapping("/user") public ResponseEntity> getMarketPostsByUser(@AuthenticationPrincipal UserDetails userDetails, - Pageable pageable) { + @ParameterObject Pageable pageable) { User user = securityService.getUserByUserDetails(userDetails); Page posts = marketPostService.getMarketPostsByUser(user, pageable); @@ -95,7 +96,7 @@ public ResponseEntity> getFilteredMarketPosts( @RequestParam(required = false) DealType dealType, @RequestParam(required = false) String currentCountry, @RequestParam(required = false) DealStatus dealStatus, - Pageable pageable) { + @ParameterObject Pageable pageable) { Page filteredPosts = marketPostService.getFilteredMarketPosts(dealType, currentCountry, dealStatus, pageable); return ResponseEntity.ok(filteredPosts); @@ -105,7 +106,7 @@ public ResponseEntity> getFilteredMarketPosts( @Operation(summary = "거래 가능 물품만 보기") @PreAuthorize("@securityService.isNotTemporaryUser()") @GetMapping("/available") - public ResponseEntity> getAvailableMarketPosts(Pageable pageable) { + public ResponseEntity> getAvailableMarketPosts(@ParameterObject Pageable pageable) { // DealStatus를 AWAIT으로 고정하여 필터링 Page availablePosts = marketPostService.getAvailableMarketPosts(pageable); @@ -127,7 +128,7 @@ public ResponseEntity updateMarketPostStatus(@PathVariabl @PreAuthorize("@securityService.isNotTemporaryUser()") @GetMapping("/search") public ResponseEntity> searchMarketPosts(@RequestParam String keyword, - Pageable pageable) { + @ParameterObject Pageable pageable) { Page searchResults = marketPostService.searchMarketPosts(keyword, pageable); return ResponseEntity.ok(searchResults); } diff --git a/src/main/java/com/on/server/domain/scrap/presentation/ScrapController.java b/src/main/java/com/on/server/domain/scrap/presentation/ScrapController.java index e917f393..b597ded0 100644 --- a/src/main/java/com/on/server/domain/scrap/presentation/ScrapController.java +++ b/src/main/java/com/on/server/domain/scrap/presentation/ScrapController.java @@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; @@ -43,7 +44,7 @@ public ResponseEntity scrapMarketPost(@RequestBody ScrapRequestDTO scrapRe @GetMapping @PreAuthorize("@securityService.isNotTemporaryUser()") public ResponseEntity> getScrappedMarketPosts(@AuthenticationPrincipal UserDetails userDetails, - Pageable pageable) { + @ParameterObject Pageable pageable) { User user = securityService.getUserByUserDetails(userDetails);