【從0開始Web開發實戰】Spring Boot集成WebSocket,詳細代碼手把手操做

目錄:
css

一,Spring Boot集成WebSockethtml

二,聲明WebSocket服務,發送接收消息前端

三,JavaScript建立WebSocket客戶端java

四,增長SocketController,返回前端頁面jquery

五,Spring Boot集成TioWebSocketgit

六,常見問題和解決方法github


WebSocket是創建在TCP協議上的全雙工通訊鏈接。不一樣於HTTP只能有客戶端發送請求消息,WebSocket在客戶端和後臺服務創建鏈接後,雙方均可以主動發送實時消息。web

image.png

在不少業務場景下,後臺服務須要實時將數據推送到客戶端,好比代駕定位系統,司機客戶端定時發送位置信息到服務器,後臺管理系統頁面實時更新顯示,這時就要使用WebSocket數據推送方式,並且不增長服務器負載壓力。spring

image.png

項目下載:https://github.com/jextop/StarterApi瀏覽器

示例代碼:https://github.com/rickding/HelloJava/tree/master/HelloSocket



代碼文件

功能要點

Spring Boot集成WebSocket

pom.xml

引入WebSocket依賴spring-boot-starter-websocket

SocketConfig.java

配置Bean,啓動WebSocketServer

SocketServer.java

聲明WebSocket服務,接收和發送消息

JavaScript建立WebSocket客戶端

socket.html

在前端頁面中接收和發送消息

前端頁面

SocketController.java

返回前端頁面

一,Spring Boot集成WebSocket

1. 新建Spring Boot項目時,選中WebSocket,將自動添加依賴。

image.png

2. 已有Spring Boot項目,能夠在pom.xml中直接引用WebSocket Starter

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

3. 增長SocketConfig.java,啓動WebSocketServer

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

二,聲明WebSocket服務,接收和發送消息

1,增長SocketServer.java,聲明服務地址

2,聲明@OnMessage,接收消息

3,聲明@OnOpen,客戶端鏈接成功時,將session保存起來

4,聲明@OnClose,客戶端斷開鏈接時,將session信息刪除

5,封裝sendMessage()函數,經過session推送消息到客戶端

@ServerEndpoint("/ws/{uid}")
@Component
public class SocketServer {
    private static ConcurrentHashMap<String, SocketServer> webSocketMap = new ConcurrentHashMap<>();

    private Session session;
    private String uid;

    public static void sendMessage(String uid, String msg) {
        System.out.printf("Send message: %s, %s\n", uid, msg);
        if (StringUtils.isNotBlank(uid) && webSocketMap.containsKey(uid)) {
            webSocketMap.get(uid).sendMessage(msg);
        } else {
            System.err.printf("Offline: %s\n", uid);
        }
    }

    public void sendMessage(String msg) {
        try {
            session.getBasicRemote().sendText(msg);
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
    }

    @OnMessage
    public void onMessage(String msg, Session session) {
        System.out.printf("Receive message: %s, %s, %s\n", uid, session.getId(), msg);

        for (String uid : webSocketMap.keySet()) {
            sendMessage(uid, String.format("%s消息: %s", uid.equals(this.uid) ? "本身" : "轉發", msg));
        }
    }

    @OnOpen
    public void onOpen(Session session, @PathParam("uid") String uid) {
        this.session = session;
        this.uid = uid;

        webSocketMap.put(uid, this);
        System.out.printf("Online: %d, %s\n", webSocketMap.size(), uid);
        sendMessage("鏈接成功");
    }

    @OnClose
    public void onClose() {
        webSocketMap.remove(uid);
        System.out.printf("Offline 1, %s, online: %d\n", uid, webSocketMap.size());
    }
}

三,JavaScript建立WebSocket客戶端

1,判斷瀏覽器是否支持WebSocket

2,建立客戶端,鏈接服務器

3,增長消息接收函數

4,增長髮送消息功能

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>HelloSocket</title>
</head>

<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
    var socket;

