Java中Spring Boot+Socket实现与html页面的长连接实例详解

Spring Boot+Socket实现与html页面的长连接,客户端给服务器端发消息,服务器给客户端轮询发送消息,附案例源码

功能介绍

客户端给所有在线用户发送消息客户端给指定在线用户发送消息服务器给客户端发送消息(轮询方式)

注意:socket只是实现一些简单的功能,具体的还需根据自身情况,代码稍微改造下

项目搭建

项目结构图

Java中Spring Boot+Socket实现与html页面的长连接实例详解_第1张图片

pom.xml



 4.0.0
 
  org.springframework.boot
  spring-boot-starter-parent
  2.3.2.RELEASE
   
 
 com.cyb
 socket_test
 0.0.1-SNAPSHOT
 socket_test
 Demo project for Spring Boot

 
  1.8
 

 
  
  
   org.springframework.boot
   spring-boot-starter-websocket
  
  
  
   com.google.guava
   guava
   18.0
  
  
  
   com.alibaba
   fastjson
   1.2.46
  
  
   org.springframework.boot
   spring-boot-starter-web
  

  
   org.springframework.boot
   spring-boot-starter-test
   test
   
    
     org.junit.vintage
     junit-vintage-engine
    
   
  
 

 
  
   
    org.springframework.boot
    spring-boot-maven-plugin
   
  
 

appliccation.properties

Java中Spring Boot+Socket实现与html页面的长连接实例详解_第2张图片

SocketTestApplication.java(Spring Boot启动类)

Java中Spring Boot+Socket实现与html页面的长连接实例详解_第3张图片

WebSocketStompConfig.java

Java中Spring Boot+Socket实现与html页面的长连接实例详解_第4张图片

package com.cyb.socket.websocket;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketStompConfig {
 //这个bean的注册,用于扫描带有@ServerEndpoint的注解成为websocket ,如果你使用外置的tomcat就不需要该配置文件
 @Bean
 public ServerEndpointExporter serverEndpointExporter()
 {
  return new ServerEndpointExporter();
 }
}

WebSocket.java(Socket核心类)

Java中Spring Boot+Socket实现与html页面的长连接实例详解_第5张图片

package com.cyb.socket.websocket;

import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * @Author:陈彦斌
 * @Description:Socket核心类
 * @Date: 2020-07-26
 */

@Component
@ServerEndpoint(value = "/connectWebSocket/{userId}")
public class WebSocket {

 private Logger logger = LoggerFactory.getLogger(this.getClass());
 /**
  * 在线人数
  */
 public static int onlineNumber = 0;
 /**
  * 以用户的姓名为key,WebSocket为对象保存起来
  */
 private static Map clients = new ConcurrentHashMap();
 /**
  * 会话
  */
 private Session session;
 /**
  * 用户名称
  */
 private String userId;

 /**
  * 建立连接
  *
  * @param session
  */
 @OnOpen
 public void onOpen(@PathParam("userId") String userId, Session session) {
  onlineNumber++;
  System.out.println("现在来连接的客户id:" + session.getId() + "用户名:" + userId);
  //logger.info("现在来连接的客户id:"+session.getId()+"用户名:"+userId);
  this.userId = userId;
  this.session = session;
  System.out.println("有新连接加入! 当前在线人数" + onlineNumber);
  // logger.info("有新连接加入! 当前在线人数" + onlineNumber);
  try {
   //messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
   //先给所有人发送通知,说我上线了
   Map map1 = Maps.newHashMap();
   map1.put("messageType", 1);
   map1.put("userId", userId);
   sendMessageAll(JSON.toJSONString(map1), userId);

   //把自己的信息加入到map当中去
   clients.put(userId, this);
   System.out.println("有连接关闭! 当前在线人数" + onlineNumber);
   //logger.info("有连接关闭! 当前在线人数" + clients.size());
   //给自己发一条消息:告诉自己现在都有谁在线
   Map map2 = Maps.newHashMap();
   map2.put("messageType", 3);
   //移除掉自己
   Set set = clients.keySet();
   map2.put("onlineUsers", set);
   sendMessageTo(JSON.toJSONString(map2), userId);
  } catch (IOException e) {
   System.out.println(userId + "上线的时候通知所有人发生了错误");
   //logger.info(userId+"上线的时候通知所有人发生了错误");
  }
 }

 @OnError
 public void onError(Session session, Throwable error) {
  //logger.info("服务端发生了错误"+error.getMessage());
  //error.printStackTrace();
  System.out.println("服务端发生了错误:" + error.getMessage());
 }

 /**
  * 连接关闭
  */
 @OnClose
 public void onClose() {
  onlineNumber--;
  //webSockets.remove(this);
  clients.remove(userId);
  try {
   //messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
   Map map1 = Maps.newHashMap();
   map1.put("messageType", 2);
   map1.put("onlineUsers", clients.keySet());
   map1.put("userId", userId);
   sendMessageAll(JSON.toJSONString(map1), userId);
  } catch (IOException e) {
   System.out.println(userId + "下线的时候通知所有人发生了错误");
   //logger.info(userId+"下线的时候通知所有人发生了错误");
  }
  //logger.info("有连接关闭! 当前在线人数" + onlineNumber);
  //logger.info("有连接关闭! 当前在线人数" + clients.size());
  System.out.println("有连接关闭! 当前在线人数" + onlineNumber);
 }

