본문 바로가기
개발/Spring

[SpringBoot] WebSocket 채팅방 구현(2) - WebSocketConfig

by 코딩하는 흰둥이 2024. 8. 17.
  • Java 로 구현

WebSocketConfig
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;


@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    private final WebSocketHandler webSocketHandler;

    private final WebSocketWidgetHandler webSocketWidgetHandler;

    public WebSocketConfig(WebSocketHandler webSocketHandler, WebSocketWidgetHandler webSocketWidgetHandler){
        this.webSocketHandler = webSocketHandler;
        this.webSocketWidgetHandler = webSocketWidgetHandler;
    }

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // 채팅방 웹소켓
        registry.addHandler(webSocketHandler, "/ws/chat/{roomNumber}").setAllowedOrigins("*");

        // top.html , 채팅방 목록 페이지에 적용
        registry.addHandler(webSocketWidgetHandler, "/ws/widget/{username}").setAllowedOrigins("*");
    }
}

 

 

WebSocketHandler - 채팅방 웹소켓
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Component
public class WebSocketHandler extends TextWebSocketHandler {

    // 접속중인 유저의 session 및 채팅방 정보를 담기위한 변수
    List<HashMap<String, Object>> rls = new ArrayList<>();

    // 메시지 send 할 때 동작
    protected void handleTextMessage(WebSocketSession session , TextMessage message) throws Exception{
        // 사용자가 전송한 데이터를 JSON 으로 변경
        String payload = message.getPayload();
        JSONObject obj = jsonToObjectParser(payload);

        // 대화중인 채팅방 ID
        String rN = String.valueOf(obj.get("roomId"));

        // 같은 채팅방에 접속 중인 유저를 찾는다
        HashMap<String, Object> temp = new HashMap<>();
        if(rls.size() > 0){
            for (int i = 0; i < rls.size(); i++) {
                String roomId = (String) rls.get(i).get("roomId");
                if(roomId.equals(rN)){

                    // session 정보를 담는다
                    temp = rls.get(i);
                    break;
                }
            }

            for(String key : temp.keySet()){
                if(key.equals("roomId")){
                    continue;
                }
                WebSocketSession wss = (WebSocketSession) temp.get(key);
                if(wss != null){
                    try {
                        // 담은 session 정보가 null 이 아니라면 전달한다
                        wss.sendMessage(new TextMessage(obj.toJSONString()));
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    // client 접속
    public void afterConnectionEstablished(WebSocketSession session) throws Exception{

        super.afterConnectionEstablished(session);
        // 접속정보가 있는지 확인하기 위한 변수
        boolean flag = false;

        String url = session.getUri().toString();

        // 접속한 채팅방 id
        String roomId = url.split("/ws/chat/")[1];

        int idx = rls.size();
        if(rls.size() > 0){
            for (int i = 0; i < rls.size(); i++) {
                // 접속정보가 있는 채팅방이 있는지 확인
                String rN = (String) rls.get(i).get("roomId");
                if (rN.equals(roomId)){
                    flag = true;
                    idx = i;
                    break;
                }
            }
        }

        if(flag){
            // 자신의 session 정보를 넣는다
            HashMap<String, Object> map = rls.get(idx);
            map.put(session.getId(), session);
        }else{
            // session이 없는 방이라면 방id 와 자신의 session 정보를 넣는다
            HashMap<String, Object> map = new HashMap<>();
            map.put("roomId", roomId);
            map.put(session.getId(), session);
            rls.add(map);
        }

//         //websocket에 접속할때 session 정보가 필요하다면 사용
//        JSONObject obj = new JSONObject();
//        obj.put("type", "getId");
//        obj.put("sessionId", session.getId());
////        session.sendMessage(new TextMessage(obj.toJSONString()));
//        session.sendMessage(new TextMessage(session.getId()));
        System.err.println(session + " client 접속");
    }

    // client 접속 해제
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception{
        System.err.println(session + "client 접속 해제");

        if(rls.size() > 0){
            for (int i = 0; i < rls.size(); i++) {
                rls.get(i).remove(session.getId());
            }
        }
        super.afterConnectionClosed(session, status);
    }


    // send 로 전달한 메세지 변환
    private static JSONObject jsonToObjectParser(String jsonStr) {
        JSONParser parser = new JSONParser();
        JSONObject obj = null;
        try {
            obj = (JSONObject) parser.parse(jsonStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return obj;
    }
}

 

 

WebSocketWidgetHandler - widget 용 웹소켓
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

@Component
public class WebSocketWidgetHandler extends TextWebSocketHandler {

    // 접속중인 유저의 session 및 채팅방 정보를 담기위한 변수
    List<HashMap<String, Object>> rls = new ArrayList<>();

    // 메시지 send 할 때 동작
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 사용자가 전송한 데이터를 JSON 으로 변경
        String payload = message.getPayload();
        JSONObject obj = jsonToObjectParser(payload);

        // 메시지를 받는 상대방 id
        String id = String.valueOf(obj.get("userId"));

        // 상대방 id를 가지고 session 정보를 찾아 담기 위한 변수
        HashMap<String, Object> temp = new HashMap<>();
        if (rls.size() > 0) {
            for (int i = 0; i < rls.size(); i++) {
                HashMap<String, Object> sessionId = rls.get(i);

                if (sessionId.size() > 1 && sessionId.get("userId").equals(id)) {
                    // sessionId가 실제로 WebSocketSession 객체인지 확인
                    temp = sessionId;
                    temp.put("userId", id);
                    break;
                }
            }
        }

        for (String key : temp.keySet()) {
            if (key.equals("userId")) {
                continue;
            }
            WebSocketSession wss = (WebSocketSession) temp.get(key);
            if (wss != null) {
                try {
                    wss.sendMessage(new TextMessage(obj.toJSONString()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

}

    // client 접속
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {

        super.afterConnectionEstablished(session);
        boolean flag = false;
        String url = session.getUri().toString();
        String userId = url.split("/ws/widget/")[1];
        int idx = rls.size();
        if (rls.size() > 0) {
            for (int i = 0; i < rls.size(); i++) {
                String id = (String) rls.get(i).get(i);
                if (id != null && id.equals(session.getId())) {
                    flag = true;
                    idx = i;
                    break;
                }
            }
        }

        if (flag) {
            HashMap<String, Object> map = rls.get(idx);
            map.put(session.getId(), session);
        } else {
            HashMap<String, Object> map = new HashMap<>();
            map.put(session.getId(), session);
            map.put("userId", userId);
            rls.add(map);
        }

        System.err.println("client 접속");
    }

    // client 접속 해제
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        System.err.println(session + "client 접속 해제");

        if (rls.size() > 0) {
            for (int i = 0; i < rls.size(); i++) {

                // session.getId() 와 userId 를 정보를 가져와서 현재 자신의 sessionId 와 비교하여 삭제한다
                Set[] test = new Set[]{rls.get(i).keySet()};
                if(test[0].size() > 1 && test[0].toArray()[0].equals(session.getId())){
                    rls.remove(i);
                }

            }
        }
        super.afterConnectionClosed(session, status);
    }

    // send 로 전달한 메세지 변환
    private static JSONObject jsonToObjectParser(String jsonStr) {
        JSONParser parser = new JSONParser();
        JSONObject obj = null;
        try {
            obj = (JSONObject) parser.parse(jsonStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return obj;
    }

}

 

 


WebSocketHandler 은 채팅방 접속 시 연결되고,

WebSocketWidgetHandler 은 top.html 과 top.js 로 인하여 모든 페이지에서 동작 하게 된다

댓글