본문 바로가기

기록하기

실시간 채팅 구현하기 (1)

@Slf4j
@RequiredArgsConstructor
@Order(Ordered.HIGHEST_PRECEDENCE + 99)
public class FilterChannelInterceptor implements ChannelInterceptor {

    private final JwtUtil jwtUtil;

    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {

        StompHeaderAccessor headerAccessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
        assert headerAccessor != null;

        if (headerAccessor.getCommand() == StompCommand.CONNECT) {
            String token = headerAccessor.getFirstNativeHeader("Authorization");

            if (token != null) {
                try {
                    if (jwtUtil.validateToken(token)) {
                        String userEmail = jwtUtil.getUserEmailFromToken(token);
                        headerAccessor.addNativeHeader("User", userEmail);
                    }

                } catch (BaseException e) {
                    log.error("토큰 검증 중 오류 발생: {}", e.getMessage());
                }
            }
        }

        return message;
    }
}

 

@Configuration
@EnableWebSocketMessageBroker
public class WebSockConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/sub");
        config.setApplicationDestinationPrefixes("/pub");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").setAllowedOriginPatterns("*");
                //.withSockJS();
    }

    @Bean
    public FilterChannelInterceptor filterChannelInterceptor(JwtUtil jwtUtil) {
        return new FilterChannelInterceptor(jwtUtil);
    }

}

 

@Component
@RequiredArgsConstructor
public class WebSocketEventListener {

    private final RedisTemplate<String, String> redisTemplate;
    private final JwtUtil jwtUtil;

    @EventListener
    public void handleWebSocketConnectListener(SessionConnectEvent event) {

        StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
        String sessionId = headerAccessor.getSessionId();
        String token = headerAccessor.getFirstNativeHeader(JwtUtil.AUTHORIZATION_HEADER);

        if (token != null && jwtUtil.validateToken(token)) {
            String userEmail = jwtUtil.getUserEmailFromToken(token);

            // 세션 ID와 사용자 이메일만 저장
            redisTemplate.opsForValue().set("websocket_session:" + sessionId, userEmail);
        }
    }

    @EventListener
    public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {

        String sessionId = event.getSessionId();
        redisTemplate.delete("websocket_session:" + sessionId);
    }

}

 

  • 계속 수정중이긴하는데, 기본 채팅기능 동작을 확인하고 정리하는 블로그 포스팅
  • 처음에는 stompHandler를 사용해서 커넥트를 관리했었는데, 뭐가 문제인지 연결 조차안됨
  • 수정의 수정의 수정의.... 무한수정을 거쳐 일단 고정시켜둔 websocket 관련 설정 클래스들
  • 레디스에 세션을 이메일로 저장하기 때문에 레디스관련 코드를 추가
    • 생각보다 레디스에 저장하는게 많음...
    • 세션(+이메일), 특정방에 들어가있는 유저의 이메일, 유저카운트(이건 아직 수정이 필요함), 리프레시토큰, 채팅방목록, 채팅방 채팅메세지 등... 생각보다 여기저기 쓰이고 있어서 이것도 한번쯤 정리가 필요할듯

'기록하기' 카테고리의 다른 글

마이페이지 관련 문제  (1) 2024.01.02
샵 관련 문제  (1) 2024.01.02
기술 선택의 이유 정리하기 (1)  (0) 2023.12.18
Dependencies [1차 정리]  (0) 2023.12.18
AWS EC2 Ubuntu Docker 실행하기  (0) 2023.12.10