WebSocket之原生使用、Spring使用(无理论)

    xiaoxiao2023-11-26  167

    github-demo(idea):https://github.com/bbwangbb/csnd-WebSocket-demo

    1.原生使用(Maven)

    1)导入jar包,javax.websocket-api,如果使用jar导入tomcat/lib下的tomcat-websocket.jar和websocket-api.jar

     

    <dependency> <groupId>javax.websocket</groupId> <artifactId>javax.websocket-api</artifactId> <version>1.1</version> <scope>provided</scope> </dependency>

    2)配置类

    package cn.mb.websocket; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.util.concurrent.CopyOnWriteArraySet; //该注解用来指定连接的 url,类似请求的url -> ws://主机:端口/websocket 即为连接地址 @ServerEndpoint("/websocket") public class WebsocketConfig { //可以通过此来记录在线人数 public static int onlineCount = 0; //可以用通过静态集合的方式存储session对象,在别处可以直接调用来逐个发送消息 public static CopyOnWriteArraySet<Session> sessions = new CopyOnWriteArraySet<>(); public WebsocketConfig() { System.out.println("init..."); } @OnOpen//连接打开时调用 public void open(Session session) { sessions.add(session); System.out.println("open..."); } @OnClose//连接关闭时调用 public void close(Session session) { sessions.remove(session); System.out.println("close..."); } @OnMessage//客户端发送消息时调用 public void send(String message, Session session) { System.out.println("客户端信息:" + message); System.out.println("send..."); //给用户发送信息 } @OnError//发生错误时调用 public void error(Session session, Throwable error) { System.out.println("error..."); } }

    3)前端页面

    <!DOCTYPE html> <html> <head> <title>My WebSocket</title> <script src="jquery-2.1.0.js"></script> </head> <body> <button id="open">Open</button> <br/> <input type="text" id="text"> <button id="send">Send</button> <br/> <button id="close">Close</button> <div id="message"> </div> </body> <script type="text/javascript"> $(function () { var websocket = null; //开起连接 $("#open").click(function () { //判断当前浏览器是否支持WebSocket if ('WebSocket' in window) { websocket = new WebSocket("ws://localhost:8080/websocket"); } else { alert('Not support websocket') } //连接发生错误的回调方法 websocket.onerror = function (event) { $("#message").html("Connect error!") }; //连接成功建立的回调方法 websocket.onopen = function (event) { $("#message").html("Connect successfully!"); } //接收到消息的回调方法 websocket.onmessage = function (event) { $("#message").html("服务端消息:" + event.data); } }) //关闭连接 $("#close").click(function () { websocket.close(); $("#message").html("Connect closing!") }) //发送消息 $("#send").click(function () { var message = $("#text").val(); websocket.send(message); $("#message").html("Send successfully!"); }) }) </script> </html>

     

    2.Spring使用

    1)导入jar

    <!--Spring Boot 的websocket方式--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <!--Spring集成--> <!-- <dependency>--> <!-- <groupId>org.springframework</groupId>--> <!-- <artifactId>spring-messaging</artifactId>--> <!-- <version>5.0.9.RELEASE</version>--> <!-- </dependency>--> <!-- <dependency>--> <!-- <groupId>org.springframework</groupId>--> <!-- <artifactId>spring-websocket</artifactId>--> <!-- <version>5.0.9.RELEASE</version>--> <!-- </dependency>--> <!--客户端使用的是sockjs方式,相当于导入前端需要使用的js文件--> <dependency> <groupId>org.webjars</groupId> <artifactId>sockjs-client</artifactId> <version>1.0.2</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>stomp-websocket</artifactId> <version>2.3.3</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.1.0</version> </dependency>

    2)配置类

    package cn.mb.websocket; import cn.mb.interceptor.HttpHandShakeInterceptor; import cn.mb.listener.STOMPConnectEventListener; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; @Configuration @EnableWebSocketMessageBroker//启用websocket注解 public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override//配置消息代理 public void configureMessageBroker(MessageBrokerRegistry config) { /** * 与 @MessageMapping 中的url拼接后就是 客户端可以发送数据的 url * @MessageMapping("/testWebSocket") * 客户端即可向 /app/testWebSocket 发送数据 */ config.setApplicationDestinationPrefixes("/app"); //前端可以订阅 /topic/... 的url config.enableSimpleBroker("/topic"); } @Override//注册 Stomp 端点 public void registerStompEndpoints(StompEndpointRegistry registry) { //添加一个/spring-websocket端点,客户端就可以通过这个端点来进行连接; registry.addEndpoint("/spring-websocket") .addInterceptors(new HttpHandShakeInterceptor())//设置握手拦截器 .setAllowedOrigins("*") // 添加允许跨域访问 .withSockJS();//添加SockJS支持 } @Bean//注入监听器 public STOMPConnectEventListener STOMPConnectEventListener(){ return new STOMPConnectEventListener(); } }

    3)监听器(可选)

    package cn.mb.listener; import org.springframework.context.ApplicationListener; import org.springframework.web.socket.messaging.SessionConnectEvent; public class STOMPConnectEventListener implements ApplicationListener<SessionConnectEvent> { @Override public void onApplicationEvent(SessionConnectEvent sessionConnectEvent) { //打开链接时会触发此方法 } }

    4)拦截器(可选)

    package cn.mb.interceptor; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.HandshakeInterceptor; import java.util.Map; //声明后需要在配置类中配置 public class HttpHandShakeInterceptor implements HandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception { System.out.println("beforeHandshake..."); return true;//返回false会疯狂请求握手 } @Override public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) { System.out.println("afterHandshake..."); } }

    5)控制层

    package cn.mb.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Controller; @Controller public class WebSocketController { @Autowired private SimpMessagingTemplate simpMessagingTemplate; @MessageMapping("/testWebSocket") @SendTo("/topic/destination") public String testWebSocket(String message) throws Exception { /** * 单播(私聊): * 1.两人订阅相同的 url * 2.这样发信息的时候可以互相看到,数据库中可以在存储好友的信息的时候带上一个url(个人想法) */ simpMessagingTemplate.convertAndSend("/topic/bb", "我是bb,你在吗?"); System.out.println("客户端说:" + message); return "Hi, client!"; } }

    6)前端页面

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="webjars/jquery/3.1.0/jquery.min.js"></script> <script src="webjars/sockjs-client/1.0.2/sockjs.min.js"></script> <script src="webjars/stomp-websocket/2.3.3/stomp.min.js"></script> </head> <body> <button id="open">Open</button> <br/> <button id="send">Send</button> <br/> <button id="close">Close</button> <div id="message"> </div> <script> $(function () { var socket = null; var stompClient = null; //开起连接 $("#open").click(function () { //创建 websocket对象 socket = new SockJS('/spring-websocket');//固定 stompClient = Stomp.over(socket); //连接成功的回调函数 stompClient.connect({username : 'bb'}, function (frame) { //... //打印连接状态 console.log('Connected: ' + frame); $("#message").html("连接成功!") /* 3.连接成功后订阅目标地址 client.subscribe(destination, callback) destination:目标地址 callback:有人向这个地址发送广播该回调函数就会执行 */ stompClient.subscribe('/topic/bb', function (resp) {//DB读取 $("#message").html("服务端回复:" + resp.body) }); //可以订阅多个,每个写一次方法即可 // stompClient.subscribe('/topic/cc', function (resp) {//DB读取 // $("#message").html("服务端回复:" + resp.body) // }); }); }) //关闭连接 $("#close").click(function () { if (stompClient !== null) { stompClient.disconnect(); $("#message").html("连接关闭!") } }) //发送消息 $("#send").click(function () { /* client.send(destination, {}, body); destination:目标地址 {}:请求头 body:请求信息(JSON格式) */ stompClient.send("/app/testWebSocket", {}, JSON.stringify({message : 'Hi, server!'})); }) }) </script> </body> </html>

    注意:在Struts中使用要放行该url,在struts.xml中配置以下内容

    <constant name="struts.action.excludePattern" value="/你的url"></constant>

    个人理解:

           1.连接WebSocket服务端

           2.连接成功后,客户端与服务端之间可以相互发送信息

           3.至于怎么做单播,原生可以使用存储Session方式,Spring中可以使用SimpMessagingTemplate对象发送(订阅同一个url)

     

    理论后期弥补。

    最新回复(0)