1. 创建springboot项目,引入spring-boot-starter-websocket依赖
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-websocket</artifactid>
</dependency>
完整项目依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelversion>4.0.0</modelversion>
<parent>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-parent</artifactid>
<version>2.5.9</version>
<relativepath/> <!-- lookup parent from repository -->
</parent>
<groupid>com.mutest</groupid>
<artifactid>websocket-demo</artifactid>
<version>0.0.1-snapshot</version>
<name>websocket-demo</name>
<description>websocket demo</description>
<properties>
<java.version>8</java.version>
</properties>
<dependencies>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-test</artifactid>
<scope>test</scope>
</dependency>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-websocket</artifactid>
</dependency>
<dependency>
<groupid>org.projectlombok</groupid>
<artifactid>lombok</artifactid>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-maven-plugin</artifactid>
</plugin>
</plugins>
</build>
</project>
2. 对websocket进行配置config
registerwebsockethandlers()方法参数是websockethandlerregistry 。调用websockethandlerregistry 的addhandler方法传递处理器和路径。处理器参数是上一步创建的textwebsockethandler 的子类。路径是客户端调用时跟在端口后的路径。再调用websockethandlerregistry 的setallowedorigins方法传递星号,允许跨域访问。
@configuration
@enablewebsocket
public class websocketconfig implements websocketconfigurer {
@autowired
private mywshandler mywshandler;
@override
public void registerwebsockethandlers(websockethandlerregistry registry) {
registry
.addhandler(mywshandler, "myws")
//允许跨域
.setallowedorigins("*");
}
}
websockethandlerregistry
addhandler()方法第一个传输传递处理器,第一个参数传递路径
setallowedorigins()方法设置允许源,传递星号,否则跨域。
3.定义处理器mywshandler
@component
@slf4j
public class mywshandler extends abstractwebsockethandler {
@override
public void afterconnectionestablished(websocketsession session) {
log.info("建立ws连接");
wssessionmanager.add(session.getid(), session);
}
@override
protected void handletextmessage(websocketsession session, textmessage message) throws exception {
// 接收客户端/浏览器端的消息 message.getpayload()消息体
string payload = message.getpayload();
log.info("server 接收到客户端/浏览器端的消息 " + payload);
log.info("发送文本消息");
//服务端准备给客户端/浏览器端发送消息
session.sendmessage(new textmessage("server 发送给的消息 " + payload + ",发送时间:" + localdatetime.now().tostring()));
}
@override
protected void handlebinarymessage(websocketsession session, binarymessage message) throws exception {
log.info("发送二进制消息");
}
@override
public void handletransporterror(websocketsession session, throwable exception) throws exception {
log.error("异常处理");
wssessionmanager.removeandclose(session.getid());
}
@override
public void afterconnectionclosed(websocketsession session, closestatus status) throws exception {
log.info("关闭ws连接");
wssessionmanager.removeandclose(session.getid());
}
}
4. 单播/多播发送消息
在mywshandler中,handletextmessage方法使用的是单播发送消息,如果要给客户端/浏览器端发送广播消息该如何发送呢,只需遍历所有客户端/浏览器端的session即可,通过session广播消息。
@service
@slf4j
public class wsservice {
/**
* 发送消息
*
* @param session 连接信息
* @param text 消息
*/
public void sendmsg(websocketsession session, string text) throws ioexception {
session.sendmessage(new textmessage(text));
}
/**
* 广播消息
*
* @param text 消息
*/
public void broadcastmsg(string text) throws ioexception {
for (websocketsession session : wssessionmanager.session_pool.values()) {
session.sendmessage(new textmessage(text));
}
}
}
5. 设置定时任务发送广播消息
@slf4j
@component
public class messagejob {
@autowired
wsservice wsservice;
/**
* 每5s发送
*/
@scheduled(cron = "0/5 * * * * *")
public void run() {
try {
log.info("推送消息===>" + localdatetime.now().tostring());
wsservice.broadcastmsg("自动生成消息 " + localdatetime.now().tostring());
} catch (ioexception e) {
e.printstacktrace();
}
}
}
6. 管理客户端/浏览器端的session工具类
@slf4j
public class wssessionmanager {
/**
* 保存连接 session 的地方
*/
public static concurrenthashmap<string, websocketsession> session_pool = new concurrenthashmap<>();
/**
* 添加 session
*
* @param key key
*/
public static void add(string key, websocketsession session) {
// 添加 session
session_pool.put(key, session);
}
/**
* 删除 session,会返回删除的 session
*
* @param key key
* @return websocketsession
*/
public static websocketsession remove(string key) {
// 删除 session
return session_pool.remove(key);
}
/**
* 删除并同步关闭连接
*
* @param key key
*/
public static void removeandclose(string key) {
websocketsession session = remove(key);
if (session != null) {
try {
// 关闭连接
session.close();
} catch (ioexception e) {
// todo: 关闭出现异常处理
e.printstacktrace();
}
}
}
/**
* 获得 session
*
* @param key key
* @return websocketsession
*/
public static websocketsession get(string key) {
// 获得 session
return session_pool.get(key);
}
}
完整的项目结构:
7. 测试
这里,我们使用在线测试工具,测试网址为:https://wstool.js.org/
客户端发送消息:
服务端后台收到的消息:
模拟服务器多播发送消息给客户端,这里我使用两个不同的浏览器去连接服务端:
发表评论