赞
踩
关于websocket的介绍,有许多的文章都讲的很详细也很好,这里就不再赘述。这里提供websocket的java代码简单实现,包括js的客户端和后台java的服务端,后端使用TomcatWebsocket和SpringWebSocket两种方式,实现tcp连接和通信,以供大家学习参考。
后端使用SpringBoot加Maven构建项目,前端直接使用html加js实现。请先准备一个能够跑起来的SpringBoot后端项目。
添加websocket的maven依赖(pom.xml):
<!-- webSocket的依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.7.12</version>
</dependency>
将这个配置类加入项目中。
/**
* 配置后会自动注册所有的 @ServerEndpoint,一定不要忘记这个配置类
* @author 广大网友
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
@ServerEndpoint注解添加服务端路径 path ,客户端在建立连tcp接时就使用:var ws = new WebSocket(“ws://你的后台项目地址/path”); 建立连接。需要携带参数时:var ws = new WebSocket(“ws://你的后台项目地址/path?accessToken=某某”) 建立连接。
import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.List; /** * TomcatWebSocket服务端 * * @author 别人家的孩子e */ @Component @ServerEndpoint("/test/tomcatWebsocket") public class WebSocketEndPoint { /** * 注意,多个会话会公用这一个num对象 */ private static Integer num = 1; /** * tcp连接建立时触发 */ @OnOpen public void onOpen(Session session) throws IOException { System.out.println("会话:" + session.getId() + "的tcp连接已建立。"); //获得路径中携带的参数,通常为认证token List<String> accessToken = session.getRequestParameterMap().get("accessToken"); //注意判路径中是否有携带参数 if (accessToken != null && accessToken.size() > 0){ String token = accessToken.get(0); System.out.println("会话人token:" + token); }else { System.out.println("会话人无访问token!!!"); } } /** * 接收到消息时触发 */ @OnMessage public String onMessage(Session session, String message) { //这里假定在访问url中都携带accessToken List<String> accessToken = session.getRequestParameterMap().get("accessToken"); String token = accessToken.get(0); System.out.println("服务端接收的消息:" + message + "---消息属于会话:" + session.getId() + "。token:" + token); return "服务端收到第" + num++ + "条消息"; } /** * 遇到错误时触发 */ @OnError public void onError(Throwable t) { System.out.println("webSocket遇到问题:"); t.printStackTrace(); } /** * tcp连接关闭时触发 */ @OnClose public void onClose(Session session, CloseReason reason) { //这里假定在访问url中都携带accessToken List<String> accessToken = session.getRequestParameterMap().get("accessToken"); String token = accessToken.get(0); System.out.println("会话:" + session.getId() + "的连接已关闭。token:" + token); num = 1; } }
实现方式和TomcatWebSocket略有区别,而效果相同,前端代码改一下访问地址就ok。
SpringWebsocket需要使用拦截器获取请求路径中的参数。
import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.stereotype.Component; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor; import javax.servlet.http.HttpServletRequest; import java.util.Map; /** * 因为 WebSocketSession 无法获得 ws 地址上的请求参数,所以只好通过该拦截器,获得 accessToken 请求参数,设置到 attributes 中。 * * 也可以 implements HandshakeInterceptor * @author 别人家的孩子e */ @Component public class WebSocketShakeInterceptor extends HttpSessionHandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { // 从请求路径中获得 accessToken if (request instanceof ServletServerHttpRequest) { ServletServerHttpRequest serverRequest = (ServletServerHttpRequest) request; HttpServletRequest servletRequest = serverRequest.getServletRequest(); attributes.put("accessToken", servletRequest.getParameter("accessToken")); } // 调用父方法,继续执行逻辑 return super.beforeHandshake(request, response, wsHandler, attributes); } }
对应TomcatWebSocket的服务端点(WebSocketEndPoint)。但是访问路径在4.3中配置。
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; /** * 处理连接和消息 * * @author 别人家的孩子e */ @Component public class DemoWebSocketHandler extends TextWebSocketHandler { private Logger logger = LoggerFactory.getLogger(getClass()); /** * 对应 open 事件 */ @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { logger.info("[afterConnectionEstablished][session({}) 接入]", session); // 解析 accessToken String accessToken = (String) session.getAttributes().get("accessToken"); System.out.println("连接建立,token:" + accessToken); } /** * 对应 message 事件 */ @Override public void handleTextMessage(WebSocketSession session, TextMessage textMessage) throws Exception { logger.info("[handleMessage][session({}) 接收到一条消息({})]", session, textMessage); System.out.println("textMessage:" + textMessage.toString()); System.out.println("textMessage.getPayload():" + textMessage.getPayload()); session.sendMessage(new TextMessage("服务端收到,over。")); } /** * 对应 close 事件 */ @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { logger.info("[afterConnectionClosed][session({}) 连接关闭。关闭原因是({})}]", session, status); System.out.println(session.getAttributes().get("accessToken").toString() + "的连接已关闭。"); } /** * 对应 error 事件 */ @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { logger.info("[handleTransportError][session({}) 发生异常]", session, exception); System.out.println("连接异常!!"); } }
将前面定义的拦截器和消息处理器添加到配置中。
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; /** * 、@EnableWebSocket :开启 springwebsocket * * @author 别人家的孩子e */ @Configuration @EnableWebSocket public class WebSocketConfiguration implements WebSocketConfigurer { /** * addHandler:配置处理器 * addInterceptors:配置拦截器 * setAllowedOrigins: 设置跨域 */ @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) { webSocketHandlerRegistry .addHandler(new DemoWebSocketHandler(), "/test/springWebsocket") .addInterceptors(new WebSocketShakeInterceptor()) .setAllowedOrigins("*"); } }
直接c走。
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="referrer" content="no-referrer"> <title>websocket案例</title> <style> body{ background-image: url("https://wallpaperm.cmcm.com/7aee1626bc5e2d89129aa61f6b6f2582.jpg"); background-color: lightyellow; background-size: cover; } #sendMessage{ height: 30px; color:brown; } #closeWebSocket{ height: 30px; color: red; } #show{ background-color: antiquewhite; width: 500px; margin: auto; text-align: left; opacity: 0.7; } </style> </head> <body> <div style="width: 100%;text-align: center;color:black;background-color: antiquewhite;opacity: 0.7;"> <h1>websocket测试用例</h1> <h2 style="color: red;">记得给我点个赞!!!</h2> <button id="sendMessage">点击发送消息</button> <button id="closeWebSocket">点击关闭tcp连接</button> <div id="show"> <h4 id="onopen">onopen:</h4> <h4 id="onmessage">onmessage:</h4> <h4 id="onerror">onerror:</h4> <h4 id="onclose">onclose:</h4> </div> </div> <script> //和websocket服务端建立tcp连接,刷新页面触发 var ws = new WebSocket("ws://127.0.0.1:8080/test/tomcatWebsocket?accessToken=秀儿"); //连接tomcatWebsocket //var ws = new WebSocket("ws://127.0.0.1:8080/test/springWebsocket?accessToken=秀儿"); //连接springWebsocket /* websocket客户端部分API如下 */ // 1.连接建立时触发 ws.onopen = function(){ //send方法用于向服务器发送消息 ws.send('这是客户端在tcp连接建立后发送的消息'); let onopen = document.getElementById('onopen'); onopen.innerText = 'onopen: ' + "webSocket客户端已和服务端创建tcp连接。"; }; // 2.接收到webSocket服务端消息就触发 ws.onmessage = function(evt){ let onmessage = document.getElementById('onmessage'); onmessage.innerText = 'onmessage: ' + evt.data; }; //3.出现异常时触发 ws.onerror = function(evt){ let onerror = document.getElementById('onerror'); onerror.innerText = 'onerror: ' + "webSocket发生异常!"; }; // 4.连接关闭时触发 ws.onclose = function(evt){ let onclose = document.getElementById('onclose'); onclose.innerText = 'onclose: ' + "webSocket的tcp连接已关闭。"; }; //点击发送消息按钮 let sendMessageButton = document.getElementById('sendMessage'); sendMessageButton.onclick = function () { ws.send('客户端发送了消息到服务器端'); } //点击关闭tcp连接按钮 let closeButton = document.getElementById('closeWebSocket'); closeButton.onclick = function(){ //关闭websocket的tcp连接 ws.close(); } </script> </body> </html>
后端项目跑起来就能实现tcp通信了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。