WebSocket实现后台向前端推送信息
什么是WebSocket?因为 HTTP 协议有一个缺陷:通信只能由客户端发起,HTTP 协议做不到服务器主动向客户端推送信息。WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端快速上手<!-- websocket --><dependency><groupId>or
什么是WebSocket?
因为 HTTP 协议有一个缺陷:通信只能由客户端发起,HTTP 协议做不到服务器主动向客户端推送信息。
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端
快速上手
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
WebSocketConfig启用WebSocket的支持
/**
* 开启WebSocket支持
* @author zhucan
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
WebSocketServer
因为WebSocket是类似客户端服务端的形式(采用ws协议),那么这里的WebSocketServer其实就相当于一个ws协议的Controller
直接@ServerEndpoint("/imserver/{userId}") 、@Component启用即可,然后在里面实现@OnOpen开启连接,@onClose关闭连接,@onMessage接收消息等方法。
新建一个ConcurrentHashMap webSocketMap 用于接收当前userId的WebSocket,方便IM之间对userId进行推送消息。单机版实现到这里就可以。
集群版(多个ws节点)还需要借助mysql或者redis等进行处理,改造对应的sendMessage方法即可。
/**
* @author
*/
@ServerEndpoint("/imserver/{userId}")
@Component
public class WebSocketService {
/**
* concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
*/
private static ConcurrentHashMap<String, WebSocketService> webSocketMap = new ConcurrentHashMap<>();
/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
private Session session;
/**
* 接收userId
*/
private String userId = "";
/**
* 连接建立成功调用的方法
* <p>
* 1.用map存 每个客户端对应的MyWebSocket对象
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
this.session = session;
this.userId = userId;
if (webSocketMap.containsKey(userId)) {
webSocketMap.remove(userId);
webSocketMap.put(userId, this);
//加入set中
} else {
webSocketMap.put(userId, this);
//加入set中
}
//服务端向客户端发送信息
sendMessage("用户" + userId + "上线了,当前在线人数为:" + webSocketMap.size() + "。");
}
/**
* 报错
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
/**
* 实现服务器推送到对应的客户端
*/
public void sendMessage(String message) {
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 自定义 指定的userId服务端向客户端发送消息
*/
public static void sendInfo(String message, String userId, String toUserId) {
//log.info("发送消息到:"+userId+",报文:"+message);
if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
webSocketMap.get(toUserId).sendMessage(message);
} else {
webSocketMap.get(userId).sendMessage(toUserId + "已经下线。");
}
}
/**
* 自定义关闭
*
* @param userId
*/
public static void close(String userId) {
if (webSocketMap.containsKey(userId)) {
webSocketMap.remove(userId);
}
}
/**
* 获取在线用户信息
*
* @return
*/
public static Map getOnlineUser() {
return webSocketMap;
}
}
controller 对外提供发送 关闭websocket方法
@RestController
public class DemoController {
@PostMapping("/push")
public ResponseEntity<String> pushToWeb(String message, String toUserId,String userId) throws IOException {
WebSocketService.sendInfo(message,userId,toUserId);
return ResponseEntity.ok("MSG SEND SUCCESS");
}
@GetMapping("/close")
public String close(String userId){
WebSocketService.close(userId);
return "ok";
}
@GetMapping("/getOnlineUser")
public Map getOnlineUser(){
return WebSocketService.getOnlineUser();
}
}
html 前端页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>websocket通讯</title>
</head>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
var socket;
function openSocket(flag) {
var socketUrl = "http://localhost:8449/imserver/" + $("#userId").val();
socketUrl = socketUrl.replace("https", "ws").replace("http", "ws");
if (socket != null) {
socket.close();
socket = null;
}
socket = new WebSocket(socketUrl);
//打开事件
socket.onopen = function () {
//获得消息事件
socket.onmessage = function (msg) {
$('#contain').html(msg.data);
};
//发生了错误事件
socket.onerror = function () {
alert("websocket发生了错误");
}
$("#userId").attr("disabled", true);
}
}
function sendMessage() {
$.ajax({
url:"http://localhost:8449/push",
type:"POST",
data:{
'message':$("#contentText").val(),
'toUserId':$("#toUserId").val(),
'userId':$("#userId").val()
}
})
}
function closeSocket() {
var userId =$("#userId").val()
$.ajax({
type:"get",
url:"http://localhost:8449/close?userId="+userId,
success:function(res) {
alert('111');
}
});
$("#userId").attr("disabled", false);
$('#contain').html("下线成功!");
}
</script>
<body>
<p>【内容】:<span id="contain"></span></p>
<p>【当前用户】:<div><input id="userId" name="userId" type="text" value="10"></div>
<p>【发送用户】:<div><input id="toUserId" name="toUserId" type="text" value="20"></div>
<p>【发送的内容】:<div><input id="contentText" name="contentText" type="text" value="hello websocket"></div>
<p>【操作】:<div><button onclick="openSocket()">登录socket</button></div>
<p>【操作】:<div><button onclick="closeSocket()">关闭socket</button></div>
<p>【操作】:<div><button onclick="sendMessage()">发送消息</button></div>
</body>
</html>
更多推荐
所有评论(0)