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

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

프로젝트 제작 동기

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개의 댓글