Skip to content
Open
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
25 changes: 6 additions & 19 deletions src/backend/chat-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
# 1️⃣ 베이스 이미지로 OpenJDK 17 사용
FROM openjdk:17-jdk-slim AS build

# 2️⃣ 작업 디렉토리 설정
WORKDIR /app

# 3️⃣ 프로젝트 복사
COPY . .

# 4️⃣ Gradle 빌드 수행 (테스트는 제외)
RUN chmod +x gradlew
RUN ./gradlew build -x test

# 5️⃣ 런타임 이미지로 OpenJDK 17 사용
# 베이스 이미지로 OpenJDK 17 사용
FROM openjdk:17-jdk-slim
WORKDIR /app

# 6️⃣ 빌드된 JAR 파일 복사
COPY --from=build /app/build/libs/*.jar app.jar
# 애플리케이션 파일을 컨테이너에 복사
ARG JAR_FILE=stomp_chat-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar

# 7️⃣ 컨테이너 실행 시 Spring Boot 애플리케이션 실행
ENTRYPOINT ["java", "-jar", "app.jar"]
# 애플리케이션 실행
ENTRYPOINT ["java", "-jar", "/app.jar"]
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.kafka.annotation.EnableKafka;
import org.springframework.kafka.core.ConsumerFactory;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public RoomController(SimpMessagingTemplate messagingTemplate, RoomManager roomM

@MessageMapping("/joinRoom")
public void joinRoom(String payload, SimpMessageHeaderAccessor headerAccessor) throws Exception {

// TODO[SMG-C]: jsonNode, map 사용 지양
// objectmapper.read 활용해서 object로 사용
JsonNode jsonNode = objectMapper.readTree(payload);
String roomId = jsonNode.get("roomId").asText();
String userId = jsonNode.get("userId").asText();
Expand Down Expand Up @@ -52,6 +55,11 @@ public void sendMessage(String payload, SimpMessageHeaderAccessor headerAccessor
//messagingTemplate.convertAndSend("/topic/" + roomId, response);
}


// TODO[SMG-C]: record 사용
// MessageResponse이거를 아래처럼 간단히 가능합니다.
record MessageResponseTest(String userId, String message) {}

public static class MessageResponse {
private String userId;
private String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
@Setter
@AllArgsConstructor
public class RoomEvent {
// TODO[SMG-C]: enum 사용 지향
// string 보다는 enum 사용하시면 switch case 문 쓸 때도 편해요
private String eventType; // 이벤트 구분
private Object data; // 이벤트 데이터

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package kickzo.stomp_chat.service;

import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.ObjectMapper;

import jakarta.annotation.PostConstruct;
import kickzo.stomp_chat.dto.PlaylistUpdateEvent;
import kickzo.stomp_chat.dto.RoomEvent;
import lombok.RequiredArgsConstructor;
Expand All @@ -20,6 +22,21 @@ public class KafkaConsumerService {
private final RoomEventHandler roomEventHandler;
private final PlaylistEventHandler playlistEventHandler;

@Value("${server.port}")
private String serverPort;

@Value("${spring.kafka.bootstrap-servers}")
private String KAFKA_BROKER; // Kafka 브로커 주소

@Value(("${spring.kafka.consumer.group-id}"))
private String groupId;

// 서버 포트에 맞춰서 groupId를 동적으로 설정하는 메서드
@PostConstruct
public void init() {
groupId = "my-group-" + serverPort; // 서버 포트에 따라 groupId 설정
}

@KafkaListener(topics = "playlist")
public void consumePlaylistEvents(ConsumerRecord<String, String> record) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public class PlaylistEventHandler {
private final MessagingService messagingService;

public void handleEvent(PlaylistUpdateEvent event) throws JsonProcessingException {
// TODO[SMG-C]: Map 사용 보다는 Object
// object 로 만들고 관리해야 추후에 변경 추적이 쉬워요
Map<String, Object> playlistResponse = new LinkedHashMap<>();
playlistResponse.put("roomId", event.getRoomId());
playlistResponse.put("playlistJson", event.getPlaylistJson());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import kickzo.stomp_chat.dto.NewUserJoinEvent;
import kickzo.stomp_chat.dto.RoleChangeEvent;
import kickzo.stomp_chat.dto.RoomData;
import kickzo.stomp_chat.dto.RoomEvent;
Expand All @@ -22,15 +21,13 @@ public class RoomEventHandler {

public void handleEvent(RoomEvent event) throws JsonProcessingException {
switch (event.getEventType()) {

case "room-update":
handleRoomUpdate(event);
break;
case "role-change":
handleRoleChange(event);
break;
case "user-list":
handleUserList(event);
break;
default:
log.warn("Unknown event type: {}", event.getEventType());
}
Expand All @@ -45,9 +42,4 @@ private void handleRoleChange(RoomEvent event) throws JsonProcessingException {
RoleChangeEvent roleChange = objectMapper.convertValue(event.getData(), RoleChangeEvent.class);
messagingService.sendMessage("role-change", roleChange.getRoomId(), roleChange);
}

private void handleUserList(RoomEvent event) throws JsonProcessingException {
NewUserJoinEvent userList = objectMapper.convertValue(event.getData(), NewUserJoinEvent.class);
messagingService.sendMessage("user-list", userList.getRoomId(), userList);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public ConcurrentMessageListenerContainer<String, ChatMessage> messageListenerCo
@Override
public void onMessage(ConsumerRecord<String, String> record) {
String message = record.value();
// TODO[SMG-C]: logger 권장. @Slf4j 사용하시면 편합니다.
System.out.println("1: Received Kafka message: " + message);
chatMessageService.saveMessage(message);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ public long getTimestamp() {
return timestamp;
}

// TODO[SMG-C]: setter 사용 지양
// 참고 : https://velog.io/@langoustine/setter-%EC%A7%80%EC%96%91-%EC%9D%B4%EC%9C%A0
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

@Repository
public interface ChatMessageRepository extends MongoRepository<ChatMessage, String> {
// TODO[SMG-Q]: 왜 채팅은 mongoDB 사용 했나요?

// 특정 방의 메시지들을 타임스탬프 기준으로 정렬하여 가져오는 메서드
List<ChatMessage> findByRoomIdOrderByTimestampDesc(String roomId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import history.kickzo.model.ChatMessage;
import history.kickzo.repository.ChatMessageRepository;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;

import java.util.List;

Expand All @@ -12,6 +13,7 @@ public class ChatMessageService {
private final ChatMessageRepository repository;
private final ObjectMapper objectMapper;

// TODO[SMG-C]: @RequiredArgsConstructor 사용 권장. 이게 편해요
public ChatMessageService(ChatMessageRepository repository, ObjectMapper objectMapper) {
this.repository = repository;
this.objectMapper = objectMapper;
Expand All @@ -24,6 +26,7 @@ public void saveMessage(String message) {
chatMessage.setTimestamp(System.currentTimeMillis()); // 현재 시간으로 타임스탬프 설정 (필요 시)

// 저장할 데이터 출력
// TODO[SMG-C]: logger 사용 권장. ex. @Slf4j
System.out.println("Saving message to DB: ");
System.out.println("ID: " + chatMessage.getId());
System.out.println("User: " + chatMessage.getUserId());
Expand All @@ -35,6 +38,8 @@ public void saveMessage(String message) {
} catch (Exception e) {
e.printStackTrace();
System.out.println("Error parsing message: " + e.getMessage());
// TODO[SMG-C]: logger 사용 권장. ex. @Slf4j
// log.error("Error parsing message: " + e.getMessage(), e);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/backend/main-server/main/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies {
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
public interface MainPageApi {

@Operation(summary = "모든 방 조회", description = "페이지 번호와 사이즈로 방 목록을 조회합니다.")
@ApiResponses(
value = {
@ApiResponses({
@ApiResponse(responseCode = "200", description = "전체 방 목록 조회 성공"),
@ApiResponse(responseCode = "DB-500-001", description = ApiResponseConstants.DATABASE_ERROR_MESSAGE),
@ApiResponse(responseCode = "JSON-500-001", description = ApiResponseConstants.JSON_PROCESSING_ERROR_MESSAGE),
Expand All @@ -46,7 +45,7 @@ ResponseEntity<List<RoomResponseDto>> getUserRooms(
);

@Operation(summary = "방 생성", description = "사용자가 새로운 방을 생성합니다.")
@ApiResponses(value = {
@ApiResponses({
@ApiResponse(responseCode = "200", description = "새로운 방 생성 성공"),
@ApiResponse(responseCode = "MAIN-400-001", description = ApiResponseConstants.INVALID_INPUT_MESSAGE),
@ApiResponse(responseCode = "MAIN-404-002", description = ApiResponseConstants.USER_NOT_FOUND_MESSAGE),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.kickzo.main.dto.request.CreateRoomRequestDto;
Expand All @@ -27,22 +30,27 @@ public class MainPageController implements MainPageApi {
private final MainPageService mainPageService;

@Override
@GetMapping("/list/all")
public ResponseEntity<List<RoomResponseDto>> getAllRooms(int page, int size) {
@GetMapping("/all")
public ResponseEntity<List<RoomResponseDto>> getAllRooms(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
log.info("get all rooms. page: {}, size: {}", page, size);
return ResponseEntity.ok(mainPageService.getAllRooms(PageRequest.of(page, size)));
}

@Override
@GetMapping("/list/my")
public ResponseEntity<List<RoomResponseDto>> getUserRooms(Long userId) {
@GetMapping("/me")
public ResponseEntity<List<RoomResponseDto>> getUserRooms(
@RequestHeader(value = "x-user-id", required = true) Long userId) {
log.info("get user rooms. userId: {}", userId);
return ResponseEntity.ok(mainPageService.getUserRooms(userId));
}

@Override
@PostMapping("/create-room")
public ResponseEntity<CreateRoomResponseDto> createRoom(Long userId, @Valid CreateRoomRequestDto requestDto) {
public ResponseEntity<CreateRoomResponseDto> createRoom(
@RequestHeader(value = "x-user-id", required = true) Long userId,
@Valid @RequestBody CreateRoomRequestDto requestDto) {
log.info("create room for userId: {}", userId);
return ResponseEntity.ok(mainPageService.createRoom(userId, requestDto));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package com.kickzo.main.controller;

import java.util.List;

import com.kickzo.main.constants.ApiResponseConstants;
import com.kickzo.main.dto.request.RoleChangeRequestDto;
import com.kickzo.main.dto.request.RoomJoinRequestDto;
import com.kickzo.main.dto.request.RoomUpdateRequestDto;
import com.kickzo.main.dto.response.RoomEntryResponseDto;
import com.kickzo.main.dto.response.UserListDto;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
Expand All @@ -29,7 +34,7 @@ public interface RoomApi {
})
ResponseEntity<RoomEntryResponseDto> joinRoom(
@RequestHeader(value = "x-user-id", required = false) Long userId,
@RequestParam String roomCode
@RequestBody RoomJoinRequestDto roomJoinRequestDto
);

@Operation(summary = "방 정보 수정", description = "특정 방의 제목, 설명, 공개여부를 수정합니다.")
Expand Down Expand Up @@ -71,7 +76,7 @@ ResponseEntity<?> updateRoomInfo(
})
ResponseEntity<String> savePlaylist(
@RequestHeader(value = "x-user-id", required = true) Long userId,
@RequestParam Long roomId,
@RequestBody Long roomId,
@RequestBody String playlistJson
);

Expand All @@ -92,8 +97,11 @@ ResponseEntity<String> savePlaylist(
})
ResponseEntity<String> changeUserRole(
@RequestHeader(value = "x-user-id", required = true) Long userId,
@RequestParam Long roomId,
@RequestParam Long targetUserId,
@RequestParam int newRole
@RequestBody RoleChangeRequestDto roleChangeRequestDto
);

@Operation(summary = "방의 userList 제공", description = "방에 소속한 participant의 userList를 제공합니다.")
ResponseEntity<List<UserListDto>> getRoomParticipants(
@RequestParam Long roomId
);
}
Loading
Loading