根据公司需求在SpringBoot项目中集成站内信,于是,我做了一个SpringBoot2.x 整合websocket 消息推送,给指定用户发送信息和群发信息即点点对方式和广播方式2种模式。


文章目录

  • 一、地址部署总览
  • 二、实战需求案例
  • 三、实战准备
    • 3.1. pom依赖
    • 3.2. application.yml
    • 3.3. 配置类
    • 3.4. 实体类
    • 3.5. websocket 服务端
    • 3.6. 控制器
    • 3.7. SpringBoot入口类
  • 四、初始化页面总览
    • 4.1. 服务端
    • 4.2. 客户端A
    • 4.3. 客户端B
    • 4.4. 客户端C
  • 五、案例实战
    • 5.1. 客户端A连接服务端
    • 5.2. 客户端B连接服务端
    • 5.3. 客户端C连接服务端
    • 5.4. 服务端连接状态ABC
  • 六、单独发送信息
    • 6.1. 服务端给指定客户端A发送消息
    • 6.2. 验证客户端A消息是否收到
  • 七、群发信息
    • 7.1. 给在线客户端群发消息
    • 7.2. 客户端A 消息验证
    • 7.2. 客户端B 消息验证
    • 7.3. 客户端C 消息验证

一、地址部署总览

服务端地址 http://localhost:8086/admin
客户端地址 http://localhost:8086/index

二、实战需求案例

服务端 实例1个
客户端A 实例1
客户端B 实例2
客户端C 实例3

三、实战准备

3.1. pom依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.gblfy</groupId><artifactId>springboot-websocket</artifactId><version>v1.0.0</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.1.RELEASE</version></parent><properties><!--编码同意设置--><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><!--JDK版本--><java.version>1.8</java.version></properties><dependencies><!--SpringMVC启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--热部署插件--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><!--websocket启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><!--thymeleaf 模板引擎启动器--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency></dependencies><build><plugins><!--maven 打包编译插件--><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

3.2. application.yml

server:port: 80
spring:devtools:restart:exclude:  static/**,public/**enabled:  true

3.3. 配置类

package com.gblfy.websocket.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** 开启websocket的支持** @Author gblfy* @Email gbly02@gmail.com* @Date 2019/11/20 PM 23:50*/
@Configuration
public class WebSocketConfig {  @Bean  public ServerEndpointExporter serverEndpointExporter(){  return new ServerEndpointExporter();  }
}

3.4. 实体类

package com.gblfy.websocket.entity;import javax.websocket.Session;
import java.io.Serializable;/*** @Author gblfy* @Email gbly02@gmail.com* @Date 2019/11/20 PM 23:50*/
public class Client implements Serializable {private static final long serialVersionUID = 8957107006902627635L;private String userName;private Session session;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public Session getSession() {return session;}public void setSession(Session session) {this.session = session;}public Client(String userName, Session session) {this.userName = userName;this.session = session;}public Client() {}
}

3.5. websocket 服务端

