基于java注解实现websocket详解
1.1 明确java服务端需要的类
服务终端类:用java注解来监听连接@ServerEndpoint、连接成功@OnOpen、连接关闭@OnClose、收到消息等状态@OnMessage
配置类:把spring中的ServerEndpointExporter对象注入进来
1.2 创建java服务项目
类型要专门选成maven项目
springboot版本选择较低的版本
添加日志依赖
搜索增加websocket依赖
1.3 启动main文件检测是否运行
不报错就算运行成功
1.4 创建com/example/demo/WsServerEndpont.java监听websocket
对websocket面临各种操作时的反应进行设定
package com.example.demo;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 监听websocket地址
*/
@ServerEndpoint("/myWs")
@Component
@Slf4j //打印日志
public class WsServerEndpont {
static Map<String, Session> sessionMap = new ConcurrentHashMap<>();
/**
* 连接建立时执行的操作
* ConcurrentHashMap 和HashMap的区别是他是线程安全的
* map文件的创建是给所有来连接的客户分配一个key区分保存,客户连接时是以session方式进行的
* static保证变量属于类而不是对象
* log.info打印日志
*
* @param session
*/
@OnOpen
public void onOpen(Session session) {
sessionMap.put(session.getId(), session);
log.info("websocket is open");
}
/**
* 收到客户端消息时执行的操作
*
* @param text
* @return
*/
@OnMessage
public String onMessage(String text) {
log.info("收到了一条消息:" + text);
return "已经收到你的消息";
}
/**
* 连接关闭时的时候执行的操作
* @param session
*/
@OnClose
public void onClose(Session session) {
sessionMap.remove(session.getId(), session);
log.info("websocket is close");
}
/**
* 在这里是每隔两秒就对所有客户端发送一次心跳
* 想要在任何时刻发消息给客户端,需要借助springboot的定时任务,这个需要在主类中实现DemoApplication.java开启定时任务支持
* 这个类结束,需要创建一个新的类WebSocketConfig,这是注入Spring WebSocket框架的一个对象
*/
@Scheduled(fixedRate = 2000)
public void sendMsg() {
for (String key : sessionMap.keySet()) {
try {
sessionMap.get(key).getBasicRemote().sendText("心跳");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
1.5 启动心跳是定时任务,这个功能需要在主类中进行开启
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@EnableScheduling //开启定时任务
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
1.6 这个时候spring框架并不能扫描到服务终端,需要添加一个配置类
com/example/demo/WebSocketConfig.java
package com.example.demo;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @Configuration 是固定模式,表示这个是一个配置类
* @Bean 上下两个注解是配合使用的,代表把依赖包里的一些类,注入进来为一个Bean
*/@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
1.7 到这服务端搭建完成,重启main文件,准备编写客户端
在src文件夹下新建src/main/resources/ws-client.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ws client</title>
</head>
<body>
</body>
<script>
<!-- 设置连接位置-->
let ws = new WebSocket("ws://localhost:8080/myWs")
ws.onopen = function (){
// 设置连接时发送的消息
ws.send("hello")
}
//打印获取的消息
ws.onmessage = function (message){
console.log(message.data)
}
</script>
</html>