Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] FEAT: 채팅 서버 - WebSocket 붙이기 #174 #181

Merged
merged 19 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a5e4f8b
[BE] FEAT: playlist 동기화를 위한 ws 연결 추가 #174
dahyun24 Feb 14, 2025
a096911
[BE] FEAT: ObjectMapper Bean 사용 #174
dahyun24 Feb 15, 2025
d717bfa
[BE] FEAT: 방, 친구 초대 websocket 연결 구현 #174
dahyun24 Feb 15, 2025
4d2abc5
[BE] FIX: Websocket 연결 실패 해결 #174
dahyun24 Feb 15, 2025
27b38b0
[BE] FEAT: Kafka로 정보 보내는 repository 추가 #174
dahyun24 Feb 15, 2025
9a2bdff
[BE] FIX: RoomManager를 WebSocketRoomService로 이름 변경 및 기능 수정 #174
dahyun24 Feb 15, 2025
9bf6acb
[BE] FIX: RoomController를 WebSocketController로 이름 변경 및 기능 수정 #174
dahyun24 Feb 15, 2025
64d3da1
[BE] FEAT: record 및 enum 추가 #174
dahyun24 Feb 15, 2025
0b1144c
[BE] FIX: 중복 코드 주석 처리 #174
dahyun24 Feb 15, 2025
c90f84e
[BE] FEAT: Message 주고 받는 로직 추가 #174
dahyun24 Feb 15, 2025
168587b
[BE] FEAT: play-time Kafka produce, consume 로직 추가 #174
dahyun24 Feb 15, 2025
63ba6e4
[BE] ETC: 폴더 이름 변경 #174
dahyun24 Feb 15, 2025
70508be
[BE] FEAT: 친구의 접속 상태 연결 구현 #174
dahyun24 Feb 15, 2025
010ce88
[BE] FEAT: 모든 웹소켓 endpoint 확인 가능한 html 코드 #174
dahyun24 Feb 15, 2025
eda1dd8
[BE] MOVE: 파일 구조 정리 #174
dahyun24 Feb 16, 2025
ef456c7
[BE] ETC: 변수명 playlist로 변경 #174
dahyun24 Feb 16, 2025
7852199
[BE] ETC: endpoint, class 이름 변경 #174
dahyun24 Feb 16, 2025
148929d
[BE] FEAT: play-time JSON에 playerState 추가 #174
dahyun24 Feb 17, 2025
527bcf1
[BE] FEAT: ChatMessage에 nickname, role, profileImageUrl 필드 추가 #174
dahyun24 Feb 17, 2025
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
@@ -0,0 +1,14 @@
package kickzo.stomp_chat.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.fasterxml.jackson.databind.ObjectMapper;

@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,13 @@

import jakarta.annotation.PostConstruct;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.EnableKafka;
import org.springframework.kafka.core.ConsumerFactory;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
import org.springframework.kafka.listener.ContainerProperties;
import org.springframework.kafka.listener.MessageListener;
import org.springframework.messaging.simp.SimpMessagingTemplate;

import java.util.HashMap;
import java.util.Map;
Expand All @@ -38,9 +32,6 @@ public void init() {
groupId = "my-group-" + serverPort; // 서버 포트에 따라 groupId 설정
}

@Autowired
private SimpMessagingTemplate messagingTemplate; // Injected by Spring