 /**
  * 收到客户端的消息
  *
  * @param message 消息
  * @param session 会话
  */
 @OnMessage
 public void onMessage(String message, Session session) {
  try {
   //logger.info("来自客户端消息:" + message+"客户端的id是:"+session.getId());
   System.out.println("来自客户端消息:" + message + " | 客户端的id是:" + session.getId());
   JSONObject jsonObject = JSON.parseObject(message);
   String textMessage = jsonObject.getString("message");
   String fromuserId = jsonObject.getString("userId");
   String touserId = jsonObject.getString("to");
   //如果不是发给所有,那么就发给某一个人
   //messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
   Map map1 = Maps.newHashMap();
   map1.put("messageType", 4);
   map1.put("textMessage", textMessage);
   map1.put("fromuserId", fromuserId);
   if (touserId.equals("All")) {
    map1.put("touserId", "所有人");
    sendMessageAll(JSON.toJSONString(map1), fromuserId);
   } else {
    map1.put("touserId", touserId);
    System.out.println("开始推送消息给" + touserId);
    sendMessageTo(JSON.toJSONString(map1), touserId);
   }
  } catch (Exception e) {
   e.printStackTrace();
   //logger.info("发生了错误了");
  }

 }

 /**
  * 给指定的用户发送消息
  *
  * @param message
  * @param TouserId
  * @throws IOException
  */
 public void sendMessageTo(String message, String TouserId) throws IOException {
  for (WebSocket item : clients.values()) {
   System.out.println("给指定的在线用户发送消息,在线人员名单:【" + item.userId.toString() + "】发送消息:" + message);
   if (item.userId.equals(TouserId)) {
    item.session.getAsyncRemote().sendText(message);
    break;
   }
  }
 }

 /**
  * 给所有用户发送消息
  *
  * @param message 数据
  * @param FromuserId
  * @throws IOException
  */
 public void sendMessageAll(String message, String FromuserId) throws IOException {
  for (WebSocket item : clients.values()) {
   System.out.println("给所有在线用户发送给消息,在线人员名单:【" + item.userId.toString() + "】发送消息:" + message);
   item.session.getAsyncRemote().sendText(message);
  }
 }

 /**
  * 给所有在线用户发送消息
  *
  * @param message 数据
  * @throws IOException
  */
 public void sendMessageAll(String message) throws IOException {
  for (WebSocket item : clients.values()) {
   System.out.println("服务器给所有在线用户发送消息,当前在线人员为【" + item.userId.toString() + "】发送消息:" + message);
   item.session.getAsyncRemote().sendText(message);
  }
 }

 /**
  * 获取在线用户数
  *
  * @return
  */
 public static synchronized int getOnlineCount() {
  return onlineNumber;
 }
}

TestController.java(前端控制器)

Java中Spring Boot+Socket实现与html页面的长连接实例详解_第6张图片

package com.cyb.socket.websocket;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;

@Controller
@RequestMapping("testMethod")
public class TestController {
 @Autowired
 private WebSocket webSocket;

 /**
  * 给指定的在线用户发送消息
  * @param userId
  * @param msg
  * @return
  * @throws IOException
  */
 @ResponseBody
 @GetMapping("/sendTo")
 public String sendTo(@RequestParam("userId") String userId,@RequestParam("msg") String msg) throws IOException {
  webSocket.sendMessageTo(msg,userId);
  return "推送成功";
 }

 /**
  * 给所有在线用户发送消息
  * @param msg
  * @return
  * @throws IOException
  * @throws IOException
  */
 @ResponseBody
 @PostMapping("/sendAll")
 public String sendAll(@RequestBody String msg) throws IOException, IOException {
  webSocket.sendMessageAll(msg);
  return "推送成功";
 }
}

SocketTask.java(轮询调度往客户端推送消息)

Java中Spring Boot+Socket实现与html页面的长连接实例详解_第7张图片

package com.cyb.socket.schedule;

import com.cyb.socket.websocket.WebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class SocketTask {
 @Autowired
 private WebSocket webSocket;
 private SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS" );
 //5秒轮询一次
 @Scheduled(fixedRate = 5000)
 public void sendClientData() throws IOException {
  String msg="{\"message\":\"你好\",\"userId\":\"002\",\"to\":\"All\"}";
  webSocket.sendMessageAll(msg);
  System.out.println("消息推送时间:"+ sdf.format(new Date()));
 }
}

测试网页

index.html




 Test My WebSocket

 
 

TestWebSocket



index2.html




 Test My WebSocket

 
 

TestWebSocket



项目地址

链接:https://pan.baidu.com/s/1yiAXTkCjHac-F3S1HFyNJQ 提取码:53tp

功能演示

客户端给所有在线用户发消息

客户端给指定在线用户发送消息

服务器给客户端发送消息(轮询方式)

注意需要加上这些注解

Java中Spring Boot+Socket实现与html页面的长连接实例详解_第8张图片

演示

通过前端控制器给指定用户发送消息

Java中Spring Boot+Socket实现与html页面的长连接实例详解_第9张图片

演示

到此这篇关于Java中Spring Boot+Socket实现与html页面的长连接实例详解的文章就介绍到这了,更多相关Java Spring Boot+Socket实现与html页面的长连接内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的:(Java中Spring Boot+Socket实现与html页面的长连接实例详解)