SpringBoot 통합 웹 소켓 전후 단 메시지 전달 방법

웹 소켓 이란 무엇 입 니까?
웹 소켓 프로 토 콜 은 TCP 를 기반 으로 한 새로운 네트워크 프로 토 콜 입 니 다.이 는 브 라 우 저 와 서버 의 모든 양 방향(full-duplex)통신 을 실현 하여 서버 가 자발적으로 클 라 이언 트 에 정 보 를 보 낼 수 있 도록 합 니 다.
 
왜 WebSocket 이 필요 합 니까?
예전 에 클 라 이언 트 가 서버 의 처리 진 도 를 알 고 싶 어 하 는 것 을 잘 알 고 있 습 니 다.끊임없이 Ajax 를 사용 하여 폴 링 을 하고 브 라 우 저 로 하여 금 몇 초 간격 으로 서버 에 요청 을 하 게 하 는 것 은 서버 에 큰 부담 이 되 었 습 니 다.또 다른 폴 링 은 롱 폴 방식 을 사용 하 는 것 이다.이것 은 전화 하 는 것 과 차이 가 많 지 않 고 소식 을 받 지 못 하면 전 화 를 끊 지 않 는 다.즉,클 라 이언 트 가 연결 을 시작 한 후에 소식 이 없 으 면 response 를 클 라 이언 트 에 게 되 돌려 주지 않 고 연결 단 계 는 계속 막 힌 것 이다.
웹 소켓 은 HTTP 의 이 몇 가지 어 려 운 문 제 를 해결 했다.서버 가 프로 토 콜 업 그 레이 드 를 마 친 후(HTTP->WebSocket)서버 는 클 라 이언 트 에 게 자발적으로 정 보 를 전송 하여 폴 링 으로 인 한 동기 지연 문 제 를 해결 할 수 있 습 니 다.웹 소켓 은 HTTP 악 수 를 한 번 만 하면 서버 가 연결 을 닫 을 때 까지 클 라 이언 트 와 계속 통신 할 수 있 기 때문에 서버 가 HTTP 프로 토 콜 을 반복 적 으로 분석 해 야 하기 때문에 자원 의 비용 을 줄 일 수 있다.

현재 SpringBoot 통합 웹 소켓 을 통 해 전후 단 통신 을 실현 하고 있 습 니 다.
통합 웹 소켓 전후 단 통신 실현
프로젝트 코드 구성 도
 
가 져 오기 의존
SpringBoot 2.0 웹 소켓 에 대한 지원 은 정말 훌륭 합 니 다.바로 가방 이 들 어 올 수 있 습 니 다.

<dependency> 
	<groupId>org.springframework.boot</groupId> 
	<artifactId>spring-boot-starter-websocket</artifactId> 
</dependency> 
WebSocketConfig 설정
웹 소켓 지원 을 사용 하 는 것 도 간단 합 니 다.ServerEndpoint Exporter 대상 을 용기 에 주입 합 니 다.

package com.tuhu.websocketsample.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
  @Bean
  public ServerEndpointExporter serverEndpointExporter() {
    return new ServerEndpointExporter();
  }
}
WebSocket 서버 WebSocket Server
웹 소켓 은 클 라 이언 트 서버 와 유사 한 형식(ws 프로 토 콜 사용)이기 때문에 이곳 의 웹 소켓 서버 는 사실상 ws 프로 토 콜 의 Controller 에 해당 한다.직접@ServerEndpoint("/websocket"),@Component 를 사용 하면 됩 니 다.그 다음 에 안에서@OnOpen,@onClose,@onMessage 등 방법 을 실현 합 니 다.

package com.tuhu.websocketsample.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;

@Component
@ServerEndpoint("/websocket/{sid}")
@Slf4j
public class WebSocketServer {