@Bean
public ConsumerFactory<String, String> consumerFactory() {
// Kafka Consumer 설정
Expand All @@ -52,33 +43,33 @@ public ConsumerFactory<String, String> consumerFactory() {
return new DefaultKafkaConsumerFactory<>(configProps);
}

@Bean
public ConcurrentMessageListenerContainer<String, String> messageListenerContainer() {
MessageListener<String, String> messageListener = new MessageListener<String, String>() {
@Override
public void onMessage(ConsumerRecord<String, String> record) {
String message = record.value();
System.out.println("Received Kafka message: " + message);


// 메시지를 처리하는 로직을 여기에 추가
String roomId = "1";

if (roomId != null && !roomId.isEmpty()) {
// WebSocket으로 메시지 전송
messagingTemplate.convertAndSend("/topic/" + roomId, message);
System.out.println("Message sent to WebSocket topic: /topic/" + roomId);
System.out.println("Broadcasting message: " + message);
} else {
System.err.println("Failed to send message: roomId is null or empty.");
}
}
};

ContainerProperties containerProps = new ContainerProperties("chatting");
containerProps.setMessageListener(messageListener);
containerProps.setGroupId(groupId); // groupId 설정

return new ConcurrentMessageListenerContainer<>(consumerFactory(), containerProps);
}
// @Bean
// public ConcurrentMessageListenerContainer<String, String> messageListenerContainer() {
// MessageListener<String, String> messageListener = new MessageListener<String, String>() {
// @Override
// public void onMessage(ConsumerRecord<String, String> record) {
// String message = record.value();
// System.out.println("Received Kafka message: " + message);
//
//
// // 메시지를 처리하는 로직을 여기에 추가
// String roomId = "1";
//
// if (roomId != null && !roomId.isEmpty()) {
// // WebSocket으로 메시지 전송
// messagingTemplate.convertAndSend("/topic/" + roomId, message);
// System.out.println("Message sent to WebSocket topic: /topic/" + roomId);
// System.out.println("Broadcasting message: " + message);
// } else {
// System.err.println("Failed to send message: roomId is null or empty.");
// }
// }
// };
//
// ContainerProperties containerProps = new ContainerProperties("chatting");
// containerProps.setMessageListener(messageListener);
// containerProps.setGroupId(groupId); // groupId 설정
//
// return new ConcurrentMessageListenerContainer<>(consumerFactory(), containerProps);
// }
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package kickzo.stomp_chat.controller;

import com.fasterxml.jackson.databind.ObjectMapper;

import kickzo.stomp_chat.enums.EventType;
import kickzo.stomp_chat.service.WebSocketRoomService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.stereotype.Controller;

@Slf4j
@Controller
@RequiredArgsConstructor
public class WebSocketController {

private final ObjectMapper objectMapper;
private final WebSocketRoomService webSocketRoomService;

@MessageMapping("/connect")
public void connect(String payload, SimpMessageHeaderAccessor headerAccessor) {
try {
// payload를 UserConnectRequest 객체로 변환
UserConnectRequest request = objectMapper.readValue(payload, UserConnectRequest.class);
Long userId = request.userId();
// 세션에 사용자 정보 저장
headerAccessor.getSessionAttributes().put("userId", userId);

webSocketRoomService.sendConnection(userId, EventType.JOIN);
log.info("User {} connected and is now online.", userId);
} catch (Exception e) {
log.error("Error processing connect message", e);
}
}

// @MessageMapping("/joinRoom")
// public void joinRoom(String payload, SimpMessageHeaderAccessor headerAccessor) throws Exception {
// try {
// JoinRoomRequest request = objectMapper.readValue(payload, JoinRoomRequest.class);
// Long userId = request.userId();
// long roomId = request.roomId();
// headerAccessor.getSessionAttributes().put("userId", userId);
// headerAccessor.getSessionAttributes().put("roomId", roomId);
//
// webSocketRoomService.handleRoomUserJoin(request.roomId(), userId);
// messagingTemplate.convertAndSend("/topic/room/" + roomId, userId + " has joined the room.");
// } catch (Exception e) {
// log.error("Error processing joinRoom message", e);
// }
// }

@MessageMapping("/send-message")
public void sendMessage(String payload, SimpMessageHeaderAccessor headerAccessor) {
try {
SendMessageRequest request = objectMapper.readValue(payload, SendMessageRequest.class);
long userId = (Long) headerAccessor.getSessionAttributes().get("userId");

webSocketRoomService.handleMessageSend(request.roomId(), userId, request.nickname(), request.role(),
request.profileImageUrl(), request.content(), request.message());
} catch (Exception e) {
log.error("Error processing sendMessage message", e);
}
}

@MessageMapping("/play-time")
public void playTime(String payload) throws Exception {
PlayTimeRequest request = objectMapper.readValue(payload, PlayTimeRequest.class);
log.info("Received roomId : {}, play time: {}", request.roomId(), request.playTime());

webSocketRoomService.sendPlayTime(request.roomId(), request.playTime(), request.playerState());
}

public record UserConnectRequest(long userId) {}
public record SendMessageRequest(long roomId, long userId, String nickname, int role, String profileImageUrl, String content, String message) {}

public record PlayTimeRequest(long roomId, long playTime, String playerState) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class RoomEvent {
private String eventType; // 이벤트 구분
private Object data; // 이벤트 데이터
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package kickzo.stomp_chat.dto.playlist;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class PlayTime {
private long roomId;
private long playTime;
private String playerState;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package kickzo.stomp_chat.dto;
package kickzo.stomp_chat.dto.playlist;

import lombok.AllArgsConstructor;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package kickzo.stomp_chat.dto;
package kickzo.stomp_chat.dto.playlist;

import java.util.List;

Expand All @@ -11,5 +11,5 @@
@NoArgsConstructor
public class PlaylistUpdateEvent {
private Long roomId;
private List<PlaylistItem> playlistJson;
private List<PlaylistItem> playlist;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package kickzo.stomp_chat.dto.room;

public record ChatMessage(long roomId, long userId, String nickname, int role, String profileImageUrl, String content, String message) {}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package kickzo.stomp_chat.dto;
package kickzo.stomp_chat.dto.room;

import lombok.AllArgsConstructor;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package kickzo.stomp_chat.dto;
package kickzo.stomp_chat.dto.room;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class RoleChangeEvent {
private Long roomId;
private Long targetUserId;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package kickzo.stomp_chat.dto;
package kickzo.stomp_chat.dto.room;

import lombok.Getter;
import lombok.NoArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package kickzo.stomp_chat.dto;
package kickzo.stomp_chat.dto.room;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfoDto {
private Long userId;
private int role;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package kickzo.stomp_chat.dto.user;

import java.time.Instant;

import kickzo.stomp_chat.enums.EventType;

public record ConnectionEvent(long userId, EventType eventType, String serverPort, long timestamp) {
public ConnectionEvent(long userId, EventType eventType, String serverPort) {
this(userId, eventType, serverPort, Instant.now().toEpochMilli());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package kickzo.stomp_chat.dto.user;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class FriendNotification {
private long userId;
private String status;
}
Loading