springboot整合websocket的总结
今天总结一下以往使用的websocket的两种方式
|第一种:
-
导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId> </dependency> <dependency>
值得一提的是,导入 spring-boot-starter-web-services 之后,spring-boot-starter-web 这个场景启动器就可以不用加了,我们可以点开 spring-boot-starter-web-services 可以看到,spring-boot-starter-web-services 里面就有依赖spring-boot-starter-web ,所以无需重复添加
-
新建一个配置类
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
-
新建一个配置websocket的类
package com.websocket; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Slf4j @ServerEndpoint(value = "/websocket") @Component public class WebSocketServer { //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 private static int onlineCount = 0; //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>(); //与某个客户端的连接会话,需要通过它来给客户端发送数据 private Session session; private final static Logger log = LoggerFactory.getLogger(WebSocketServer.class); /** * 连接建立成功调用的方法*/ public WebSocketServer() { System.out.println("初始化!"); } @OnOpen public void onOpen(Session session) { this.session = session; webSocketSet.add(this); //加入set中 addOnlineCount(); //在线数加1 log.info("有新连接加入!当前在线人数为" + getOnlineCount()); try { sendMessage("连接成功"); } catch (IOException e) { log.error("websocket IO异常"); } } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); //从set中删除 subOnlineCount(); //在线数减1 log.info("有一连接关闭!当前在线人数为" + getOnlineCount()); } /** * 收到客户端消息后调用的方法 * * @param message 客户端发送过来的消息*/ @OnMessage public void onMessage(String message, Session session) { log.info("来自客户端的消息:" + message); //群发消息 for (WebSocketServer item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { e.printStackTrace(); } } } /** * * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { log.error("发生错误"); error.printStackTrace(); } public void sendMessage(String message) throws IOException { session.getBasicRemote().sendText(message); } /** * 群发消息 * */ public static void sendInfo(String message) throws IOException { log.info(message); for (WebSocketServer item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { continue; } } } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketServer.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketServer.onlineCount--; } }
-
新建一个html文本
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>WebSocket Echo Demo</title> <meta name="viewport" content="width=device-width, initial-scale=1"/> <script src="js/jquery-1.12.3.min.js"></script> <script> var ws = new WebSocket("ws://localhost:8080/websocket"); ws.onopen = function (e) { console.log('Connection to server opened'); } function sendMessage() { ws.send($('#message').val()); } ws.onmessage = function (evt) { var received_msg = evt.data; alert(received_msg); }; ws.onclose = function(){ // 关闭 websocket alert("连接已关闭..."); }; ws.onerror = function(err) { alert("Error: " + err); }; </script> </head> <body > <div class="vertical-center"> <div class="container"> <p> </p> <form role="form" id="chat_form" onsubmit="sendMessage(); return false;"> <div class="form-group"> <input class="form-control" type="text" name="message" id="message" placeholder="Type text to echo in here" value="" /> </div> <button type="button" id="send" class="btn btn-primary" onclick="sendMessage();"> Send! </button> </form> </div> </div> </body> </html>
第二种:
第二种相对来说麻烦一点,需要配置握手拦截器(HttpSessionHandshakeInterceptor) 以及实现一个WebSocketConfigurer。
-
1.老规矩 引入websocket依赖(具体版本可以自己添加 不过springboot 默认会由一个版本)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId> </dependency> <dependency>
-
2.配置一个Handle
package springboot; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.WebSocketMessage; import org.springframework.web.socket.WebSocketSession; //extending either TextWebSocketHandler orBinaryWebSocketHandler public class MyHandler implements WebSocketHandler { public Map<WebSocketSession,String> map = new HashMap<WebSocketSession,String >(); //连接关闭后 @Override public void afterConnectionClosed(WebSocketSession arg0, CloseStatus arg1) throws Exception { // TODO Auto-generated method stub System.out.println("Connection closed..."+arg0.getRemoteAddress().toString()); map.remove(arg0); } //连接建立后 @Override public void afterConnectionEstablished(WebSocketSession arg0) throws Exception { // TODO Auto-generated method stub System.out.println("Connection established..."+arg0.getRemoteAddress().toString()); } //收到消息后 @Override public void handleMessage(WebSocketSession arg0, WebSocketMessage<?> arg1) throws Exception { // TODO Auto-generated method stub try { if(map.containsKey(arg0)) { System.out.println("Req: "+arg1.getPayload()); TextMessage returnMessage = new TextMessage(map.get(arg0)+":"+arg1.getPayload().toString()); //arg0.sendMessage(returnMessage); SendAllUser(returnMessage); }else { map.put(arg0,arg1.getPayload().toString()); } } catch (Exception e) { e.printStackTrace(); } } private void SendAllUser(TextMessage returnMessage) { // TODO Auto-generated method stub if(map.size()!=0) { for (Entry<WebSocketSession, String> entry : map.entrySet()) { try { entry.getKey().sendMessage(returnMessage); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } //错误后(客户端强制断开) @Override public void handleTransportError(WebSocketSession arg0, Throwable arg1) throws Exception { // TODO Auto-generated method stub if(arg0.isOpen()){ arg0.close(); } map.remove(arg0); System.out.println(arg1.toString()); System.out.println("WS connection error,close..."); } @Override public boolean supportsPartialMessages() { // TODO Auto-generated method stub return false; } }
-
- 配置一个握手拦截器(拦截请求)
package springboot; import java.util.Map; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; /** * * 类描述:握手拦截器 * com.watcher.websocket.spring MyHandshakeInterceptor * Created by 78098 on 2016年11月15日. * version 1.0 */ public class MyHandshakeInterceptor extends HttpSessionHandshakeInterceptor{ @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) { // TODO Auto-generated method stub System.out.println("After handshake "+request.getRemoteAddress().toString()); super.afterHandshake(request, response, wsHandler, ex); } @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler, Map<String, Object> map) throws Exception { // TODO Auto-generated method stub System.out.println("Before handshake "+request.getRemoteAddress().toString()); return super.beforeHandshake(request, response, handler, map); } } ```
-
-
4.实现配置类
package springboot; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; @Configuration //配置类 @EnableWebSocket //声明支持websocket public class WebSocketConfig implements WebSocketConfigurer{ @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { //注册websocket实现类,指定参数访问地址;allowed-origins="*" 允许跨域 registry.addHandler(myHandler(), "/ws").addInterceptors(myHandshake()).setAllowedOrigins("*"); //允许客户端使用SockJS registry.addHandler(myHandler(), "/sockjs/ws").addInterceptors(myHandshake()).withSockJS(); /* registry.addHandler(myHandler(), "/webSocket"); registry.addHandler(myHandler(), "/webSocket/socketJs").withSockJS();*/ } @Bean public MyHandler myHandler(){ return new MyHandler(); } @Bean public MyHandshakeInterceptor myHandshake(){ return new MyHandshakeInterceptor(); } }
以上就是springboot使用websocket的两种方法,用了websocket感觉真的挺简单的 ,原来,我们有了springboot,世界如此简单。还有一种node.js也可以搭建websocket 后台服务器,那个就更简单了。。有兴趣的可以试试。