来源: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>