项目背景:
IM通讯,双方在线聊天,IM服务器进行数据转发。vue前端app登录成功建立websocket请求,后端map存储session并根据id进行消息实时推送。
一、JAVA后端实现WebSocket:
1、项目使用的是maven管理,pom中引入如下依赖,gradle直接复制粘贴,会自动转换。
<!--websock-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>${boot.version}</version>
</dependency>
2、启动类中添加如下注解
@EnableWebSocket
3、写配置类,暴露服务器端点
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
4、业务逻辑类
/**
* webSocket协商
*/
@ServerEndpoint("/rainbow/{id}")
@Component
@Slf4j
public class WebSocketService {
private static String id = "";
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("id") String id) {
this.id = id;
//将session放入map中,用于进行消息转发
SessionMapConstants.webSocketMap.put(id, session);
sendMessage(id, RainBowResult.ok());
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
SessionMapConstants.webSocketMap.remove(this.id);
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的确认消息
*/
@OnMessage
public void onMessage(String message, Session session) throws IOException, EncodeException {
try {
RainBowResult result = JsonUtils.jsonToPojo(message, RainBowResult.class);
if (result != null) {
if (result.getStatus() == 200) {
String jsonOk = JsonUtils.objectToJson(RainBowResult.ok());
session.getAsyncRemote().sendText(jsonOk);
}
}
} catch (Exception e) {
log.error("webSocket has get the messsage but can't finish case by" + e);
}
}
/**
* @param error
*/
@OnError
public void onError(Throwable error) {
log.error("some inner error occur case by" + error.getCause());
error.printStackTrace();
}
/**
* 实现服务器主动推送,业务逻辑层实现群发消息
*/
public boolean sendMessage(String wx_id, RainBowResult message) {
try {
Session session = SessionMapConstants.webSocketMap.get(wx_id);
String jsonMessage = JsonUtils.objectToJson(message);
session.getBasicRemote().sendText(jsonMessage);
return true;
} catch (Exception e) {
log.error("inner web socket send message to the client [{}] failed case by:" + e,id);
return false;
}
}
}
2、Vue视图层WebSocket
1、初始化websocket
export function initWebSocket(id) {
if (id) {
const ws_uri = wsUrl + "/rainbow/" + id;
const websock = new WebSocket(ws_uri);
websock.onopen = onWSOpen;
websock.onmessage = onWSMessage;
websock.onclose = onWSClose;
websock.onerror = onWSError;
}
}
2、建立连接后的回调函数
export function onWSOpen() {
console.log("WebSocket连接成功")
}
3、接受到后端消息的回调函数
tip:websocket需要进行协商,最好前后端定义好统一的数据格式,用于进行不同业务处理。
export function onWSMessage(response) { //数据接收
if (response.data.status === 200) {
if (response.data.type === MESSAGE_VIDEO_REQUEST || response.data.type === MESSAGE_AUDIO_REQUEST) {
alert(JSON.stringify(JSON.parse(response.data)));
const token = null;
const room_name = response.data.data.room_name;
const room_data = null;
const room_id = response.data.data.room_id;
const type = response.data.data.type;
//JNI调用android端进行视频/语音初始化
callMedia.callAndroidMedia(token, room_name, room_data, room_id, type);
} else if (MESSAGE_MESSAGE_REQUEST === response.data.type) {
} else if (MESSAGE_CIRCLE_REQUEST === response.data.type) {
} else if (MESSAGE_FRIEND_REQUEST === response.data.type) {
}
}
}
4、关闭和异常回调函数
export function onWSClose() { //websocket关闭回调函数
this.websock.close();
}
export function onWSError() { //websocket异常回调函数
}
项目中只有服务器端使用到了消息发送,考虑到需要进行数据封装处理,websokcet需要进行编码解析,客户端发送数据不使用websocket,使用http进行消息转发 。netty同样支持websocket编解码,在这里就不展示了。