config中添加两个类MyWebSocketHandler和WebSocketConfig
WebSocketConfig
package com.ckm.ball.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
/**
* registerWebSocketHandlers 是一个函数或方法,通常用于在 Web 应用程序中注册 WebSocket 处理程序。
* WebSocket 是一种基于 TCP 的协议,可以实现客户端和服务器之间的双向通信,可以用于实时应用程序,如聊天应用、游戏、实时更新等。在 Java Web 应用程序中,可以使用 Spring 框架提供的 WebSocket 支持来处理 WebSocket 连接。
* registerWebSocketHandlers 方法是 Spring WebSocket 的一个 API,它允许开发人员在应用程序中注册 WebSocket 处理程序,并将其映射到特定的 URI。在调用 registerWebSocketHandlers 方法时,需要传递一个 WebSocketHandler 实例和一个 URI 路径作为参数。当客户端请求与该 URI 路径对应的 WebSocket 连接时,Spring 将调用相应的 WebSocket 处理程序来处理连接。
*/
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
//参数1:注册我们自定义的MyWebSocketHandler类
//参数2:路径【UniApp中建立连接的路径】如:我的ip是192.168.1.8:8099则UniApp需要输入的url是ws://192.168.1.8:8099/websocket
//参数3:setAllowedOrigins("*")设置允许全部来源【在WebSocket中,浏览器会发送一个带有Origin头部的HTTP请求来请求建立WebSocket连接。服务器可以使用setAllowedOrigins方法来设置允许的来源,即允许建立WebSocket连接的域名或IP地址。这样,服务器就可以限制建立WebSocket连接的客户端,避免来自不信任的域名或IP地址的WebSocket连接。】
registry.addHandler(new MyWebSocketHandler(), "/websocket").setAllowedOrigins("*");
}
}
MyWebSocketHandler
package com.ckm.ball.config;
import com.alibaba.fastjson.JSON;
import com.ckm.ball.dto.WebSocketSendInfoDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
@Component
public class MyWebSocketHandler extends TextWebSocketHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(MyWebSocketHandler.class);
private Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
private Map<String, String> users = new ConcurrentHashMap<>();
/**
* afterConnectionEstablished 是一个 WebSocket API 中的回调函数,它是在建立 WebSocket 连接之后被调用的。
* 当 WebSocket 连接建立成功后,浏览器会发送一个握手请求给服务器端,如果服务器成功地接受了该请求,那么连接就会被建立起来
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
LOGGER.info("WebSocket已连接: {}", session.getId());
System.out.println(session.getUri());
// 当 WebSocket 连接建立后,将用户 ID 和 WebSocketSession 关联起来,保存到 sessions 和 users 映射表中
String userId = extractUserId(String.valueOf(session.getUri()));
System.out.println(userId);
users.put(session.getId(), userId);
sessions.put(userId, session);
System.out.println(sessions);
}
/**
* handleMessage 是 WebSocket API 中的回调函数,它是用来处理从客户端接收到的 WebSocket 消息的。
* 当客户端通过 WebSocket 连接发送消息到服务器端时,服务器端会自动调用 handleMessage 函数并传递收到的消息作为参数,你可以在该函数中处理这个消息,并根据需要向客户端发送一些响应消息。
*/
@Override
public void handleTextMessage(WebSocketSession session,TextMessage message) throws Exception {
System.out.println(message);
LOGGER.info("WebSocket收到的消息: {}", message.getPayload());
WebSocketSendInfoDto webSocketSendInfoDto = JSON.parseObject(message.getPayload(), WebSocketSendInfoDto.class);
System.out.println(webSocketSendInfoDto);
// sessions.forEach(s -> {
// try {
// s.sendMessage(new TextMessage("我现在正在向客户端发送一条消息, " + s.getId() + "!"));
// } catch (IOException e) {
// LOGGER.error("无法发送WebSocket消息", e);
// }
// });
}
/**
* afterConnectionClosed 是 WebSocket API 中的回调函数,它是在 WebSocket 连接关闭后被调用的。
* 当客户端或服务器端主动关闭 WebSocket 连接时,afterConnectionClosed 回调函数会被调用,你可以在该函数中执行一些资源释放、清理工作等操作,比如关闭数据库连接、清理缓存等。
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
LOGGER.info("WebSocket已断开连接: {}", session.getId());
String userId = extractUserId(String.valueOf(session.getUri()));
sessions.remove(userId);
}
/**
* supportsPartialMessages 是 WebSocket API 中的方法,它用来指示 WebSocket 消息是否支持分段传输。
* WebSocket 消息可以分段传输,也就是说一个消息可以被分成多个部分依次传输,这对于大型数据传输和流媒体传输非常有用。当消息被分成多个部分传输时,WebSocket 会自动将这些部分合并成完整的消息。
* supportsPartialMessages 方法用来指示服务器是否支持分段消息传输,如果支持,则可以在接收到部分消息时开始处理消息,否则需要等待接收到完整消息后才能开始处理。
*/
@Override
public boolean supportsPartialMessages() {
return false;
}
/**
* handleTransportError 是 WebSocket API 中的回调函数,它用来处理 WebSocket 传输层出现错误的情况。
*当 WebSocket 传输层出现错误,比如网络中断、协议错误等,WebSocket 会自动调用 handleTransportError 函数,并传递相应的错误信息。在该函数中,我们可以处理这些错误,比如关闭 WebSocket 连接、记录错误日志等。
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
LOGGER.error("WebSocket错误", exception);
}
//截取出userId
private String extractUserId(String path) {
return path.split("=")[1];
}
}
小程序app.js全局中配置WebSocket连接
App({
globalData: {
// url: "http://192.168.1.3:8088"
url: "http://192.168.2.50:8088",
ws: null
},
//首次加载触发
onLaunch() {
let userInfo = wx.getStorageSync('userInfo')
if (userInfo != '') {
let ws = wx.connectSocket({
url: 'ws://192.168.2.50:8088/websocket?id='+userInfo.id,
timeout: 3000,
})
this.globalData.ws = ws;
console.log(this.globalData.ws)
}
console.log("app.js -> onLaunch")
},
//小程序进入后台时(卸载)触发
onHide() {
console.log("app.js -> onHide")
if (this.globalData.ws) {
this.globalData.ws.close({
code: 1000, // 1000表示正常关闭
reason: '用户主动关闭连接',
});
} else {
console.log('WebSocket连接未建立或已经关闭');
}
console.log(this.globalData.ws)
},
// 更新 WebSocket 实例的方法
setWs(wsInstance) {
this.globalData.ws = wsInstance;
},
})
这个做法可以在小程序加载的时候去连接服务端WebSocket,注意,我这里判断userInfo登录信息,如果没有登录,那我们就不要连接,这时候我们再去login.js登录方法里面登录成功后再去配置连接。(这里url后面的id传参是当前用户的id,用于用户之前相互通讯)
let ws = wx.connectSocket({
url: 'ws://192.168.2.50:8088/websocket?id='+result.id,
timeout: 3000,
})
app.setWs(ws);
注意,当我们退出登录的时候,需要在里面调用以下方法,去把WebSocket断开。
colseWebSocket(){
if (app.globalData.ws) {
app.globalData.ws.close({
code: 1000, // 1000表示正常关闭
reason: '用户主动关闭连接',
});
} else {
console.log('WebSocket连接未建立或已经关闭');
}
}
发送消息
send(){
let info = {
senderId: wx.getStorageSync("userInfo").id,
recipientId: 100,
chatContent: '你好啊~',
chatContentType: 'text'
}
let that = this
app.globalData.ws.send({
data: JSON.stringify(info),
success:(res)=>{
console.log(res)
that.setData({
tips: "发送信息成功"
})
}
})
}
点击按钮调用send方法后,观察后端就会看到打印信息