All Articles

Redis Publish/Subscribe

chatting

채팅시작 → return room view

채팅 방 개설 또는 입장

채팅 방 개설 (chat/room/{room_name}

// room.ftl
createRoom: function() {
	var params = new URLSearchParams();
	axios.post('/chat/room', params)
// ChatController.java
@PostMapping("/room")
@ResponseBody
public ChatRoom createRoom(@RequestParam String name) {
    return chatService.createRoom(name);
}

채팅 방 입장 (chat/room/enter/{room_id} → return roomdetail view

  • Login 한 유저 정보로 token 생성
  • 유저가 입장한 채팅방에 들어오는 메시지를 계속 수신하고 있음
  • 유저가 입장한 내용을 입장한 채팅방에 발신, 이 때 생성한 토큰값 전달하여 유저 정보를 확인할 수 있도록 함
axios.get('/chat/user').then(response => {
    _this.token = response.data.token;
    ws.connect({"token":_this.token}, function(frame) {
				// 채팅방에 들어오는 메시지를 계속 수신
		    ws.subscribe("/subscribe/chat/room/" + _this.roomId, function(message) {
		    var recv = JSON.parse(message.body);
        _this.recvMessage(recv);
        });
				// 유저가 입장한 내용을 입장한 채팅방에 발신
        _this.**sendMessage**('ENTER');
    }
// 생성한 토큰값 전달하여 유저 정보를 확인
sendMessage: function(type) {
    ws.send("/publish/chat/message", {"token":this.token}, JSON.stringify({messageType:type, roomId:this.roomId, sender:this.sender, message:this.message}));
    this.message = '';
},

채팅 방 메시지 발신 (chat/message)

  • Publisher : 같은 주제를 구독하고 있는 구독자에 메시지를 publish
  • 입장 했을 때 호출
  • 메시지 전송 버튼 누를 때 호출
// publisher
    @MessageMapping("/chat/message")
    public void sendMessage(ChatMessage chatMessage, @Header("token") String token) {
        String nickname = jwtTokenProvider.getUserNameFromJwt(token);
        chatMessage.setSender(nickname);
        if (chatMessage.getMessageType().equals(MessageType.ENTER)) {
            chatMessage.setMessage(nickname + " 님이 입장하셨습니다.");
        }
        **redisTemplate.convertAndSend(channelTopic.getTopic(), chatMessage);**
    }

채팅 방 메시지 수신 (←redisTemplate.convertAndSend(channelTopic.getTopic(), chatMessage)

  • Subscribe : 메시지를 받으면 처리함
  • 메시지를 수신하고 있는 채팅방에 전송하는 역할을 빈으로 등록 (+ RedisSubscriber 객체)
class RedisConfig {
// ...
		@Bean
    public MessageListenerAdapter listenerAdapter(RedisSubscriber subscriber) {
        return new MessageListenerAdapter(subscriber, "sendMessage");
    }
//...
}
public class RedisSubscriber {
// ...
	public void sendMessage(String publishMessage) {
    try {
      ChatMessage chatMessage = objectMapper.readValue(publishMessage, ChatMessage.class);
	    messageSendingOperations.convertAndSend("/subscribe/chat/room/" + chatMessage.getRoomId(), chatMessage);
    } catch (Exception e) {
	  log.error("Exception {}", e);
	}
}
created() {
            this.roomId = localStorage.getItem('wschat.roomId');
            this.sender = localStorage.getItem('wschat.sender');
            this.findRoom();
            var _this = this;
            axios.get('/chat/user').then(response => {
                _this.token = response.data.token;
                ws.connect({"token":_this.token}, function(frame) {
                    ws.subscribe(" /subscribe/chat/room/" + _this.roomId, function(message) {
                        var recv = JSON.parse(message.body);
                        _this.recvMessage(recv);
                    });
                    _this.sendMessage('ENTER');
                }, function (error) {
                    alert("서버 연결에 실패했습니다. 다시 접속해 주세요.");
                    location.href="/chat/room";
                });
            });
        },

Reference

https://daddyprogrammer.org/post/5072/spring-websocket-chatting-server-spring-security-jwt/