学习地址:https://blog.csdn.net/qq_43898141/article/details/123744468
org.springframework.boot spring-boot-starter-websocket org.springframework.boot spring-boot-starter-web
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configurationpublic class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}
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对象。@JsonBackReferenceprivate static Map webSocketMap = new ConcurrentHashMap<>();/*** 与某个客户端的连接会话,需要通过它来给客户端发送数据*/private Session session;/*** 接收userName*/private String userName = "";/*** 连接建立成功调用的方法*/@OnOpenpublic 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));}/*** 连接关闭调用的方法*/@OnClosepublic void onClose(@PathParam("userName") String userName) {if (webSocketMap.containsKey(userName)) {webSocketMap.remove(userName);}System.err.println("----------------------------------------------------------------------------");System.err.println(userName + "用户退出,当前在线人数为:" + webSocketMap.size());}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) {System.err.println("收到用户消息:" + userName + ",报文:" + message);//可以群发消息//消息保存到数据库、redisif (message != null) System.err.println("");}/*** 连接失败调用方法* @param session* @param error*/@OnErrorpublic 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();}}/*** 向指定客户端发送消息* * // * @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 getWebSocketMap() {return webSocketMap;}public static void setWebSocketMap(Map 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/xxfilters:- StripPrefix=1


# 不校验白名单ignore:whites:- /code- /auth/logout- /auth/login- /auth/smsLogin- /auth/xcxLogin- /auth/mobileLogin- /websocket/**

如果以上都可以了 还是不行,那就是因为他的子模块默认也是需要Token 权限的 我在解决了两天的情况下发现 需要加上以下配置
/**
* 校验是否从网关转发
*/
@Beanpublic SaServletFilter getSaServletFilter() {return new SaServletFilter().addInclude("/**").addExclude("/actuator/**").addExclude("/socket/**").setAuth(obj -> SaIdUtil.checkCurrentRequestToken()).setError(e -> SaResult.error("认证失败,无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED));
}
出现的错误提示
WebSocketClientHandshakeException Create breakpoint : Invalid handshake response getStatus: 200 OKAn 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 的如果只在网管放开白名单 在子模块也是不行的 所以直接在这个地方加上
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的拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注解拦截器registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");}/*** 校验是否从网关转发*/@Beanpublic SaServletFilter getSaServletFilter() {return new SaServletFilter().addInclude("/**").addExclude("/actuator/**").addExclude("/socket/**").setAuth(obj -> SaIdUtil.checkCurrentRequestToken()).setError(e -> SaResult.error("认证失败,无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED));}}