package com.gblfy.websocket.server;import com.gblfy.websocket.entity.Client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.List;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;/**** @Author gblfy* @Email gbly02@gmail.com* @Date 2019/11/20 PM 23:50*/
@ServerEndpoint(value = "/socketServer/{userName}")
@Component
public class SocketServer {private static final Logger logger = LoggerFactory.getLogger(SocketServer.class);/**** 用线程安全的CopyOnWriteArraySet来存放客户端连接的信息*/private static CopyOnWriteArraySet<Client> socketServers = new CopyOnWriteArraySet<>();/**** websocket封装的session,信息推送,就是通过它来信息推送*/private Session session;/**** 服务端的userName,因为用的是set,每个客户端的username必须不一样,否则会被覆盖。* 要想完成ui界面聊天的功能,服务端也需要作为客户端来接收后台推送用户发送的信息*/private final static String SYS_USERNAME = "niezhiliang9595";/**** 用户连接时触发,我们将其添加到* 保存客户端连接信息的socketServers中** @param session* @param userName*/@OnOpenpublic void open(Session session,@PathParam(value="userName")String userName){this.session = session;socketServers.add(new Client(userName,session));logger.info("客户端:【{}】连接成功",userName);}/**** 收到客户端发送信息时触发* 我们将其推送给客户端(niezhiliang9595)* 其实也就是服务端本身,为了达到前端聊天效果才这么做的** @param message*/@OnMessagepublic void onMessage(String message){Client client = socketServers.stream().filter( cli -> cli.getSession() == session).collect(Collectors.toList()).get(0);sendMessage(client.getUserName()+"<--"+message,SYS_USERNAME);logger.info("客户端:【{}】发送信息:{}",client.getUserName(),message);}/**** 连接关闭触发,通过sessionId来移除* socketServers中客户端连接信息*/@OnClosepublic void onClose(){socketServers.forEach(client ->{if (client.getSession().getId().equals(session.getId())) {logger.info("客户端:【{}】断开连接",client.getUserName());socketServers.remove(client);}});}/**** 发生错误时触发* @param error*/@OnErrorpublic void onError(Throwable error) {socketServers.forEach(client ->{if (client.getSession().getId().equals(session.getId())) {socketServers.remove(client);logger.error("客户端:【{}】发生异常",client.getUserName());error.printStackTrace();}});}/**** 信息发送的方法,通过客户端的userName* 拿到其对应的session,调用信息推送的方法* @param message* @param userName*/public synchronized static void sendMessage(String message,String userName) {socketServers.forEach(client ->{if (userName.equals(client.getUserName())) {try {client.getSession().getBasicRemote().sendText(message);logger.info("服务端推送给客户端 :【{}】",client.getUserName(),message);} catch (IOException e) {e.printStackTrace();}}});}/**** 获取服务端当前客户端的连接数量,* 因为服务端本身也作为客户端接受信息,* 所以连接总数还要减去服务端* 本身的一个连接数** 这里运用三元运算符是因为客户端第一次在加载的时候* 客户端本身也没有进行连接,-1 就会出现总数为-1的情况,* 这里主要就是为了避免出现连接数为-1的情况** @return*/public synchronized static int getOnlineNum(){return socketServers.stream().filter(client -> !client.getUserName().equals(SYS_USERNAME)).collect(Collectors.toList()).size();}/**** 获取在线用户名,前端界面需要用到* @return*/public synchronized static List<String> getOnlineUsers(){List<String> onlineUsers = socketServers.stream().filter(client -> !client.getUserName().equals(SYS_USERNAME)).map(client -> client.getUserName()).collect(Collectors.toList());return onlineUsers;}/**** 信息群发,我们要排除服务端自己不接收到推送信息* 所以我们在发送的时候将服务端排除掉* @param message*/public synchronized static void sendAll(String message) {//群发,不能发送给服务端自己socketServers.stream().filter(cli -> cli.getUserName() != SYS_USERNAME).forEach(client -> {try {client.getSession().getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}});logger.info("服务端推送给所有客户端 :【{}】",message);}/**** 多个人发送给指定的几个用户* @param message* @param persons*/public synchronized static void SendMany(String message,String [] persons) {for (String userName : persons) {sendMessage(message,userName);}}
}

3.6. 控制器

package com.gblfy.websocket.controller;import com.gblfy.websocket.server.SocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.List;/*** websocket* 消息推送(个人和广播)** @Author gblfy* @Email gbly02@gmail.com* @Date 2019/11/20 PM 23:50*/
@Controller
public class WebSocketController {@Autowiredprivate SocketServer socketServer;/**** 客户端页面* @return*/@RequestMapping(value = "/index")public String idnex() {return "index";}/**** 服务端页面* @param model* @return*/@RequestMapping(value = "/admin")public String admin(Model model) {int num = socketServer.getOnlineNum();List<String> list = socketServer.getOnlineUsers();model.addAttribute("num",num);model.addAttribute("users",list);return "admin";}/*** 个人信息推送* @return*/@RequestMapping("sendmsg")@ResponseBodypublic String sendmsg(String msg, String username){//第一个参数 :msg 发送的信息内容//第二个参数为用户长连接传的用户人数String [] persons = username.split(",");SocketServer.SendMany(msg,persons);return "success";}/*** 推送给所有在线用户* @return*/@RequestMapping("sendAll")@ResponseBodypublic String sendAll(String msg){SocketServer.sendAll(msg);return "success";}
}

3.7. SpringBoot入口类

package com.gblfy.websocket;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** SpringBoot 启动器入口*/
@SpringBootApplication
public class SpringBootWebSocketApplication {public static void main(String[] args) {SpringApplication.run(SpringBootWebSocketApplication.class,args);}
}

四、初始化页面总览

4.1. 服务端

4.2. 客户端A

4.3. 客户端B

4.4. 客户端C

五、案例实战

5.1. 客户端A连接服务端

5.2. 客户端B连接服务端

5.3. 客户端C连接服务端

5.4. 服务端连接状态ABC

六、单独发送信息

6.1. 服务端给指定客户端A发送消息

6.2. 验证客户端A消息是否收到

七、群发信息

7.1. 给在线客户端群发消息

7.2. 客户端A 消息验证

7.2. 客户端B 消息验证

7.3. 客户端C 消息验证


从以上图中可以看出,测试符合预期。

项目源码:https://github.com/gb-heima/springboot-websocket

zip包下载链接:
https://github.com/gb-heima/springboot-websocket/archive/master.zip

SpringBoot2.x 整合websocket 消息推送,单独发送信息,群发信息相关推荐