  /**
   *     ,           。            。
   */
  private static int onlineCount = 0;
  /**
   * concurrent      Set,            MyWebSocket  。
   */
  private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();
  /**
   *            ,              
   */
  private Session session;
  /**
   *   sid
   */
  private String sid="";
  /**
   *            
   **/
  @OnOpen
  public void onOpen(Session session,@PathParam("sid") String sid) {
    this.session = session;
    //  set 
    webSocketSet.add(this);
    //    1
    addOnlineCount();
    log.info("        :"+sid+",       " + getOnlineCount());
    this.sid=sid;
    try {
      sendMessage("    ");
    } catch (IOException e) {
      log.error("websocket IO  ");
    }
  }
  /**
   *          
   */
  @OnClose
  public void onClose() {
    // set   
    webSocketSet.remove(this);
    //    1
    subOnlineCount();
    log.info("      !       " + getOnlineCount());
  }
  /**
   *              
   * @param message           
   **/
  @OnMessage
  public void onMessage(String message, Session session) {
    log.info("      "+sid+"   :"+message);
    //    
    for (WebSocketServer item : webSocketSet) {
      try {
        item.sendMessage(message);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  /**
   * @param session
   * @param error
   */
  @OnError
  public void onError(Session session, Throwable error) {
    log.error("    ");
    error.printStackTrace();
  }
  /**
   *          
   */
  public void sendMessage(String message) throws IOException {
    this.session.getBasicRemote().sendText(message);
  }
  /**
   *        
   * */
  public static void sendInfo(String message,@PathParam("sid") String sid) throws IOException {
    log.info("       "+sid+",    :"+message);
    for (WebSocketServer item : webSocketSet) {
      try {
        //            sid , null     
        if(sid==null) {
          item.sendMessage(message);
        }else if(item.sid.equals(sid)){
          item.sendMessage(message);
        }
      } catch (IOException e) {
        continue;
      }
    }
  }
  public static synchronized int getOnlineCount() {
    return onlineCount;
  }
  public static synchronized void addOnlineCount() {
    WebSocketServer.onlineCount++;
  }
  public static synchronized void subOnlineCount() {
    WebSocketServer.onlineCount--;
  }
}
메시지 푸 시
새로운 정 보 를 푸 시 하 는 것 에 대해 서 는 자신의 Controller 에 방법 을 써 서 WebSocketServer.sendInfo()를 호출 하면 됩 니 다.

package com.tuhu.websocketsample.controller;

import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.io.IOException;

@RestController
@RequestMapping("/checkcenter")
public class CheckCenterController {
  /**
   *     
   * @param cid
   * @return
   */
  @GetMapping("/socket/{cid}")
  public ModelAndView socket(@PathVariable String cid) {
    ModelAndView mav=new ModelAndView("/socket");
    mav.addObject("cid", cid);
    return mav;
  }
  /**
   *       
   * @param cid
   * @param message
   * @return
   */
  @ResponseBody
  @RequestMapping("/socket/push/{cid}")
  public String pushToWeb(@PathVariable String cid,String message) {
    try {
      WebSocketServer.sendInfo(message,cid);
    } catch (IOException e) {
      e.printStackTrace();
      return "error:"+cid+"#"+e.getMessage();
    }
    return "success:"+cid;
  }

}
페이지 소켓 요청
그리고 페이지 에서 js 코드 로 socket 을 호출 합 니 다.물론 너무 오래된 브 라 우 저 는 안 됩 니 다.보통 새로운 브 라 우 저 나 구 글 브 라 우 저 는 문제 가 없습니다.또 하 나 는 합의 가 ws 였 던 것 으로 기억 합 니 다.브 라 우 저 콘 솔 에서 직접 연결 을 엽 니 다.

var socket; 
  if(typeof(WebSocket) == "undefined") { 
    console.log("        WebSocket"); 
  }else{ 
    console.log("       WebSocket"); 
    	//   WebSocket  ,                   
      socket = new WebSocket("ws://localhost:8080/websocket/20"); 
      //    
      socket.onopen = function() { 
        console.log("Socket    "); 
        //socket.send("          " + location.href + new Date());
      }; 
      //      
      socket.onmessage = function(msg) { 
        console.log(msg.data); 
        //                  
      }; 
      //    
      socket.onclose = function() { 
        console.log("Socket   "); 
      }; 
      //       
      socket.onerror = function() { 
        alert("Socket     "); 
        //          
      } 
      //     ,  socket
      //jquery1.8      ,3.0     
      // $(window).unload(function(){
      //   socket.close();
      //});
  }
실행 효과
현재 브 라 우 저 에서 연결 을 열 수 있 습 니 다.클 라 이언 트 를 통 해 인터페이스 서버 를 호출 하면 브 라 우 저 에 메 시 지 를 보 낼 수 있 습 니 다.
현재 두 페이지 를 열 고 두 개의 연결 을 엽 니 다:

socket = new WebSocket("ws://localhost:8080/websocket/20") ; 

socket = new WebSocket("ws://localhost:8080/websocket/22") ;
전단 으로 데이터 전송:
  • http://localhost:8080/checkcenter/socket/push/20?message=Hello
  • http://localhost:8080/checkcenter/socket/push/22?message=HelloWorld
  • 서버 에서 클 라 이언 트 에 게 메 시 지 를 보 낸 것 을 볼 수 있 습 니 다.

    클 라 이언 트 도 메 시 지 를 받 았 습 니 다.
     

    먼저 페이지 를 열 고 cid 를 지정 합 니 다.socket 수신 을 사용 한 다음 다른 페이지 에서 방금 Controller 가 봉 인 된 푸 시 메 시 지 를 이 cid 의 socket 으로 호출 하면 전단 에 메 시 지 를 푸 시 할 수 있 습 니 다.
    후속
    server Endpoint Exporter 오류
    
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘serverEndpointExporter' defined in class path resource [com/xxx/WebSocketConfig.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available
    tomcat 배치 가 계속 이 오 류 를 보고 하면 WebSocketConfig 에서@Bean ServerEndpoint Exporter 의 주입 을 제거 하 십시오.
    ServerEndpoint Exporter 는 Spring 이 공식 적 으로 제공 하 는 표준 으로 이 루어 졌 으 며,ServerEndpoint Config 설정 클래스 와@ServerEndpoint 주석 인 스 턴 스 를 검색 하 는 데 사 용 됩 니 다.사용 규칙 도 간단 하 다.
    1.Tomcat 와 같은 기본 내장 용 기 를 사용 하려 면 컨 텍스트 에 ServerEndpoint Exporter 를 수 동 으로 제공 해 야 합 니 다.
    2.외부 용 기 를 사용 하여 war 패 키 지 를 배치 하면 ServerEndpoint Exporter 를 제공 할 필요 가 없습니다.이 때 SpringBoot 는 기본적으로 서버 를 스 캔 하 는 행 위 를 외부 용기 에 맡 기 므 로 온라인 으로 배치 할 때 WebSocketConfig 에 bean 을 주입 하 는 코드 를 주석 해 야 합 니 다.
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기