来源:https://www.cnblogs.com/leigepython/p/11058902.html
pom.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5 <parent>
6 <groupId>org.springframework.boot</groupId>
7 <artifactId>spring-boot-starter-parent</artifactId>
8 <version>2.1.1.RELEASE</version>
9 <relativePath/> <!-- lookup parent from repository -->
10 </parent>
11 <groupId>com.zhengcj</groupId>
12 <artifactId>spring-boot-09-websocket</artifactId>
13 <version>0.0.1-SNAPSHOT</version>
14 <name>spring-boot-09-websocket</name>
15 <description>Demo project for Spring Boot</description>
16
17 <properties>
18 <java.version>1.8</java.version>
19 </properties>
20
21 <dependencies>
22 <dependency>
23 <groupId>org.springframework.boot</groupId>
24 <artifactId>spring-boot-starter-thymeleaf</artifactId>
25 </dependency>
26 <dependency>
27 <groupId>org.springframework.boot</groupId>
28 <artifactId>spring-boot-starter-web</artifactId>
29 </dependency>
30 <dependency>
31 <groupId>org.springframework.boot</groupId>
32 <artifactId>spring-boot-starter-websocket</artifactId>
33 </dependency>
34
35 <dependency>
36 <groupId>org.springframework.boot</groupId>
37 <artifactId>spring-boot-starter-test</artifactId>
38 <scope>test</scope>
39 </dependency>
40 </dependencies>
41
42 <build>
43 <plugins>
44 <plugin>
45 <groupId>org.springframework.boot</groupId>
46 <artifactId>spring-boot-maven-plugin</artifactId>
47 </plugin>
48 </plugins>
49 </build>
50
51
52 </project>
SpringBoot09WebsocketApplication.java
1 package com.zhengcj.websocket;
2
3 import org.springframework.boot.SpringApplication;
4 import org.springframework.boot.autoconfigure.SpringBootApplication;
5
6 /**
7 * 地址:https://www.cnblogs.com/leigepython/p/11058902.html
8 * @author zhengcj
9 *
10 */
11 @SpringBootApplication
12 public class SpringBoot09WebsocketApplication {
13
14 public static void main(String[] args) {
15 SpringApplication.run(SpringBoot09WebsocketApplication.class, args);
16 }
17
18 }
WebSocketConfig.java
1 package com.zhengcj.websocket.config;
2
3 import org.springframework.context.annotation.Bean;
4 import org.springframework.context.annotation.Configuration;
5 import org.springframework.web.socket.server.standard.ServerEndpointExporter;
6
7 /**
8 * @author zhengcj
9 * @Date 2020年4月27日 上午11:37:26
10 * @version
11 * @Description socket配置类,往 spring 容器中注入ServerEndpointExporter实例
12 *
13 */
14 @Configuration
15 public class WebSocketConfig {
16 @Bean
17 public ServerEndpointExporter serverEndpointExporter() {
18 return new ServerEndpointExporter();
19 }
20
21 }
WebSocketServer.java
1 package com.zhengcj.websocket.common;
2
3 import java.io.IOException;
4 import java.util.HashMap;
5 import java.util.Map;
6 import java.util.concurrent.atomic.AtomicInteger;
7
8 import javax.websocket.OnClose;
9 import javax.websocket.OnError;
10 import javax.websocket.OnMessage;
11 import javax.websocket.OnOpen;
12 import javax.websocket.Session;
13 import javax.websocket.server.PathParam;
14 import javax.websocket.server.ServerEndpoint;
15
16 import org.springframework.stereotype.Component;
17
18 /**
19 * WebSocket服务端代码,包含接收消息,推送消息等接口
20 * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
21 * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
22 * @author zhengcj
23 * @Date 2020年4月27日 下午1:36:13
24 * @version
25 * @Description
26 */
27 @Component
28 @ServerEndpoint(value = "/socket/{name}")
29 public class WebSocketServer {
30
31 // 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
32 private static AtomicInteger online = new AtomicInteger();
33 // concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
34 // private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
35 private static Map<String, Session> sessionPools = new HashMap<>();
36
37 /**
38 * 发送消息方法
39 * @param session 客户端与socket建立的会话
40 * @param message 消息
41 * @throws IOException
42 */
43 public void sendMessage(Session session, String message) throws IOException {
44 if (session != null) {
45 session.getBasicRemote().sendText(message);
46 }
47 }
48
49 /**
50 * 连接建立成功调用
51 * @param sessionv 客户端与socket建立的会话
52 * @param userName 客户端的userName
53 */
54 @OnOpen
55 public void onOpen(Session session, @PathParam(value = "name") String userName) {
56 sessionPools.put(userName, session);
57 addOnlineCount();
58 System.out.println(userName + "加入webSocket!当前人数为" + online);
59 try {
60 sendMessage(session, "欢迎" + userName + "加入连接!");
61 } catch (IOException e) {
62 e.printStackTrace();
63 }
64 }
65
66 /**
67 * 关闭连接时调用
68 * @param userName 关闭连接的客户端的姓名
69 */
70 @OnClose
71 public void onClose(@PathParam(value = "name") String userName) {
72 sessionPools.remove(userName);
73 subOnlineCount();
74 System.out.println(userName + "断开webSocket连接!当前人数为" + online);
75 }
76
77 /**
78 * 收到客户端消息时触发(群发)
79 * @param message
80 * @throws IOException
81 */
82 @OnMessage
83 public void onMessage(String message) throws IOException {
84 System.out.println("群发信息:"+message);
85 for (Session session : sessionPools.values()) {
86 try {
87 sendMessage(session, message);
88 } catch (Exception e) {
89 e.printStackTrace();
90 continue;
91 }
92 }
93 }
94
95 /**
96 * 发生错误时候
97 * @param session
98 * @param throwable
99 */
100 @OnError
101 public void onError(Session session, Throwable throwable) {
102 System.out.println("发生错误");
103 throwable.printStackTrace();
104 }
105
106 /**
107 * 给指定用户发送消息
108 *
109 * @param userName
110 * 用户名
111 * @param message
112 * 消息
113 * @throws IOException
114 */
115 public void sendInfo(String userName, String message) {
116 Session session = sessionPools.get(userName);
117 try {
118 sendMessage(session, message);
119 } catch (Exception e) {
120 e.printStackTrace();
121 }
122 }
123
124 public static void addOnlineCount() {
125 online.incrementAndGet();
126 }
127
128 public static void subOnlineCount() {
129 online.decrementAndGet();
130 }
131 }
WebMvcConfig.java
1 package com.zhengcj.websocket.config;
2
3 import org.springframework.context.annotation.Configuration;
4 import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
5 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
6
7 /**
8 * @author zhengcj
9 * @Date 2020年4月27日 下午1:38:31
10 * @version
11 * @Description
12 *
13 * 在SpringBoot2.0及Spring 5.0 WebMvcConfigurerAdapter已被废弃,目前找到解决方案就有
14 * 1 直接实现WebMvcConfigurer (官方推荐)
15 * 2 直接继承WebMvcConfigurationSupport
16 * @ https://blog.csdn.net/lenkvin/article/details/79482205
17 */
18 @Configuration
19 public class WebMvcConfig implements WebMvcConfigurer{
20 /**
21 * 为各个页面提供路径映射
22 * @param registry
23 */
24 @Override
25 public void addViewControllers(ViewControllerRegistry registry) {
26 registry.addViewController("/zhengcj").setViewName("zhengcj");
27 registry.addViewController("/yuzh").setViewName("yuzh");
28 }
29 }
SocketController.java
1 package com.zhengcj.websocket.controller;
2
3 import java.io.IOException;
4
5 import javax.annotation.Resource;
6
7 import org.springframework.web.bind.annotation.GetMapping;
8 import org.springframework.web.bind.annotation.RequestParam;
9 import org.springframework.web.bind.annotation.RestController;
10
11 import com.zhengcj.websocket.common.WebSocketServer;
12
13 /**
14 * @author zhengcj
15 * @Date 2020年4月27日 下午1:44:32
16 * @version
17 * @Description
18 *
19 */
20 @RestController
21 public class SocketController {
22 @Resource
23 private WebSocketServer webSocketServer;
24
25 /**
26 * 给指定用户推送消息
27 * @param userName 用户名
28 * @param message 消息
29 * @throws IOException
30 */
31 @GetMapping("/socket")
32 public void pushOneUser(@RequestParam String userName, @RequestParam String message){
33 System.err.println("====socket===="+message);
34 webSocketServer.sendInfo(userName, message);
35 }
36
37 /**
38 * 给所有用户推送消息
39 * @param message 消息
40 * @throws IOException
41 */
42 @GetMapping("/socket/all")
43 public void pushAllUser(@RequestParam String message){
44 try {
45 System.err.println("====socket/all===="+message);
46 webSocketServer.onMessage(message);
47 } catch (IOException e) {
48 e.printStackTrace();
49 }
50 }
51 }
yuzh.html
<!DOCTYPE HTML>
<html>
<head>
<title>WebSocket</title>
</head> <body>
Welcome
<br />
<input id="text" type="text" />
<button onclick="send()">Send</button>
<button onclick="closeWebSocket()">Close</button>
<div id="message"></div>
</body> <script type="text/javascript">
var websocket = null; //判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/socket/yuzh");
} else {
alert('Not support websocket')
} //连接发生错误的回调方法
websocket.onerror = function() {
setMessageInnerHTML("error");
}; //连接成功建立的回调方法
websocket.onopen = function(event) {
setMessageInnerHTML("open");
} //接收到消息的回调方法
websocket.onmessage = function(event) {
setMessageInnerHTML(event.data);
} //连接关闭的回调方法
websocket.onclose = function() {
setMessageInnerHTML("close");
} //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
websocket.close();
} //将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
} //关闭连接
function closeWebSocket() {
websocket.close();
} //发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>
zhengcj.html
<!DOCTYPE HTML>
<html>
<head>
<title>WebSocket</title>
</head> <body>
Welcome
<br />
<input id="text" type="text" />
<button onclick="send()">Send</button>
<button onclick="closeWebSocket()">Close</button>
<div id="message"></div>
</body> <script type="text/javascript">
var websocket = null; //判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/socket/zhengcj");
} else {
alert('Not support websocket')
} //连接发生错误的回调方法
websocket.onerror = function() {
setMessageInnerHTML("error");
}; //连接成功建立的回调方法
websocket.onopen = function(event) {
setMessageInnerHTML("open");
} //接收到消息的回调方法
websocket.onmessage = function(event) {
setMessageInnerHTML(event.data);
} //连接关闭的回调方法
websocket.onclose = function() {
setMessageInnerHTML("close");
} //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
websocket.close();
} //将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
} //关闭连接
function closeWebSocket() {
websocket.close();
} //发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>