mirror of https://gitee.com/stylefeng/roses
【8.1.0】【socket】移除socket模块
parent
6d731c8647
commit
14bd16efad
|
@ -1,36 +0,0 @@
|
|||
<?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>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>roses-kernel</artifactId>
|
||||
<version>8.1.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>kernel-d-socket</artifactId>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>socket-api</module>
|
||||
<module>socket-business-websocket</module>
|
||||
<module>socket-spring-boot-starter</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- 开发规则 -->
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>kernel-a-rule</artifactId>
|
||||
<version>${roses.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
|
@ -1 +0,0 @@
|
|||
socket模块的api
|
|
@ -1,41 +0,0 @@
|
|||
<?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>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>kernel-d-socket</artifactId>
|
||||
<version>8.1.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>socket-api</artifactId>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!--config模块的api-->
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>config-api</artifactId>
|
||||
<version>${roses.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Getty核心包 -->
|
||||
<dependency>
|
||||
<groupId>com.gettyio</groupId>
|
||||
<artifactId>getty-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 拓展包 -->
|
||||
<dependency>
|
||||
<groupId>com.gettyio</groupId>
|
||||
<artifactId>getty-expansion</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -1,70 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.api;
|
||||
|
||||
import cn.stylefeng.roses.kernel.socket.api.exception.SocketException;
|
||||
import cn.stylefeng.roses.kernel.socket.api.message.SocketMsgCallbackInterface;
|
||||
|
||||
/**
|
||||
* Socket通用操作类
|
||||
* <p>
|
||||
* 可通过该类直接发送消息,每一个Socket实现的子模块必须实现该接口,以提供统一的操作API
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/2 上午9:25
|
||||
*/
|
||||
public interface SocketOperatorApi {
|
||||
|
||||
/**
|
||||
* 发送消息到指定会话
|
||||
*
|
||||
* @param msgType 消息类型可参考{@link cn.stylefeng.roses.kernel.socket.api.enums}枚举类
|
||||
* @param sessionId 会话ID
|
||||
* @param msg 消息体
|
||||
* @author majianguo
|
||||
* @since 2021/6/11 下午2:19
|
||||
**/
|
||||
void sendMsgOfUserSessionBySessionId(String msgType, String sessionId, Object msg) throws SocketException;
|
||||
|
||||
/**
|
||||
* 发送消息到指定用户的所有会话
|
||||
* <p>
|
||||
* 如果用户同一个消息类型建立了多个会话,则统一全部发送
|
||||
*
|
||||
* @param msgType 消息类型可参考{@link cn.stylefeng.roses.kernel.socket.api.enums}枚举类
|
||||
* @param userId 用户ID
|
||||
* @param msg 消息体
|
||||
* @author majianguo
|
||||
* @since 2021/6/2 上午9:35
|
||||
**/
|
||||
void sendMsgOfUserSession(String msgType, String userId, Object msg) throws SocketException;
|
||||
|
||||
/**
|
||||
* 发送消息到所有会话
|
||||
*
|
||||
* @param msgType 消息类型可参考{@link cn.stylefeng.roses.kernel.socket.api.enums}枚举类
|
||||
* @param msg 消息体
|
||||
* @author majianguo
|
||||
* @since 2021/6/2 上午9:35
|
||||
**/
|
||||
void sendMsgOfAllUserSession(String msgType, Object msg);
|
||||
|
||||
/**
|
||||
* 根据会话id关闭会话
|
||||
*
|
||||
* @param socketId 会话id
|
||||
* @author majianguo
|
||||
* @since 2021/8/13 16:00
|
||||
**/
|
||||
void closeSocketBySocketId(String socketId);
|
||||
|
||||
/**
|
||||
* 监听指定类型消息
|
||||
* <p>
|
||||
* 1.该方法每调用一次即注册一个监听,同一个消息类型多次调用只有最后一次生效
|
||||
*
|
||||
* @param msgType 消息类型可参考{@link cn.stylefeng.roses.kernel.socket.api.enums}枚举类
|
||||
* @param callbackInterface 消息监听器
|
||||
* @author majianguo
|
||||
* @since 2021/6/2 上午9:54
|
||||
**/
|
||||
void msgTypeCallback(String msgType, SocketMsgCallbackInterface callbackInterface);
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright [2020-2030] [https://www.stylefeng.cn]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||
*
|
||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||||
* 2.请不要删除和修改Guns源码头部的版权声明。
|
||||
* 3.请保留源码和相关描述文件的项目出处,作者声明等。
|
||||
* 4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns
|
||||
* 5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns
|
||||
* 6.若您的项目无法满足以上几点,可申请商业授权
|
||||
*/
|
||||
package cn.stylefeng.roses.kernel.socket.api.constants;
|
||||
|
||||
/**
|
||||
* socket 模块常量
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 上午11:21
|
||||
*/
|
||||
public interface SocketConstants {
|
||||
|
||||
/**
|
||||
* socket模块的名称
|
||||
*/
|
||||
String SOCKET_MODULE_NAME = "kernel-d-socket";
|
||||
|
||||
/**
|
||||
* 异常枚举的步进值
|
||||
*/
|
||||
String SOCKET_EXCEPTION_STEP_CODE = "30";
|
||||
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.api.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 客户端消息类型枚举
|
||||
* <p>
|
||||
* 说明:该枚举适用于服务器接收到客户端发来的消息,判断消息类型时使用
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/3 上午9:14
|
||||
*/
|
||||
@Getter
|
||||
public enum ClientMessageTypeEnum {
|
||||
|
||||
/**
|
||||
* 用户连接鉴权
|
||||
*/
|
||||
USER_CONNECTION_AUTHENTICATION("200000", "用户连接鉴权"),
|
||||
|
||||
/**
|
||||
* 用户心跳消息类型
|
||||
*/
|
||||
USER_HEART("299999", "用户心跳消息类型");
|
||||
|
||||
private final String code;
|
||||
|
||||
private final String name;
|
||||
|
||||
ClientMessageTypeEnum(String code, String name) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.api.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 服务端消息类型枚举
|
||||
* <p>
|
||||
* 说明:该枚举适用于服务器推送给客户端消息时使用
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/3 上午9:14
|
||||
*/
|
||||
@Getter
|
||||
public enum ServerMessageTypeEnum {
|
||||
|
||||
/**
|
||||
* 系统通知消息类型
|
||||
*/
|
||||
SYS_NOTICE_MSG_TYPE("100001", "系统通知消息类型"),
|
||||
|
||||
/**
|
||||
* 连接消息回复
|
||||
*/
|
||||
SYS_REPLY_MSG_TYPE("100002", "连接消息回复");
|
||||
|
||||
private final String code;
|
||||
|
||||
private final String name;
|
||||
|
||||
ServerMessageTypeEnum(String code, String name) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.api.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 服务端监听器枚举
|
||||
* <p>
|
||||
* 说明:该枚举适用于服务端监听首次连接和断开连接
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/3 上午9:14
|
||||
*/
|
||||
@Getter
|
||||
public enum SystemMessageTypeEnum {
|
||||
|
||||
/**
|
||||
* 监听首次连接
|
||||
*/
|
||||
SYS_LISTENER_ONOPEN("S00001", "监听首次连接"),
|
||||
|
||||
/**
|
||||
* 监听断开连接
|
||||
*/
|
||||
SYS_LISTENER_ONCLOSE("S00002", "监听断开连接"),
|
||||
|
||||
/**
|
||||
* 监听异常信息
|
||||
*/
|
||||
SYS_LISTENER_ONERROR("S00003", "监听异常信息");
|
||||
|
||||
private final String code;
|
||||
|
||||
private final String name;
|
||||
|
||||
SystemMessageTypeEnum(String code, String name) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright [2020-2030] [https://www.stylefeng.cn]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||
*
|
||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||||
* 2.请不要删除和修改Guns源码头部的版权声明。
|
||||
* 3.请保留源码和相关描述文件的项目出处,作者声明等。
|
||||
* 4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns
|
||||
* 5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns
|
||||
* 6.若您的项目无法满足以上几点,可申请商业授权
|
||||
*/
|
||||
package cn.stylefeng.roses.kernel.socket.api.exception;
|
||||
|
||||
import cn.stylefeng.roses.kernel.rule.exception.AbstractExceptionEnum;
|
||||
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
|
||||
import cn.stylefeng.roses.kernel.socket.api.constants.SocketConstants;
|
||||
|
||||
/**
|
||||
* Socket模块异常
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 上午11:23
|
||||
*/
|
||||
public class SocketException extends ServiceException {
|
||||
|
||||
public SocketException(AbstractExceptionEnum exception) {
|
||||
super(SocketConstants.SOCKET_MODULE_NAME, exception);
|
||||
}
|
||||
|
||||
public SocketException(String errorCode, String userTip) {
|
||||
super(SocketConstants.SOCKET_MODULE_NAME, errorCode, userTip);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright [2020-2030] [https://www.stylefeng.cn]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||
*
|
||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||||
* 2.请不要删除和修改Guns源码头部的版权声明。
|
||||
* 3.请保留源码和相关描述文件的项目出处,作者声明等。
|
||||
* 4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns
|
||||
* 5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns
|
||||
* 6.若您的项目无法满足以上几点,可申请商业授权
|
||||
*/
|
||||
package cn.stylefeng.roses.kernel.socket.api.exception.enums;
|
||||
|
||||
import cn.stylefeng.roses.kernel.rule.constants.RuleConstants;
|
||||
import cn.stylefeng.roses.kernel.rule.exception.AbstractExceptionEnum;
|
||||
import cn.stylefeng.roses.kernel.socket.api.constants.SocketConstants;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Socket模块相关异常枚举
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 上午11:25
|
||||
*/
|
||||
@Getter
|
||||
public enum SocketExceptionEnum implements AbstractExceptionEnum {
|
||||
|
||||
/**
|
||||
* Socket操作异常
|
||||
*/
|
||||
SOCKET_ERROR(RuleConstants.THIRD_ERROR_TYPE_CODE + SocketConstants.SOCKET_EXCEPTION_STEP_CODE + "01", "操作异常,具体信息为:{}"),
|
||||
|
||||
/**
|
||||
* 会话不存在
|
||||
*/
|
||||
SESSION_NOT_EXIST(RuleConstants.THIRD_ERROR_TYPE_CODE + SocketConstants.SOCKET_EXCEPTION_STEP_CODE + "02", "会话不存在");
|
||||
|
||||
/**
|
||||
* 错误编码
|
||||
*/
|
||||
private final String errorCode;
|
||||
|
||||
/**
|
||||
* 提示用户信息
|
||||
*/
|
||||
private final String userTip;
|
||||
|
||||
SocketExceptionEnum(String errorCode, String userTip) {
|
||||
this.errorCode = errorCode;
|
||||
this.userTip = userTip;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.api.message;
|
||||
|
||||
import cn.stylefeng.roses.kernel.socket.api.session.pojo.SocketSession;
|
||||
|
||||
/**
|
||||
* Socket消息接收回调接口
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/2 上午9:53
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SocketMsgCallbackInterface {
|
||||
|
||||
/**
|
||||
* 收到消息的回调
|
||||
*
|
||||
* @param msgType 消息类型
|
||||
* @param msg 消息体
|
||||
* @param socketSession 本次通信的会话
|
||||
* @author majianguo
|
||||
* @since 2021/6/2 上午9:51
|
||||
**/
|
||||
void callback(String msgType, Object msg, SocketSession socketSession);
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* Copyright [2020-2030] [https://www.stylefeng.cn]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||
*
|
||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||||
* 2.请不要删除和修改Guns源码头部的版权声明。
|
||||
* 3.请保留源码和相关描述文件的项目出处,作者声明等。
|
||||
* 4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns
|
||||
* 5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns
|
||||
* 6.若您的项目无法满足以上几点,可申请商业授权
|
||||
*/
|
||||
package cn.stylefeng.roses.kernel.socket.api.session;
|
||||
|
||||
/**
|
||||
* socket会话操作接口
|
||||
* <p>
|
||||
* 该接口面向会话,须基于会话的通道调用。
|
||||
* 该接口支持扩展,可参考WebSocket模块中{@link cn.stylefeng.roses.kernel.socket.websocket.operator.channel}包下的类
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 上午11:46
|
||||
*/
|
||||
public interface SocketSessionOperatorApi {
|
||||
|
||||
/**
|
||||
* 写出数据,经过责任链
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 上午11:48
|
||||
**/
|
||||
void writeAndFlush(Object obj);
|
||||
|
||||
/**
|
||||
* 写出数据,不经过责任链
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 上午11:48
|
||||
**/
|
||||
void writeToChannel(Object obj);
|
||||
|
||||
/**
|
||||
* 关闭会话
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 上午11:48
|
||||
**/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* 是否存活
|
||||
*
|
||||
* @return {@link boolean}
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 上午11:50
|
||||
**/
|
||||
boolean isInvalid();
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.api.session.pojo;
|
||||
|
||||
import cn.stylefeng.roses.kernel.socket.api.session.SocketSessionOperatorApi;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Socket会话
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 上午11:28
|
||||
*/
|
||||
@Data
|
||||
public class SocketSession<T extends SocketSessionOperatorApi> {
|
||||
|
||||
/**
|
||||
* 会话ID,每一个新建的会话都有(目前使用通道ID)
|
||||
*/
|
||||
private String sessionId;
|
||||
|
||||
/**
|
||||
* 会话唯一标识
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 该会话监听的消息类型
|
||||
*/
|
||||
private String messageType;
|
||||
|
||||
/**
|
||||
* token信息
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 连接时间
|
||||
*/
|
||||
private Long connectionTime;
|
||||
|
||||
/**
|
||||
* 最后活跃时间
|
||||
*/
|
||||
private Long lastActiveTime;
|
||||
|
||||
/**
|
||||
* 操作API
|
||||
*/
|
||||
private T socketOperatorApi;
|
||||
|
||||
/**
|
||||
* 自定义数据
|
||||
*/
|
||||
private Object data;
|
||||
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
<?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>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>kernel-d-socket</artifactId>
|
||||
<version>8.1.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>socket-business-websocket</artifactId>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!--Spring boot WebSocket实现-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--web模块-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--socket模块api-->
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>socket-api</artifactId>
|
||||
<version>${roses.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--jwt模块的sdk-->
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>auth-api</artifactId>
|
||||
<version>${roses.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -1,20 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.business.websocket.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||
|
||||
/**
|
||||
* 开启WebSocket支持
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/21 下午5:01
|
||||
*/
|
||||
@Configuration
|
||||
public class WebSocketConfig {
|
||||
|
||||
@Bean
|
||||
public ServerEndpointExporter serverEndpointExporter() {
|
||||
return new ServerEndpointExporter();
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.business.websocket.message;
|
||||
|
||||
import cn.stylefeng.roses.kernel.socket.api.message.SocketMsgCallbackInterface;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 会话消息中心
|
||||
* <p>
|
||||
* 维护所有消息类型对应的处理器
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午2:20
|
||||
*/
|
||||
public class SocketMessageCenter {
|
||||
|
||||
/**
|
||||
* 所有消息监听器维护
|
||||
*/
|
||||
private static final Map<String, SocketMsgCallbackInterface> MESSAGE_LISTENER_MAP = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 设置消息类型的监听器
|
||||
*
|
||||
* @param msgType 消息类型
|
||||
* @param listener 监听器
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午2:25
|
||||
**/
|
||||
public static void setMessageListener(String msgType, SocketMsgCallbackInterface listener) {
|
||||
MESSAGE_LISTENER_MAP.put(msgType, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取消息监听器
|
||||
*
|
||||
* @param msgType 消息类型
|
||||
* @return {@link SocketMsgCallbackInterface}
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午2:26
|
||||
**/
|
||||
public static SocketMsgCallbackInterface getSocketMsgCallbackInterface(String msgType) {
|
||||
return MESSAGE_LISTENER_MAP.get(msgType);
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.business.websocket.operator;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.stylefeng.roses.kernel.socket.api.SocketOperatorApi;
|
||||
import cn.stylefeng.roses.kernel.socket.api.exception.SocketException;
|
||||
import cn.stylefeng.roses.kernel.socket.api.exception.enums.SocketExceptionEnum;
|
||||
import cn.stylefeng.roses.kernel.socket.api.message.SocketMsgCallbackInterface;
|
||||
import cn.stylefeng.roses.kernel.socket.api.session.pojo.SocketSession;
|
||||
import cn.stylefeng.roses.kernel.socket.business.websocket.message.SocketMessageCenter;
|
||||
import cn.stylefeng.roses.kernel.socket.business.websocket.pojo.WebSocketMessageDTO;
|
||||
import cn.stylefeng.roses.kernel.socket.business.websocket.session.SessionCenter;
|
||||
import cn.stylefeng.roses.kernel.socket.business.websocket.operator.channel.GunsSocketOperator;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* WebSocket操作实现类
|
||||
* <p>
|
||||
* 如果是Spring boot项目,通过注入SocketOperatorApi接口操作socket,需将本来交给Spring管理
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/2 上午10:41
|
||||
*/
|
||||
public class WebSocketOperator implements SocketOperatorApi {
|
||||
|
||||
@Override
|
||||
public void sendMsgOfUserSessionBySessionId(String msgType, String sessionId, Object msg) throws SocketException {
|
||||
SocketSession<GunsSocketOperator> session = SessionCenter.getSessionBySessionId(sessionId);
|
||||
if (ObjectUtil.isEmpty(session)) {
|
||||
throw new SocketException(SocketExceptionEnum.SESSION_NOT_EXIST);
|
||||
}
|
||||
WebSocketMessageDTO webSocketMessageDTO = new WebSocketMessageDTO();
|
||||
webSocketMessageDTO.setData(msg);
|
||||
webSocketMessageDTO.setServerMsgType(msgType);
|
||||
session.getSocketOperatorApi().writeAndFlush(webSocketMessageDTO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMsgOfUserSession(String msgType, String userId, Object msg) throws SocketException {
|
||||
// 根据用户ID获取会话
|
||||
List<SocketSession<GunsSocketOperator>> socketSessionList = SessionCenter.getSessionByUserIdAndMsgType(userId);
|
||||
if (ObjectUtil.isEmpty(socketSessionList)) {
|
||||
throw new SocketException(SocketExceptionEnum.SESSION_NOT_EXIST);
|
||||
}
|
||||
WebSocketMessageDTO webSocketMessageDTO = new WebSocketMessageDTO();
|
||||
webSocketMessageDTO.setData(msg);
|
||||
webSocketMessageDTO.setServerMsgType(msgType);
|
||||
for (SocketSession<GunsSocketOperator> session : socketSessionList) {
|
||||
// 发送内容
|
||||
session.getSocketOperatorApi().writeAndFlush(webSocketMessageDTO);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMsgOfAllUserSession(String msgType, Object msg) {
|
||||
Collection<List<SocketSession<GunsSocketOperator>>> values = SessionCenter.getSocketSessionMap().values();
|
||||
WebSocketMessageDTO webSocketMessageDTO = new WebSocketMessageDTO();
|
||||
webSocketMessageDTO.setData(msg);
|
||||
webSocketMessageDTO.setServerMsgType(msgType);
|
||||
for (List<SocketSession<GunsSocketOperator>> sessions : values) {
|
||||
for (SocketSession<GunsSocketOperator> session : sessions) {
|
||||
// 找到该类型的通道
|
||||
if (session.getMessageType().equals(msgType)) {
|
||||
session.getSocketOperatorApi().writeAndFlush(webSocketMessageDTO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeSocketBySocketId(String socketId) {
|
||||
SessionCenter.closed(socketId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void msgTypeCallback(String msgType, SocketMsgCallbackInterface callbackInterface) {
|
||||
SocketMessageCenter.setMessageListener(msgType, callbackInterface);
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.business.websocket.operator.channel;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import javax.websocket.Session;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Socket操作类实现
|
||||
* <p>
|
||||
* 简单封装Spring Boot的默认WebSocket
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午3:41
|
||||
*/
|
||||
public class GunsSocketOperator implements SocketChannelExpandInterFace {
|
||||
|
||||
/**
|
||||
* 实际操作的通道
|
||||
*/
|
||||
private Session socketChannel;
|
||||
|
||||
public GunsSocketOperator(Session socketChannel) {
|
||||
this.socketChannel = socketChannel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeAndFlush(Object obj) {
|
||||
try {
|
||||
if (socketChannel.isOpen()) {
|
||||
socketChannel.getBasicRemote().sendText(JSON.toJSONString(obj));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToChannel(Object obj) {
|
||||
if (socketChannel.isOpen()) {
|
||||
socketChannel.getAsyncRemote().sendText(JSON.toJSONString(obj));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
if (socketChannel.isOpen()) {
|
||||
socketChannel.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvalid() {
|
||||
return socketChannel.isOpen();
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.business.websocket.operator.channel;
|
||||
|
||||
import cn.stylefeng.roses.kernel.socket.api.session.SocketSessionOperatorApi;
|
||||
|
||||
/**
|
||||
* 对Api模块的操作类进行扩展
|
||||
* <p>
|
||||
* 暂时只写接口,SocketOperatorApi方法不够用时再对此类进行扩展
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午3:44
|
||||
*/
|
||||
public interface SocketChannelExpandInterFace extends SocketSessionOperatorApi {
|
||||
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.business.websocket.pojo;
|
||||
|
||||
import cn.stylefeng.roses.kernel.socket.api.SocketOperatorApi;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* WebSocket交互通用对象
|
||||
* <p>
|
||||
* 特殊说明一下serverMsgType和clientMsgType的区别
|
||||
* 1.serverMsgType字段是服务端发送给客户端的字段
|
||||
* 例如:服务端发送一个系统消息(type:100001),客户端接收到该消息以后判断需不需要处理,不需要处理跳过即可
|
||||
* <p>
|
||||
* 2.clientMsgType字段是客户端发送给服务器的字段
|
||||
* 例如:客户端发送给服务器一个心跳消息(type:299999),服务端如果需要处理该消息就注册一个该消息的监听器,
|
||||
* 那么收到消息服务端会把消息推送给对应的监听器,接口见{@link SocketOperatorApi#msgTypeCallback}
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午2:56
|
||||
*/
|
||||
@Data
|
||||
public class WebSocketMessageDTO {
|
||||
|
||||
/**
|
||||
* 服务端发送的消息类型(客户端如果需要监听该消息类型,注册对应的消息处理器即可)
|
||||
*/
|
||||
private String serverMsgType;
|
||||
|
||||
/**
|
||||
* 客户端发送的消息类型(服务端需要处理的消息类型)
|
||||
*/
|
||||
private String clientMsgType;
|
||||
|
||||
/**
|
||||
* 目标Id
|
||||
*/
|
||||
private String toUserId;
|
||||
|
||||
/**
|
||||
* 发送者ID
|
||||
*/
|
||||
private String formUserId;
|
||||
|
||||
/**
|
||||
* 具体发送的数据
|
||||
*/
|
||||
private Object data;
|
||||
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.business.websocket.server;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.stylefeng.roses.kernel.auth.api.context.AuthJwtContext;
|
||||
import cn.stylefeng.roses.kernel.auth.api.pojo.payload.DefaultJwtPayload;
|
||||
import cn.stylefeng.roses.kernel.socket.api.enums.ClientMessageTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.socket.api.enums.ServerMessageTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.socket.api.enums.SystemMessageTypeEnum;
|
||||
import cn.stylefeng.roses.kernel.socket.api.message.SocketMsgCallbackInterface;
|
||||
import cn.stylefeng.roses.kernel.socket.api.session.pojo.SocketSession;
|
||||
import cn.stylefeng.roses.kernel.socket.business.websocket.message.SocketMessageCenter;
|
||||
import cn.stylefeng.roses.kernel.socket.business.websocket.operator.channel.GunsSocketOperator;
|
||||
import cn.stylefeng.roses.kernel.socket.business.websocket.pojo.WebSocketMessageDTO;
|
||||
import cn.stylefeng.roses.kernel.socket.business.websocket.session.SessionCenter;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.websocket.*;
|
||||
import javax.websocket.server.PathParam;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 消息监听处理器
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午2:35
|
||||
*/
|
||||
@Slf4j
|
||||
@ServerEndpoint(value = "/webSocket/{token}")
|
||||
@Component
|
||||
public class WebSocketServer {
|
||||
|
||||
/**
|
||||
* 连接建立调用的方法
|
||||
* <p>
|
||||
* 暂时无用,需要在建立连接的时候做一些事情的话可以修改这里
|
||||
*
|
||||
* @param session 会话信息
|
||||
* @author majianguo
|
||||
* @since 2021/6/21 下午5:14
|
||||
**/
|
||||
@OnOpen
|
||||
public void onOpen(Session session, @PathParam("token") String token) {
|
||||
String userId = null;
|
||||
try {
|
||||
// 解析用户信息
|
||||
DefaultJwtPayload defaultPayload = AuthJwtContext.me().getDefaultPayload(token);
|
||||
userId = defaultPayload.getUserId().toString();
|
||||
} catch (io.jsonwebtoken.JwtException e) {
|
||||
try {
|
||||
session.close();
|
||||
} catch (IOException ioException) {
|
||||
ioException.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// 操作api包装
|
||||
GunsSocketOperator gunsSocketOperator = new GunsSocketOperator(session);
|
||||
|
||||
// 回复消息
|
||||
WebSocketMessageDTO replyMsg = new WebSocketMessageDTO();
|
||||
replyMsg.setServerMsgType(ServerMessageTypeEnum.SYS_REPLY_MSG_TYPE.getCode());
|
||||
replyMsg.setToUserId(userId);
|
||||
|
||||
// 创建会话对象
|
||||
SocketSession<GunsSocketOperator> socketSession = new SocketSession<>();
|
||||
try {
|
||||
// 设置回复内容
|
||||
replyMsg.setData(session.getId());
|
||||
socketSession.setSessionId(session.getId());
|
||||
socketSession.setUserId(userId);
|
||||
socketSession.setSocketOperatorApi(gunsSocketOperator);
|
||||
socketSession.setToken(token);
|
||||
socketSession.setConnectionTime(System.currentTimeMillis());
|
||||
|
||||
// 维护会话
|
||||
SessionCenter.addSocketSession(socketSession);
|
||||
} finally {
|
||||
// 回复消息
|
||||
gunsSocketOperator.writeAndFlush(replyMsg);
|
||||
|
||||
// 触发首次连接回调
|
||||
SocketMsgCallbackInterface socketMsgCallbackInterface = SocketMessageCenter.getSocketMsgCallbackInterface(SystemMessageTypeEnum.SYS_LISTENER_ONOPEN.getCode());
|
||||
if (ObjectUtil.isNotEmpty(socketMsgCallbackInterface)) {
|
||||
// 触发回调
|
||||
socketMsgCallbackInterface.callback(SystemMessageTypeEnum.SYS_LISTENER_ONOPEN.getCode(), null, socketSession);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接关闭调用的方法
|
||||
*
|
||||
* @param session 会话信息
|
||||
* @author majianguo
|
||||
* @since 2021/6/21 下午5:14
|
||||
**/
|
||||
@OnClose
|
||||
public void onClose(Session session) {
|
||||
try {
|
||||
SocketSession<GunsSocketOperator> socketSession = SessionCenter.getSessionBySessionId(session.getId());
|
||||
// 触发首次连接回调
|
||||
SocketMsgCallbackInterface socketMsgCallbackInterface = SocketMessageCenter.getSocketMsgCallbackInterface(SystemMessageTypeEnum.SYS_LISTENER_ONCLOSE.getCode());
|
||||
if (ObjectUtil.isNotEmpty(socketSession) && ObjectUtil.isNotEmpty(socketMsgCallbackInterface)) {
|
||||
// 触发回调
|
||||
socketMsgCallbackInterface.callback(SystemMessageTypeEnum.SYS_LISTENER_ONCLOSE.getCode(), null, socketSession);
|
||||
}
|
||||
} finally {
|
||||
SessionCenter.deleteById(session.getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 收到消息调用的方法
|
||||
*
|
||||
* @param message 接收到的消息
|
||||
* @param socketChannel 会话信息
|
||||
* @author majianguo
|
||||
* @since 2021/6/21 下午5:14
|
||||
**/
|
||||
@OnMessage
|
||||
public void onMessage(String message, Session socketChannel) {
|
||||
|
||||
// 转换为Java对象
|
||||
WebSocketMessageDTO WebSocketMessageDTO = JSON.parseObject(message, WebSocketMessageDTO.class);
|
||||
|
||||
// 维护通道是否已初始化
|
||||
SocketSession<GunsSocketOperator> socketSession = SessionCenter.getSessionBySessionId(socketChannel.getId());
|
||||
|
||||
// 心跳包
|
||||
if (ObjectUtil.isNotEmpty(socketSession) && ClientMessageTypeEnum.USER_HEART.getCode().equals(WebSocketMessageDTO.getClientMsgType())) {
|
||||
// 更新会话最后活跃时间
|
||||
if (ObjectUtil.isNotEmpty(socketSession)) {
|
||||
socketSession.setLastActiveTime(System.currentTimeMillis());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 用户ID为空不处理直接跳过
|
||||
if (ObjectUtil.isEmpty(WebSocketMessageDTO.getFormUserId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 会话建立成功执行业务逻辑
|
||||
if (ObjectUtil.isNotEmpty(socketSession)) {
|
||||
|
||||
// 更新最后会话时间
|
||||
socketSession.setLastActiveTime(System.currentTimeMillis());
|
||||
|
||||
// 找到该消息的处理器
|
||||
SocketMsgCallbackInterface socketMsgCallbackInterface = SocketMessageCenter.getSocketMsgCallbackInterface(WebSocketMessageDTO.getClientMsgType());
|
||||
if (ObjectUtil.isNotEmpty(socketMsgCallbackInterface)) {
|
||||
// 触发回调
|
||||
socketMsgCallbackInterface.callback(WebSocketMessageDTO.getClientMsgType(), WebSocketMessageDTO, socketSession);
|
||||
} else {
|
||||
socketChannel.getAsyncRemote().sendText("{\"serverMsgType\":\"404\"}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话发送异常调用的方法
|
||||
*
|
||||
* @param session 会话信息
|
||||
* @param error 错误信息
|
||||
* @author majianguo
|
||||
* @since 2021/6/21 下午5:14
|
||||
**/
|
||||
@OnError
|
||||
public void onError(Session session, Throwable error) {
|
||||
SocketSession<GunsSocketOperator> socketSession = SessionCenter.getSessionBySessionId(session.getId());
|
||||
// 触发首次连接回调
|
||||
SocketMsgCallbackInterface socketMsgCallbackInterface = SocketMessageCenter.getSocketMsgCallbackInterface(SystemMessageTypeEnum.SYS_LISTENER_ONERROR.getCode());
|
||||
if (ObjectUtil.isNotEmpty(socketMsgCallbackInterface)) {
|
||||
// 触发回调
|
||||
socketMsgCallbackInterface.callback(SystemMessageTypeEnum.SYS_LISTENER_ONERROR.getCode(), error, socketSession);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.socket.business.websocket.session;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.stylefeng.roses.kernel.socket.api.session.pojo.SocketSession;
|
||||
import cn.stylefeng.roses.kernel.socket.business.websocket.operator.channel.GunsSocketOperator;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* 会话中心
|
||||
* <p>
|
||||
* 维护所有的会话
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午1:43
|
||||
*/
|
||||
public class SessionCenter {
|
||||
|
||||
/**
|
||||
* 所有用户会话维护
|
||||
*/
|
||||
private static ConcurrentMap<String, List<SocketSession<GunsSocketOperator>>> socketSessionMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 获取维护的所有会话
|
||||
*
|
||||
* @return {@link ConcurrentMap< String, SocketSession<GunsSocketOperator>>}
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午2:13
|
||||
**/
|
||||
public static ConcurrentMap<String, List<SocketSession<GunsSocketOperator>>> getSocketSessionMap() {
|
||||
return socketSessionMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID获取会话信息列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return {@link SocketSession <GunsSocketOperator>}
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午1:48
|
||||
**/
|
||||
public static List<SocketSession<GunsSocketOperator>> getSessionByUserId(String userId) {
|
||||
return socketSessionMap.get(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID和消息类型获取会话信息列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return {@link SocketSession <GunsSocketOperator>}
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午1:48
|
||||
**/
|
||||
public static List<SocketSession<GunsSocketOperator>> getSessionByUserIdAndMsgType(String userId) {
|
||||
return socketSessionMap.get(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据会话ID获取会话信息
|
||||
*
|
||||
* @param sessionId 会话ID
|
||||
* @return {@link SocketSession <GunsSocketOperator>}
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午1:48
|
||||
**/
|
||||
public static SocketSession<GunsSocketOperator> getSessionBySessionId(String sessionId) {
|
||||
Set<Map.Entry<String, List<SocketSession<GunsSocketOperator>>>> entrySet = socketSessionMap.entrySet();
|
||||
for (Map.Entry<String, List<SocketSession<GunsSocketOperator>>> stringListEntry : entrySet) {
|
||||
List<SocketSession<GunsSocketOperator>> stringListEntryValue = stringListEntry.getValue();
|
||||
for (SocketSession<GunsSocketOperator> socketSession : stringListEntryValue) {
|
||||
if (sessionId.equals(socketSession.getSessionId())) {
|
||||
return socketSession;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置会话
|
||||
*
|
||||
* @param socketSession 会话详情
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午1:49
|
||||
**/
|
||||
public static void addSocketSession(SocketSession<GunsSocketOperator> socketSession) {
|
||||
List<SocketSession<GunsSocketOperator>> socketSessions = socketSessionMap.get(socketSession.getUserId());
|
||||
if (ObjectUtil.isEmpty(socketSessions)) {
|
||||
socketSessions = Collections.synchronizedList(new ArrayList<>());
|
||||
socketSessionMap.put(socketSession.getUserId(), socketSessions);
|
||||
}
|
||||
socketSessions.add(socketSession);
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接关闭
|
||||
*
|
||||
* @param sessionId 会话ID
|
||||
* @author majianguo
|
||||
* @since 2021/6/1 下午3:25
|
||||
**/
|
||||
public static void closed(String sessionId) {
|
||||
// 删除维护关系
|
||||
SocketSession<GunsSocketOperator> operatorSocketSession = getSessionBySessionId(sessionId);
|
||||
if (ObjectUtil.isNotEmpty(operatorSocketSession)) {
|
||||
operatorSocketSession.getSocketOperatorApi().close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除维护关系
|
||||
*
|
||||
* @param sessionId 会话ID
|
||||
* @return {@link cn.stylefeng.roses.kernel.socket.api.session.pojo.SocketSession<cn.stylefeng.roses.kernel.socket.business.websocket.operator.channel.GunsSocketOperator>}
|
||||
* @author majianguo
|
||||
* @since 2021/8/30 9:20
|
||||
**/
|
||||
public static SocketSession<GunsSocketOperator> deleteById(String sessionId) {
|
||||
// 获取所有人员的连接会话信息
|
||||
Set<Map.Entry<String, List<SocketSession<GunsSocketOperator>>>> entrySet = socketSessionMap.entrySet();
|
||||
Iterator<Map.Entry<String, List<SocketSession<GunsSocketOperator>>>> iterator = entrySet.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, List<SocketSession<GunsSocketOperator>>> next = iterator.next();
|
||||
List<SocketSession<GunsSocketOperator>> value = next.getValue();
|
||||
if (ObjectUtil.isNotEmpty(value)) {
|
||||
|
||||
// 找出该人员的指定会话信息
|
||||
Iterator<SocketSession<GunsSocketOperator>> socketSessionIterator = value.iterator();
|
||||
while (socketSessionIterator.hasNext()) {
|
||||
SocketSession<GunsSocketOperator> operatorSocketSession = socketSessionIterator.next();
|
||||
if (operatorSocketSession.getSessionId().equals(sessionId)) {
|
||||
// 在列表中删除
|
||||
socketSessionIterator.remove();
|
||||
return operatorSocketSession;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Socket的spring boot自动加载模块
|
|
@ -1,29 +0,0 @@
|
|||
<?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>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>kernel-d-socket</artifactId>
|
||||
<version>8.1.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>socket-spring-boot-starter</artifactId>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- WebSocket模块 -->
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>socket-business-websocket</artifactId>
|
||||
<version>${roses.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright [2020-2030] [https://www.stylefeng.cn]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
|
||||
*
|
||||
* 1.请不要删除和修改根目录下的LICENSE文件。
|
||||
* 2.请不要删除和修改Guns源码头部的版权声明。
|
||||
* 3.请保留源码和相关描述文件的项目出处,作者声明等。
|
||||
* 4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns
|
||||
* 5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns
|
||||
* 6.若您的项目无法满足以上几点,可申请商业授权
|
||||
*/
|
||||
package cn.stylefeng.roses.kernel.socket.starter;
|
||||
|
||||
import cn.stylefeng.roses.kernel.socket.api.SocketOperatorApi;
|
||||
import cn.stylefeng.roses.kernel.socket.business.websocket.operator.WebSocketOperator;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Socket的自动配置类
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/2 下午5:48
|
||||
*/
|
||||
@Configuration
|
||||
public class ProjectSocketAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Socket操作实现类
|
||||
*
|
||||
* @author majianguo
|
||||
* @since 2021/6/2 下午5:48
|
||||
**/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(SocketOperatorApi.class)
|
||||
public SocketOperatorApi socketOperatorApi() {
|
||||
return new WebSocketOperator();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.stylefeng.roses.kernel.socket.starter.ProjectSocketAutoConfiguration
|
|
@ -117,13 +117,6 @@
|
|||
<version>${roses.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--Socket模块-->
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>socket-spring-boot-starter</artifactId>
|
||||
<version>${roses.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--wrapper工具-->
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
|
|
Loading…
Reference in New Issue