1. 程式人生 > 程式設計 >spring boot websocket 實時訊息推送和資料展示

spring boot websocket 實時訊息推送和資料展示

一、實現目標

  • 1、線上聊天,客服聊天,聊天室
  • 2、業務資料實時展示,自動更新

二、實踐步驟

以下是為了實現:業務資料實時展示,自動更新

1. Maven引入

<dependency>  
   <groupId>org.springframework.boot</groupId>  
   <artifactId>spring-boot-starter-websocket</artifactId>  
</dependency> 
複製程式碼

2. 建立配置檔案

WebSocketConfig

/**
 * 開啟WebSocket支援
 * @author
zhengkai */
@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } 複製程式碼

3. 建立服務端

@ServerEndpoint(value = "/websocket")
@Component
public class WebSocketServer {

    private final Logger log = LoggerFactory.getLogger(this
.getClass()); //concurrent包的執行緒安全Set,用來存放每個客戶端對應的MyWebSocket物件。 private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>(); //與某個客戶端的連線會話,需要通過它來給客戶端傳送資料 private Session session; /** * 連線建立成功呼叫的方法 */ @OnOpen
public void onOpen(Session session) { this.session = session; webSocketSet.add(this); sendMessage("連線成功"); } /** * 連線關閉呼叫的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); log.info("有一連線關閉!"); } /** * 收到客戶端訊息後呼叫的方法 * * @param queryType 客戶端傳送過來的訊息 */ @OnMessage public void onMessage(String queryType) { log.info("收到資訊:" + queryType); //群發訊息 for (WebSocketServer item : webSocketSet) { item.sendMessage("hello"); } } /** * @param session * @param error */ @OnError public void onError(Session session,Throwable error) { log.error("發生錯誤"); error.printStackTrace(); } /** * 實現伺服器主動推送 */ public void sendMessage(Object message) { try { this.session.getBasicRemote().sendText(JSON.toJSONString(message)); } catch (IOException e) { e.printStackTrace(); } } /** * 實現伺服器主動群發訊息 */ public static void sendInfo(Object message) { for (WebSocketServer item : webSocketSet) { item.sendMessage(message); } } } 複製程式碼

4. 前端發起websocket請求

  <script> 
    var socket;  
    if(typeof(WebSocket) == "undefined") {  
        console.log("您的瀏覽器不支援WebSocket");  
    }else{  
        console.log("您的瀏覽器支援WebSocket");  
        	//實現化WebSocket物件,指定要連線的伺服器地址與埠  建立連線  
            socket = new WebSocket("ws://localhost:8080/webscoket");
            //開啟事件  
            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發生了錯誤");  
                //此時可以嘗試重新整理頁面
            } 
    }
    </script> 
複製程式碼

三、實踐中會遇到的問題

1. 前端發起websocket請求,卻無法連線websocket

  • 錯誤一:被許可權攔截,例如spring security 解決方式:放開許可權或允許訪問
// spring security
.antMatchers(
    "/websocket"
    )
.permitAll()

複製程式碼
  • 錯誤二:請求的websocket地址錯誤
@ServerEndpoint(value = "/websocket")

對應的地址是:ws://localhost:8080/webscoket
複製程式碼
  • 錯誤三:被AOP攔截
@Pointcut("execution(public * com.xxx.xxx.controller..*(..))")
public void webLog() {
}
複製程式碼

解決辦法

// 排除攔截
@Pointcut("execution(public * com.xxx.xxx.controller..*(..)) && !execution(public * com.xxx.xxx.controller.xxx*(..))")
public void webLog() {
}
複製程式碼

2. 在WebSocketServer中,無法注入Bean,無法使用@Autowired

即你按如下方式直接使用@Autowired,會報錯

@ServerEndpoint(value = "/websocket")
@Component
public class WebSocketServer {
    @Autowired
    ChartDataService chartDataService;
}
複製程式碼

在WebSocket中, 因 SpringBoot+WebSocket 對每個客戶端連線都會建立一個 WebSocketServer(@ServerEndpoint 註解對應的) 物件,Bean 注入操作會被直接略過,因而手動注入一個全域性變數(即你需要注入的bean)

@Configuration
public class WebSocketConfig {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

    // 在這裡注入你需要的bean
    @Autowired
    public void setMessageService(ChartDataService chartDataService) {
        WebSocketServer.chartDataService = chartDataService;
        // ...
    }
}

複製程式碼

使用你注入的bean

@ServerEndpoint(value = "/websocket")
@Component
public class WebSocketServer {

    public static ChartDataService chartDataService;

複製程式碼

此方式經實踐,有效

其他解決方式: stackoverflow.com/questions/2…

  • 1.使用@Inject
@ServerEndpoint("/ws")
public class MyWebSocket {   
    @Inject
    private ObjectMapper objectMapper;
}
複製程式碼
  • 2.使用SpringConfigurator
@ServerEndpoint(value = "/ws",configurator = SpringConfigurator.class)
複製程式碼
  • 3.使用@PostConstruct
@PostConstruct
public void init(){
    SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
複製程式碼

經過實踐,上述三種方式,對於我而言,均無效

參考連結:blog.csdn.net/moshowgame/…