一、 Springboot整合WebSocket
1. 引入socket依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
引入依赖后需要刷新maven,Websocket的版本默认跟随Springboot版本,如果当后面配置好WebSocket后,发现项目无法启动,有可能是版本问题,记得查看一下maven下载的依赖是否与当前Springboot版本一致,如果不一致并且删除依赖重新下载版本号还是无法对应需要指定一下版本号
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>{Springboot的版本号}</version>
</dependency>
2.创建WebSocket配置类
ServerEndpointExporter 是一个Spring框架提供的类,它可以自动注册和管理WebSocket的端点。它会扫描带有 @ServerEndpoint 注解的类,并将其注册为WebSocket的端点,以便客户端可以连接和通信
@Configuration
@EnableWebSocket
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter()
{
return new ServerEndpointExporter();
}
}
3.创建WebSocket自定义编码类
/**
* 自定义编码类
* 因为WebSocketServer发送消息使用sendObject()方法,需要自定义编码类,将Object转化为Json传输。
*/
public class MyEncoder implements Encoder.Text<ArrayList> {
private static final Logger log = LoggerFactory.getLogger(MyEncoder.class);
/**
* 这里的参数要和Encoder.Text<T>保持一致
*
* @param list
* @return
* @throws EncodeException
*/
@Override
public String encode(ArrayList list) throws EncodeException {
/*
* 只需要返回Object序列化后的json字符串就行
* 你也可以使用gosn,fastJson来序列化
*/
try {
JsonMapper jsonMapper = new JsonMapper();
return jsonMapper.writeValueAsString(list);
} catch (Exception e) {
log.info("ServerEncoder编码异常:{}", e.getMessage());
}
return null;
}
@Override
public void init(EndpointConfig endpointConfig) {
//可忽略
}
@Override
public void destroy() {
//可忽略
}
}
4.创建WebSocketServer
@Component
@ServerEndpoint(value = "/websocket/{userId}", encoders = {MyEncoder.class})
public class WebSocketServer {
private final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
// 会话池,用来存在线连接数
private static final Map<String, Session> SESSION_POOL = new ConcurrentHashMap<>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
@OnOpen
public void onOpen(Session session, @PathParam(value = "userId") String userId)
{
try
{
this.session = session;
SESSION_POOL.put(userId, session);
}
catch (Exception e) { }
}
//收到客户端消息后调用的方法
@OnMessage
public void onMessage(String data)
{
sendMessageById(socketMessage.getAcceptUserId(), socketMessage.getMessage());
}
/**
* 连接关闭@PathParam("userId") String userId
* 调用的方法
*/
@OnClose
public void onClose(@PathParam("userId") String userId)
{
SESSION_POOL.remove(userId);
}
//发送消息给客户端
public void sendMessageById(String userId, String message)
{
Session session = SESSION_POOL.get(userId);
if (session != null)
{
session.getAsyncRemote().sendText(message);
}
}
//发送消息给所有客户端
public void sendMessage(List<Map<Object, Object>> message) throws EncodeException, IOException
{
for (Session session : SESSION_POOL.values()) {
session.getBasicRemote().sendObject(message);
}
}
}
注:
1.代码到这里我们一个简易的websocket服务端就已经搭建完成,这个时候我们已经可以启动项目,如果启动报错请翻阅导入依赖时我提到的情况进行问题排查
2.我们如果进行本地测试的话下面是我们websocket的请求路径,不要忘记在自己的后端的白名单中开放路径
/websocket/** // 开放的白名单路径
ws://127.0.0.1:8080/websocket/{userId} // api调用路径
二、在WebSocket中注入Redis
1. 了解为什么WebSocket无法注入Redis
- 直接通过Java的@ServerEndpoint注解来配置WebSocket,那么它可能不会被Spring容器管理,因此无法自动注入Spring的bean。
- RedisTemplate通常是一个单例(Singleton)作用域的bean。如果你的WebSocket端点是以请求(Request)或会话(Session)作用域创建的,那么直接注入单例bean通常不是问题,但作用域不匹配可能导致其他类型的依赖注入问题。
2.解决@Autowired无法注入RedisTemplate问题
// @Autowired
// private RedisTemplate redisTemplate;
private static RedisTemplate redisTemplate;
@Autowired
public void setRedisTemplate(RedisTemplate redisTemplate) {
WebSocketServer.redisTemplate = redisTemplate;
}
@Autowired注解用于自动装配该方法的参数。在Spring容器启动时,Spring会查找与RedisTemplate类型匹配的bean,并将其注入到该方法的参数中。
三、微信小程序调用和Uniapp调用的区别,
// 微信需要使用微信封装wx.connectSocket()来创建连接
const socket = wx.connectSocket({
url,
success: () => {
console.log("WebSocket 连接请求已发送");
},
fail: (error) => {
console.error("WebSocket 连接失败", error);
},
})
// uniapp需要用本身封装的uni.connectSocket()调用 如果用uniapp开发微信小程序还是需要用wx.connectSocket()
const socket = uni.connectSocket({
url,
success: () => {
console.log("WebSocket 连接请求已发送");
},
fail: (error) => {
console.error("WebSocket 连接失败", error);
},
})
// 我们拥有了socket 实例以后就可以发送消息了
let message = "你好,websocket"
socket.send({data: message});
如果我们发布微信小程序后想要访问我们的服务器的websocket需要使用wss开头进行请求
wss://www.XXXX.com/websocket/{userId}