91名师指路-头部
91名师指路

springboot 集成websocket

由于某些原因,现在不支持支付宝支付,如需要购买源码请加博主微信进行购买,微信号:13248254750

一:引入maven依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.4.4</version>
</dependency>

二:配置WebSocketConfig

package com.mszl.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

// WebSocket
@Configuration
public class WebSocketConfig {

@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}

}

三:编写WebSocketServer

package com.mszl.config;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
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;

@ServerEndpoint("/imserver/{userId}")
@Component
public class WebSocketServer {

static Log log=LogFactory.get(WebSocketServer.class);

/** 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的 */
private static int onlineCount = 0;

/**concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象 */
private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();

/**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
private Session session;

/**接收userId*/
private String userId="";

@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中
addOnlineCount();
//在线数加1
}

log.info("用户连接:"+userId+", 当前在线人数为:" + getOnlineCount());

try {
sendMessage("连接成功");
} catch (IOException e) {
log.error("用户:"+userId+", 网络异常!!!!!!");
}
}

/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
if(webSocketMap.containsKey(userId)){
webSocketMap.remove(userId);
// 从set中删除
subOnlineCount();
}
log.info("用户退出:" +userId+ ", 当前在线人数为: " + getOnlineCount());
}

/**
* 收到客户端消息后调用的方法
* @param message 客户端发送过来的消息*/
@OnMessage
public void onMessage(String message) {
log.info("用户消息:"+userId+",报文:"+message);
// 可以群发消息
// 消息保存到数据库、redis
if(StringUtils.isNotBlank(message)){
try {
//解析发送的报文
JSONObject jsonObject = JSON.parseObject(message);
// 追加发送人(防止串改)
jsonObject.put("fromUserId",this.userId);
String toUserId=jsonObject.getString("toUserId");
// 传送给对应toUserId用户的websocket
if(StringUtils.isNotBlank(toUserId)&&webSocketMap.containsKey(toUserId)){
webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
} else{
log.error("请求的userId:"+toUserId+"不在该服务器上");
// 否则不在这个服务器上,发送到mysql或者redis
}
} catch (Exception e){
e.printStackTrace();
}
}
}

@OnError
public void onError(Session session, Throwable error) {
log.error("用户错误:" +this.userId+",原因: " + error.getMessage());
error.printStackTrace();
}

/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}

/**
* 发送自定义消息
* */
public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException {
log.info("发送消息到:" +userId+ ",报文:"+message);
if(StringUtils.isNotBlank(userId)&&webSocketMap.containsKey(userId)){
webSocketMap.get(userId).sendMessage(message);
} else{
log.error("用户" +userId+ ",不在线!");
}
}

public static synchronized int getOnlineCount() {
return onlineCount;
}

public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}

public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}


}

四:编写controller

package com.mszl.controller;

import com.mszl.config.WebSocketServer;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import java.io.IOException;

@RestController
public class DemoController {

@GetMapping("/index")
public ResponseEntity<String> index(){
return ResponseEntity.ok("请求成功");
}

@GetMapping("/page")
public ModelAndView page(){
return new ModelAndView("websocket");
}

@GetMapping("/push")
public ResponseEntity<String> pushToWeb(String message, String toUserId) throws IOException {
WebSocketServer.sendInfo(message,toUserId);
return ResponseEntity.ok("MSG SEND SUCCESS");
}


}

五:配置文件application.yml

server:
port: 9001

spring:
application:
name: mszl
freemarker:
request-context-attribute: request
suffix: .html
content-type: text/html
enabled: true
cache: false
charset: UTF-8
allow-request-override: false
expose-request-attributes: true
expose-session-attributes: true
expose-spring-macro-helpers: true
#template-loader-path: classpath:/templates/

六:页面websocket.html

6.1)在resources下新建一个templates(关键字)文件夹,然后新建一个名叫websocket.html(名称自己随便取,和DemoController的page方法保持一致即可)的html页面,如下图所示。

6.2)websocket.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() {
if(typeof(WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
} else{
console.log("您的浏览器支持WebSocket");
//实现化WebSocket对象,指定要连接的服务器地址与端口 建立连接
//等同于socket = new WebSocket("ws://localhost:8888/xxxx/im/25");
//var socketUrl="${request.contextPath}/im/"+$("#userId").val();
var socketUrl="http://localhost:9001/imserver/"+$("#userId").val();
socketUrl=socketUrl.replace("https","ws").replace("http","ws");
console.log(socketUrl);
if(socket!=null){
socket.close();
socket=null;
}
socket = new WebSocket(socketUrl);
//打开事件
socket.onopen = function() {
console.log("websocket已打开");
//socket.send("这是来自客户端的消息" + location.href + new Date());
};
//获得消息事件
socket.onmessage = function(msg) {
console.log(msg.data);
//发现消息进入 开始处理前端触发逻辑
};
//关闭事件
socket.onclose = function() {
console.log("websocket已关闭");
};
//发生了错误事件
socket.onerror = function() {
console.log("websocket发生了错误");
}
}
}
function sendMessage() {
if(typeof(WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
} else {
console.log("您的浏览器支持WebSocket");
console.log('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
socket.send('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
}
}
</script>
<body>
<p>发送人用户ID: userId:<div><input id="userId" name="userId" type="text" value="10"></div>
<p>接收人用户ID: toUserId】:<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="sendMessage()">发送消息</button></div>
</body>

</html>

七:验证是否集成websocket成功。

7.1)访问:http://localhost:9001/page,如下图所示。


7.2)我们在浏览器打开2个tab,方便演示两个用户相互之间发送消息。

发送人用户ID为10的界面,我们点击开启socket按钮和发送消息按钮后的效果图如下所示:


7.3)发送人用户Id为20的界面,我们点击开启socket按钮和发送消息按钮后的效果图如下所示:

7.4)后端向前端推送消息接口:http://localhost:9001/push?message=杨过你好&toUserId=10

然后我们看到发送人用户ID为10的界面,收到了这条消息。


参考资料:

https://blog.csdn.net/moshowgame/article/details/80275084


2021-05-21 16:24:46     阅读(823)

名师出品,必属精品    https://www.91mszl.com

联系博主    
用户登录遮罩层
x

账号登录

91名师指路-底部