С сегодняшнего дня закатай рукава и следуй за мной.
Совет: если у вас есть какие-либо вопросы, пожалуйста, свяжитесь с личным сообщением, адрес исходного кода ниже, пожалуйста, получите его самостоятельно
предисловие
Использование Spring Boot может быть очень удобным и быстрым для сборки проекта, так что нам не нужно заботиться о совместимости между фреймворками, применимыми версиями и другими вопросами, мы хотим использовать что угодно, просто добавляем конфигурацию.
Совет: Ниже приведен основной текст этой статьи, следующие случаи приведены для справки.
1. Техническое введение
1. Что такое веб-сокет?
WebSocket — это протокол для полнодуплексной связи по одному TCP-соединению. Протокол связи WebSocket был установлен IETF в качестве стандарта RFC 6455 в 2011 году и дополнен RFC7936. WebSocket API также является стандартом W3C. WebSocket упрощает обмен данными между клиентом и сервером, позволяя серверу активно передавать данные клиенту. В API WebSocket браузеру и серверу нужно выполнить только одно рукопожатие, и между ними может быть создано постоянное соединение, и может выполняться двусторонняя передача данных.2. Используйте шаги
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
Адрес источника:Нажмите здесь, чтобы просмотреть исходный код.