  1. java socket 推送机制_Java中websocket消息推送的实现代码

    一.服务层 package com.demo.websocket; import java.io.IOException; import java.util.Iterator; import java ...

  2. node.js Websocket消息推送---GoEasy

    Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送速度快,代码简单易懂上手快 浏览器兼容性:GoEasy推送支持websocket 和 ...

  3. GO实现websocket消息推送

    在慕课网学习了GO实现websocket消息推送,这边记录一下 依赖包: go get github.com/gorilla/websocket 然后是一个connection包 package im ...

  4. Java版WebSocket消息推送系统搭建

    Java版WebSocket消息推送系统搭建 最近在做消息推送,网上查了一些资料,开始想的是用MQ来做,后面发现用WebSocket来做的话感觉应该要简单点,话不多说,准备撸代码. 后端核心代码 /* ...

  5. WebSocket消息推送和聊天功能实现

    WebSocket消息推送 SpringBoot集成WebSocket实现消息推送和聊天Demo gradle引入依赖 测试用的Controller 两个测试页面 WebSocket的Endpoint ...

  6. java/web/springboot项目使用WebSocket消息推送

    java/web/springboot项目使用WebSocket消息推送 最近项目中,有消息推送的广播和在线咨询的功能,以前也没搞过啊,有些小伙伴估计也是,那肯定要赶紧学习起来啊~ 不说废话,今天就告 ...

  7. EasyGBS国标平台新增WebSocket消息推送,可快速定位视频播放故障

    WebSocket是建立在TCP之上的一种双向通信协议,它能实现浏览器与服务器全双工通信,在性能上具有较强的优势.尤其是在海量并发及客户端与服务器交互负载流量大的情况下,WebSocket可以极大节省 ...

  8. 微信小程序使用swoole实现websocket消息推送

    swoole我个人建议在linux环境下操作,毕竟在windows下有那么一点点麻烦.首先linux安装php和swoole环境(有手就行,建议百度). 因为我们的业务是实现消息推送,也就是在完成特定 ...

  9. 千万级WebSocket消息推送服务技术分析

    拉模式和推模式区别 拉模式(定时轮询访问接口获取数据) 数据更新频率低,则大多数的数据请求时无效的 在线用户数量多,则服务端的查询负载很高 定时轮询拉取,无法满足时效性要求 推模式(向客户端进行数据的 ...

最新文章

  1. 2021年大数据Flink(三十二):​​​​​​​Table与SQL案例准备 API
  2. TSPL学习笔记(1)
  3. python实战===图片转换为字符的源码(转)
  4. echarts 表格与 div 之间 空白的设置
  5. 容器底层实现技术Namespace/Cgroup
  6. android menu item 显示,Android 如何通过menu id来得到menu item 控件 .
  7. C++ STL标准模板库
  8. 悟空问答 模板 html,悟空问答上首页技巧每小时2500个阅读快速为自己吸粉.pdf
  9. 深度图像配准_【阅读笔记】深度学习在医学图像分析领域的综述
  10. 【图像分割】基于matlab粒子群优化指数熵图像分割【含Matlab源码 287期】
  11. 发现一个导致Arduino无法打开串口监视器问题
  12. 字体加密woff(@font-face)防爬-学习记录
  13. 二维六点对称格式matlab,热传导方程求解的程序
  14. 如何使用Mediawiki搭建个人wiki系统、以及wiki的部分基本操作和设置
  15. 努比亚 N1 (Nubia NX541J) 解锁BootLoader 并刷入recovery
  16. 新书推荐 | 供应链质量防线:供应商质量管理的策略、方法与实践
  17. Android Studio完成简单UI设计
  18. 笔记本 服务器 性能,笔记本CPU性能天梯图2021最新6月
  19. 如何把EAN13码外观设置和code128码一样
  20. UI设计都有哪些分类,UI设计岗位哪个更好

热门文章

  1. 浙江省二级计算机vfp,浙江省计算机2级vfp程序调试真题集.doc
  2. pupload 文件分块 php,基于Plupload实现Base64分割的文件上传方案
  3. 在模糊查询中怎样事先加载页面_8种信息类型,中后台产品功能自查清单
  4. linux动态库查找路径以及依赖关系梳理
  5. 多线程笔记补充之线程通信wait和notify方法以及Lock和Condition接口的使用
  6. 语音识别学习日志 2019-7-17 语音识别基础知识准备6 {维特比算法(Viterbi Algorithm)}
  7. 浏览器多代理配置 - SwitchyOmega
  8. 汽车之家:基于 Flink + Iceberg 的湖仓一体架构实践
  9. 傅奎:十年安全路,一颗好奇心
  10. F1 Query: Declarative Querying at Scale