学习地址:https://blog.csdn.net/qq_43898141/article/details/123744468
- 添加websocket 依赖
<!--添加websockert依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId><exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
- 添加配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
- webSocket 代码
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.ruoyi.common.core.config.systemConfig;
import com.ruoyi.common.core.utils.SpringUtils;
import com.ruoyi.common.redis.service.RedisService;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint(value = "/websocket/{userName}")
@Component
public class WebSocketService implements Serializable {
//concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
@JsonBackReference
private static Map<String, WebSocketService> webSocketMap = new ConcurrentHashMap<>();
/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
private Session session;
/**
* 接收userName
*/
private String userName = "";
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("userName") String userName) {
this.session = session;
this.userName = userName;
webSocketMap.put(userName, this);
System.err.println("----------------------------------------------------------------------------");
System.err.println("用户连接:" + userName + ":" + userName + ",当前在线人数为:" + webSocketMap.size());
sendMessage("来自后台的反馈:连接成功");
webSocketMap.forEach((k, v) -> System.err.println(k));
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(@PathParam("userName") String userName) {
if (webSocketMap.containsKey(userName)) {
webSocketMap.remove(userName);
}
System.err.println("----------------------------------------------------------------------------");
System.err.println(userName + "用户退出,当前在线人数为:" + webSocketMap.size());
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
System.err.println("收到用户消息:" + userName + ",报文:" + message);
//可以群发消息
//消息保存到数据库、redis
if (message != null) System.err.println("");
}
/**
* 连接失败调用方法
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
System.err.println("用户错误:" + this.userName + ",原因:" + error.getMessage());
error.printStackTrace();
}
/**
* 连接服务器成功后主动推送
*/
public void sendMessage(String message) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 向指定客户端发送消息
* <p>
* // * @param userName
* //* @param message
*/
public static void sendMessage(String userName, String message) {
try {
WebSocketService webSocketService = webSocketMap.get(userName);
if (webSocketService != null) {
webSocketService.getSession().getBasicRemote().sendText(message);
}
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
//下面方法根据自己情况 删 留
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public static Map<String, WebSocketService> getWebSocketMap() {
return webSocketMap;
}
public static void setWebSocketMap(Map<String, WebSocketService> webSocketMap) {
WebSocketService.webSocketMap = webSocketMap;
}
public static void put(String key, WebSocketService data) {
webSocketMap.put(key, data);
}
public static WebSocketService get(String key) {
return webSocketMap.get(key);
}
public static void del(String key) {
webSocketMap.remove(key);
}
- 网管配置服务转发
# websocket模块
#服务名称
- id: ruoyi-chat-websocket
#转发的服务
uri: lb:ws://ruoyi-chat
#转发设置
predicates:
- Path=/websocket/**
#请求地址后一位,如:/socket/xxx/xx 去掉socket = /xxx/xx
filters:
- StripPrefix=1
- 重要: 如果你的webSocket 没有Token 也没有任何认证的话 需要开放白名单。
# 不校验白名单
ignore:
whites:
- /code
- /auth/logout
- /auth/login
- /auth/smsLogin
- /auth/xcxLogin
- /auth/mobileLogin
- /websocket/**
- **开始测试 **http://www.jsons.cn/websocket/
-
如果出现连接成功 立马断开的问题 排查思路如下
- 排查网关里面的转发url 是否使用的ws=> lb:ws://ruoyi-chat
- 是否开启了白名单
如果以上都可以了 还是不行,那就是因为他的子模块默认也是需要Token 权限的 我在解决了两天的情况下发现 需要加上以下配置
- 在 SecurityConfiguration implements WebMvcConfigurer 文件下面增加 放过
/**
* 校验是否从网关转发
*/
@Bean
public SaServletFilter getSaServletFilter() {
return new SaServletFilter()
.addInclude("/**")
.addExclude("/actuator/**")
.addExclude("/socket/**")
.setAuth(obj -> SaIdUtil.checkCurrentRequestToken())
.setError(e -> SaResult.error("认证失败,无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED));
}
出现的错误提示文章来源:https://www.toymoban.com/news/detail-425282.html
WebSocketClientHandshakeException Create breakpoint : Invalid handshake response getStatus: 200 OK
An exception has been observed post termination, use DEBUG level to see the full stack:io.netty . handler . codec . http . websocketx . webSocketClientHandshakeExcept ion: Connection prematurely closed BEFORE opening handshake is complete.
结论:
在子模块中也是需要鉴权的Token 的如果只在网管放开白名单 在子模块也是不行的 所以直接在这个地方加上文章来源地址https://www.toymoban.com/news/detail-425282.html
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.id.SaIdUtil;
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
import cn.dev33.satoken.util.SaResult;
import com.yawei.common.core.constant.HttpStatus;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 权限安全配置
*
* @author Suiquantong
*/
@AutoConfiguration
public class SecurityConfiguration implements WebMvcConfigurer {
/**
* 注册sa-token的拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注解拦截器
registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");
}
/**
* 校验是否从网关转发
*/
@Bean
public SaServletFilter getSaServletFilter() {
return new SaServletFilter()
.addInclude("/**")
.addExclude("/actuator/**")
.addExclude("/socket/**")
.setAuth(obj -> SaIdUtil.checkCurrentRequestToken())
.setError(e -> SaResult.error("认证失败,无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED));
}
}
到了这里,关于RuoYi-Cloud-Plus集成 WebSocket的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!