프로젝트

자프실 프로젝트 - 6 controller, 이벤트 흐름

aerimi-code 2025. 12. 6. 16:06

📌 초기화 (initialize)

public void initialize(ChatPanel view, Long userId) {
    this.chatView = view;

    // Service → Controller 리스너 등록
    chatService.initialize(userId, this::handleIncomingMessage);
    userStateService.setUserListListener(this::handleUserListUpdate);

    // View → Controller 이벤트 연결
    view.setOnSendMessage(this::onSendButtonClick);
    view.setOnSendWhisper(this::onWhisperButtonClick);
    view.setOnDisconnect(this::onDisconnect);
    view.setOnJoin(this::onJoinButtonClick); 
}

 

  • 서비스 → 컨트롤러:
    • chatService.initialize() → 서버 연결 및 메시지 수신 시 handleIncomingMessage 실행.
    • userStateService.setUserListListener() → 유저 목록 갱신 시 handleUserListUpdate 실행.
  • 뷰 → 컨트롤러:
    • UI에서 버튼 클릭 이벤트 발생 시 컨트롤러 메서드(onSendButtonClick, onWhisperButtonClick, onDisconnect, onJoinButtonClick) 실행.

📌 이벤트 핸들러 (View → Service)

1. 입장 버튼

public void onJoinButtonClick() {
    chatService.joinChatRoom();  // 네트워크 구독 + JOIN 요청
    chatView.addSystemMessage("Chatroom Join!");
}
  • 유저가 "입장" 버튼을 누르면 채팅방에 들어가고, 시스템 메시지를 뷰에 표시.

2. 메시지 전송 버튼

public void onSendButtonClick(String text) {
    if (text == null || text.trim().isEmpty()) return;
    String trimmed = text.trim();

    if (trimmed.startsWith("/w ")) {
        handleWhisperCommand(trimmed); // 귓속말 처리
    } else {
        chatService.sendPublicMessage(trimmed); // 전체 채팅
    }
}
  • /w로 시작하면 귓속말, 아니면 전체 채팅으로 처리.

3. 귓속말 처리

private void handleWhisperCommand(String command) {
    String[] parts = command.substring(3).split(" ", 2);
    if (parts.length < 2) { showError("귓속말 형식: /w 받는사람 메시지"); return; }

    String recipientName = parts[0].trim();
    String message = parts[1].trim();

    if (message.isEmpty()) { showError("메시지 내용을 입력해주세요."); return; }

    Long recipientId = userStateService.getUserIdByName(recipientName);
    if (recipientId == null) { showError("사용자를 찾을 수 없습니다: " + recipientName); return; }

    if (!userStateService.isUserActive(recipientName)) {
        showError(recipientName + "님은 현재 접속 중이 아닙니다."); return;
    }

    chatService.sendWhisper(recipientId, message);
}
  • /w 받는사람 메시지 형식 파싱
  • 유저 존재 여부 및 접속 여부 확인
  • recipientName → recipientId 변환 후 chatService.sendWhisper() 호출

4. 연결 종료

public void onDisconnect() {
    chatService.disconnect();
    //chatView.close();
}
  • 서버 연결 종료.

📌 이벤트 핸들러 (Service → View)

메시지 수신 처리

private void handleIncomingMessage(ChatMessageResponse message) {
    switch (message.getType()) {
        case "CHAT":
            chatView.addPublicMessage(...);
            break;
        case "WHISPER":
            chatView.addWhisperMessage(...);
            break;
        case "JOIN":
        case "LEAVE":
            chatView.addSystemMessage(message.getContent());
            break;
    }
}
  • 서버에서 받은 메시지 타입에 따라 뷰에 표시:
    • CHAT → 일반 메시지
    • WHISPER → 귓속말 (특별 표시)
    • JOIN/LEAVE → 시스템 메시지

유저 목록 갱신

private void handleUserListUpdate(Set<String> users) {
    //chatView.updateUserList(users);
}
  • 접속자 목록이 갱신되면 뷰에 반영 (현재는 주석 처리).

📌 showError

private void showError(String content) {
    //chatView.showError(string);
}
  • 에러 메시지를 뷰에 표시하는 메서드 (아직 구현 안 됨).

 

✅ 요약

  • ChatController중간 제어자로서 View와 Service를 연결.
  • View 이벤트 → Controller 메서드 → Service 호출.
  • Service 이벤트 → Controller 메서드 → View 업데이트.
  • 귓속말 처리 시 이름을 ID로 변환하는 이유는 서버가 ID 기반으로 유저를 식별하기 때문.

 

 

 

 

메시지 전송/받기 이벤트 진행 과정

1. [Controller → ChatService]

chatService.initialize(userId, this::handleIncomingMessage)

💡 Controller의 handleIncomingMessage() 메서드를 ChatService에 등록

 

2. [Controller → UserStateService]

userStateService.setUserListListener(this::handleUserListUpdate)

💡 Controller의 handleUserListUpdate() 메서드를 UserStateService에 등록

 

 

3. [Controller → View]
view.setOnSendMessage(this::onSendButtonClick)
💡 Controller의 onSendButtonClick() 메서드를 View에 등록

 

 

4. [ChatService → Network]
networkService.connect(url, this::onConnected, this::onError)
networkService.connect(url, this::onConnected, this::onError)
💡 ChatService의 onConnected() 메서드를 Network에 등록

 

5. [ChatService (onConnected 실행됨)]
networkService.subscribe("/topic/public", this::handlePublicMessage)
💡 ChatService의 handlePublicMessage() 메서드를 구독 핸들러로 등록

 

 

📌 이벤트 흐름 단계별 설명

1. 구독(Subscribe) 등록

networkService.subscribe("/topic/public", this::handlePublicMessage);
  • 클라이언트가 특정 채널(/topic/public)을 구독합니다.
  • 이때 this::handlePublicMessage라는 콜백 함수를 등록합니다.
  • 의미: "이 채널에서 메시지가 오면 handlePublicMessage를 실행해라."

2. 서버에서 메시지 발행(Publish)

  • 다른 사용자가 메시지를 보내면 서버(STOMP broker)가 해당 채널에 메시지를 발행합니다.
  • 예: /topic/public으로 JSON 메시지 전송.

3. 클라이언트가 메시지 수신

  • STOMP 클라이언트(StompSession)는 구독한 채널을 계속 듣고 있습니다.
  • 메시지가 도착하면 내부적으로 이벤트가 발생합니다.
  • NetworkService 구현체(StompNetworkService)가 이 이벤트를 감지하고, 등록된 콜백을 호출합니다.

 

=> 네트워크에서 구독해놓고, 그 경로로 메시지 들어오면 실행할 함수(chat서비스 함수)를 등록해준다. 

들어오면 해당 서비스 함수에서 이벤트에 있는 함수들을 실행하여(controller에서 등록) view에 update.