Spring boot + React로 간단한 채팅방 제작하기

600g (Kim Dong Geun)·2020년 4월 14일

프로젝트 제작 동기

Node로만 소켓 통신을 사용해오다가, Spring boot를 통해서 간단한 소켓 통신을 해보면 어떨까 생각 해봤다.

프로젝트 구성

Spring Boot + SockJS + Stomp

SockJS : WebSocket과 유사한 객체를 생성해주는 라이브러리,
웹소켓을 형성하거나 웹소켓을 지원하지 않을 경우에는, Long 폴링 방식(확실하지 않음)을 통해서 소켓 통신을 구현.

Stomp : Simple (or Streaming) Text Orientated Messaging Protocol의 약자로써, 메시지로 소켓 통신을 구현하는 경우 좀 더 효율적으로 구성을 할 수 있게 해준다.

프로젝트 내용

  • SocketConfig.java
@Configuration
@EnableWebSocketMessageBroker
public class SocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/webSocket")
                .setAllowedOrigins("http://localhost:3000")
                .withSockJS();
    }
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic","/queue");
        registry.setApplicationDestinationPrefixes("/");
    }
}

WebSocketMessageBrokerConfigurer를 implements 해서 소켓 통신에 대한 설정을 구현한다.
한가지 흥미로운 점은 아무래도 리액트와 구현을 하다보니 proxy서버를 구성하지 않는 이상, cross origin이 프론트 단에서 발생할 수 밖에 없다.

그래서 처음에는 WebMvcConfig 부분에서 setAllowedOrgins를 설정해주면 되겠지라고 생각했는데, 소켓은 registerStompEndpoints 메소드에서 설정해줘야 한다는 점

만약 Cross Origin 문제가 발생한다면 참고 바람.

  • Message.java
@Getter
@Setter
public class Message {

    private String username;
    private String content;
    private Date date;

    public Message(String username, String content, Date date) {
        this.username = username;
        this.content = content;
        this.date = date;
    }

}

Lombok을 이용해서 데이터 송/수신을 받을 객체를 Model로 작성한다.

  • ChatController.java
@RestController
public class ChatController {


    @MessageMapping("/hello")
    @SendTo("/topic/roomId")
    public Message boradCast(Message message){
        return message;
    }
}

나머지는 전처리 해준대로 설정하고 프론트 단에서 다음과 같은 코드를 작성해준다.
sendTo를 통해서 구독한 client에게 리턴 값을 전송하고
hello를통해서 사용자로부터 소켓 메시지를 받을 수 있다.

  • ChatContainer.tsx
export type message = {
  username: string;
  content: string;
};

let sockJS = new SockJS("http://localhost:8080/webSocket");
let stompClient : Stomp.Client = Stomp.over(sockJS);
stompClient.debug= () => {};

export const ChatContainer = ({}) => {
  const [contents, setContents] = React.useState<message[]>([]);
  const [username, setUsername] = React.useState('');
  const [message, setMessage] = React.useState("");

  useEffect(()=>{
    stompClient.connect({},()=>{
      stompClient.subscribe('/topic/roomId',(data)=>{
        const newMessage : message = JSON.parse(data.body) as message;
        addMessage(newMessage);
      });
  });
  },[contents]);
  
  const handleEnter = (username: string, content: string) => {
    const newMessage: message = { username, content };
    stompClient.send("/hello",{},JSON.stringify(newMessage));
    setMessage("");
  };

  const addMessage = (message : message) =>{
    setContents(prev=>[...prev, message]);
  };

  return (
    <div className={"container"}>
      <ChatPresenter
        contents={contents}
        handleEnter={handleEnter}
        message={message}
        setMessage={setMessage}
        username={username}
        setUsername={setUsername}
      />
    </div>
  );
};

stompClient객체를 초기화 해준뒤에, Controller에서 제공하는 경로와 request형식에 맞게 보낸다면,
통신이 가능한 간단한 채팅창을 만들 수 있게 된다.
프론트, 백엔드 소스는 여기서 확인할 수 있다.

깃허브 레포지토리 주소

https://github.com/ehdrms2034/SpringBootChatting
에서 간단한 소스를 볼 수 있다.

profile
수동적인 과신과 행운이 아닌, 능동적인 노력과 치열함

0개의 댓글