springBoot整合websocket实现服务端向客户端推送消息 Http只能由客户端发起请求,服务端返回请求,这就导致如果服务端有新的消息需要发送给客户端就⽐较⿇烦,所以websocket就应运⽽⽣了。下⾯是springBoot整合websocket,实现服务端推送消息到客户端的⼀个⼩demo,这⾥使⽤的是定时任务的⽅式来模拟这种推送,实际使⽤中,可以根据情况主动推送。
1.创建maven⼯程,添加如下依赖(使⽤的是springBoot
2.2.2.RELEASE):
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.44</version>
</dependency>
<!-- Hutool超级⼯具类 doc.io/ -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.3.2</version>
</dependency>
</dependencies>
2.websocket服务端:
@ServerEndpoint("/ws/{userId}")
@Component
public class WebSocketServer {
/**concurrent包的线程安全Set,⽤来存放每个客户端对应的MyWebSocket对象。*/
private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<String,WebSocketServer>();
/**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
private Session session;
/**接收userId*/
private String userId="";
/**
* 连接建⽴成功调⽤的⽅法*/
@OnOpen
public void onOpen(Session session,@PathParam("userId") String userId) {
this.session = session;
this.userId=userId;
ainsKey(userId)){
webSocketMap.put(userId,this);
}else{
webSocketMap.put(userId,this);
}
System.out.println("当前连接⽤户:"+userId);
}
/**
* 连接关闭调⽤的⽅法
*/
@OnClose
@OnClose
public void onClose() {
ainsKey(userId)){
}
System.out.println("⽤户 "+userId+" 退出:");
}
/**
* 收到客户端消息后调⽤的⽅法
*websocket和socket
* @param message 客户端发送过来的消息*/
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("收到⽤户消息:"+userId+",报⽂:"+message);
if(StrUtil.isNotBlank(message)){
try {
//解析发送的报⽂
JSONObject jsonObject = JSON.parseObject(message);
//追加发送⼈(防⽌串改)
jsonObject.put("fromUserId",this.userId);
String String("toUserId");
//传送给对应toUserId⽤户的websocket
if(StrUtil.isNotBlank(toUserId) && ainsKey(toUserId)){
<(toUserId).JSONString());
}else{
<(this.userId).sendMessage("请求的userId:"+toUserId+"不在该服务器上"); System.out.println("请求的userId:"+toUserId+"不在该服务器上");
}
}catch (Exception e){
e.printStackTrace();
}
}
}
/**
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("⽤户错误:"+this.userId+",原因:"+Message());
error.printStackTrace();
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
BasicRemote().sendText(message);
}
/**
* 发送⾃定义消息
* */
public static void sendInfo(String message,String userId) throws IOException {
System.out.println("发送消息到:"+userId+",报⽂:"+message);
if(StrUtil.isNotBlank(userId) && ainsKey(userId)){
<(userId).sendMessage(message);
}else{
System.out.println("⽤户"+userId+",不在线!");
}
}
public static ConcurrentHashMap<String, WebSocketServer> getWebSocketMap() {
public static ConcurrentHashMap<String, WebSocketServer> getWebSocketMap() {
return webSocketMap;
}
public static void setWebSocketMap(ConcurrentHashMap<String, WebSocketServer> webSocketMap) {
WebSocketServer.webSocketMap = webSocketMap;
}
}
3.websocket客户端,在resources⽬录下,创建static⽬录,在创建⼀个⽂件test.html,其内容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>websocket通讯</title>
</head>
<script src="cdn.bootcss/jquery/3.3.1/jquery.js"></script>
<script>
var socket;
//开启连接
function openSocket() {
if(typeof(WebSocket) == "undefined") {
console.log("您的浏览器不⽀持WebSocket");
}else{
if (!$("#fromUserId").val()){
alert("请输⼊⽤户名");
return;
}
console.log("您的浏览器⽀持WebSocket");
//实现化WebSocket对象,指定要连接的服务器地址与端⼝建⽴连接
//等同于socket = new WebSocket("ws://localhost:8888/xxxx/im/25");
/
/var socketUrl="${tPath}/im/"+$("#userId").val();
var socketUrl="localhost:8080/ws/"+$("#fromUserId").val();
place("https","ws").replace("http","ws");
console.log(socketUrl);
if(socket!=null){
socket.close();
socket=null;
}
socket = new WebSocket(socketUrl);
//打开事件
console.log("websocket已打开");
$("#allContent")
.append("<div>" + "收到消息:已建⽴连接,"+new Date() + "</div>");
};
//获得消息事件
$("#allContent")
.append("<div>" + "收到消息" +":"+msg.data + "</div>");
console.log(msg.data);
};
//关闭事件
$("#allContent")
.append("<div>" + "收到消息:websocket已关闭,"+new Date() + "</div>");
console.log("websocket已关闭");
};
//发⽣了错误事件
$("#allContent")
.append("<div>" + "收到消息:websocket连接发⽣了错误,"+new Date() + "</div>");
console.log("websocket发⽣了错误");
console.log("websocket发⽣了错误");
}
}
}
// 关闭连接
function closeSocket() {
if (socket){
socket.disconnect();
}
}
// 发送消息
function sendMessage() {
if(typeof(WebSocket) == "undefined") {
console.log("您的浏览器不⽀持WebSocket");
}else {
// 判断是否已建⽴连接
if (socket){
socket.send('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}'); }else {
alert("请先建⽴连接");
}
}
}
</script>
<body>
【请输⼊⽤户名】:<input id="fromUserId" name="fromUserId" type="text" value="admin"/>
【⽬标⽤户名】:<input id="toUserId" name="toUserId" type="text" value="qxf"/>
<button onclick="openSocket()" >开启连接</button>
<button onclick="closeSocket()" >关闭连接</button>
<button onclick="sendMessage()" >发送消息</button>
【内容】:<input id="contentText" name="contentText" type="text" value="hello websocket">
<div id="allContent">
</div>
</body>
</html>
主要就是那⼏个监听事件,⽐如
onmessage,表⽰收到消息时的回调
4.定时任务模式主动推送:
@Component
public class SendMsgToClient {
//从第10秒开始,每隔5秒发送⼀次
@Scheduled(cron="10/5 * * * * ?")
public void sendMsg() {
try {
ConcurrentHashMap<String, WebSocketServer> webSocketMap = WebSocketMap(); ConcurrentHashMap.KeySetView<String, WebSocketServer> userIds = webSocketMap.keySet();
if (userIds.size() <= 0){
System.out.println("当前没有⽤户连接,不发送消息");
return;
}
String toUserId = null;
int count = new Random(System.currentTimeMillis()).nextInt(userIds.size());
//取⼀个发送消息
for (int i = 0; i < userIds.size();i++){
Iterator<String> iterator = userIds.iterator();
if (iterator.hasNext()){
if (i == count){
toUserId = ();
}else {
<();
}
}
}
if (StrUtil.isNotBlank(toUserId)){
WebSocketServer.sendInfo("这是服务端主动推送的消息:"+new Date(),toUserId);
}else {
System.out.println("当前没有⽤户连接,不发送消息");
}
}catch (IOException e){
System.out.println("定时推送消息失败...");
}
}
}
5.启动类添加如下配置:
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论