上一篇:深夜看了张一鸣的微博,让我越想越后怕

在一次项目开发中,使用到了Netty 网络应用框架,以及 MQTT 进行消息数据的收发,这其中需要后台来将获取到的消息主动推送给前端,于是就使用到了MQTT,特此记录一下。

一、什么是websocket?

WebSocket 协议是基于 TCP 的一种新的网络协议。

它实现了客户端与服务器之间的全双工通信,学过计算机网络都知道,既然是全双工,就说明了服务器可以主动发送信息给客户端

这与我们的推送技术或者是多人在线聊天的功能不谋而合。

为什么不使用 HTTP 协议呢?

这是因为HTTP是单工通信,通信只能由客户端发起,客户端请求一下,服务器处理一下,这就太麻烦了。

于是 websocket 应运而生。

下面我们就直接开始使用 Spring Boot 开始整合。以下案例都在我自己的电脑上测试成功,你可以根据自己的功能进行修改即可。

我的项目结构如下:

二、使用步骤

1.添加依赖

Maven 依赖:

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

2.启用Springboot对WebSocket的支持

启用 WebSocket 的支持也是很简单,几句代码搞定。Spring Boot 最新教程推荐看这个:https://github.com/javastacks/spring-boot-best-practice

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/*** @ Auther: 马超伟* @ Date: 2020/06/16/14:35* @ Description: 开启WebSocket支持*/
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

3.核心配置:WebSocketServer

因为 Web Socket 是类似客户端服务端的形式(采用 ws 协议),那么这里的 WebSocketServer 其实就相当于一个 ws 协议的 Controller。

@ServerEndpoint 注解这是一个类层次的注解,它的功能主要是将目前的类定义成一个 websocket 服务器端。注解的值将被用于监听用户连接的终端访问 URL 地址,客户端可以通过这个 URL 来连接到 WebSocket 服务器端

再新建一个 ConcurrentHashMap webSocketMap 用于接收当前 userId 的 WebSocket,方便传递之间对 userId 进行推送消息。

下面是具体业务代码:

package cc.mrbird.febs.external.webScoket;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;/*** Created with IntelliJ IDEA.* @ Auther: 马超伟* @ Date: 2020/06/16/14:35* @ Description:* @ ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,* 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端*/
@Component
@Slf4j
@Service
@ServerEndpoint("/api/websocket/{sid}")
public class WebSocketServer {//当前在线连接数private static int onlineCount = 0;//存放每个客户端对应的MyWebSocket对象private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();private Session session;//接收sidprivate String sid = "";/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("sid") String sid) {this.session = session;webSocketSet.add(this);     //加入set中this.sid = sid;addOnlineCount();           //在线数加1try {sendMessage("conn_success");log.info("有新窗口开始监听:" + sid + ",当前在线人数为:" + getOnlineCount());} catch (IOException e) {log.error("websocket IO Exception");}}/*** 连接关闭调用的方法*/@OnClosepublic void onClose() {webSocketSet.remove(this);  //从set中删除subOnlineCount();           //在线数减1log.info("释放的sid为:"+sid);log.info("有一连接关闭!当前在线人数为" + getOnlineCount());}/*** 收到客户端消息后调用的方法* @ Param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) {log.info("收到来自窗口" + sid + "的信息:" + message);//群发消息for (WebSocketServer item : webSocketSet) {try {item.sendMessage(message);} catch (IOException e) {e.printStackTrace();}}}/*** @ Param session* @ Param error*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("发生错误");error.printStackTrace();}/*** 实现服务器主动推送*/public void sendMessage(String message) throws IOException {this.session.getBasicRemote().sendText(message);}/*** 群发自定义消息*/public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {log.info("推送消息到窗口" + sid + ",推送内容:" + message);for (WebSocketServer item : webSocketSet) {try {//为null则全部推送if (sid == null) {
//                    item.sendMessage(message);} else if (item.sid.equals(sid)) {item.sendMessage(message);}} catch (IOException e) {continue;}}}public static synchronized int getOnlineCount() {return onlineCount;}public static synchronized void addOnlineCount() {WebSocketServer.onlineCount++;}public static synchronized void subOnlineCount() {WebSocketServer.onlineCount--;}public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {return webSocketSet;}
}