    function openSocket() {
        if (typeof(WebSocket) === "undefined") {
            $("#status").html("瀏覽器不支持WebSocket");
        } else {
            if (socket !== undefined) {
                socket.close();
                socket = undefined;
            }

            // 創建鏈接
            var socketUrl = "ws://localhost:8080/ws/" + $("#uid").val();
            socket = new WebSocket(socketUrl);
            socket.onmessage = function (msg) {
                $("#status").html(msg.data);
            };
        }
    }

    function sendMessage() {
        if (socket === undefined) {
            $("#status").html("請先鏈接Socket");
        } else {
            socket.send($("#msg").val() + ", " + new Date().getTime());
        }
    }
</script>

<body>
${msg}
<br/>uid: <div><input id="uid" name="uid" value="user_id"></div>
<br/>msg: <div><input id="msg" name="msg" value="Hello WebSocket"></div>

<br/>
<div>
    <button onclick="openSocket()">鏈接Socket</button>
</div>
<br/>
<div>
    <button onclick="sendMessage()">發送消息</button>
</div>

<br/>
<div><label id="status">Status</label></div>
</body>
</html>

四,增長SocketController,返回前端頁面

@Controller
public class SocketController {
    @RequestMapping("/ws")
    public String ws(Model model){
        model.addAttribute("msg","Web Socket!");
        return "socket";
    }
}

啓動項目,瀏覽器打開頁面,鏈接WebSocket服務,接收和發送消息。

image.png

五,Spring Boot集成TioWebSocket

tio-websocket是基於T-io 網絡通信框架實現的開源websocket服務器,易於使用,沒必要關心鏈接的維護問題,只要作好業務處理便可。


代碼文件

功能要點

Spring Boot集成TioWebSocket

pom.xml

引入TioWebSocket依賴tio-websocket-spring-boot-starter

application.xml

配置端口、超時等屬性

TioMsgHandler.java

實現IWsMsgHandler,接收和發送消息

JavaScript建立WebSocket客戶端

tio.html

在前端頁面中接收和發送消息

前端頁面

SocketController.java

返回前端頁面

1,pom.xml中引入依賴

<dependency>
   <groupId>org.t-io</groupId>
   <artifactId>tio-websocket-spring-boot-starter</artifactId>
   <version>3.6.0.v20200315-RELEASE</version>
</dependency>

2,在application.xml中配置端口、超時等屬性

tio:
  websocket:
    server:
      port: 8200
      heartbeat-timeout: 3600000

3,增長TioMsgHandler.java,實現接收和發送消息功能

@Component
public class TioMsgHandler implements IWsMsgHandler {
    @Autowired
    private TioWebSocketServerBootstrap tioServer;

    public void sendMessage(String msg) {
        Tio.sendToAll(tioServer.getServerTioConfig(), WsResponse.fromText(msg, "utf-8"));
    }

    @Override
    public Object onText(WsRequest wsRequest, String msg, ChannelContext channelContext) throws Exception {
        System.out.printf("收到文本消息:%s\n", msg);

        sendMessage(String.format("轉發消息: %s", msg));
        return String.format("收到消息: %s", msg);
    }

    @Override
    public Object onBytes(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception {
        System.out.printf("收到二進制數據:%d\n", bytes.length);
        return null;
    }
}

4,開發前端頁面,JavaScript建立WebSocket客戶端

5,SocketController.java返回前端頁面

6,啓動項目,看到WebSocket服務信息

image.png

六,常見問題和解決方法

運行單元測試時錯誤,不能建立Bean 'serverEndpointExporter'

IllegalStateException: javax.websocket.server.ServerContainer not available


解決:聲明@SpringBootTest時指定webEnvironment參數。

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)


緣由:WebSocket運行在servlet容器中,因此須要加載servlet容器。

webEnvironment爲Spring Boot指定啓動時的ApplicationContext, SpringBootTest.WebEnvironment.DEFINED_PORT表示內嵌的服務器將會在定義的端口啓動。


運行單元測試時不能啓動,Failed to load ApplicationContext

Web server failed to start. Port 8011 was already in use.

解決:服務端口被佔用,若是項目已經啓動,先停掉再運行測試。

相關文章
相關標籤/搜索