从今天起,撸起袖子跟着我加油干
提示:如有疑问请私信联系、下方有源代码地址,请自行拿取
前言
使用Spring Boot 可以非常方便、快速搭建项目,使我们不用关心框架之间的兼容性,适用版本等各种问题,我们想使用任何东西,仅仅添加一个配置就可以。
提示:以下是本篇文章正文内容,下面案例可供参考
一、技术介绍
1.WebSocket是什么?
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。 WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。二、使用步骤
1.引入maven库
代码如下(示例):
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/>
</parent>
<dependencies>
<!-- websocket依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>LATEST</version>
</dependency>
</dependencies>
2.WebSocket具体使用示例
WebSocket配置类:
package com.hyh.websocket.config;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* WebSocket配置
*
* @Author: HEYUHUA
* @Date: 2021/1/7 11:54
*/
@Configuration
public class WebSocketConfig {
/**
* 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
服务接口类:
package com.hyh.websocket;
import javax.websocket.Session;
/**
* WebSocket 服务端接口
*
* @Author: heyuhua
* @Date: 2021/1/7 11:51
*/
public interface IWebSocketServer {
/**
* 连接建立成功调用
*
* @param session
*/
void onOpen(Session session, String userId);
/**
* 收到客户端消息后调用
*
* @param message
* @param session
*/
void onMessage(String message, Session session);
/**
* 连接关闭调用
*/
void onClose();
/**
* 发生错误/异常时调用
*
* @param session
* @param error
*/
void onError(Session session, Throwable error);
}
WebSocket支撑类:
package com.hyh.websocket.support;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hyh.utils.common.StringUtils;
import com.hyh.websocket.IWebSocketServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PathVariable;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
/**
* WebSocket支撑类,需要继承此类
*
* @Author: heyuhua
* @Date: 2021/1/7 14:07
*/
public class WebSocketServerSupport implements IWebSocketServer {
private static Logger LOG = LoggerFactory.getLogger(WebSocketServerSupport.class);
/**
* 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
*/
private static int onlineCount = 0;
/**
* concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
*/
private static ConcurrentHashMap<String, WebSocketServerSupport> webSocketMap = new ConcurrentHashMap<>();
/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
private Session session;
/**
* 接收userId
*/
private String userId;
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
this.session = session;
this.userId = userId;
if (webSocketMap.containsKey(userId)) {
webSocketMap.remove(userId);
webSocketMap.put(userId, this);
} else {
webSocketMap.put(userId, this);
addOnlineCount();
}
LOG.info("用户连接:" + userId + ",当前在线人数为:" + getOnlineCount());
try {
sendMessage("连接成功");
} catch (IOException e) {
LOG.error("用户:" + userId + ",网络异常!!!!!!");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
if (webSocketMap.containsKey(userId)) {
webSocketMap.remove(userId);
//从set中删除
subOnlineCount();
}
LOG.info("用户退出:" + userId + ",当前在线人数为:" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
LOG.info("用户消息:" + userId + ",报文:" + message);
//可以群发消息
//消息保存到数据库、redis
if (StringUtils.isNotBlank(message)) {
try {
//解析发送的报文
JSONObject jsonObject = JSON.parseObject(message);
//追加发送人(防止串改)
jsonObject.put("fromUserId", this.userId);
String toUserId = jsonObject.getString("toUserId");
//传送给对应toUserId用户的websocket
if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
} else {
LOG.error("请求的userId:" + toUserId + "不在该服务器上");
//否则不在这个服务器上,发送到mysql或者redis
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 用户异常调用
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
LOG.error("用户错误:" + this.userId + ",原因:" + error.getMessage());
error.printStackTrace();
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 发送自定义消息
*/
public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException {
LOG.info("发送消息到:" + userId + ",报文:" + message);
if (StringUtils.isNotBlank(userId) && webSocketMap.containsKey(userId)) {
webSocketMap.get(userId).sendMessage(message);
} else {
LOG.error("用户" + userId + ",不在线!");
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServerSupport.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketServerSupport.onlineCount--;
}
}
3.配置文件
代码如下(示例):
server:
port: 8088
4.单元测试
测试代码如下(示例):
import com.hyh.websocket.support.WebSocketServerSupport;
import org.springframework.stereotype.Component;
import javax.websocket.server.ServerEndpoint;
/**
* 继承WebSocketServerSupport轻松实现websocket
* 亦可以重写WebSocketServerSupport类里的方法
*
* @Author: heyuhua
* @Date: 2021/1/7 15:56
*/
@ServerEndpoint("/websocket/{userId}")
@Component
public class WebSocketServer extends WebSocketServerSupport {
//可用浏览器测试,在hyh-boot-ore的com.hyh.core.web下的WebSocketServer类
//可打开websocket在线测试地址,输入地址ws://localhost:8088/websocket/1即可进行测试
//实现方法均在WebSocketServerSupport类里,没错目的就是让你直接集成即可使用
}
总结
更多用法请点击下方查看源码,是不是感觉很简单?关注我带你揭秘更多Quartz高级用法
源码地址:点此查看源码.