4.测试Controller

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;import java.io.IOException;
import java.util.HashMap;
import java.util.Map;/*** Created with IntelliJ IDEA.** @ Auther: 马超伟* @ Date: 2020/06/16/14:38* @ Description:*/
@Controller("web_Scoket_system")
@RequestMapping("/api/socket")
public class SystemController {//页面请求@GetMapping("/index/{userId}")public ModelAndView socket(@PathVariable String userId) {ModelAndView mav = new ModelAndView("/socket1");mav.addObject("userId", userId);return mav;}//推送数据接口@ResponseBody@RequestMapping("/socket/push/{cid}")public Map pushToWeb(@PathVariable String cid, String message) {Map<String,Object> result = new HashMap<>();try {WebSocketServer.sendInfo(message, cid);result.put("code", cid);result.put("msg", message);} catch (IOException e) {e.printStackTrace();}return result;}
}

5.测试页面index.html

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Java 后端 WebSocket 的 Tomcat 实现</title><script type="text/javascript" src="js/jquery.min.js"></script></head><body><div id="main" style="width: 1200px;height:800px;"></div>Welcome<br/><input id="text" type="text" /><button onclick="send()">发送消息</button><hr/><button onclick="closeWebSocket()">关闭WebSocket连接</button><hr/><div id="message"></div></body><script type="text/javascript">var websocket = null;//判断当前浏览器是否支持WebSocketif('WebSocket' in window) {websocket = new WebSocket("ws://192.168.100.196:8082/api/websocket/100");} else {alert('当前浏览器 Not support websocket')}//连接发生错误回调方法websocket.onerror = function() {setMessageInnerHTML("WebSocket连接发生错误");};//连接成功建立回调方法websocket.onopen = function() {setMessageInnerHTML("WebSocket连接成功");}var U01data, Uidata, Usdata//接收消息回调方法websocket.onmessage = function(event) {console.log(event);setMessageInnerHTML(event);setechart()}//连接关闭回调方法websocket.onclose = function() {setMessageInnerHTML("WebSocket连接关闭");}//监听窗口关闭事件window.onbeforeunload = function() {closeWebSocket();}//将消息显示在网页上function setMessageInnerHTML(innerHTML) {document.getElementById('message').innerHTML += innerHTML + '<br/>';}//关闭WebSocket连接function closeWebSocket() {websocket.close();}//发送消息function send() {var message = document.getElementById('text').value;websocket.send('{"msg":"' + message + '"}');setMessageInnerHTML(message + "
");}</script></html>

6.结果展示

后台:

如果有连接请求

前台显示:

总结

这中间我遇到一个问题,就是说 WebSocket 启动的时候优先于 spring 容器,从而导致在 WebSocketServer 中调用业务Service会报空指针异常。

所以需要在 WebSocketServer 中将所需要用到的 service 给静态初始化一下:

如图所示:

还需要做如下配置:

原文:blog.csdn.net/MacWx/article/details/111319558

感谢您的阅读,也欢迎您发表关于这篇文章的任何建议,关注我,技术不迷茫!小编到你上高速。

· END ·

最后,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Java 系列面试题和答案,非常齐全。

正文结束

推荐阅读 ↓↓↓

1.不认命,从10年流水线工人,到谷歌上班的程序媛,一位湖南妹子的励志故事

2.如何才能成为优秀的架构师?

3.从零开始搭建创业公司后台技术栈

4.程序员一般可以从什么平台接私活?

5.37岁程序员被裁,120天没找到工作,无奈去小公司,结果懵了...

6.IntelliJ IDEA 2019.3 首个最新访问版本发布,新特性抢先看

7.漫画:程序员相亲图鉴,笑屎我了~

8.15张图看懂瞎忙和高效的区别!

一个人学习、工作很迷茫?

点击「阅读原文」加入我们的小圈子!

