웹소켓

[웹소켓] @EntityListeners를 이용해서 실시간 정보 업데이트

JinhaakM 2024. 6. 26. 10:57

프로젝트를 끝내기 전에 꼭 해보고 싶은 게 있었다. 웹소켓을 이용해서 실시간으로 바뀌는 시스템을 만들어보는 것. 실시간으로 주식 가격이 바뀌듯이, 음식을 주문하면 실시간으로 라이더의 위치를 알 수 있듯이 말이다. 나는 아주 단순하게 유저가 서울로의 여행계획을 작성하고 저장했을 때, 다른 유저의 화면에서 실시간으로 서울로 여행하고자하는 여행객이 +N 증가됐다는 알림? 정보 전달 기능을 구현하고자 한다.

 

@EntityListeners(MyEntityListener.class)
public class PlanVO {
	
	@Id
	@GeneratedValue(
			strategy= GenerationType.SEQUENCE,
			generator= "plan_seq"
			)
	@Column(name= "plan_no", nullable = false)
	private int planNo;

 

이제 PlanVO의 변경 사항에 맞춰 추가적인 로직을 구현할 수 있다.

 

@Component
public class MyEntityListener {

    private static SocketHandler2 socketHandler2;
    
    @Autowired
    public void setSocketHandler2(SocketHandler2 socketHandler2) {
        MyEntityListener.socketHandler2 = socketHandler2;
    }
    

    @PostPersist
    //@PostUpdate
    public void onPostPersistOrUpdate(PlanVO p) {

        String message = "서울 여행객이 추가됩니다.";
        socketHandler2.broadcast(message);
    }
}

 

  • @PrePersist: 엔티티가 영속성 컨텍스트에 저장되기 전에 호출
  • @PostPersist: 엔티티가 영속성 컨텍스트에 저장된 후에 호출
  • @PreUpdate: 엔티티의 데이터가 데이터베이스에 업데이트되기 전에 호출
  • @PostUpdate: 엔티티의 데이터가 데이터베이스에 업데이트된 후에 호출
  • @PreRemove: 엔티티가 데이터베이스에서 삭제되기 전에 호출
  • @PostRemove: 엔티티가 데이터베이스에서 삭제된 후에 호출
  • @PostLoad: 엔티티가 데이터베이스에서 로드된 후에 호출

 

@Component
public class SocketHandler2 extends TextWebSocketHandler {

    private static Set<WebSocketSession> clients = Collections.synchronizedSet(new HashSet<>());
    private static int seoulTravelerCount = 0; 
       
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        clients.add(session);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
    	seoulTravelerCount = 0; 
        clients.remove(session);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
    }

    
    public void broadcast(String message) {
        synchronized (clients) {
            seoulTravelerCount++;
            String messageWithCount = message + seoulTravelerCount;

            for (WebSocketSession client : clients) {
                try {
                    client.sendMessage(new TextMessage(messageWithCount));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}​

 

이제 전달받은 메시지와 함께 실시간으로 추가되는 서울 여행객 수를 업데이트 한다. 웹소켓이 종료되기전까지, 그니까 유저가 페이지를 새로고침하거나 해당 페이지를 나가기 전까지는 수를 고정. 만약 웹소켓이 종료된다면 추가적인 서울 여행객 수는 다시 0부터 시작.

 

 

여행 계획을 저장했을 때 수를 업데이트 하는 단순한 로직이 완성된다. 실제로 운영되는 서버였다면 현재 날짜에 여행 중인 여행객의 수를 표시하는 게 더 효과적이라고 생각한다. 또한 여행객 수에 비례해 도시 위로 원? 같은 도형을 표시한다면 시각적으로도 훌륭한 페이지가 완성될 것 같다. 

 

실시간으로 정보를 업데이트하고자 하는 생각이 들었고, 그렇다면 실시간으로 DB의 변동 사항을 확인할 수 있어야 했기에 자연스레 @EntityListeners에 대해 알게 된 기능 구현 후기다. 

* 여행객이 추가되는 메시지와 함께 숫자가 업데이트 되는 기능은 가능하지만 그에 맞춰 현재 서울 여행객 45 숫자는 업데이트가 되지 않는다는 문제가 남아 있다. 물론 새로고침하면 46으로 증가한다. 누군가는 실시간으로 증가되는 숫자를 굳이 현재 여행객 수에 반영하지 않아도 된다고하지만, 나는 반영이 되는 게 맞다고 생각하기도 하고, 무엇보다 구현 자체를 하고 싶은 이유도 있다. 현재 서울 여행객을 구하는 로직(이건 웹소켓을 이용하지 않았다...)과 실시간으로 추가되는 여행객 수를 업데이트 해주는 웹소켓 로직이 따로 관리되기 때문에 현재 여행객 수를 실시간으로 업데이트 해줄 수가 없다... 그래서 각 여행지마다의 여행객 수만 관리하는 클래스를 따로 만들어 웹소켓과 연결해준다면 현재 여행객과 추가되는 여행객을 한 번에 관리할 수 있지 않을까 조심스레 예상해본다... 구현해보고 다시 글을 써야겠다.