1.基于java注解实现websocket服务器端
1.1需要的类
1.1.1服务终端类
用java注解来监听连接@ServerEndpoint、连接成功@OnOpen、连接失败@OnClose、收到消息等状态@OnMessage
1.1.2配置类
把spring中的ServerEndpointExporter对象注入进来
2.1代码示例
2.1.1 maven配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.heima</groupId><artifactId>ws-demo</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.7.3</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.22</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-websocket --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.7.14</version></dependency></dependencies></project>
2.1.2 WsServerEndpoint类
package com.heima;import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;/**** 监听websocket地址 /myWs*/
@ServerEndpoint("/myWs")
@Component
@Slf4j
@EnableScheduling
public class WsServerEndpoint {static Map<String,Session> map = new ConcurrentHashMap<String,Session>();/**** 连接建立时执行的操作* @param session*/@OnOpenpublic void onOpen(Session session){map.put(session.getId(),session);log.info("websocket is open");}/**** 收到客户端消息执行的操作* @param text*/@OnMessagepublic String OnMessage(String text){log.info("收到了一条信息"+text);return "已收到你的信息" ;}/**** 连接关闭时执行的操作* @param session*/@OnClosepublic void OnClose(Session session){map.remove(session.getId());log.info("连接关闭时执行的操作");}/**** 向客户端发送信息*/@Scheduled(fixedRate = 2000)public void sendMsg() throws IOException {for (String key : map.keySet()){map.get(key).getBasicRemote().sendText("你好,你好");}}
}
2.1.3 WebSocketConfig
package com.heima;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}}
2.1.3 前端测试代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>wsClient</title>
</head>
<body><script>// 创建websocketlet ws = new WebSocket("ws://localhost:8080/myWs")//向服务器发送hellows.onopen=function (){ws.send("hello")}//监听数据ws://localhost:8080/myWsws.onmessage=function (message){console.log(message.data)}
</script>
</body>
</html>
2.1.4测试结果
2.1.4.1 当打开浏览器时
2.1.4.2 当关闭浏览器时
2.1.4.3 当刷新浏览器的时候
2.基于spring提供的类和接口刷新websocket服务器端
2.1:HttpSessionHandShakeInter 握手拦截器
package com.spring;import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;import java.util.Map;/**** 握手拦截器*/
@Component
@Slf4j
public class MyWsInterceptor extends HttpSessionHandshakeInterceptor {@Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {log.info(request.getRemoteAddress().toString()+"开始握手");return super.beforeHandshake(request, response, wsHandler, attributes);}@Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) {log.info(request.getRemoteAddress().toString()+"完成握手");super.afterHandshake(request, response, wsHandler, ex);}
}
2.2 MyWsHandler 主处理程序
sessionbean封装类
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.web.socket.WebSocketSession;@Data
@AllArgsConstructor
public class SessionBean {private WebSocketSession webSocketSession;private Integer clientId;
}
主处理程序
package com.spring;import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.server.Session;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
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.AbstractWebSocketHandler;import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;/**** webSocket 主处理程序*/
@Component
@Slf4j
@EnableScheduling
public class MyWsHandler extends AbstractWebSocketHandler {//map有并发线程问题 所以用ConcurrentHashMapprivate static Map<String, SessionBean> map ;//id有并发问题 所以用Integer的安全类型private static AtomicInteger clientIdMaker;static {map = new ConcurrentHashMap<>();clientIdMaker=new AtomicInteger(0);}//连接建立@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {super.afterConnectionEstablished(session);//将session 进一步封装 id采用的是自增SessionBean sessionBean = new SessionBean(session, clientIdMaker.getAndIncrement());map.put(session.getId(),sessionBean);log.info(map.get(session.getId()).getClientId()+"建立了连接");}//收到消息@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {super.handleTextMessage(session, message);log.info(map.get(session.getId()).getClientId()+":"+message.getPayload());}//传输异常@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {super.handleTransportError(session, exception);if (session.isOpen()){session.close();}map.remove(session.getId());}//连接关闭@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {super.afterConnectionClosed(session, status);log.info(map.get(session.getId()).getClientId()+"关闭连接");}/**** 向客户端发送信息*/@Scheduled(fixedRate = 2000)public void sendMsg() throws IOException {for (String key : map.keySet()){map.get(key).getWebSocketSession().sendMessage(new TextMessage("hello," +"spring socket"));}}
}
2.3 WebSocketConfigurer 注册拦截器和主处理程序以及监听路径
package com.spring;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;import javax.annotation.Resource;@Configuration
@EnableWebSocket
public class MyWsConfig implements WebSocketConfigurer {@Resourceprivate MyWsHandler wsHandler;@Resourceprivate MyWsInterceptor wsInterceptor;@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(wsHandler,"/myWs1").addInterceptors(wsInterceptor).setAllowedOriginPatterns("*");}
}
2.4 前端测试
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>wsClient</title>
</head>
<body><script>// 创建websocketlet ws = new WebSocket("ws://localhost:8080/myWs1")//向服务器发送hellows.onopen=function (){ws.send("hello")}//监听数据ws://localhost:8080/myWsws.onmessage=function (message){console.log(message.data)}
</script>
</body>
</html>