1.依赖
<!--webSocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.配置
/**
* web_socket配置类
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
3.服务器部署:
package com.ciih.workshop.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author Lenovo
*/
@Component
@Slf4j
@ServerEndpoint("/webSocket/{id}")
public class WebSocketServer {
/**
* 存储用户建立的连接Session
*/
public static ConcurrentHashMap<String, Session> webSocketMap = new ConcurrentHashMap<>();
/**
* 建立连接调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("id") String id) throws IOException {
if (webSocketMap.containsKey(id)) {
webSocketMap.remove(id);
webSocketMap.put(id, session);
} else {
webSocketMap.put(id, session);
}
log.info("连接成功:" + id);
webSocketMap.get(id).getBasicRemote().sendText("连接成功");
}
/**
* 连接关闭
* 调用的方法
*/
@OnClose
public void onClose(@PathParam("id") String id) {
webSocketMap.remove(id);
log.info("连接关闭:" + id);
}
/**
* 接收到客户端消
**/
@OnMessage
public void onMessage(@PathParam("id") String id, String message) throws IOException {
log.info("用户消息:" + id + ",报文:" + message);
//可以群发消息
//消息保存到数据库、redis
if (StringUtils.isNotBlank(message)) {
//解析发送的报文
JSONObject jsonObject = JSON.parseObject(message);
//追加发送人(防止串改)
jsonObject.put("fromUserId", id);
//解析收件人
String toUserId = jsonObject.getString("toUserId");
//传送给对应toUserId用户的websocket
if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
webSocketMap.get(toUserId).getBasicRemote().sendText(message);
} else {
//否则不在这个服务器上,发送到mysql或者redis
log.error("请求的id:" + toUserId + "不在该服务器上");
}
}
}
@OnError
public void onError(@PathParam("id") String id, Throwable error) {
log.error("发生错误:" + id + ",原因:" + error.getMessage());
error.printStackTrace();
}
}
4.前端页面JSX
import { ref, reactive } from "vue";
let msg = ref("");
let socket;
// 主组件
const HelloWorld = () => {
//发起websocket连接
const openSocket = () => {
const socketUrl = "ws://localhost:8080/webSocket/1";
if (socket != null) {
socket.close();
socket = null;
}
socket = new WebSocket(socketUrl);
//打开事件
socket.onopen = function () {
console.log("websocket已打开");
};
//监听服务器消息
socket.onmessage = function (msg) {
//存储服务器发来的消息
messageList.set.add(msg.data);
};
//监听连接关闭事件
socket.onclose = function () {
console.log("websocket已关闭");
};
//监听连接错误事件
socket.onerror = function () {
console.log("websocket发生了错误");
};
};
// 向Socket服务器发送消息
const sendMessage = () => {
socket.send(msg.value);
};
return (
<>
<el-button type={"primary"} size="default" onClick={openSocket}>
连接websocket服务
</el-button>
<el-divider />
<el-input style={{ width: "100px" }} v-model={msg.value}></el-input>
<el-divider />
<el-button type="primary" size="default" onClick={sendMessage}>
发送消息
</el-button>
<el-divider />
<h4>--------------收到消息-----------------</h4>
<ReceivedMessage></ReceivedMessage>
</>
);
};
let messageList = reactive({
set: new Set(),
});
// JSX组件 展示服务器发来的消息
const ReceivedMessage = () => {
return (
<>
{Array.from(messageList.set).map((msg,index) => {
return <div>{index}.{msg}</div>;
})}
</>
);
};
export default HelloWorld;
获取IP工具类
package com.ciih.workshop.utils.sun;
import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
public class WebSocketUtil {
public static InetSocketAddress getRemoteAddress(Session session) {
if (session == null) {
return null;
}
RemoteEndpoint.Async async = session.getAsyncRemote();
//在Tomcat 8.0.x版本有效
InetSocketAddress addr0 = (InetSocketAddress) getFieldInstance(async,"base#sos#socketWrapper#socket#sc#remoteAddress");
System.out.println("clientIP0" + addr0);
//在Tomcat 8.5以上版本有效
InetSocketAddress addr = (InetSocketAddress) getFieldInstance(async, "base#socketWrapper#socket#sc#remoteAddress");
System.out.println("clientIP1" + addr);
return addr;
}
private static Object getFieldInstance(Object obj, String fieldPath) {
String fields[] = fieldPath.split("#");
for (String field : fields) {
obj = getField(obj, obj.getClass(), field);
if (obj == null) {
return null;
}
}
return obj;
}
private static Object getField(Object obj, Class<?> clazz, String fieldName) {
for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
try {
Field field;
field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
}
}
return null;
}
}