Skip to content

Commit

Permalink
Merge pull request #127 from farmingsoon/develop
Browse files Browse the repository at this point in the history
Main merge를 위한 배포
  • Loading branch information
gkfktkrh153 authored Mar 8, 2024
2 parents 8d757ee + 2ed3762 commit 1828f38
Show file tree
Hide file tree
Showing 25 changed files with 342 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.api.farmingsoon.common.util.CookieUtils;
import com.api.farmingsoon.common.util.JwtUtils;
import com.api.farmingsoon.domain.chatroom.event.ChatRoomConnectEvent;
import com.api.farmingsoon.domain.chatroom.event.ChatRoomDisConnectEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
Expand All @@ -28,17 +29,26 @@ public class StompInterceptor implements ChannelInterceptor {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
log.info("command : " + accessor.getCommand());


if (StompCommand.CONNECT.equals(accessor.getCommand()))
StompCommand command = accessor.getCommand();
log.info("command : " + command);
/**
* @Description
* 1. 모든 메시지 읽음 처리
* 2. Redis에 채팅방 참여 정보 저장
*/
if (StompCommand.CONNECT.equals(command))
eventPublisher.publishEvent(ChatRoomConnectEvent.builder()
.memberId(Long.valueOf(accessor.getFirstNativeHeader("memberId")))
.chatRoomId(Long.valueOf(accessor.getFirstNativeHeader("chatRoomId")))
.build()
.connectMemberId(Long.valueOf(accessor.getFirstNativeHeader("memberId")))
.chatRoomId(Long.valueOf(accessor.getFirstNativeHeader("chatRoomId")))
.sessionId(accessor.getSessionId())
.build()
);


else if (StompCommand.DISCONNECT.equals(command)) {
eventPublisher.publishEvent(ChatRoomDisConnectEvent.builder()
.chatRoomId(Long.valueOf(accessor.getFirstNativeHeader("chatRoomId")))
.sessionId(accessor.getSessionId())
.build());
}

return message;
}
Expand Down
30 changes: 18 additions & 12 deletions src/main/java/com/api/farmingsoon/common/redis/RedisService.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,27 @@ public Set<String> getKeySet(String domain) {
return redisTemplate.keys(domain);
}

