項目結構
pom 文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.46</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
SocketConfig裝配
package com.winmine.websocket.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class SocketConfig {
/**
* ServerEndpointExporter 作用
* 這個Bean會自動註冊使用@ServerEndpoint註解聲明的websocket endpoint
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
SocketServer核心服務層
package com.winmine.websocket.service;
import com.alibaba.fastjson.JSONObject;
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.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@ServerEndpoint("/robot/webSocket/{sid}")//前端頁面請求的uri地址,其中{sid}是動態參數,通過@PathParam(value = "sid") 獲取
@Component
public class SocketServer {
//記錄當前在線連接數。需要保證線程安全
private static AtomicInteger onlineNum = new AtomicInteger();
//線程安全Set,存放每個客戶端對應的WebSocketServer對象。
private static ConcurrentHashMap<String, Session> sessionMap = new ConcurrentHashMap<>();
//發送消息
public void sendMessage(Session session, String message) throws IOException {
if (session != null) {
synchronized (session) {
session.getBasicRemote().sendText(message);
}
}
}
//建立連接成功調用
@OnOpen
public void onOpen(Session session, @PathParam(value = "sid") String userName) {
sessionMap.put(userName, session);
onlineNum.incrementAndGet();
System.out.println(userName + "加入webSocket!當前人數爲" + onlineNum);
try {
sendMessage(session, "歡迎" + userName + "加入連接!");
} catch (IOException e) {
e.printStackTrace();
}
}
//關閉連接時調用
@OnClose
public void onClose(@PathParam(value = "sid") String userName) {
sessionMap.remove(userName);
onlineNum.decrementAndGet();
System.out.println(userName + "斷開連接!當前人數爲" + onlineNum);
}
//收到客戶端信息併發送到另一個客戶端
@OnMessage
public void onMessage(@PathParam(value = "sid") String userName, String message) throws IOException {
JSONObject req = JSONObject.parseObject(message);
String toUserId = req.getString("toUserId");
String contentText = req.getString("contentText");
Session session = sessionMap.get(toUserId);
System.out.println(userName + " -> " + toUserId + "\n" + contentText);
try {
sendMessage(session, userName + "對" + toUserId + "說:" + contentText);
} catch (Exception e) {
System.out.println("消息發送異常"+e.getMessage());
}
}
//異常調用
@OnError
public void onError(Session session, Throwable throwable) {
System.out.println("發生錯誤");
throwable.printStackTrace();
}
}
SocketController控制層
package com.winmine.websocket.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class SocketController {
//web頁面入口
@GetMapping("/index")
public ModelAndView socket() {
return new ModelAndView("/robot/webSocket");//訪問/resources/templates下的資源路徑
}
}
Application入口
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
webSocket.html 前端頁面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocket</title></head>
<body>
<p>【當前用戶id】:
<div><input id="userId" name="userId" type="text" value="1"></div>
<p>【推送消息用戶id】:
<div><input id="toUserId" name="toUserId" type="text" value="2"></div>
<p>【推送內容】:
<div><input id="contentText" name="contentText" type="text" value="默認內容"></div>
<p>操作:
<div>
<button type="button" οnclick="openSocket()">開啓socket</button>
</div>
<p>【操作】:
<div>
<button type="button" οnclick="sendMessage()">發送消息</button>
</div>
<p>--------------------分隔符--------------------</p>
<div id="text">【響應】</div>
</body>
<script type="text/javascript">
var socket;
function openSocket() {
if (typeof (WebSocket) == "undefined") {
var serverMsg = "瀏覽器不支持WebSocket"
document.getElementById("text").innerHTML = serverMsg;
} else {
var serverMsg = "瀏覽器支持WebSocket"
document.getElementById("text").innerHTML = serverMsg;
//實現化WebSocket對象,指定要連接的服務器地址與端口 建立連接
var userId = document.getElementById('userId').value;
var socketUrl = "ws://127.0.0.1:8080/robot/webSocket/" + userId;//訪問SocketServer,並傳輸當前id
if (socket != null) {
socket.close();
socket = null;
}
socket = new WebSocket(socketUrl);
socket.onopen = function () {//websocket已打開
socket.send('{"toUserId":"' + userId + '","contentText":"加入客戶端' + location.href + DateUtil.now() + '"}');
};
//獲得消息事件
socket.onmessage = function (msg) {
var serverMsg = "收到服務端信息:" + msg.data;
document.getElementById("text").innerHTML = serverMsg;
};
socket.onclose = function () {//WebSocket關閉事件
};
socket.onerror = function () {//WebSocket發生了錯誤事件
}
}
}
function sendMessage() {
if (typeof (WebSocket) == "undefined") {//您的瀏覽器不支持WebSocket
} else {
var toUserId = document.getElementById('toUserId').value;
var contentText = document.getElementById('contentText').value;
var msg = '{"toUserId":"' + toUserId + '","contentText":"' + contentText + '"}';
socket.send(msg);
}
}
</script>
</html>
訪問地址 http://127.0.0.1:8080/index
操作界面