SpringBoot 통합 웹 소켓 전후 단 메시지 전달 방법
10488 단어 SpringBootWebSocket소식 이 서로 전하 다.
웹 소켓 프로 토 콜 은 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") ;
전단 으로 데이터 전송:클 라 이언 트 도 메 시 지 를 받 았 습 니 다.
먼저 페이지 를 열 고 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 을 주입 하 는 코드 를 주석 해 야 합 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
【Java・SpringBoot・Thymeleaf】 에러 메세지를 구현(SpringBoot 어플리케이션 실천편 3)로그인하여 사용자 목록을 표시하는 응용 프로그램을 만들고, Spring에서의 개발에 대해 공부하겠습니다 🌟 마지막 데이터 바인딩에 계속 바인딩 실패 시 오류 메시지를 구현합니다. 마지막 기사🌟 src/main/res...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.