public boolean isExistsKey(String key){
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
public boolean isNotExistsKey(String key){
return Boolean.FALSE.equals(redisTemplate.hasKey(key));
}

public void addToSet(String key, Long itemId){
if(!isExistsKey(key)) {// 키가 없다면(set이 없다면)
redisTemplate.opsForSet().add(key, String.valueOf(itemId)); // set생성
redisTemplate.expire(key, TimeUtils.getRemainingTimeUntilMidnight(), TimeUnit.SECONDS); // 만료기간 설정
}
else // 기존 키 값으로 된 set에 추가
redisTemplate.opsForSet().add(key,String.valueOf(itemId));

public void addToSet(String key, String value){
redisTemplate.opsForSet().add(key,value);
}
public void setExpireTime(String key, Long ttl){
redisTemplate.expire(key, ttl , TimeUnit.SECONDS); // 만료기간 설정
}
public boolean isExistInSet(String key, Long itemId){
return Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(key, String.valueOf(itemId)));
public void createSet(String key, String value){
redisTemplate.opsForSet().add(key, value); // set생성
}
public void deleteToSet(String key, String value){
redisTemplate.opsForSet().remove(key, value);
}
public Long getSetSize(String key){
return redisTemplate.opsForSet().size(key);
}

public boolean isNotExistInSet(String key, String value){
return Boolean.FALSE.equals(redisTemplate.opsForSet().isMember(key, value));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void onMessage(Message key, byte[] pattern) {
String[] expiredKey = key.toString().split("_");
if (expiredKey[0].equals("bidEnd")) {
applicationEventPublisher.publishEvent(new BidEndKeyExpiredEvent((Long.valueOf(expiredKey[1])))); ; // itemId
} else if (expiredKey[0].equals("chatting")) { // memberId
} else if (expiredKey[0].equals("debouncing")) { // memberId
applicationEventPublisher.publishEvent(new ChatNotificationDebounceKeyExpiredEvent(Long.valueOf(expiredKey[1]))); // receiverId
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,5 @@ public class ChatController {
public void sendMessage(ChatMessageRequest chatMessageRequest) {
chatService.create(chatMessageRequest);
}
@MessageMapping("/chat/read")
public void readMessage(ReadMessageRequest readMessageRequest) {
chatService.read(readMessageRequest);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class ChatResponse {
private Long senderId;
private Boolean isRead;
private LocalDateTime createAt;
private final String type = "SEND";

@Builder
private ChatResponse(Long senderId, String message, Boolean isRead, Long chatId, LocalDateTime createAt) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.api.farmingsoon.domain.chat.dto;

import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@Getter
public class ChattingConnectResponse {

private Long connectMemberId;
private final String type = "SEND";

public ChattingConnectResponse(Long connectMemberId) {
this.connectMemberId = connectMemberId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ public class ChatEventListener {
public void sendChatAndDebounceNotification(ChatSaveEvent event) throws InterruptedException {
messagingTemplate.convertAndSend("/sub/chat-room/" + event.getChatRoomId(), event.getChatResponse());

if(!redisService.isExistsKey("chatting_" + event.getReceiverId())) // 알림 디바운싱
redisService.setData("chatting_" + event.getReceiverId(),"", 2L,TimeUnit.SECONDS);
if(redisService.isNotExistsKey("debouncing_" + event.getReceiverId())) // 알림 디바운싱
redisService.setData("debouncing_" + event.getReceiverId(),"", 2L,TimeUnit.SECONDS);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
import com.api.farmingsoon.domain.chat.model.Chat;
import com.api.farmingsoon.domain.chat.repository.ChatRepository;
import com.api.farmingsoon.domain.chatroom.model.ChatRoom;
import com.api.farmingsoon.domain.chatroom.service.ChatRoomRedisService;
import com.api.farmingsoon.domain.chatroom.service.ChatRoomService;
import com.api.farmingsoon.domain.member.model.Member;
import com.api.farmingsoon.domain.member.service.MemberService;
import com.api.farmingsoon.domain.notification.event.NotReadChatEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
Expand All @@ -31,23 +33,31 @@ public class ChatService {
private final ChatRoomService chatRoomService;
private final MemberService memberService;
private final ApplicationEventPublisher eventPublisher;
private final ChatRoomRedisService chatRoomRedisService;

@Transactional
public void create(ChatMessageRequest chatMessageRequest) {
Long connectMemberSize = chatRoomRedisService.getConnectMemberSize("chatRoom_" + chatMessageRequest.getChatRoomId());

ChatRoom chatRoom = chatRoomService.getChatRoom(chatMessageRequest.getChatRoomId());
Member sender = memberService.getMemberById(chatMessageRequest.getSenderId());
Chat chat = chatRepository.save(
Chat.builder().
sender(sender)
.message(chatMessageRequest.getMessage())
.isRead(false)
.isRead(connectMemberSize == 2) // 채팅방에 둘 모두 존재한다면 읽음으로 처리
.chatRoom(chatRoom).build()
);

Member receiver = ChatRoom.resolveToReceiver(chatRoom, sender.getEmail());

if(connectMemberSize == 1) // 채팅방에 상대방이 없다면 알림을 전송
eventPublisher.publishEvent(new NotReadChatEvent(receiver.getId()));

eventPublisher.publishEvent(
ChatSaveEvent.builder()
.chatRoomId(chatMessageRequest.getChatRoomId())
.receiverId(ChatRoom.resolveToReceiver(chatRoom, sender.getEmail()).getId())
.receiverId(receiver.getId())
.chatResponse(ChatResponse.of(chat))
.build());

Expand All @@ -58,13 +68,6 @@ public ChatListResponse getChats(Long chatRoomId, Pageable pageable) {
return ChatListResponse.of(chatRepository.findByChatRoomOrderByIdAsc(chatRoom, pageable));
}

@Transactional
public void read(ReadMessageRequest readMessageRequest) {
Chat chat = chatRepository.findById(readMessageRequest.getChatId()).orElseThrow(() -> new NotFoundException(ErrorCode.NOT_FOUND_CHAT));
chat.read();
log.info(chat.getId() + " "+ chat.getIsRead());
}

@Transactional
public void readAllMyNotReadChatList(Long chatRoomId, Long memberId) {
ChatRoom chatRoom = chatRoomService.getChatRoom(chatRoomId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
@Getter
public class ChatRoomConnectEvent {

private Long memberId;
private Long connectMemberId;
private Long chatRoomId;
private String sessionId;

@Builder
private ChatRoomConnectEvent(Long memberId, Long chatRoomId) {
this.memberId = memberId;
private ChatRoomConnectEvent(Long connectMemberId, Long chatRoomId, String sessionId) {
this.connectMemberId = connectMemberId;
this.chatRoomId = chatRoomId;
this.sessionId = sessionId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.api.farmingsoon.domain.chatroom.event;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@Getter
public class ChatRoomDisConnectEvent {

private Long chatRoomId;
private String sessionId;

@Builder
private ChatRoomDisConnectEvent(Long chatRoomId, String sessionId) {
this.chatRoomId = chatRoomId;
this.sessionId = sessionId;
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,40 @@
package com.api.farmingsoon.domain.chatroom.listener;

import com.api.farmingsoon.common.sse.SseService;
import com.api.farmingsoon.domain.chat.dto.ChattingConnectResponse;
import com.api.farmingsoon.domain.chat.service.ChatService;
import com.api.farmingsoon.domain.chatroom.event.ChatRoomConnectEvent;
import com.api.farmingsoon.domain.chatroom.service.ChatRoomRedisService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component;

@RequiredArgsConstructor
@Component
public class ChatRoomEventListener {
private final ChatService chatService;
private final ChatRoomRedisService chatRoomRedisService;
private final SimpMessagingTemplate messagingTemplate;


/**
* @Description
* 1. 채팅방에 연결됐음을 저장
* 2. 연결된 사람의 채팅방에 안읽었던 메시지를 모두 읽음 처리
* 3. 채팅방에 상대방이 연결되었음을 알리는 알림
*/
@EventListener
public void readAllChatAndSaveConnectMember(ChatRoomConnectEvent event){
chatRoomRedisService.connectChatRoom(event.getChatRoomId(), event.getSessionId());
chatService.readAllMyNotReadChatList(event.getChatRoomId(), event.getConnectMemberId());
messagingTemplate.convertAndSend("/sub/chat-room/" + event.getChatRoomId(), new ChattingConnectResponse(event.getConnectMemberId()));

}

@EventListener
public void readAllChatMessage(ChatRoomConnectEvent event){
chatService.readAllMyNotReadChatList(event.getChatRoomId(), event.getMemberId());
public void deleteConnectMember(ChatRoomConnectEvent event){
chatRoomRedisService.disConnectChatRoom(event.getChatRoomId(), event.getSessionId());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.api.farmingsoon.domain.chatroom.service;

import com.api.farmingsoon.common.redis.RedisService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class ChatRoomRedisService {
private final RedisService redisService;

public void connectChatRoom(Long chatRoomId, String sessionId) {
redisService.addToSet("chatRoom_" + chatRoomId, sessionId);
}

/**
* 채팅방에 남은 사람이 한명이라면 나갈 때 키 삭제
*/
public void disConnectChatRoom(Long chatRoomId, String sessionId) {
if(redisService.getSetSize("chatRoom_" + chatRoomId) == 1){
redisService.deleteData("chatRoom_" + chatRoomId);
}
redisService.deleteToSet("chatRoom_" + chatRoomId, sessionId);
}
public Long getConnectMemberSize(String key){
return redisService.getSetSize(key);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import com.api.farmingsoon.common.util.CookieUtils;
import com.api.farmingsoon.domain.item.dto.*;
import com.api.farmingsoon.domain.item.service.ItemService;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
Expand All @@ -18,8 +17,6 @@
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;

@RestController
@Slf4j
@RequestMapping("/api/items")
Expand Down Expand Up @@ -60,6 +57,7 @@ public Response<ItemListResponse> getItemList(
ItemListResponse items = itemService.getItemList(category, keyword, pageable, sortcode);
return Response.success(HttpStatus.OK, "상품 목록 조회 성공!", items);
}

@GetMapping("/me")
public Response<MyItemListResponse> getMyItemList(
@PageableDefault(size = 12, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) {
Expand Down Expand Up @@ -87,5 +85,16 @@ public Response<Void> soldOut(@PathVariable(name = "itemId") Long itemId, @Reque
itemService.soldOut(itemId, buyerId);
return Response.success(HttpStatus.OK, "상품 판매 완료!");
}
/*
@GetMapping("/test")
public Response<ItemListBySubQueryResponse> getItemListBySubQuery(
@PageableDefault(size = 12) Pageable pageable,
@RequestParam(value = "sortcode", defaultValue = "recent") String sortcode,
@RequestParam(value = "category", required = false) String category,
@RequestParam(value = "keyword", required = false) String keyword) {
ItemListBySubQueryResponse itemListBySubQuery = itemService.getItemListBySubQuery(category, keyword, pageable, sortcode);
return Response.success(HttpStatus.OK, "상품 목록 조회 성공!", itemListBySubQuery);
}
*/
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.api.farmingsoon.domain.member.model.Member;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.BatchSize;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;

Expand Down Expand Up @@ -57,8 +58,10 @@ public class Item extends BaseTimeEntity {

// *Todo 양방향 안쓰는 쪽으로 고려해보기
@OneToMany(mappedBy = "item")
@BatchSize(size = 12)
private List<Bid> bidList;

@BatchSize(size = 12)
@OneToMany(mappedBy = "item")
private List<LikeableItem> likeableItemList;

Expand Down
Loading

0 comments on commit 1828f38

Please sign in to comment.