Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
import com.campick.server.api.chat.entity.ChatRoom;
import com.campick.server.api.chat.service.ChatService;
import com.campick.server.common.config.security.SecurityMember;
import com.campick.server.common.dto.PageResponseDto;
import com.campick.server.common.response.ApiResponse;
import com.campick.server.common.response.SuccessStatus;
import lombok.RequiredArgsConstructor;
import org.checkerframework.checker.units.qual.A;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
Expand All @@ -32,8 +35,11 @@ public ResponseEntity<ApiResponse<Long>> startChat(@RequestBody ChatRoomReqDto c
}

@GetMapping("/{chatRoomId}")
public ResponseEntity<ApiResponse<ChatRoomResDto>> getChatRoom(@PathVariable Long chatRoomId) {
return ApiResponse.success(SuccessStatus.SEND_LOAD_CHATROOM, chatService.getChatRoom(chatRoomId));
public ResponseEntity<ApiResponse<ChatRoomPageResDto<ChatMessage>>> getChatRoom(@PathVariable Long chatRoomId,
@RequestParam(defaultValue = "0") Integer page,
@RequestParam(defaultValue = "20") Integer size) {
Pageable pageable = PageRequest.of(page, size);
return ApiResponse.success(SuccessStatus.SEND_LOAD_CHATROOM, chatService.getChatRoom(chatRoomId, pageable));
}

@PatchMapping("/{chatRoomId}")
Expand All @@ -45,10 +51,13 @@ public ResponseEntity<ApiResponse<Void>> readChatRoom(@PathVariable Long chatRoo
}

@GetMapping("/my")
public ResponseEntity<ApiResponse<MyChatResDto>> getMyChatRoom(@AuthenticationPrincipal SecurityMember securityMember) {
public ResponseEntity<ApiResponse<MyChatPageResDto<ChatListDto>>> getMyChatRoom(@RequestParam(defaultValue = "0") Integer page,
@RequestParam(defaultValue = "10") Integer size,
@AuthenticationPrincipal SecurityMember securityMember) {
Pageable pageable = PageRequest.of(page, size);
Long memberId = securityMember.getId();

return ApiResponse.success(SuccessStatus.SEND_MY_CHATROOMS, chatService.getMyChatRooms(memberId));
return ApiResponse.success(SuccessStatus.SEND_MY_CHATROOMS, chatService.getMyChatRooms(memberId, pageable));
}

@GetMapping("/totalUnreadMessage")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.campick.server.api.chat.dto;

import lombok.Getter;
import lombok.Setter;
import org.springframework.data.domain.Page;

import java.util.List;

@Getter @Setter
public class ChatRoomPageResDto<T> {
private final long totalElements; // 잔체 요소 수
private final int totalPages; // 전체 페이지 수
private final int page; // 현재 페이지(0부터 시작)
private final int size; // 요청한 페이지 사이즈
private final boolean isLast; // 마지막 페이지 여부

private Long sellerId;
private Long buyerId;
private String sellerNickname;
private String buyerNickname;
private String sellerProfileImage;
private String sellerPhoneNumber;
private Long productId;
private String productTitle;
private String productImage;
private String productStatus;
private String productPrice;
private Boolean isActive;

private final List<T> chatData;

public ChatRoomPageResDto(Page<T> page) {
this.chatData = page.getContent();
this.page = page.getNumber();
this.size = page.getSize();
this.totalElements = page.getTotalElements();
this.totalPages = page.getTotalPages();
this.isLast = page.isLast();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.campick.server.api.chat.dto;

import lombok.Getter;
import org.springframework.data.domain.Page;

import java.util.List;

@Getter
public class MyChatPageResDto<T> {
private final long totalElements; // 잔체 요소 수
private final int totalPages; // 전체 페이지 수
private final int page; // 현재 페이지(0부터 시작)
private final int size; // 요청한 페이지 사이즈
private final boolean isLast; // 마지막 페이지 여부
private final int totalUnreadMessage;
private final List<T> content;

public MyChatPageResDto(Page<T> page, int totalUnreadMessage) {
this.content = page.getContent();
this.page = page.getNumber();
this.size = page.getSize();
this.totalElements = page.getTotalElements();
this.totalPages = page.getTotalPages();
this.isLast = page.isLast();
this.totalUnreadMessage = totalUnreadMessage;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.campick.server.api.chat.repository;

import com.campick.server.api.chat.entity.ChatMessage;
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.Modifying;
import org.springframework.data.jpa.repository.Query;
Expand Down Expand Up @@ -30,6 +32,15 @@ Integer markMessagesAsRead(@Param("chatRoomId") Long chatRoomId,
"ORDER BY m.createdAt DESC LIMIT 1")
ChatMessage findLastMessageByChatRoomId(@Param("chatRoomId") Long chatRoomId);

@Query("""
SELECT m FROM ChatMessage m
WHERE m.chatRoom.id IN :chatRoomIds
AND m.createdAt IN (
SELECT MAX(m2.createdAt) FROM ChatMessage m2 WHERE m2.chatRoom.id = m.chatRoom.id
)
""")
List<ChatMessage> findLastMessages(@Param("chatRoomIds") List<Long> chatRoomIds);

@Query("SELECT COUNT(m) FROM ChatMessage m " +
"WHERE m.chatRoom.id = :chatRoomId " +
"AND m.isRead = false " +
Expand All @@ -43,4 +54,6 @@ Integer countUnreadMessages(@Param("chatRoomId") Long chatRoomId,
"AND cm.isRead = false " +
"AND cm.member.id <> :memberId")
Integer countAllUnreadMessages(@Param("memberId") Long memberId);

Page<ChatMessage> findByChatRoomIdOrderByCreatedAtDesc(Long chatRoomId, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.campick.server.api.chat.entity.ChatRoom;
import com.campick.server.api.member.entity.Member;
import com.campick.server.api.product.entity.Product;
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;
Expand All @@ -28,5 +30,20 @@ public interface ChatRoomRepository extends JpaRepository<ChatRoom, Long> {
" OR (b.id = :memberId AND cr.isBuyerOut = false))")
List<ChatRoom> findAllByMemberId(@Param("memberId") Long memberId);

@Query("""
SELECT c FROM ChatRoom c
WHERE c.seller.id = :memberId OR c.buyer.id = :memberId
ORDER BY (
SELECT MAX(m.createdAt) FROM ChatMessage m WHERE m.chatRoom = c
) DESC
""")
Page<ChatRoom> findByMemberIdOrderByLastMessageDesc(@Param("memberId") Long memberId, Pageable pageable);

Optional<ChatRoom> findByProductAndSellerAndBuyer(Product product, Member seller, Member buyer);

@Query("""
SELECT COUNT(c) FROM ChatRoom c
WHERE c.seller.id = :memberId OR c.buyer.id = :memberId
""")
long countChatRoomByMemberId(@Param("memberId") Long memberId);
}
67 changes: 37 additions & 30 deletions src/main/java/com/campick/server/api/chat/service/ChatService.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
Expand Down Expand Up @@ -108,11 +113,11 @@ public Long startChatRoom(ChatRoomReqDto chatRoomReqDto, Long memberId) {
return chatRoom.getId();
}

public ChatRoomResDto getChatRoom(Long chatRoomId) {
public ChatRoomPageResDto<ChatMessage> getChatRoom(Long chatRoomId, Pageable pageable) {
ChatRoom chatRoom = chatRoomRepository.findDetailById(chatRoomId).orElseThrow(
() -> new NotFoundException(ErrorStatus.CHAT_NOT_FOUND.getMessage())
);
List<ChatMessage> chatMessages = chatMessageRepository.findMessagesByChatRoomId(chatRoomId);
Page<ChatMessage> chatMessages = chatMessageRepository.findByChatRoomIdOrderByCreatedAtDesc(chatRoomId, pageable);

return convertToChatRoomResDto(chatRoom, chatMessages);
}
Expand All @@ -121,8 +126,14 @@ public void readChatRoom(Long chatRoomId, Long memberId) {
Integer readMessageCount = chatMessageRepository.markMessagesAsRead(chatRoomId, memberId);
}

public MyChatResDto getMyChatRooms(Long memberId) {
List<ChatRoom> myChatRooms = chatRoomRepository.findAllByMemberId(memberId);
public MyChatPageResDto<ChatListDto> getMyChatRooms(Long memberId, Pageable pageable) {
Page<ChatRoom> myChatRooms = chatRoomRepository.findByMemberIdOrderByLastMessageDesc(memberId, pageable);
List<Long> chatRoomIds = myChatRooms.stream().map(ChatRoom::getId).toList();
Map<Long, ChatMessage> lastMessageMap = chatMessageRepository.findLastMessages(chatRoomIds)
.stream()
.collect(Collectors.toMap(m -> m.getChatRoom().getId(), Function.identity()));
long total = chatRoomRepository.countChatRoomByMemberId(memberId);

List<ChatListDto> chatListDtos = myChatRooms.stream().map(
chatRoom -> {
String thumbnailUrl = chatRoom.getProduct().getImages().stream()
Expand All @@ -131,7 +142,7 @@ public MyChatResDto getMyChatRooms(Long memberId) {
.findFirst()
.orElse(null);

ChatMessage lastChatMessage = chatMessageRepository.findLastMessageByChatRoomId(chatRoom.getId());
ChatMessage lastChatMessage = lastMessageMap.get(chatRoom.getId());
Integer unreadMessageCount = chatMessageRepository.countUnreadMessages(chatRoom.getId(), memberId);

return ChatListDto.builder()
Expand All @@ -146,10 +157,10 @@ public MyChatResDto getMyChatRooms(Long memberId) {
.build();
}).toList();

return MyChatResDto.builder()
.chatRoom(chatListDtos)
.totalUnreadMessage(chatMessageRepository.countAllUnreadMessages(memberId))
.build();
Integer totalUnreadMessage = chatMessageRepository.countAllUnreadMessages(memberId);
Page<ChatListDto> pageImpl = new PageImpl<>(chatListDtos, pageable, total);

return new MyChatPageResDto<>(pageImpl, totalUnreadMessage);
}

public Integer getTotalUnreadMessage(Long memberId) {
Expand Down Expand Up @@ -247,33 +258,29 @@ public void broadcastSoldEvent(WebSocketSession session, JsonNode data) {
}
}

private ChatRoomResDto convertToChatRoomResDto(ChatRoom chatRoom, List<ChatMessage> chatMessages) {
private ChatRoomPageResDto<ChatMessage> convertToChatRoomResDto(ChatRoom chatRoom, Page<ChatMessage> chatMessages) {
String thumbnailImage = chatRoom.getProduct().getImages().stream()
.filter(ProductImage::getIsThumbnail)
.map(ProductImage::getImageUrl)
.findFirst()
.orElse(null);

ChatRoomResDto chatRoomResDto = new ChatRoomResDto();
chatRoomResDto.setSellerId(chatRoom.getSeller().getId());
chatRoomResDto.setSellerNickname(chatRoom.getSeller().getNickname());
chatRoomResDto.setBuyerId(chatRoom.getBuyer().getId());
chatRoomResDto.setBuyerNickname(chatRoom.getBuyer().getNickname());
chatRoomResDto.setSellerProfileImage(chatRoom.getSeller().getProfileImageUrl());
chatRoomResDto.setSellerPhoneNumber(chatRoom.getSeller().getMobileNumber());
chatRoomResDto.setProductId(chatRoom.getProduct().getId());
chatRoomResDto.setProductTitle(chatRoom.getProduct().getTitle());
chatRoomResDto.setProductImage(thumbnailImage);
chatRoomResDto.setProductStatus(chatRoom.getProduct().getStatus().toString());
chatRoomResDto.setProductPrice(chatRoom.getProduct().getCost().toString());
chatRoomResDto.setIsActive(!chatRoom.getIsSellerOut() && !chatRoom.getIsBuyerOut());

List<ChatMessageResDto> chatMessageResDto = chatMessages.stream()
.map(this::convertToChatMessageResDto
).toList();
chatRoomResDto.setChatData(chatMessageResDto);

return chatRoomResDto;
ChatRoomPageResDto<ChatMessage> chatRoomPageResDto = new ChatRoomPageResDto<>(chatMessages);

chatRoomPageResDto.setSellerId(chatRoom.getSeller().getId());
chatRoomPageResDto.setSellerNickname(chatRoom.getSeller().getNickname());
chatRoomPageResDto.setBuyerId(chatRoom.getBuyer().getId());
chatRoomPageResDto.setBuyerNickname(chatRoom.getBuyer().getNickname());
chatRoomPageResDto.setSellerProfileImage(chatRoom.getSeller().getProfileImageUrl());
chatRoomPageResDto.setSellerPhoneNumber(chatRoom.getSeller().getMobileNumber());
chatRoomPageResDto.setProductId(chatRoom.getProduct().getId());
chatRoomPageResDto.setProductTitle(chatRoom.getProduct().getTitle());
chatRoomPageResDto.setProductImage(thumbnailImage);
chatRoomPageResDto.setProductStatus(chatRoom.getProduct().getStatus().toString());
chatRoomPageResDto.setProductPrice(chatRoom.getProduct().getCost().toString());
chatRoomPageResDto.setIsActive(!chatRoom.getIsSellerOut() && !chatRoom.getIsBuyerOut());

return chatRoomPageResDto;
}

public void removeFromChatRoomMap(Long memberId, WebSocketSession session) {
Expand Down