From 5d36ffc391a9c8a2eca5ed9b736405cdcce4ce57 Mon Sep 17 00:00:00 2001 From: junho <2171168@hansung.ac.kr> Date: Sat, 26 Jul 2025 01:21:30 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=9C=ED=95=84?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C(=ED=94=BC=EB=93=9C=20=EC=A0=9C=EC=99=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../card/repository/CardRepository.java | 1 + .../user/controller/UserRestController.java | 19 ++++++- .../domain/user/converter/UserConverter.java | 57 ++++++++++++------- .../user/dto/response/UserResponseDTO.java | 32 ++++++++++- .../user/repository/UserFollowRepository.java | 3 + .../domain/user/service/UserService.java | 19 ++++++- 6 files changed, 107 insertions(+), 24 deletions(-) diff --git a/src/main/java/EatPic/spring/domain/card/repository/CardRepository.java b/src/main/java/EatPic/spring/domain/card/repository/CardRepository.java index b6c7b55..ae44d70 100644 --- a/src/main/java/EatPic/spring/domain/card/repository/CardRepository.java +++ b/src/main/java/EatPic/spring/domain/card/repository/CardRepository.java @@ -24,4 +24,5 @@ public interface CardRepository extends JpaRepository { Slice findByCursor(@Param("cursor") Long cursor, Pageable pageable); boolean existsByUserIdAndMealAndCreatedAtBetween(Long userId, Meal meal, LocalDateTime start, LocalDateTime end); + Long countCardById(Long id); } diff --git a/src/main/java/EatPic/spring/domain/user/controller/UserRestController.java b/src/main/java/EatPic/spring/domain/user/controller/UserRestController.java index aa0b8ea..43baee3 100644 --- a/src/main/java/EatPic/spring/domain/user/controller/UserRestController.java +++ b/src/main/java/EatPic/spring/domain/user/controller/UserRestController.java @@ -19,7 +19,7 @@ public class UserRestController { description = "페이지는 1부터 시작하며 total은 전체 항목 수 입니다.") @GetMapping("/users") @Tag(name = "User", description = "사용자 관련 API") - public ApiResponse followingUsers( + public ApiResponse followingUsersIcon( @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "15") int size) { //todo : userId -> 본인 @@ -30,7 +30,7 @@ public ApiResponse followingUsers( summary = "커뮤니티 상단 팔로잉 유저 아이콘(나)") @GetMapping("/me") @Tag(name = "User", description = "사용자 관련 API") - public ApiResponse myIcon() { + public ApiResponse myIcon() { return ApiResponse.onSuccess(userService.getMyIcon()); } @@ -41,4 +41,19 @@ public ApiResponse blockUser(@PathVariable return ApiResponse.onSuccess(userService.blockUser(userId)); } + @Operation(summary = "유저 프로필 조회") + @PostMapping("/{userId}/profile") + @Tag(name = "User", description = "사용자 관련 API") + public ApiResponse getProfile(@PathVariable Long userId) { + return ApiResponse.onSuccess(userService.getProfile(userId)); + } + +// @Operation(summary = "유저 프로필 조회(이미지)") +// @PostMapping("/{userId}/profile/cards") +// @Tag(name = "User", description = "사용자 관련 API") +// public ApiResponse getProfile(@PathVariable Long userId) { +// return ApiResponse.onSuccess(userService.getProfile(userId)); +// } + + } diff --git a/src/main/java/EatPic/spring/domain/user/converter/UserConverter.java b/src/main/java/EatPic/spring/domain/user/converter/UserConverter.java index 29f4441..68402e0 100644 --- a/src/main/java/EatPic/spring/domain/user/converter/UserConverter.java +++ b/src/main/java/EatPic/spring/domain/user/converter/UserConverter.java @@ -11,29 +11,16 @@ import org.springframework.data.domain.Page; public class UserConverter { - - public static UserResponseDTO.UserIconListResponseDto toUserIconListResponseDto(Page followingPage){ - return UserResponseDTO.UserIconListResponseDto.builder() - .total((int)followingPage.getTotalElements()) - .page(followingPage.getNumber()+1) - .size(followingPage.getSize()) - .userIconList(followingPage.stream() - .map(UserFollow::getTargetUser) - .map(UserConverter::toProfileIconDto) - .toList()) - .build(); - } - - public static UserResponseDTO.ProfileDto toProfileIconDto(User user){ - return UserResponseDTO.ProfileDto.builder() + public static UserResponseDTO.ProfileIconDto toProfileIconDto(User user) { + return UserResponseDTO.ProfileIconDto.builder() .userId(user.getId()) .profileImageUrl(user.getProfileImageUrl()) .nameId(user.getNameId()) - .isFollowing(true) + .nickname(user.getNickname()) .build(); } - // todo: 두개 비슷함 -> 합치기 - public static UserResponseDTO.ProfileDto toProfileDto(User user, Boolean isFollowing){ + + public static UserResponseDTO.ProfileDto toProfileDto(User user, Boolean isFollowing) { return UserResponseDTO.ProfileDto.builder() .userId(user.getId()) .profileImageUrl(user.getProfileImageUrl()) @@ -42,6 +29,38 @@ public static UserResponseDTO.ProfileDto toProfileDto(User user, Boolean isFollo .isFollowing(isFollowing) .build(); } + + public static UserResponseDTO.DetailProfileDto toDetailProfileDto( + User user, + Boolean isFollowing, + Long totalCard, + Long totalFollower, + Long totalFollowing) { + + return UserResponseDTO.DetailProfileDto.builder() + .userId(user.getId()) + .profileImageUrl(user.getProfileImageUrl()) + .nameId(user.getNameId()) + .nickname(user.getNickname()) + .isFollowing(isFollowing) + .introduce(user.getIntroduce()) + .totalCard(totalCard) + .totalFollower(totalFollower) + .totalFollowing(totalFollowing) + .build(); +} + + public static UserResponseDTO.UserIconListResponseDto toUserIconListResponseDto(Page followingPage){ + return UserResponseDTO.UserIconListResponseDto.builder() + .total((int)followingPage.getTotalElements()) + .page(followingPage.getNumber()+1) + .size(followingPage.getSize()) + .userIconList(followingPage.stream() + .map(UserFollow::getTargetUser) + .map(UserConverter::toProfileIconDto) + .toList()) + .build(); + } public static ReactionResponseDTO.CardReactionUserListDto toCardReactionUsersListDto(Long cardId, ReactionType reactionType, Page profileList){ return ReactionResponseDTO.CardReactionUserListDto.builder() @@ -70,4 +89,4 @@ public static UserResponseDTO.UserBlockResponseDto toUserBlockResponseDto(UserBl .targetUserId(userBlock.getBlockedUser().getId()) .build(); } -} +} \ No newline at end of file diff --git a/src/main/java/EatPic/spring/domain/user/dto/response/UserResponseDTO.java b/src/main/java/EatPic/spring/domain/user/dto/response/UserResponseDTO.java index 0fb8103..2affc2e 100644 --- a/src/main/java/EatPic/spring/domain/user/dto/response/UserResponseDTO.java +++ b/src/main/java/EatPic/spring/domain/user/dto/response/UserResponseDTO.java @@ -9,6 +9,19 @@ public class UserResponseDTO { + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class ProfileIconDto { + private Long userId; + private String profileImageUrl; + private String nameId; + private String nickname; + private Boolean isFollowing; + private String introduce; + } + @Getter @Builder @AllArgsConstructor @@ -21,6 +34,23 @@ public static class ProfileDto { private Boolean isFollowing; } + @Getter + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class DetailProfileDto { + private Long userId; + private String profileImageUrl; + private String nameId; + private String nickname; + private Boolean isFollowing; + private String introduce; + private Long totalCard; + private Long totalFollower; + private Long totalFollowing; + } + + @Getter @Builder @AllArgsConstructor @@ -29,7 +59,7 @@ public static class UserIconListResponseDto{ private int page; private int size; private int total; - private List userIconList; + private List userIconList; } @Getter diff --git a/src/main/java/EatPic/spring/domain/user/repository/UserFollowRepository.java b/src/main/java/EatPic/spring/domain/user/repository/UserFollowRepository.java index 6dc4d35..21f6502 100644 --- a/src/main/java/EatPic/spring/domain/user/repository/UserFollowRepository.java +++ b/src/main/java/EatPic/spring/domain/user/repository/UserFollowRepository.java @@ -12,4 +12,7 @@ public interface UserFollowRepository extends JpaRepository { Page findByUser(User user, Pageable pageable); Boolean existsByUserAndTargetUser(User user, User targetUser); + + Long countUserFollowByTargetUser(User targetUser); + Long countUserFollowByUser(User user); } diff --git a/src/main/java/EatPic/spring/domain/user/service/UserService.java b/src/main/java/EatPic/spring/domain/user/service/UserService.java index 4ad8d2b..e6a4e92 100644 --- a/src/main/java/EatPic/spring/domain/user/service/UserService.java +++ b/src/main/java/EatPic/spring/domain/user/service/UserService.java @@ -1,5 +1,6 @@ package EatPic.spring.domain.user.service; +import EatPic.spring.domain.card.repository.CardRepository; import EatPic.spring.domain.user.converter.UserConverter; import EatPic.spring.domain.user.dto.response.UserResponseDTO; import EatPic.spring.domain.user.entity.User; @@ -30,6 +31,7 @@ public class UserService { private final UserFollowRepository userFollowRepository; private final PasswordEncoder passwordEncoder; + private final CardRepository cardRepository; public User signup(SignupRequestDTO request) { // 이메일 중복 검사 @@ -85,9 +87,22 @@ public UserResponseDTO.UserIconListResponseDto followingUserIconList(Long userId } @Transactional - public UserResponseDTO.ProfileDto getMyIcon() { + public UserResponseDTO.ProfileIconDto getMyIcon() { User me = userRepository.findUserById(1L); - return UserConverter.toProfileDto(me,true); + return UserConverter.toProfileIconDto(me); + } + + public UserResponseDTO.DetailProfileDto getProfile(Long userId) { + // todo: 로그인 사용자 + User me = userRepository.findUserById(1L); + + User user = userRepository.findUserById(userId); + Boolean isFollowing = userFollowRepository.existsByUserAndTargetUser(me, user); + Long totalCard = cardRepository.countCardById(userId); + Long totalFollower = userFollowRepository.countUserFollowByTargetUser(me); + Long totalFollowing = userFollowRepository.countUserFollowByUser(user); + + return UserConverter.toDetailProfileDto(user, isFollowing,totalCard,totalFollower,totalFollowing); } } \ No newline at end of file From d149c889b976630635df916f64a8fb42b2119fff Mon Sep 17 00:00:00 2001 From: junho <2171168@hansung.ac.kr> Date: Mon, 28 Jul 2025 23:52:42 +0900 Subject: [PATCH 2/2] =?UTF-8?q?Feat:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../card/controller/CardController.java | 16 ++++++++------ .../domain/card/converter/CardConverter.java | 21 +++++++++++++++++++ .../card/dto/response/CardResponse.java | 21 +++++++++++++++++++ .../card/repository/CardRepository.java | 6 +++++- .../domain/card/service/CardService.java | 1 + .../domain/card/service/CardServiceImpl.java | 20 +++++++++++++++++- 6 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/main/java/EatPic/spring/domain/card/controller/CardController.java b/src/main/java/EatPic/spring/domain/card/controller/CardController.java index be638b4..79fe8f3 100644 --- a/src/main/java/EatPic/spring/domain/card/controller/CardController.java +++ b/src/main/java/EatPic/spring/domain/card/controller/CardController.java @@ -1,6 +1,7 @@ package EatPic.spring.domain.card.controller; import EatPic.spring.domain.card.dto.request.CardCreateRequest; +import EatPic.spring.domain.card.dto.response.CardResponse; import EatPic.spring.domain.card.dto.response.CardResponse.CardDetailResponse; import EatPic.spring.domain.card.dto.response.CardResponse.CardFeedResponse; import EatPic.spring.domain.card.dto.response.CardResponse.CreateCardResponse; @@ -16,12 +17,7 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -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 org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor @@ -74,4 +70,12 @@ public ApiResponse getCardFeed(@PathVariable Long cardId) { return ApiResponse.onSuccess(cardService.getCardFeed(cardId, userId)); } + @GetMapping("/profile/{userId}/cards") + @Operation(summary = "프로필 화면 피드 미리보기", description = "공유한 카드의 번호와 이미지 url 조회 API") + public ApiResponse getProfileCardsList(@PathVariable Long userId, + @RequestParam(required = false) Long cursor, + @RequestParam(defaultValue = "15") int size) { + return ApiResponse.onSuccess(cardService.getProfileCardList(userId,size,cursor)); + } + } diff --git a/src/main/java/EatPic/spring/domain/card/converter/CardConverter.java b/src/main/java/EatPic/spring/domain/card/converter/CardConverter.java index e07ebdb..f3087c7 100644 --- a/src/main/java/EatPic/spring/domain/card/converter/CardConverter.java +++ b/src/main/java/EatPic/spring/domain/card/converter/CardConverter.java @@ -11,6 +11,9 @@ import EatPic.spring.domain.card.mapping.CardHashtag; import EatPic.spring.domain.reaction.entity.Reaction; import EatPic.spring.domain.user.entity.User; +import org.springframework.context.annotation.Profile; +import org.springframework.data.domain.Slice; + import java.util.List; import java.util.stream.Collectors; @@ -107,4 +110,22 @@ public static CardResponse.CardFeedResponse toFeedResponse( .isBookmarked(isBookmarked) .build(); } + + public static CardResponse.ProfileCardDTO toProfileCardDto(Card card){ + return CardResponse.ProfileCardDTO.builder() + .cardId(card.getId()) + .cardImageUrl(card.getCardImageUrl()) + .build(); + } + + public static CardResponse.profileCardListDTO toProfileCardList(Long userId, Slice cardList){ + return CardResponse.profileCardListDTO.builder() + .hasNext(cardList.hasNext()) + .nextCursor(cardList.hasNext()?cardList.getContent().get(cardList.getContent().size()-1).getId():null) + .userId(userId) + .cardsList(cardList.getContent().stream() + .map(CardConverter::toProfileCardDto) + .toList()) + .build(); + } } diff --git a/src/main/java/EatPic/spring/domain/card/dto/response/CardResponse.java b/src/main/java/EatPic/spring/domain/card/dto/response/CardResponse.java index 9109af9..8ce0989 100644 --- a/src/main/java/EatPic/spring/domain/card/dto/response/CardResponse.java +++ b/src/main/java/EatPic/spring/domain/card/dto/response/CardResponse.java @@ -181,6 +181,27 @@ public static class CardFeedUserDTO { private String profileImageUrl; } + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class profileCardListDTO{ + private Long userId; + private boolean hasNext; + private Long nextCursor; + private List cardsList; + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class ProfileCardDTO { + private Long cardId; + private String cardImageUrl; + } + + diff --git a/src/main/java/EatPic/spring/domain/card/repository/CardRepository.java b/src/main/java/EatPic/spring/domain/card/repository/CardRepository.java index ae44d70..2f4bceb 100644 --- a/src/main/java/EatPic/spring/domain/card/repository/CardRepository.java +++ b/src/main/java/EatPic/spring/domain/card/repository/CardRepository.java @@ -22,7 +22,11 @@ public interface CardRepository extends JpaRepository { ORDER BY c.id ASC """) Slice findByCursor(@Param("cursor") Long cursor, Pageable pageable); + boolean existsByUserIdAndMealAndCreatedAtBetween(Long userId, Meal meal, LocalDateTime start, LocalDateTime end); Long countCardById(Long id); -} + + Slice findByUserIdAndIsSharedTrueOrderByIdDesc(Long userId, Pageable pageable); + Slice findByUserIdAndIsSharedTrueAndIdLessThanOrderByIdDesc(Long userId, Long cursor, Pageable pageable); +} \ No newline at end of file diff --git a/src/main/java/EatPic/spring/domain/card/service/CardService.java b/src/main/java/EatPic/spring/domain/card/service/CardService.java index c9f435b..2e9427c 100644 --- a/src/main/java/EatPic/spring/domain/card/service/CardService.java +++ b/src/main/java/EatPic/spring/domain/card/service/CardService.java @@ -9,4 +9,5 @@ public interface CardService { CardResponse.CreateCardResponse createNewCard(CardCreateRequest.CreateCardRequest request, Long userId); CardDetailResponse getCardDetail(Long cardId, Long userId); CardFeedResponse getCardFeed(Long cardId, Long userId); + CardResponse.profileCardListDTO getProfileCardList(Long userId, int size, Long cursor); } diff --git a/src/main/java/EatPic/spring/domain/card/service/CardServiceImpl.java b/src/main/java/EatPic/spring/domain/card/service/CardServiceImpl.java index 1257657..7d81a1a 100644 --- a/src/main/java/EatPic/spring/domain/card/service/CardServiceImpl.java +++ b/src/main/java/EatPic/spring/domain/card/service/CardServiceImpl.java @@ -22,9 +22,12 @@ import java.time.LocalTime; import java.util.Comparator; import java.util.List; -import java.util.stream.Collectors; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -142,4 +145,19 @@ public CardFeedResponse getCardFeed(Long cardId, Long userId) { card, hashtags, writer, reaction, reactionCount, commentCount, isBookmarked ); } + + @Override + @Transactional(readOnly = true) + public CardResponse.profileCardListDTO getProfileCardList(Long userId, int size, Long cursor) { + + Slice cardSlice; + Pageable pageable = PageRequest.of(0, size); + + if (cursor == null) { + cardSlice = cardRepository.findByUserIdAndIsSharedTrueOrderByIdDesc(userId, pageable); + } else { + cardSlice = cardRepository.findByUserIdAndIsSharedTrueAndIdLessThanOrderByIdDesc(userId, cursor, pageable); + } + return CardConverter.toProfileCardList(userId, cardSlice); + } }