Spring Boot 集成 WebSocket,轻松实现信息推送!相关推荐

  1. spring boot 集成 websocket 实现消息主动推送

    前言 http协议是无状态协议,每次请求都不知道前面发生了什么,而且只可以由浏览器端请求服务器端,而不能由服务器去主动通知浏览器端,是单向的,在很多场景就不适合,比如实时的推送,消息通知或者股票等信息 ...

  2. SpringBoot2.x系列教程(四十五)Spring Boot集成WebSocket实现技术交流群功能

    在上篇文章中,我们了解了WebSocket的基本功能及相关概念.本篇文章中我们以具体的实例来演示,在Spring Boot中整合WebSocket,同时实现一个场景的业务场景功能. 针对在Spring ...

  3. Spring Boot 集成 WebSocket通信信息推送!

    一.什么是websocket? WebSocket 协议是基于 TCP 的一种新的网络协议. 它实现了客户端与服务器之间的全双工通信,学过计算机网络都知道,既然是全双工,就说明了服务器可以主动发送信息 ...

  4. java websocket注解_【websocket】spring boot 集成 websocket 的四种方式

    集成 websocket 的四种方案 1. 原生注解 pom.xml org.springframework.boot spring-boot-starter-websocket WebSocketC ...

  5. SpringBoot 集成 WebSocket 实现消息群发推送

    一. 什么是 WebSocket WebSocket 是一种全新的协议.它将 TCP 的 Socket(套接字)应用在了web page上,从而使通信双方建立起一个保持在活动状态的连接通道,并且属于全 ...

  6. Spring Boot入门教程(五十三): 极光推送Java-SDK

    pom.xml <!-- 极光推送 begin --> <dependency><groupId>cn.jpush.api</groupId><a ...

  7. Spring Boot进阶之Web进阶 代码推送的github上面去

    还是搜狗的输入法比较好 Exception.class  上面开不见的部分是这里的 代码上次github上面去保存起来 https://github.com/yangjiabinylg/girl2 h ...

  8. spring boot 集成socketIo 做消息推送

    spring boot 集成socketIo 做消息推送 项目需求 代码展示 客户端代码 服务端代码 项目需求 后台管理系统用户小铃铛,消息推送功能并展示有多少条消息或者小红点 代码展示 客户端代码 ...

  9. Spring Boot 集成 Druid 监控数据源

    关注"Java后端技术全栈" 回复"面试"获取全套大厂面试资料 Druid 介绍 Druid 是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池.插件框架和 ...

  10. Spring Boot教程(十六):Spring Boot集成shiro

    Apache Shiro™是一个功能强大且易于使用的Java安全框架,可执行身份验证,授权,加密和会话管理.借助Shiro易于理解的API,您可以快速轻松地保护任何应用程序 - 从最小的移动应用程序到 ...

最新文章

  1. 成为优秀高级程序员的10个要点(转)
  2. JPA基础(一):全面阐释和精彩总结JPA
  3. 苹果回应中情局攻击事件:许多漏洞已经得到解决
  4. 后盾网lavarel视频项目---页面post方式提交之后动态弹出错误信息
  5. NOJ37 回文字符串---整理一下都是各种回文类型啊,
  6. 微软面试题目(一) 计算两个日期之间的天数
  7. do { ....} while(0) 在宏里冗余的意义
  8. CSS3中的display:grid网格布局介绍
  9. 第 5-6 课:Java 并发包中的高级同步工具 + 面试题
  10. JavaScript:综合案例---房贷计算器的实现
  11. csv数据源的创建(一)
  12. Android 设计模式:(一)策略模式 —— 封装行为的大局观
  13. 学习日记| javaScript在网页绘制国际象棋盘
  14. Java全栈工程实践
  15. 区块链学习笔记20——权益证明
  16. My Seventy-seventh Page - 零钱兑换 - By Nicolas
  17. vmware虚拟机连不上服务器,VMware虚拟机nat模式连不上网怎么办
  18. 绿城离职员工万言书全文,不看你后悔!当今很少有此类文言文!
  19. 面试技巧: 轻松过关10种方法
  20. 教你如何微信公众号图文中怎么下载封面图

热门文章

  1. vscode调试typescript
  2. SQL语句中AND OR运算符优先级
  3. ASP.NET MVC 解析模板生成静态页一(RazorEngine)
  4. Spring Cloud实战(六)-Spring Cloud Netflix Bus
  5. Postfix 电子邮件系统精要
  6. 《vSphere性能设计:性能密集场景下CPU、内存、存储及网络的最佳设计实践》一1.1.4 从默认值开始...
  7. React源码剖析系列 - 玩转 React Transition
  8. html的meta标签的作用
  9. angular之service、factory预provider区别
  10. 并查集详细讲解(转载) 模板